Bob
Bob

Reputation: 41

Overwrite HOST header in okhttp request

I am using okhttp to send some http request from my Android APK. Due to some server-side proxy requirement, I would like the url endpoint to be like: "https://api.example.com", however in the http request, I would like to overwrite the HOST header to be "Host: proxy.example.com". I tried to use something like:

    HttpUrl url = new HttpUrl.Builder()
      .scheme("https")
      .host("api.example.com")
      .build();

    okhttprequest = new com.squareup.okhttp.Request.Builder()
      .url(url)
      .method("GET", requestBody)
      .header("Host", "proxy.example.com")
      .build();

    response = mOkHttpClient.newCall(okhttprequest).execute();

However, when I looked into the http request in the network packages, the HOST header was still "api.example.com". Just wonder, any advice that I can actually overwrite the HOST header? Thanks a lot!

Upvotes: 4

Views: 7757

Answers (2)

fiver
fiver

Reputation: 191

I had a similar problem. This is how I applied to your case:

import javax.net.ssl.HttpsURLConnection;
import okhttp3.Dns;
import okhttp3.OkHttpClient;

OkHttpClient mOkHttpClient= new OkHttpClient.Builder()
            .dns(hostname -> {
                if(hostname.equals("proxy.example.com"))
                    hostname = "api.example.com";
                return Dns.SYSTEM.lookup(hostname);
            })
            .hostnameVerifier((hostname, session) -> {
                if(hostname.equals("proxy.example.com"))
                    return true;
                return HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session);
            }).build();

Then update your code like this:

  HttpUrl url = new HttpUrl.Builder()
      .scheme("https")
      //.host("api.example.com") don't use this host
      .host("proxy.example.com") // use the one in the host header
      .build();

okhttprequest = new com.squareup.okhttp.Request.Builder()
  .url(url)
  .method("GET", requestBody)
  //.header("Host", "proxy.example.com") don't need anymore
  .build();

response = mOkHttpClient.newCall(okhttprequest).execute();

Here what the problem is and how this solution works:

You want 'proxy.example.com' in your host header but okhttp also creates this header with what it finds in the given URL which is 'api.example.com' in your case.

I couldn't find a way to prevent okhttp from doing this. Another way exists.

We use 'proxy.example.com' in the URL so that the host header created by okhttp will be 'host: proxy.example.com' then we also add a special case for DNS lookup.

During the DNS resolution of 'proxy.example.com' we change the host as 'api.example.com' so that your request will go to the server with the IP address pointed by 'api.example.com'.

This creates a side effect. The certificate returned by your server will include the name 'api.example.com' and since the host in the URL is 'proxy.example.com', hostname verification will fail.

To prevent this, we add a special case for the verification of 'proxy.example.com' and we return true if the hostname is 'proxy.example.com' during verification.

'

Upvotes: 1

Jesse Wilson
Jesse Wilson

Reputation: 40623

By default OkHttp won’t let you set a host header that’s different from the URL’s host. You can hack it by using a network interceptor that sets the host header.

Upvotes: 0

Related Questions