[
https://issues.apache.org/jira/browse/CAMEL-25757?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Work on CAMEL-25757 started by shashank.
----------------------------------------
> camel-azure-files - resumeDownload never completes an interrupted download:
> the 206 Partial Content answer to the ranged download is taken as a failure,
> and the file is then never routed
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-25757
> URL: https://issues.apache.org/jira/browse/CAMEL-25757
> Project: Camel
> Issue Type: Bug
> Components: camel-azure
> Reporter: shashank
> Assignee: shashank
> Priority: Major
>
> With {{resumeDownload=true}} and a {{localWorkDirectory}}, an interrupted
> download leaves {{<name>.inprogress}} in the local work directory. On the
> next poll {{FilesOperations.retrieveFileToFileInLocalWorkDirectory}} (main
> ddca15435112, lines 376-387) asks the file service for the rest of the file
> and accepts only 200:
> {code:java}
> ShareFileRange range = new ShareFileRange(0);
> if (resumeDownload && existingSize > 0) {
> range = new ShareFileRange(existingSize);
> }
> var ret = cwd().getFileClient(remoteName).downloadWithResponse(os, range,
> null, endpoint.getDataTimeout(), Context.NONE);
> result = ret.getStatusCode() == HTTP_OK;
> {code}
> With a range that does not start at 0 the SDK sends {{x-ms-range:
> bytes=<existingSize>-}} ({{ShareFileRange.toHeaderValue()}}), and Azure Files
> answers a ranged Get File with *206 Partial Content*. The Azure Files REST
> reference ("Specifying the range header for FileREST operations", format
> {{bytes=startByte-}}) says: "If the offset is valid and does not exceed the
> file's total length, the request will return a status code 206 (Partial
> Content)." The SDK's generated {{FilesService.download}} also declares 200
> and 206 as the expected answers. So:
> # poll 1 after the interruption: the rest of the file is appended to
> {{<name>.inprogress}} (which now holds the whole file), but {{result}} is
> {{false}}: the file is not renamed, the consumer reports "Cannot retrieve
> file" and does not route it;
> # every later poll: the range now starts at the end of the file; the service
> answers 416 (Requested Range Not Satisfiable, as HTTP range rules give for a
> start at or after the end), the download throws, and the {{.inprogress}} file
> is kept because {{resumeDownload=true}}. (Even if the service answered such a
> range with an empty 206, it is still not 200 and the result is the same.)
> The file is never routed again, and an error is logged on every poll, until
> someone deletes the {{.inprogress}} file by hand. This is the only case
> {{resumeDownload}} exists for, so the option never works. A download without
> a range (no {{.inprogress}} file, or {{resumeDownload=false}}) is answered
> with 200 and is not affected.
> *Fix*: a 206 answer to a download whose range starts after 0 is a successful
> retrieve ({{HTTP_PARTIAL_CONTENT}} next to {{HTTP_OK}}). The status of the
> other downloads is still checked against 200 only.
> *Tests*: new {{FilesOperationsResumeDownloadTest}} (2 tests). The real
> {{FilesOperations}} and the real Azure SDK client, with an {{HttpClient}}
> that answers Get File like Azure Files (200 without a range, 206 with a range
> inside the file, 416 with a range at or after its end).
> {{resumedDownloadIsCompletedAndRenamed}}: a 4-byte {{hello.txt.inprogress}}
> of a 10-byte file; the SDK asks for {{bytes=4-}}; on main {{retrieveFile}}
> returns false ({{expected: <true> but was: <false>}}); with the fix it
> returns true and the local work file holds the 10 bytes.
> {{downloadWithoutPartialFileIsRetrieved}} (no {{.inprogress}} file) passes on
> main and with the fix; it shows that the normal download is unchanged.
> camel-azure-files unit tests: 30 run, 0 failures.
> *How it was found*: a Z3 model of the byte ranges of a resumed download
> across polls (size of the {{.inprogress}} file before each poll, remote size
> S, the status the service gives for the range, the {{result}} check, the
> rename). On the code of main the formula "the file is routed in one of the 6
> polls after an interruption at byte k" is unsatisfiable for every S > 0 and 0
> < k < S (counterexample S=2, k=1: in-progress sizes 1, 2, 2, 2, ...); with
> the fix the file is routed on the first poll and the routed size is always S.
> The JUnit test above is the evidence.
> Not changed: a {{.inprogress}} file that already holds the whole file (the
> JVM stopped after the last byte and before the rename) still gets 416 on the
> next poll; that needs a comparison with the remote size and is a separate
> case.
> *Affected*: main, camel-4.23.x, camel-4.22.x, camel-4.18.x and camel-4.14.x
> (the same lines; read, not run).
> _Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)