I have an Android app that uses OkHttp to send Requests to various HTTP 1.1 servers.
The Problem
It works in almost all cases, but will eventually time out for one server that does not separate the status line and message body with a CRLF line break. Reviewing the intermediate response, it appears OkHttp is interpreting the message body as a list of headers.
The message body will always start with a D3 ASCII character. Is it possible to get OkHttp to treat a "header" that starts with this character as the response body?
Tried
I tried using an Interceptor that manually sends the request to the socket and reads from the socket until CRLF or D3 is received (also collecting the StatusLine and headers). But OkHttp requires Chain.proceed() to be called (which duplicates the request).
Unpleasant Solution
My goal is to solve this with a Call. If that is impossible, it appears my only option would be to get a socket manually from the Socket factory, send the request, and manually parse the response.
Really would rather not reinvent the wheel. Any other solutions would be greatly appreciated.
CodePudding user response:
Never found a way to fix this directly with OkHttp. Thankfully, it accepts a SocketFactory. What I had to do was:
- Add a socket factory.
- Which created a custom socket.
- Which had a custom FilteredInputStream that overrides all read methods.
- Each read method calls the super read method and modifies the bytes.
- If
(byte)0xD6
is encountered before the first two CRLF pairs, it is replaced by CR. Then LF and D6 are buffered or appended to the result (depending on the method call).
You can't sadly just override read()
. read(byte[] b, int off, int len)
is also called (the parent implementation does not call read()
).
This fixes the request structure, allowing it to be parsed by OkHttp, so the framework can still be taken advantage of and the request does not need to be sent directly.