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

Jetty 12: Looking for a way to abruptly finish a request, similar to OpenResty's ngx.exit(444) #12305

Closed
paulhilliar opened this issue Sep 24, 2024 · 7 comments
Labels

Comments

@paulhilliar
Copy link

Jetty Version 12.0.9

Jetty Environment ee10

Java Version 21

Question I'm porting a HTTP 1.1/2 proxy server application from OpenResty to Jetty 12.

There is a scenario where we have already sent the response headers and possibly some of the request body, before learning that the remainder of the request is not valid.

In that scenario in OpenResty, we call ngx.exit(444) and Nginx will abruptly close the connection. This is enough of a signal to curl or OkHttp that something has gone wrong. Other HTTP clients like Apache don't notice it but hey you can't have everything.

Please can you explain how can we tell Jetty server to abruptly close the connection, similar to Nginx?

For further explanation, the scenario here is a response caching feature. The headers and body (too big to hold all in memory) from a previous request have been cached (separately) in Redis. The headers have already been read from Redis and sent back to the client. If there is a failure to read a response chunk then we want to let the client know that they can't rely on the contents of the response.

Thanks in advance

@paulhilliar paulhilliar changed the title Looking for a way to abruptly finish a request, similar to OpenResty's ngx.exit(444) Jetty 12: Looking for a way to abruptly finish a request, similar to OpenResty's ngx.exit(444) Sep 24, 2024
@lorban
Copy link
Contributor

lorban commented Sep 24, 2024

Since Jetty 12.0.13 you can do:

  • when using the servlet API, call HttpServletResponse.sendError(-1).
  • when using the core API, call Callback.failed(new Request.Handler.AbortException()) onto the callback passed to handle().

Let us know if this does what you're looking for.

@paulhilliar
Copy link
Author

Thanks for the suggestion.
I upgraded to 12.0.13 and am calling HttpServletResponse.sendError(-1); but Jetty is still closing the connection 'politely'.

I can compare the same test scenario with nginx via curl and I get

curl -k -v --http1.1 https://localhost:64881/dep/large-response
.....

GET /dep/large-response HTTP/1.1
Host: localhost:64881
User-Agent: curl/8.7.1
Accept: /

  • Request completely sent off
  • Empty reply from server
  • Closing connection
    curl: (52) Empty reply from server

On Jetty 12.0.13
curl -k -v --http1.1 https://localhost:64724/dep/large-response
.....
< HTTP/1.1 200 OK
< Date: Tue, 24 Sep 2024 14:04:46 GMT
< Strict-Transport-Security: max-age=31536000
< Server: Oracle API Gateway
< X-Frame-Options: sameorigin
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Opc-Request-Id: /987135FED6D045E599BE2F5ED99513BF/3A8F2C6E8A844DD1AFDCD7568C6E2E66
< X-Cache-Status: HIT
< Date: Tue, 24 Sep 2024 14:03:43 GMT
< Transfer-Encoding: chunked
<

  • Connection #0 to host localhost left intact
    foobar%

The scenario here on both sides is that the HTTP status + headers are written, then "foobar" is written to the response body and then:
On Nginx: nginx.exit(444)
On Jetty 12.0.13: httpServletResponse.sendError(-1);

The 'closing connection' response is what I'm looking for, to indicate to the client that "foobar" is actually a response body that cannot be relied upon

@joakime
Copy link
Contributor

joakime commented Sep 24, 2024

This is surprising, as PR #12206 recently attempted to restore the harsh abort behavior from Jetty 11

@sbordet
Copy link
Contributor

sbordet commented Sep 24, 2024

This is strange, we have tests that prove that sendError(-1) actually closes the EndPoint, see:

https://github.com/jetty/jetty.project/blob/jetty-12.0.13/jetty-ee10/jetty-ee10-servlet/src/test/java/org/eclipse/jetty/ee10/servlet/ErrorPageTest.java#L889

The linked test should be identical to your case: promise 10 bytes, write only 6, sendError(-1), and the client sees the response headers, the 6 bytes, and then the -1 from the socket.

@paulhilliar
Copy link
Author

Thanks both - I'll dig into the test/PR and see if I can replicate the behaviour.

@paulhilliar
Copy link
Author

I did a repo to replicate the sendError(-1) in a little embedded Jetty project. It still doesn't appear to be doing quite what I'm looking for. I'm adding nginx/OpenResty into the repo as a comparison to really dig into the differences. I'll report back with how that pans out.

@paulhilliar
Copy link
Author

Ah.... I found out my error. Turns out nginx was just buffering the response and that was why it looked like it was doing something special.

I replicated the situation both in Jetty 12.0.13 and nginx here: https://github.com/paulhilliar/jetty-terminate-connection-replication

And when you explicitly flush the response, you get the same behaviour from both Nginx's ngx.exit(444) and Jetty's HttpServletResponse.sendError(-1).

Thank you very much for your help - I'll close this question.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants