fix(azure): switch to OkHttp transport to avoid Netty %2F/uppercase request-line rejection - #72
Merged
Merged
Conversation
…tion Azure SDK percent-encodes '/' in blob names as '%2F' in the request line. Reactor-netty's HttpUtil.validateRequestLineTokens rejects '%2F' in DefaultFullHttpRequest, breaking single-shot REST ops (e.g. copyFromUrl) on nested blob paths. Switching the Azure BlobServiceClient to the OkHttp HTTP transport avoids that validation while preserving all other SDK behaviour. Bump version to 2.0.2-beta. Co-Authored-By: Claude Opus 4.7 <[email protected]>
fix: Use OkHttp transport for Azure to bypass reactor-netty %2F rejection
Exclude the transitive azure-core-http-netty from azure-storage-blob and azure-identity so the SDK ships only the OkHttp HTTP transport. This removes reactor-netty entirely from the SDK classpath, eliminating any future netty validation regressions (e.g. the 4.1.129 bitmask bug where 1L << c wraps modulo 64 and rejects uppercase ASCII chars J/M/backtick as LF/CR/SPACE). Downgrade azure-core-http-okhttp 1.11.20 -> 1.11.0 to match the azure-core 1.45.0 bundled by downstream consumers (asset-enrichment fat jar in knowledge-platform-jobs). 1.11.20 calls BinaryData.writeTo(WritableByteChannel) which was added in azure-core 1.49.0 and triggers NoSuchMethodError at runtime. Co-Authored-By: Claude Opus 4.7 <[email protected]>
fix: Exclude azure-core-http-netty and align okhttp to azure-core 1.45.0
pallakartheekreddy
left a comment
Collaborator
There was a problem hiding this comment.
Overall the fix is well-researched and the root cause analysis is excellent. A few inline notes below — two are must-fix before merge (import + pom comment), the rest are recommendations.
Switch AzureStorageService to use the azure-core OkHttp async HTTP client (OkHttpAsyncHttpClientBuilder) to avoid reactor-netty's request-line validation bug that can reject percent-encoded/uppercase characters in blob names. Add and pin azure.core.http.okhttp.version to 1.11.0 in pom.xml with a comment noting newer okhttp bindings require azure-core >=1.49.0 while the build currently bundles azure-core 1.45.0.
fix: Use OkHttp transport for Azure SDK
pallakartheekreddy
approved these changes
Jun 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Azure SDK percent-encodes
/in blob names as%2Fin the HTTP request line, and Netty 4.1.108–4.1.130'sHttpUtil.isEncodingSafeStartLineTokenuses a buggy bitmask check (1L << c) that wraps modulo 64 and incorrectly rejects uppercase ASCII charactersJ(74),M(77), and backtick (96) as if they were LF / CR / SPACE. The combined effect breaksBlobClient.copyFromUrl(no-body PUT) for any blob whose name contains those characters — e.g.SCORM_API.js— withIllegalArgumentException: The URI contain illegal characters: ....This PR switches the Azure
BlobServiceClientfrom the default reactor-netty HTTP transport to OkHttp, which does not perform that validation. It also excludesazure-core-http-nettyfrom the SDK classpath so consumers do not accidentally pick reactor-netty back up.Root cause
BlobClient.getBlobUrl()and the request builder URL-encode/in blob names as%2Fin the request lineisEncodingSafeStartLineTokenbuilds a bitmask with1L << c. Java<<onlongwraps modulo 64, so'M' = 77maps to bit13(CR),'J' = 74maps to bit10(LF),'`' = 96maps to bit32(SPACE). All three trigger rejection.destBlobClient.copyFromUrl(...)→ no-bodyDefaultFullHttpRequest→ Netty validates →IllegalArgumentException: The URI contain illegal charactersProduction stack trace excerpt:
The
%2Fportion is a red herring — it is valid percent-encoding. The actual char that trips the bitmask is the uppercaseMinSCORM_API.js. Lowercasescorm_api.js(same content) passes because lowercasem(109) maps to bit45, which is not in the forbidden mask. Streaming/chunked uploads also avoid the issue because they do not useDefaultFullHttpRequest.Changes
pom.xml: addazure.core.http.okhttp.version = 1.11.0property andazure-core-http-okhttpdependencyManagemententry. Version1.11.0is intentional — it is compatible withazure-core 1.45.0bundled by downstream consumers (e.g.asset-enrichmentfat jar inknowledge-platform-jobs). Newer1.11.20callsBinaryData.writeTo(WritableByteChannel)(added in azure-core 1.49.0) and throwsNoSuchMethodErrorat runtime.cloud-storage-sdk-azure/pom.xml:azure-core-http-okhttpdependency.azure-core-http-nettyfromazure-storage-blobandazure-identityso reactor-netty is not on the SDK classpath at all.cloud-storage-sdk-azure/.../AzureStorageService.java: wire the OkHttp client on theBlobServiceClientBuilder:copyObjectitself is unchanged.2.0.1→2.0.2across parent + all modules.Verification
Integration test against dev Azure account using the exact failing SCORM snapshot (
content/scorm/do_2145843106720808961102-snapshot/) andSCORM_API.jsfilename:SCORM_API.jsSCORM_API.jsURI contain illegal characters: ...%2F...SCORM_API.js(production bug reproduced)scorm_api.js(lowercase)SCORM_API.jsSCORM_API.js.httpClient(okhttp)overrides default even when reactor-netty is presentAll existing Azure integration tests (upload, list, download, signed URLs, copy, delete, search, getPaths) continue to pass on OkHttp.
Why OkHttp vs. other workarounds
BlobClientviaBlobClientBuilder.endpoint(decodedUrl)Test plan
uploadAndList,uploadFolder,putAndGetData,downloadFile,getSignedReadUrl,getSignedWriteUrl,copyObject,deleteObject,searchObjectsByDate,getPaths,getObjectMetadata,getObjectWithPayload, etc.)SCORM_API.js(uppercase M) successfullyknowledge-platform-jobsSCORM publish end-to-end on dev withcloud-store-sdk = 2.0.2