Skip to content

Fix #2286 HTTP/2 communication may return HTTP 400#2291

Merged
carryel merged 3 commits into
eclipse-ee4j:mainfrom
11rx4f:http2_pri
Apr 23, 2026
Merged

Fix #2286 HTTP/2 communication may return HTTP 400#2291
carryel merged 3 commits into
eclipse-ee4j:mainfrom
11rx4f:http2_pri

Conversation

@11rx4f

@11rx4f 11rx4f commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Fixes the HTTP/2 connection preface validation to prevent PRI-specific validation from being executed multiple times.

Signed-off-by: 11rx4f ryosuke.okada@fujitsu.com

@11rx4f 11rx4f force-pushed the http2_pri branch 2 times, most recently from b1d3951 to 50ffc82 Compare April 15, 2026 05:26
@11rx4f 11rx4f changed the title fix the process of client connection preface FiX #2286 HTTP/2 communication may return HTTP 400 Apr 15, 2026
@11rx4f 11rx4f changed the title FiX #2286 HTTP/2 communication may return HTTP 400 Fix #2286 HTTP/2 communication may return HTTP 400 Apr 15, 2026
@carryel

carryel commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

@11rx4f Thank you for submitting the PR! Could you possibly add relevant test cases for this issue as well?

@11rx4f

11rx4f commented Apr 15, 2026

Copy link
Copy Markdown
Contributor Author

@carryel Sure, I’ll add the relevant test cases.


private Http2Session http2Session;

private volatile boolean isPriReceived;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No other field here is volatile. Why this one should be?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Additionally, have you considered putting that property into Http2Session? The reason I thought of this is that Http2Session already manages similar states, such as isPrefaceReceived.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@pzygielo I made this field volatile for better safety and visibility in a potential concurrent scenario.
Do you think it would also make sense to apply volatile to the other fields?

@carryel I did consider putting this property into Http2Session.
However, since this flag is intended to suppress PRI re-validation before the HTTP/2 session is established,
I thought it might fit more naturally in Http2State, which handles connection-phase state.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do you think it would also make sense to apply volatile to the other fields?

No. To drop it from this one.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  1. As @pzygielo mentioned, it does not need to be declared as volatile.

In contrast, Http2Session's isPrefaceReceived is declared as volatile, but this is likely due to multi-thread checks between handleRead() and handleEvent().

It seems that the newly defined Http2State's isPriReceived does not need to be declared as volatile. Cases where handleRead() is called simultaneously by multiple threads on the same connection will not occur.


final Buffer framePayload;
if (!http2Session.isHttp2InputEnabled()) { // Preface is not received yet
if (!http2Session.isHttp2InputEnabled() && !http2State.isPriReceived()) { // Preface is not received yet

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If http2State.isPriReceived() is false, wouldn't http2Session.isHttp2InputEnabled() always be false as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for pointing that out. When isPriReceived is false, isHttp2InputEnabled is also false in this implementation. They still represent different states: isPriReceived is about PRI validation completion, while isHttp2InputEnabled is about full handshake readiness.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would like to recommend two things. Please take a look at my suggestion as well.

  1. We have separated the logic for Preface received and the logic for PRI checked. Since Preface is always 'not received' if PRI is not checked, we have clearly separated these logics.
        if (!http2Session.isHttp2InputEnabled()) { // Preface is not received yet
            if (http2State.isHttpUpgradePhase()) {
                // It's plain HTTP/1.1 data coming with upgrade request
                if (httpContent.isLast()) {
                    http2State.setDirectUpgradePhase(); // expecting preface
                    enableOpReadNow(ctx);
                }
                return ctx.getInvokeAction();
            }
        }
        final Buffer framePayload;
        if (!http2State.isPriReceived()) { // PRI is not checked yet
            final HttpRequestPacket httpRequest = (HttpRequestPacket) httpHeader;

            // PRI message hasn't been checked
            try {
                if (!checkPRI(httpRequest, httpContent)) {
                    // Not enough PRI content read
                    return ctx.getStopAction(httpContent);
                }
                http2State.setPriReceived(true);
            } catch (Exception e) {
                httpRequest.getProcessingState().setError(true);
                httpRequest.getProcessingState().setKeepAlive(false);

                final HttpResponsePacket httpResponse = httpRequest.getResponse();
                httpResponse.setStatus(HttpStatus.BAD_REQUEST_400);
                ctx.write(httpResponse);
                connection.closeSilently();

                return ctx.getStopAction();
            }

            final Buffer payload = httpContent.getContent();
            framePayload = payload.split(payload.position() + PRI_PAYLOAD.length);
        } else {
            framePayload = httpContent.getContent();
        }

@11rx4f 11rx4f left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

FYI, this review was started unintentionally while replying.
Please treat the comments as regular discussion points.


private Http2Session http2Session;

private volatile boolean isPriReceived;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@pzygielo I made this field volatile for better safety and visibility in a potential concurrent scenario.
Do you think it would also make sense to apply volatile to the other fields?

@carryel I did consider putting this property into Http2Session.
However, since this flag is intended to suppress PRI re-validation before the HTTP/2 session is established,
I thought it might fit more naturally in Http2State, which handles connection-phase state.


final Buffer framePayload;
if (!http2Session.isHttp2InputEnabled()) { // Preface is not received yet
if (!http2Session.isHttp2InputEnabled() && !http2State.isPriReceived()) { // Preface is not received yet

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for pointing that out. When isPriReceived is false, isHttp2InputEnabled is also false in this implementation. They still represent different states: isPriReceived is about PRI validation completion, while isHttp2InputEnabled is about full handshake readiness.

11rx4f added 2 commits April 17, 2026 17:28
Signed-off-by: 11rx4f <ryosuke.okada@fujitsu.com>
Signed-off-by: 11rx4f <ryosuke.okada@fujitsu.com>
@11rx4f

11rx4f commented Apr 17, 2026

Copy link
Copy Markdown
Contributor Author

I’ve added the relevant test cases.

@carryel

carryel commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

I have given you two recommendations regarding the PR you submitted.
Please take another look at this.
Thanks!

Signed-off-by: 11rx4f <ryosuke.okada@fujitsu.com>
@11rx4f

11rx4f commented Apr 22, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the comments.
I’ve addressed the two points you mentioned.

@carryel carryel merged commit 42922a8 into eclipse-ee4j:main Apr 23, 2026
3 checks passed
@dmatej dmatej added this to the 5.0.1 milestone Apr 28, 2026
@11rx4f 11rx4f deleted the http2_pri branch May 4, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HTTP/2 communication may return HTTP 400

4 participants