Okhttp: Support 307s and 308s

Created on 18 Jun 2014  Â·  25Comments  Â·  Source: square/okhttp

Does okhttp support POST'ing to redirect url returned in 301 response to a POST? We're using v1.3 right now and it does not appear to be supported?

bug

Most helpful comment

Well the reason why it doesn't follow the 307 or 308 with a POST is that OkHttp really blocks this.

The code can be found here: https://github.com/square/okhttp/blob/07309c1c7d9e296014268ebd155ebf7ef8679f6c/okhttp/src/main/java/okhttp3/internal/http/RetryAndFollowUpInterceptor.java#L290

A workaround could be:

public Response post(String url, String content) throws IOException {
        RequestBody body = RequestBody.create(PROTOCOL, content);

        Request.Builder requestBuilder = new Request.Builder().url(url).post(body);
        Request request = requestBuilder.build();
        Response response = this.client.newCall(request).execute();

        if(response.code() == 307) {
            String location = response.header("Location");
            return post(location, content);
        }

        return response;
    }

All 25 comments

What do Chrome and Firefox do? If we aren't consistent with them, we want to be.

Also, get up to date! v1.3 is ancient history.

Just tried with v1.6 and see same issue. I also saw https://github.com/square/okhttp/pull/668 which let me to believe that this might be working.

Also tried 2.0.0-RC2.

I stepped through okhttp code (in HttpEngine.followUpRequest()) and it looks like it explicitly forces a GET after getting a 301 (HTTP_MOVED_PERM) in response to a POST. Is there any known way right now to override this behaviour?

        // Redirects don't include a request body.
        Request.Builder requestBuilder = userRequest.newBuilder();
        if (HttpMethod.hasRequestBody(userRequest.method())) {
          requestBuilder.method("GET", null);
          requestBuilder.removeHeader("Transfer-Encoding");
          requestBuilder.removeHeader("Content-Length");
          requestBuilder.removeHeader("Content-Type");
        }

@joreilly what do Firefox and Chrome do for 301s?

Hi Jesse, I'm not sure what different browsers typically do. We're using OkHttp in conjunction with Retrofit to consume a REST API and need to support doing a POST to an endpoint from which we may get redirect (and want to POST same body again to redirected url). Does OkHttp support any mechanism to override current behaviour? if we could at least call something like setFollowRedirects(false) we could handle this ourselves.

Just saw following very timely pull request from @MiguelLavigne (promise I didn't put him up to it :) )! This would, as mentioned, at least allow us to handle redirect ourselves.
https://github.com/square/okhttp/pull/944

What we should do is confirm that we change the request method in a way that's consistent with Firefox and Chrome for all the redirect response codes.

Chrome seems to handle 301's the same way as okhttp by performing a GET after following on, based on the code here: https://code.google.com/p/chromium/codesearch#chromium/src/net/url_request/url_request.cc&l=575

@joreilly, i think perhaps your REST API should return a 307 response on your post, see here: http://programmers.stackexchange.com/questions/99894/why-doesnt-http-have-post-redirect#99966

Thanks @neil477. Do you know if okhttp (and retrofit) support 307 right now?

@joreilly OkHttp won't automatically follow 407s. If you want to follow it manually, do this:

    String location = userResponse.header("Location");
    if (location != null) {
      URL url = new URL(userRequest.url(), location);
    }

@swankjesse would you be interested in a pr to handle 307s?

We intentionally don't handle 'em now, but I'm not completely convinced our reasoning is sound.

Sure, send a PR.

Am getting guidance that 308 (permanent redirect) is actually probably the correct code for what I'm doing. How does okhttp (and retrofit) in turn handle 308? BTW 308 was included in recent HTTP/1.1 update (http://evertpot.com/http-11-updated/).

Retrofit doesn't handle redirects at all.

Does Retrofit accepts now 307 and 308 redirection ?

No. 3xx shouldn't make it to Retrofit.

On Tue, Sep 22, 2015, 6:41 AM alaaghribi [email protected] wrote:

Does Retrofit accepts now 307 and 308 ?

—
Reply to this email directly or view it on GitHub
https://github.com/square/okhttp/issues/936#issuecomment-142243670.

I don't know why you've simply chose to disable that feature. I added setFollowRedirects into OKHttp client and pass it to RestAdapter but it's not working. Can you please give the possibility to the user to switch that feature ON or OFF ?

What feature? OkHttp follows redirects and it offers the API for enabling.

On Tue, Sep 22, 2015, 8:06 AM alaaghribi [email protected] wrote:

I don't know why you've simply chose to disable that feature. I added
setFollowRedirects into OKHttp client and pass it to RestAdapter but it's
not working. Can you please give the possibility to the user to switch that
feature ON or OFF ?

—
Reply to this email directly or view it on GitHub
https://github.com/square/okhttp/issues/936#issuecomment-142269230.

Strange, even when setting setFollowRedirects to true I do not have redirection, but I have the failure block that called with 307 Temporary Redirect response failure message. (Using Retrofit 1.9 and OKHttp 2.5)

Well the reason why it doesn't follow the 307 or 308 with a POST is that OkHttp really blocks this.

The code can be found here: https://github.com/square/okhttp/blob/07309c1c7d9e296014268ebd155ebf7ef8679f6c/okhttp/src/main/java/okhttp3/internal/http/RetryAndFollowUpInterceptor.java#L290

A workaround could be:

public Response post(String url, String content) throws IOException {
        RequestBody body = RequestBody.create(PROTOCOL, content);

        Request.Builder requestBuilder = new Request.Builder().url(url).post(body);
        Request request = requestBuilder.build();
        Response response = this.client.newCall(request).execute();

        if(response.code() == 307) {
            String location = response.header("Location");
            return post(location, content);
        }

        return response;
    }

Well the reason why it doesn't follow the 307 or 308 with a POST is that OkHttp really blocks this.

The code can be found here:

okhttp/okhttp/src/main/java/okhttp3/internal/http/RetryAndFollowUpInterceptor.java

Line 290 in 07309c1

if (!method.equals("GET") && !method.equals("HEAD")) {
A workaround could be:

public Response post(String url, String content) throws IOException {
        RequestBody body = RequestBody.create(PROTOCOL, content);

        Request.Builder requestBuilder = new Request.Builder().url(url).post(body);
        Request request = requestBuilder.build();
        Response response = this.client.newCall(request).execute();

        if(response.code() == 307) {
            String location = response.header("Location");
            return post(location, content);
        }

        return response;
    }

Note that you should do some sanity checking on the received location header (for example when a redirect leads to an HTTP endpoint instead of HTTPS - do you really want that? The query string or post body could contain sensitive information). Furthermore you should keep track of how many times you have been redirected and bail when exceeding for example 10 redirects, otherwise you can get stuck in an infinite loop.

Also, why was this bugreport closed? For a library abstracting the HTTP proces, this should be handled inside the library...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mleibner picture mleibner  Â·  3Comments

dannyZhou picture dannyZhou  Â·  3Comments

albka1986 picture albka1986  Â·  3Comments

SandroMachado picture SandroMachado  Â·  3Comments

vanshg picture vanshg  Â·  3Comments