[ 
https://issues.apache.org/jira/browse/HTTPCORE-799?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Oleg Kalnichevski resolved HTTPCORE-799.
----------------------------------------
    Resolution: Fixed

> Async entity producers retain stale state after interrupted writes
> ------------------------------------------------------------------
>
>                 Key: HTTPCORE-799
>                 URL: https://issues.apache.org/jira/browse/HTTPCORE-799
>             Project: HttpComponents HttpCore
>          Issue Type: Bug
>          Components: HttpCore
>    Affects Versions: 5.4.3, 5.5-beta2
>            Reporter: Matthias
>            Priority: Major
>             Fix For: 5.4.4, 5.5-beta3
>
>          Time Spent: 40m
>  Remaining Estimate: 0h
>
> h2. Description
> Several repeatable async entity producers do not fully reset their 
> per-production state when {{releaseResources()}} is called before the current 
> production has completed.
> h3. Buffered output
> {{FileEntityProducer}}, {{PathEntityProducer}}, 
> {{AbstractCharAsyncEntityProducer}}, and {{AbstractBinAsyncEntityProducer}} 
> can retain bytes that the data channel did not accept. Although the 
> underlying source is reset for a replay, the internal staging buffer still 
> contains the unwritten tail, so those stale bytes are emitted before the 
> complete entity.
> {{StringAsyncEntityProducer}} is affected through 
> {{AbstractCharAsyncEntityProducer}}. Repeatable custom binary producers can 
> be affected through {{AbstractBinAsyncEntityProducer}}.
> For example, with content {{abcdef}}:
> # The producer reads {{abcdef}} and the data channel accepts only {{abc}}.
> # {{releaseResources()}} is called, simulating an interrupted request.
> # The same repeatable producer is used again.
> # The second production emits {{defabcdef}} instead of {{abcdef}}.
> h3. Digest state
> {{DigestingEntityProducer.releaseResources()}} delegates to the wrapped 
> producer but does not reset its {{MessageDigest}}. If the first production 
> writes {{abc}} before interruption and the replay writes {{abcdef}}, the 
> replay body can be correct while {{getDigest()}} and the {{digest}} trailer 
> contain the MD5 of {{abcabcdef}} ({{89091e2d8ada6ecb23f3d2b71fb1764b}}) 
> instead of the MD5 of {{abcdef}} ({{e80b5017098950fc58aad83c8c14978e}}).
> h2. Context
> This was exposed while testing an HTTP/2 authentication retry after a server 
> returned a {{401}} response and then reset the stream with 
> {{RST_STREAM(NO_ERROR)}}. The request producer was released mid-write and 
> reused for the retry. See 
> [HTTPCLIENT-2433|https://issues.apache.org/jira/browse/HTTPCLIENT-2433] for 
> the related HttpClient issue.
> The HttpCore problem is not specific to HTTP/2 or authentication; it can 
> occur whenever a repeatable producer is released after a partial write and 
> then reused.
> h2. Expected behavior
> Calling {{releaseResources()}} should discard pending output and reset all 
> per-production digest state. A subsequent production should emit exactly the 
> original entity, and its digest should cover only that production.
> h2. Actual behavior
> Buffered but unwritten bytes can be prepended to the next production, and 
> bytes accepted during an interrupted production can be included in the 
> replay's digest.
> h2. Affected code
> * {{org.apache.hc.core5.http.nio.entity.FileEntityProducer}}
> * {{org.apache.hc.core5.http.nio.entity.PathEntityProducer}}
> * {{org.apache.hc.core5.http.nio.entity.AbstractCharAsyncEntityProducer}} 
> (including {{StringAsyncEntityProducer}})
> * {{org.apache.hc.core5.http.nio.entity.AbstractBinAsyncEntityProducer}} (for 
> repeatable subclasses)
> * {{org.apache.hc.core5.http.nio.entity.DigestingEntityProducer}}
> The problem is present in HttpCore 5.4.3, 5.5-beta2, and the current 
> {{5.4.x}} and {{master}} branches.
> h2. Proposed fix
> Clear the internal staging buffers when the file, path, character, and binary 
> producers are released. Reset {{DigestingEntityProducer}}'s {{MessageDigest}} 
> before releasing its wrapped producer, while preserving the completed 
> {{digest}} value returned by {{getDigest()}}.
> Add regression tests that interrupt production after a partial channel write, 
> release the producer, and verify that the next production contains the 
> original entity exactly once and calculates its digest only from the replayed 
> bytes.
> Implementation: 
> [apache/httpcomponents-core#698|https://github.com/apache/httpcomponents-core/pull/698]



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to