Skip to content

Add autest to make sure H2 grace shutdown is working as intended#11046

Merged
duke8253 merged 1 commit intoapache:masterfrom
duke8253:master-h2_shutdown
Jun 26, 2024
Merged

Add autest to make sure H2 grace shutdown is working as intended#11046
duke8253 merged 1 commit intoapache:masterfrom
duke8253:master-h2_shutdown

Conversation

@duke8253
Copy link
Contributor

@duke8253 duke8253 commented Feb 7, 2024

This PR addresses a few issues:

- If a HTTP2_SESSION_EVENT_FINI is received after a HTTP2_SESSION_EVENT_SHUTDOWN_INIT, the GOAWAY frame with the correct last_stream_id isn't sent out.

  • Correctly set and remove the Connection: close header for HTTP/2 (this header is only used as a internal flag to indicate a grace shutdown is needed).
  • Initiate a grace shutdown when status is 429.
  • Add test to make sure grace shutdown is working as intended.

@duke8253 duke8253 added the HTTP/2 label Feb 7, 2024
@duke8253 duke8253 added this to the 10.0.0 milestone Feb 7, 2024
@duke8253 duke8253 requested a review from shinrich February 7, 2024 18:36
@duke8253 duke8253 self-assigned this Feb 7, 2024
// Schedule session shutdown if response header has "Connection: close",
// then remove "Connection: close" which is a protocol violation for HTTP/2.
if (!this->_send_header.is_keep_alive_set()) {
this->_send_header.field_delete(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION);
Copy link
Member

Choose a reason for hiding this comment

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

Do we really need to delete the header here? I think it (and other headers that are invalid for H2) will be deleted by VersionConverter later.

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 think it does get deleted, added that mostly for testing purpose. I'll remove that.

case VC_EVENT_INACTIVITY_TIMEOUT:
case VC_EVENT_INACTIVITY_TIMEOUT: {
if (this->connection_state.get_shutdown_state() == HTTP2_SHUTDOWN_NONE) {
this->connection_state.set_shutdown_state(HTTP2_SHUTDOWN_INITIATED, Http2ErrorCode::HTTP2_ERROR_NO_ERROR);
Copy link
Member

Choose a reason for hiding this comment

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

I may not understand the issue, but the state should not be changed directly here. It should be set by HTTP2_SESSION_EVENT_SHUTDOWN_INIT event handler. Changing the state at multiple places is going to be super confusing.

Copy link
Member

Choose a reason for hiding this comment

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

Will sending this with the SHUTDOWN_CONT event below trigger SHUTDOWN_INIT? Or are you suggesting that this case should send the SHUTDOWN_INIT event instead and rely on that flow to set the appropriate state?

Copy link
Member

Choose a reason for hiding this comment

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

I was suggesting scheduling SHUTDOWN_INIT event instead. But if canceling grace shutdown works we don't need it.

@maskit
Copy link
Member

maskit commented Feb 7, 2024

If a HTTP2_SESSION_EVENT_FINI is received after a HTTP2_SESSION_EVENT_SHUTDOWN_INIT, the GOAWAY frame with the correct last_stream_id isn't sent out.
If a HTTP/2 session timed out, no grace shutdown is triggered.

Aren't these immediate close? Why do we want to initiate grace shutdown on timeout?

@duke8253
Copy link
Contributor Author

duke8253 commented Feb 7, 2024

If a HTTP2_SESSION_EVENT_FINI is received after a HTTP2_SESSION_EVENT_SHUTDOWN_INIT, the GOAWAY frame with the correct last_stream_id isn't sent out.
If a HTTP/2 session timed out, no grace shutdown is triggered.

Aren't these immediate close? Why do we want to initiate grace shutdown on timeout?

We got a complaint from a property saying they don't have a way to determine whether a connection is closed, since the HTTP/2 doesn't have the Connection: close header, sending a GOAWAY when that happens should give them what they want.

The problem with the HTTP2_SESSION_EVENT_FINI is , if we started the grace shutdown, I think we should finish the that process even if HTTP2_SESSION_EVENT_FINI is received, since the first step is sending a GOAWAY with INT32_MAX.

About that timeout part, was doing some testing and wasn't sure whether we need that, left it in there to get some comments.

@maskit
Copy link
Member

maskit commented Feb 7, 2024

Ok, I wonder why the property can't check if the connection is closed on TCP layer, but let's leave it aside.

The RFC says:

A server that is attempting to gracefully shut down a connection SHOULD send an initial GOAWAY frame with the last stream identifier set to 231-1 and a NO_ERROR code. This signals to the client that a shutdown is imminent and that initiating further requests is prohibited. After allowing time for any in-flight stream creation (at least one round-trip time), the server MAY send another GOAWAY frame with an updated last stream identifier. This ensures that a connection can be cleanly shut down without losing requests.

and

If a connection terminates without a GOAWAY frame, the last stream identifier is effectively the highest possible stream identifier.

So, a client cannot expect a GOAWAY. A connection close without GOAWAY can happen. I don't think current behavior of ATS is wrong.

That said, the RFC also says:

An endpoint MAY send multiple GOAWAY frames if circumstances change. For instance, an endpoint that sends GOAWAY with NO_ERROR during graceful shutdown could subsequently encounter a condition that requires immediate termination of the connection. The last stream identifier from the last GOAWAY frame received indicates which streams could have been acted upon.

I'd take this as "A server can cancel graceful shutdown and send a GOAWAY without waiting for the 1 RTT of grace time, to close a connection immediately". This may be just a different way of saying what you do on this PR, but I think this is what we should do, and I'd take a different approach.

In most cases, send_goaway_frame() is called right before we schedule HTTP2_SESSION_EVENT_FINI event. So if ATS receives HTTP2_SESSION_EVENT_FINI, GOAWAY should be sent. I don't think we need to forcibly progress the shutdown process (we can simply cancel it) to send the second GOAWAY. The only exception is Http2ClientSession::do_io_close. It schedules the event without calling send_goaway_frame(). But if the event is scheduled in do_io_close, it's probably too late to send something anyway.

TLDR; Isn't canceling graceful shutdown process enough?

@duke8253 duke8253 marked this pull request as draft February 8, 2024 19:18
shutdown_cont_event->cancel();
}
this->_shutdown_cont();
}
Copy link
Member

Choose a reason for hiding this comment

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

So cleaning up the in progress shutdown events, since we just shutdown cleanly here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, since we already started a grace shutdown, I think we should finish the whole process.

Copy link
Member

Choose a reason for hiding this comment

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

I still don't get why we need to call finish_grace_shutdown() here.
When we schdule HTTP2_SESSION_EVENT_FINI, we send GOAWAY with latest_streamid_in, right? Doesn't this send an extra GOAWAY?

  • GOAWAY with the big number for graceful shutdown
  • GOAWAY with latest_streamid_in at the place we schedule HTTP2_SESSION_EVENT_FINI
  • GOAWAY with latest_streamid_in here in the HTTP2_SESSION_EVENT_FINI handler .

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because when we get a HTTP2_SESSION_EVENT_FINI we set the handler to Http2ConnectionState::state_closed, which just does shutdown_cont_event = nullptr, so the GOAWAY with latest_streamid_in never gets sent out.

Copy link
Member

Choose a reason for hiding this comment

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

We only want to send two GOAWAY frames at most, A) one with the big number, and B) one with latest_streamid_in, right?

B is sent when we schedule HTTP2_SESSION_EVENT_FINI event. For example:

this->send_goaway_frame(this->latest_streamid_in, error.code);
this->session->set_half_close_local_flag(true);
if (fini_event == nullptr) {
fini_event = this_ethread()->schedule_imm_local(static_cast<Continuation *>(this), HTTP2_SESSION_EVENT_FINI);
}

So when we reach this line, which is in HTTP2_SESSION_EVENT_FINI handler, B is already sent (or it's in the send buffer at least). Calling finish_grace_shutdown would send third GOAWAY.

Copy link
Contributor Author

@duke8253 duke8253 Jun 25, 2024

Choose a reason for hiding this comment

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

The only way we get an event HTTP2_SESSION_EVENT_SHUTDOWN_INIT is when shutdown_state == HTTP2_SHUTDOWN_NOT_INITIATED, and that is the trigger for a grace shutdown since we only schedule that event when checking for the state like this.

if (this->connection_state.get_shutdown_state() == HTTP2_SHUTDOWN_NOT_INITIATED) {
  send_connection_event(&this->connection_state, HTTP2_SESSION_EVENT_SHUTDOWN_INIT, this);
}

And from testing I've done so far, I was never able to get the second GOAWAY frame as described in the RFC when a grace shutdown is initiated, and that's why I created this PR. But I can move this->_finish_grace_shutdown(); two lines above where it is at now, since shutdown_cont_event is only scheduled during a grace shutdown. I'm also fine with adding that flag you mentioned.

Copy link
Member

@maskit maskit Jun 25, 2024

Choose a reason for hiding this comment

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

I just checked the behavior on the latest master (without the change on this PR), and I see the second GOAWAY.

Unfortunately the test was not done with ProxyVerifier but with my own tool though, I see this:

$ ./h2seq.js inactive.json |  openssl s_client -quiet -connect 127.0.0.1:8443 | ./h2res.js 
Connecting to 127.0.0.1
Can't use SSL_get_servername
depth=1 O=foo, L=Denver, ST=Colorado, C=US, CN=ca.example.com
verify error:num=19:self-signed certificate in certificate chain
verify return:1
depth=1 O=foo, L=Denver, ST=Colorado, C=US, CN=ca.example.com
verify return:1
depth=0 C=US, ST=Colorado, O=foo, CN=server.example.com
verify return:1
Seq#0 done
(node:98221) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
Seq#1 done
Seq#2 done
Seq#3 done
(node:98219) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
[Lenght: 18, Type: SETTINGS(4), Flags: 0, StreamID: 0]
 Params:
  SETTINGS_ENABLE_PUSH: 0
  SETTINGS_MAX_CONCURRENT_STREAMS: 100
  SETTINGS_MAX_HEADER_LIST_SIZE: 16383
[Lenght: 0, Type: SETTINGS(4), Flags: 1, StreamID: 0]
 Flags: ACK
[Lenght: 131, Type: HEADERS(1), Flags: 4, StreamID: 1]
 Flags: END_HEADERS
[Lenght: 9, Type: DATA(0), Flags: 1, StreamID: 1]
 Flags: END_STREAM
 Data:
Not Foun���
[Lenght: 8, Type: GOAWAY(7), Flags: 0, StreamID: 0]
 Last-Stream-ID: 2147483647
 Error Code: NO_ERROR
[Lenght: 8, Type: GOAWAY(7), Flags: 0, StreamID: 0]
 Last-Stream-ID: 1
 Error Code: NO_ERROR
^C

And this is ATS side:

[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2ConnectionState.cc:2384 (send_headers_frame)> (http2_con) [2] [1] Send HEADERS frame
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2ConnectionState.cc:2461 (send_headers_frame)> (http2_con) [2] [1] Send HEADERS frame flags: 0x4 length: 160
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2ConnectionState.cc:2165 (cancel_retransmit)> (http2_con) [2] [0] Canceling retransmitting data frames
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <HttpTunnel.cc:1035 (producer_run)> (http_tunnel) Start read vio 9 bytes
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <HttpTunnel.cc:1168 (producer_handler)> (http_tunnel) [1] producer_handler [cache read VC_EVENT_READ_COMPLETE/TS_EVENT_VCONN_READ_COMPLETE]
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <HttpTunnel.cc:1204 (producer_handler)> (http_redirect) [1] enable_redirection: [1 1 0] event: 102, state: 0
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <HttpSM.cc:3644 (tunnel_handler_cache_read)> (http) [1] [&HttpSM::tunnel_handler_cache_read, VC_EVENT_READ_COMPLETE/TS_EVENT_VCONN_READ_COMPLETE]
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2Stream.cc:802 (update_write_request)> (http2_stream) [2] [1] update_write_request parse_done=1
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2ConnectionState.cc:2292 (send_a_data_frame)> (http2_con) [2] [1] End of Data Frame
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2ConnectionState.cc:2302 (send_a_data_frame)> (http2_con) [2] [1] Send a DATA frame - peer window con: 65526 stream: 65526 payload:     9 flags: 0x1
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2ConnectionState.cc:2165 (cancel_retransmit)> (http2_con) [2] [0] Canceling retransmitting data frames
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2ConnectionState.cc:2308 (send_a_data_frame)> (http2_con) [2] [1] END_STREAM
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2Stream.cc:495 (change_state)> (http2_stream) [2] [1] Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE -> Http2StreamState::HTTP2_STREAM_STATE_CLOSED
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2ConnectionState.cc:2350 (send_data_frames)> (http2_con) [2] [1] Shutdown stream
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <HttpTunnel.cc:1375 (consumer_handler)> (http_tunnel) [1] consumer_handler [user agent VC_EVENT_WRITE_COMPLETE/TS_EVENT_VCONN_WRITE_COMPLETE]
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <HttpSM.cc:3412 (tunnel_handler_ua)> (http) [1] [&HttpSM::tunnel_handler_ua, VC_EVENT_WRITE_COMPLETE/TS_EVENT_VCONN_WRITE_COMPLETE]
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2Stream.cc:554 (do_io_close)> (http2_stream) [2] [1] do_io_close
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <HttpSM.cc:2608 (main_handler)> (http) [1] HTTP_TUNNEL_EVENT_DONE, 2301
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <HttpSM.cc:2984 (tunnel_handler)> (http) [1] [&HttpSM::tunnel_handler, HTTP_TUNNEL_EVENT_DONE]
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <HttpSM.cc:8729 (clear)> (http_redirect) [PostDataBuffers::clear]
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <HttpSM.cc:7485 (kill_this)> (http_seq) [1] Logging transaction
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2Stream.cc:83 (~Http2Stream)> (http2_stream) [2] [1] Destroy stream, sent 9 bytes, registered: true
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2ConnectionState.cc:1993 (delete_stream)> (http2_con) [2] [1] Delete stream
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <HttpSM.cc:7534 (kill_this)> (http) [1] deallocating sm
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <SSLNetVConnection.cc:310 (_ssl_read_from_net)> (ssl) amount_to_read=4024
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <SSLNetVConnection.cc:315 (_ssl_read_from_net)> (ssl) nread=0
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <SSLNetVConnection.cc:338 (_ssl_read_from_net)> (ssl.error) SSL_ERROR_WOULD_BLOCK(read)
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <SSLNetVConnection.cc:396 (_ssl_read_from_net)> (ssl) bytes_read == 0
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <SSLNetVConnection.cc:759 (net_read_io)> (ssl) read finished - would block
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2ConnectionState.cc:2700 (send_goaway_frame)> (http2_con) [2] Send GOAWAY frame: Error Code: 0, Last Stream Id: 2147483647
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <Http2ConnectionState.cc:2165 (cancel_retransmit)> (http2_con) [2] [0] Canceling retransmitting data frames
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <SSLNetVConnection.cc:814 (load_buffer_and_write)> (ssl) towrite=204
[Jun 25 10:07:11.935] [ET_NET 0] DIAG: <SSLNetVConnection.cc:870 (load_buffer_and_write)> (ssl) try_to_write=204 written=204 total_written=204
[Jun 25 10:07:13.932] [ET_NET 0] DIAG: <Http2ConnectionState.cc:2700 (send_goaway_frame)> (http2_con) [2] Send GOAWAY frame: Error Code: 0, Last Stream Id: 1
[Jun 25 10:07:13.932] [ET_NET 0] DIAG: <Http2ConnectionState.cc:2165 (cancel_retransmit)> (http2_con) [2] [0] Canceling retransmitting data frames
[Jun 25 10:07:13.932] [ET_NET 0] DIAG: <Http2CommonSession.cc:153 (set_half_close_local_flag)> (http2_cs) [2] session half-close local
[Jun 25 10:07:13.932] [ET_NET 0] DIAG: <SSLNetVConnection.cc:814 (load_buffer_and_write)> (ssl) towrite=17
[Jun 25 10:07:13.932] [ET_NET 0] DIAG: <SSLNetVConnection.cc:870 (load_buffer_and_write)> (ssl) try_to_write=17 written=17 total_written=17

inactive.json is below, if you want to try it by yourself:

[
    { "action": "send", "stream": 0, "type": "preface"},
    { "action": "send", "stream": 0, "type": "settings", "flags": "",    "settings": [] },
    { "action": "send", "stream": 0, "type": "settings", "flags": "ACK", "settings": [] },
    { "action": "send", "stream": 1, "type": "headers",  "flags": "END_HEADERS,END_STREAM", "headers": [
        [":method", "GET"],
        [":scheme", "https"],
        [":authority", "localhost"],
        [":path", "/httpbin/get"]
    ]},
    { "action": "pause", "duration": 300000 }
]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe some other changes in the past few months have fixed this in a different way then, I just checked with Proxy Verifier and it is also getting the second GOAWAY frame now. So it's your call then, do you want to add a flag to make sure the second GOAWAY gets sent during a grace shutdown, or I can remove this part of the change and just add the test to check things are working as intended.

Copy link
Member

Choose a reason for hiding this comment

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

Okay, nice. Then the current code works as I expect. I would not add the flag, because I think something is wrong if the flag has to work.

Let's just add the test. Thank you for writing the test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good.

@duke8253 duke8253 closed this Feb 13, 2024
@duke8253 duke8253 reopened this Feb 13, 2024
@duke8253
Copy link
Contributor Author

@maskit forgot to mention one thing, when doing a curl command, if no GOAWAY frame is sent, it reports connection left intact even when ATS says the H2 session is destroyed. I'm not sure that is the correct behavior, or should we even care about that?

@maskit
Copy link
Member

maskit commented Feb 14, 2024

Closing a connection without sending GOAWAY is not polite, but I don't think it's a violation. Depends on why the connection was closed.

Endpoints SHOULD always send a GOAWAY frame before closing a connection so that the remote peer can know whether a stream has been partially processed or not. For example, if an HTTP client sends a POST at the same time that a server closes a connection, the client cannot know if the server started to process that POST request if the server does not send a GOAWAY frame to indicate what streams it might have acted on.

An endpoint might choose to close a connection without sending a GOAWAY for misbehaving peers.

@duke8253 duke8253 force-pushed the master-h2_shutdown branch 2 times, most recently from 46f497d to a71a773 Compare March 18, 2024 16:17
@duke8253 duke8253 marked this pull request as ready for review March 18, 2024 16:17
void set_expect_send_trailer() override;
bool expect_receive_trailer() const override;
void set_expect_receive_trailer() override;
void set_close_connection(HTTPHdr &hdr) const override;
Copy link
Member

Choose a reason for hiding this comment

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

Unused

Copy link
Member

Choose a reason for hiding this comment

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

Ah, nvm. I just realized it's override.

Copy link
Member

Choose a reason for hiding this comment

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

Does this relay Connection header value between a request and a response? I think that should not happen.

Client <-- (H2) -- ATS <-- (H1) -- Origin

When an origin server returns Connection: close, ATS should not close the connection between the client and ATS, right? It's just the origin wants to close the connection between ATS and the origin. The client should be allowed to make another request, which can be served from the cache, on the same connection.

Copy link
Contributor Author

@duke8253 duke8253 Apr 5, 2024

Choose a reason for hiding this comment

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

This sets the Connection: close, but it doesn't decide whether the connection will be closed. HttpTransact::handle_response_keep_alive_headers actually decides whether that close will remain in the response or be removed. But before we never set it in the first place, so all the logic there does nothing for h2 connections.

heads->field_delete(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION);

It removes the connection header, and added it back if needed.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, I think I was confused by this line. It seemed like to modify a client response based on a server response, but it doesn't.

s->state_machine->get_ua_txn()->set_close_connection(*heads);

Http1Transaction and Http2Stream do the same thing in set_close_connection. It's not conditional at all. I assume Http3Transaction should do the same. Now I wonder why we don't modify the heads directly in HttpTransact. What's the reason for letting transactions to set the header? I think we should remove this confusing function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was added in #8178 , maybe at the time we had some issues with our H2 streams and this header was causing trouble?

Copy link
Member

Choose a reason for hiding this comment

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

So we are going back to the original behavior (do the same thing for H1 and H2). Are you sure you don't have the issue that was resolved by #8178, with this change?

If we don't have to to differentiate the behavior, I prefer the original code that modifies heads directly in HttpTransact.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, let me dig a bit deeper.

Copy link
Member

Choose a reason for hiding this comment

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

The intent with #8178 was to not drain the session if the HttpSM logic sets the connection close due to detected transaction failures. Shutting down the connection in HTTP/1 makes sense since the TCP connection may be polluted in the case of bad request bodies. However, this is not an issue with HTTP/2. An error with a request body should not require shutting down the session due to cross-contamination.

Explicitly setting the Connection: close header in the HTTP/2 processing logic when w want to close the session seems reasonable if it makes our client's lives easier. But blindly interpreting Connection: Close passed from the state machine processing will cause HTTP/2 sessions to shut down needlessly in some cases.

@duke8253 duke8253 force-pushed the master-h2_shutdown branch 2 times, most recently from c729304 to e187962 Compare May 1, 2024 15:35
SCOPED_MUTEX_LOCK(lock, this->session->get_mutex(), this_ethread());
this->session->set_half_close_local_flag(true);
this->_shutdown_cont();
} break;
Copy link
Member

Choose a reason for hiding this comment

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

Looks like we no longer need a scope here. Let's remove the braces.

@maskit
Copy link
Member

maskit commented Jun 4, 2024

@duke8253 What's the status of this PR? Is it ready for review?

@duke8253 duke8253 force-pushed the master-h2_shutdown branch 4 times, most recently from 99ff1fc to 64a77df Compare June 18, 2024 20:06
@JosiahWI
Copy link
Contributor

The AuTest dns_host_down failed:

file /tmp/sandbox/dns_host_down/ts/log/error.log : DNS lookup should fail - Failed
        Reason: Contents of /tmp/sandbox/dns_host_down/ts/log/error.log did not contains expression: "DNS Error: no valid server http://resolve.this.com/"
        ```

@duke8253
Copy link
Contributor Author

@maskit It's ready for another review.

@duke8253 duke8253 force-pushed the master-h2_shutdown branch from 64a77df to 44782b7 Compare June 25, 2024 18:10
@duke8253 duke8253 changed the title Make sure the grace shutdown of HTTP/2 connections are completed Add autest to make sure H2 grace shutdown is working as intended. Jun 25, 2024
@duke8253 duke8253 changed the title Add autest to make sure H2 grace shutdown is working as intended. Add autest to make sure H2 grace shutdown is working as intended Jun 25, 2024
@@ -0,0 +1,71 @@
'''
Abort HTTP/2 connection using RST_STREAM frame.
Copy link
Member

@maskit maskit Jun 25, 2024

Choose a reason for hiding this comment

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

Please update the comment and the summary (it looks like truncated).

@duke8253 duke8253 force-pushed the master-h2_shutdown branch from 44782b7 to 5784d0d Compare June 26, 2024 14:38
@duke8253 duke8253 merged commit 36bbb0e into apache:master Jun 26, 2024
@cmcfarlen
Copy link
Contributor

Cherry-picked to v10.0.x to avoid conflicts with another PR

cmcfarlen pushed a commit that referenced this pull request Jul 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: picked-10.0.0

Development

Successfully merging this pull request may close these issues.

5 participants