Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure ContentSourceTransformer.read() calls release() on fail() and never call release() more than once #12865

Open
wants to merge 5 commits into
base: jetty-12.1.x
Choose a base branch
from

Conversation

lorban
Copy link
Contributor

@lorban lorban commented Mar 5, 2025

Fixes #12855

lorban added 2 commits March 5, 2025 16:00
… called and make sure release() is only called once

Signed-off-by: Ludovic Orban <[email protected]>
Signed-off-by: Ludovic Orban <[email protected]>
@lorban lorban added the Bug For general bugs on Jetty side label Mar 5, 2025
@lorban lorban requested review from joakime and sbordet March 5, 2025 15:03
@lorban lorban self-assigned this Mar 5, 2025
@lorban lorban linked an issue Mar 5, 2025 that may be closed by this pull request
Signed-off-by: Ludovic Orban <[email protected]>
@@ -28,6 +28,7 @@ public class BrotliDecoderSource extends DecoderSource
{
private final DecoderJNI.Wrapper decoder;
private final BrotliCompression compression;
private boolean released;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary, as release() is called from ContentSourceTransformer.finish() and it is already protected from multiple invocations there.

Likewise, isReleased() could be moved to ContentSourceTransformer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added isReleased() only to test that the DecoderSource implementation received the release() call. It's not meant to be a useful API.

@@ -43,6 +43,7 @@ private enum State
private int size;
private long value;
private byte flags;
private boolean released;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as brotli.

finished = true;
release();
}
finish();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhm, so finished is only used to early return EOF.

Here we handle rawChunk failures, so I think it was wrong before that finished was set; we should just call release() and make sure it is called only once in case of multiple reads.

Perhaps rename finished to eof, finish() to terminate() and use a boolean terminated to guarantee only one call to release().

finished = true;
release();
}
finish();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here also, if terminated==true, set eof=true, but if terminalFailure==true we only need to call terminate() (see previous comment about renaming).

Comment on lines 157 to 164
needsRawRead = false;
if (rawChunk != null)
rawChunk.release();
rawChunk = Content.Chunk.from(failure, true);
if (transformedChunk != null)
transformedChunk.release();
transformedChunk = rawChunk;
finish();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be re-evaluated.
As failures are asynchronous, we want to do as little as possible here to avoid having to use a lock.
Possibly just delegating to the rawSource.

The reason is that there may be non-failed transformed content to read, and possibly the failure has been serialized in the rawSource so reading would be possible, and only eventually the failure is detected (for example a queued rawSource).

The idea was to do as little as possible, as the failure would be handled by the rawSource, and will be eventually seen via read().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember that after a call to fail(), all resources should have been released, even if you may decide to stop reading entirely.

Signed-off-by: Ludovic Orban <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug For general bugs on Jetty side
Projects
Status: 🏗 In progress
Development

Successfully merging this pull request may close these issues.

ContentSourceTransformer.read() may call release() more than once
3 participants