SocketTimeoutException using POST-Redirect-GET pattern with Retrofit and OkHttp - retrofit

I am using Retrofit 1.5.0 and OkHttp to invoke a REST POST endpoint that returns a 302 for a subsequent GET request. Using OkHttp 1.3.0 this works as expected. However, after upgrading to OkHttp 1.5.0 (or later), I receive a SocketTimeoutException even though both requests were made. My RestAdapter uses the default OkClient.
The OkHttp team recently fixed an issue (https://github.com/square/okhttp/issues/296) where the Content-Length header was being preserved from the POST request to the GET request. Looking at the code for OkHttp 1.5.2, the fix seems to be achieved by removing that header in com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getResponse() before creating the GET Request; however, if the instance field fixedContentLength is not -1, the Content-Length header is recreated in com.squareup.okhttp.internal.http.HttpURLConnectionImpl.newHttpEngine(). The fixedContentLength field is set by retrofit.client.UrlConnectionClient.prepareRequest() before the original POST request, so the upshot is that the Content-Length header is present with a positive value when the GET request is issued.
Is this a bug or am I missing something from a configuration standpoint?

Sounds like a bug to me. Report it against OkHttp's bugtracker and I'll have a fix for you very soon.

Related

One time nonce http digest authentication

I try to implement a one time none for HTTP digest authentication process. First of all I'm aware of the fact that the authentication is not perfectly secure. Please do not tell me to use something else. The authentication process is working as expected. When the user authenticate successfully I append a http Authentication-Info field with the next nonce. The browser in this case Firefox is not using this nonce for further requests.
Authentication-Info: nextnonce="06e8043d3fb8c26156829c4b55afd13040"
Why is the browser not using my new nonce for future requests? It still uses the old now invalid one!
RFC7616 describes the header field.
https://www.rfc-editor.org/rfc/rfc7616#section-3.5
The value of the nextnonce parameter is the nonce the server
wishes the client to use for a future authentication response.
The server MAY send the Authentication-Info header field with a
nextnonce field as a means of implementing one-time nonces or
otherwise changing nonces. If the nextnonce field is present, ...
RFC2617 describes the syntax in section 3.2.3
https://www.ietf.org/rfc/rfc2617.txt
[Edit]
Is it possible that firefox is not supporting this feature. If I search here
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate
for the header field I can't find a result.
But it is listed as standard header flag here:
https://www.iana.org/assignments/message-headers/message-headers.xhtml
nextnonce is not supported in Firefox, not even Authentication-Info header.
The bug "next nonce digest auth test fails" was opened 18 years ago and it's still not fixed yet.
I downloaded the source code of the latest Firefox version 65.0.1 and searched the project. "Authentication-Info" only appears in netwerk/protocol/http/nsHttpDigestAuth.cpp as a comment, nowhere else.

Akka-http POST results in "The server-side HTTP version is not supported"

I have an issue when trying to do a simple POST request to some internal endpoint using akka-http. When this piece of code is executed:
for {
request <- Marshal(merchantTransactionRequest).to[RequestEntity]
response <- Http().singleRequest(
HttpRequest(
method = HttpMethods.POST,
uri = "http://foo/bar:8080",
entity = request.withContentType(ContentTypes.`application/json`)
)
)
...
} yield ...
I get greeted with the following error:
akka.http.scaladsl.model.IllegalResponseException: The server-side HTTP version is not supported
at akka.http.impl.engine.client.OutgoingConnectionBlueprint$PrepareResponse$$anon$1.onPush(OutgoingConnectionBlueprint.scala:191)
...
which is immediately preceded by the following log:
[0] </10.0.0.135:42610->foo:8080> pushing request to connection: POST bar Strict(508 bytes)
As part of my debugging journey, I executed the same query to the endpoint using curl, which magically succeeded (and responds with HTTP/1.1). Since HttpRequest(...) defaults to using protocol = HttpProtocols.`HTTP/1.1`, it is my suspicion that somehow the HTTP version negotiated between akka-http and this other endpoint is incorrect.
Is it possible to somehow enforce a HTTP version when akka-http does a POST? Or any other clue as to why curl succeeds doing the POST, while akka-http does not? Note that problem only occurs while doing POST's, not GET's.
It turned out the problem had a very strange solution: Instead of connecting to directly connecting to the other endpoint through address http://foo/bar:8080 (using our internal DNS resolver), we connected indirectly to the endpoint using https://our-domain.com:443. Everything worked as expected in that case. It seems that akka-http is somehow troubled by the absence of a TLD.

Why does OkHttp treat the Date header the same as it treats the Last-Modified header when setting the If-Modified-Since header?

I am using a Jenkins plugin that uses the OkHttp library for handling integration with Github API.
Github's /repos/:owner/:repo endpoint returns error 404 when the OkHttp tries to requesting the resource with a token that is not allowed to access the resource. When the token's scope is expanded to allow it to access the resource, OkHttp makes the request with an If-Modified-Since header. The header's value is set to the Date header's value from the 404's response. The response from this second request is HTTP 304. According to Github's support team, this behavior is the proper behavior, since the resource (the data behind the /repos/:owner/:repo endpoint) has not been modified since the first request was made. However, this means that the OkHttp client now uses the cached 404 response.
It seems like the Date header was intended for calculating freshness, not checking when a resource was last modified. RFC 7232 section 3.3 says that clients may use the Date header's value as the If-Modified-Since value, but I have not come across other literature on the web suggesting that this behavior is accepted. I do not see any reference to the Date header in Mozilla's documentation on the If-Modified-Since header.
Wouldn't Postel's Law suggest that OkHttp should try not to misuse the Date header by using it as another source for the If-Modified-Since header?
The RFCs are definitive on what behavior is appropriate. If the RFC says that a Date header can be used with If-Modified-Since, then it can be.
Consider persuading GitHub to invalidate caches when a scope is expanded. If a response was served on 2017-03-01, and a token’s scope was expanded on 2017-04-01, then the resource was effectively modified on 2017-04-01.
Your other option is to disable OkHttp’s cache. Like every cache it violates of Postel’s Law as a consequence of honoring the directives of buggy cache configuration.

In okhttp I'd like to handle Last-Modified and ETags but without caching the whole response

I'm using okhttp and Retrofit to call a REST service. The data that is returned from that service is store in my Android app inside an sqlite database.
Whenever I call the REST api, if the data hasn't changed (determined by either ETag or Last-Modified header) I want to have the Retrofit callback do nothing (data in DB is ok). Otherwise I want to download the updated JSON from the REST service and update the database (via the onSuccess method of my callback).
The okhttp examples on caching all setup disk caches for the responses, I just need to cache/store the Etag/last-modified time of each request (and not the whole response).
Should I be doing this through a custom Cache implementation that I pass to okhttp, or is there a better interface I should be using with okhttp or Retrofit?
Once I have the implementation setup do I just need to handle the 304 "errors" in my onFailure callback and do nothing?
To know if you've got a 304 as response, in the onResponse callback you can catch it as follows:
if (response.raw().networkResponse().code() == 304){
// Do what you want to do
}
At least, this is when you are using Retrofit 2 and okHttp 3. Not sure about earlier versions, but I guess it would be kind of the same? You could always try to find a 304 response when setting breakpoints in the response.

What should be the default version if I have many versions for a REST api?

I have a REST api that will accept a version via a custom HTTP header or a request parameter. I'm doing this because I don't want the URI to contain the version like del.icio.us .e.g http://server/api/v1/...
Now in my design, the HTTP header has a higher priority than the request param.
What happens then if the user does not supply any version at all ?
Should I default to the oldest version, or default to the latest version ?
Don't version the URI at all. Instead just version the representation. This way the client can decide which version of the API they want to use and it degrades well.
Example:
GET /contacts/3 HTTP/1.1
Accept: application/myapp-v2+xml
HTTP/1.1 200 OK
Content-Type: application/myapp-v2+xml
Why not simply make the version required and throw an error if it's not there?
If that's not an option then you have to go with the oldest version, otherwise if you upgrade and don't maintain backwards compatability you'll break existing clients.
Of course, if you don't mind breaking existing clients it might be more convenient to go with the latest version.
If your API defines specific URIs or URI naming conventions for accessing resources, your API is not RESTful. Versioning of URI construction is a non-issue for any REST API. Please see http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven for more information.

Resources