jetty.project icon indicating copy to clipboard operation
jetty.project copied to clipboard

AsyncProxyServlet calls onProxyResponseSuccess() when internally it throws "Response header too large" exception

Open arshadwkhan opened this issue 4 years ago • 14 comments

Jetty version 9.4.30

Java version 8

OS type/version Mac

Description I am using embedded jetty version 9.4.30 and use AsyncProxyServlet to reverse proxy request to the server. When the server returns a very large header, AsyncProxyServlet calls onProxyResponseSuccess() with proxyResponse.status=200 even though the servlet sends http status 500 to the client. Is it possible to detect "Response header too large" error in AsyncProxyServlet ?

arshadwkhan avatar Nov 18 '20 05:11 arshadwkhan

@arshadwkhan can you attach any stack traces that you have, as that will make it easier to replicate.

gregw avatar Nov 18 '20 08:11 gregw

@gregw Attaching logs jetty.log

arshadwkhan avatar Nov 18 '20 17:11 arshadwkhan

@gregw @joakime Did you get a chance to look into this issue ? Will apprreciate your guidance on this ?

arshadwkhan avatar Nov 19 '20 18:11 arshadwkhan

@arshadwkhan not yet. Other priorities sorry.

But just to clarify the scenario:

  1. request received client->proxy
  2. request sent proxy->server
  3. response received server-> proxy with large header
  4. 200 response fails to be sent proxy->server because of header too large. 500 actually sent, but onProxyResponseSuccess is called with 200

I think this is because onProxyResponseSuccess is an event to say the proxy has successfully received the 200 from the server and probably happens prior to the forwarding of the response to the client.

How big is the response body? Would it likely overflow a buffer and cause the response to the client to be committed during transfer of the body, or is it smallish, and thus we'd only discover the too large header once the handling is over and we try to commit?

So if I'm reading this right, the code in onProxyResponseSuccess actually does an AsyncContext.complete(), so it is after that that any problem with the size of the headers in the response will be detected. Moreover that complete call does not give any mechanism to report errors... Hmmm or does it... maybe an onError could get called on the AsyncContext...

Eitherway, it is a difficult case where there error happens after the proxy app says it is finished with the request/response. We'll have to do some experiments to see. At the very least, you should be able to install a HttpChannel.Listener and see all events, including this 500 - but it would be a little separate from the proxy.

I probably wont have time to look at this in detail until next week.

gregw avatar Nov 20 '20 08:11 gregw

I think OnProxyResponseSuccess() is called after a response is committed to the client. It sends http status 500 to the client. This problem started happening after we upgraded from 9.4.27 to 9.4.30. Before the upgrade to 9.4.30 it used to call onProxyResponseFailure().

Here is the call stack when header overflow is detected.

HttpConnection:761 ==>case HEADER_OVERFLOW:
                    {
                        if (_header.capacity() >= _config.getResponseHeaderSize())
                            throw new BadMessageException(INTERNAL_SERVER_ERROR_500, "Response header too large");
                        releaseHeader();
                        _header = _bufferPool.acquire(_config.getResponseHeaderSize(), HEADER_BUFFER_DIRECT);
                        continue;
                    }

process:761, HttpConnection$SendCallback (org.eclipse.jetty.server) processing:241, IteratingCallback (org.eclipse.jetty.util) iterate:223, IteratingCallback (org.eclipse.jetty.util) send:543, HttpConnection (org.eclipse.jetty.server) sendResponse:833, HttpChannel (org.eclipse.jetty.server) write:910, HttpChannel (org.eclipse.jetty.server) channelWrite:283, HttpOutput (org.eclipse.jetty.server) access$400:60, HttpOutput (org.eclipse.jetty.server) process:1668, HttpOutput$AsyncWrite (org.eclipse.jetty.server) processing:241, IteratingCallback (org.eclipse.jetty.util) iterate:223, IteratingCallback (org.eclipse.jetty.util) write:818, HttpOutput (org.eclipse.jetty.server) onWritePossible:246, AsyncProxyServlet$StreamWriter (org.eclipse.jetty.proxy) onResponseContent:90, AsyncProxyServlet (org.eclipse.jetty.proxy) onContent:220, ProxyServlet$ProxyResponseListener (org.eclipse.jetty.proxy) onContent:189, Response$AsyncContentListener (org.eclipse.jetty.client.api) notifyContent:155, ResponseNotifier (org.eclipse.jetty.client) notifyContent:139, ResponseNotifier (org.eclipse.jetty.client) notifyContent:726, HttpReceiver$ContentListeners (org.eclipse.jetty.client) access$500:688, HttpReceiver$ContentListeners (org.eclipse.jetty.client) responseContent:409, HttpReceiver (org.eclipse.jetty.client) content:295, HttpReceiverOverHTTP (org.eclipse.jetty.client.http) parseContent:1691, HttpParser (org.eclipse.jetty.http) parseNext:1526, HttpParser (org.eclipse.jetty.http) parse:200, HttpReceiverOverHTTP (org.eclipse.jetty.client.http) process:141, HttpReceiverOverHTTP (org.eclipse.jetty.client.http) receive:75, HttpReceiverOverHTTP (org.eclipse.jetty.client.http) demand:118, HttpReceiver (org.eclipse.jetty.client) accept:-1, 342518151 (org.eclipse.jetty.client.HttpReceiver$ContentListeners$$Lambda$137) demand:734, HttpReceiver$ContentListeners (org.eclipse.jetty.client) accept:-1, 1711914035 (org.eclipse.jetty.client.HttpReceiver$ContentListeners$$Lambda$147) lambda$notifyContent$1:139, ResponseNotifier (org.eclipse.jetty.client) accept:-1, 1473556966 (org.eclipse.jetty.client.ResponseNotifier$$Lambda$148) lambda$onContent$0:192, Response$AsyncContentListener (org.eclipse.jetty.client.api) run:-1, 859920362 (org.eclipse.jetty.client.api.Response$AsyncContentListener$$Lambda$149) succeeded:129, Callback$3 (org.eclipse.jetty.util) succeeded:266, Callback$Nested (org.eclipse.jetty.util) complete:284, AsyncProxyServlet$StreamWriter (org.eclipse.jetty.proxy) onWritePossible:252, AsyncProxyServlet$StreamWriter (org.eclipse.jetty.proxy) run:1492, HttpOutput (org.eclipse.jetty.server) handle:1454, ContextHandler (org.eclipse.jetty.server.handler) handle:487, HttpChannel (org.eclipse.jetty.server) run:335, HttpChannel (org.eclipse.jetty.server) runJob:806, QueuedThreadPool (org.eclipse.jetty.util.thread) run:938, QueuedThreadPool$Runner (org.eclipse.jetty.util.thread) run:748, Thread (java.lang)

arshadwkhan avatar Nov 20 '20 19:11 arshadwkhan

@gregw any update on this issue ? This looks like a defect. Can you please confirm ?

arshadwkhan avatar Dec 10 '20 19:12 arshadwkhan

@gregw @joakime is there a way I can escalate this ? This is definitely a bug.

arshadwkhan avatar Dec 14 '20 19:12 arshadwkhan

@gregw @joakime any update on this issue. I have provided all the stack trace and logs. Let me know if you need anything else ?

arshadwkhan avatar Feb 22 '21 21:02 arshadwkhan

Sorry, we've not looked at this as we have other priorities.

joakime avatar Feb 22 '21 21:02 joakime

@joakime thanks for the update. Can you please convert this to defect ? The underlying layer eats up the error and sends http status 500 to the client but reports http status 200 to asyncservlet.

arshadwkhan avatar Feb 24 '21 19:02 arshadwkhan

This issue has been automatically marked as stale because it has been a full year without activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Feb 25 '22 00:02 github-actions[bot]

This issue has been automatically marked as stale because it has been a full year without activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Mar 03 '23 01:03 github-actions[bot]

This issue has been automatically marked as stale because it has been a full year without activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Mar 05 '24 00:03 github-actions[bot]