How can I override the "Host" header in the request when using Apache commons HttpClient
Asked Answered
R

4

13

I am using Jakarta Commons HttpClient 3.1 writing a load test tool that needs to target different servers and pretend like it targeted the correct virtual host in the HTTP server. For that I need to be able to set the "Host" HTTP header in the request to a different host name then the actual host name that I'm connecting to.

It seemed pretty obvious that I should use Method.setRequestHeader("Host","fakehostname"), but HttpClient just ignores this and always sends the real host name I'm connecting to in the "Host" header (I've enabled debug logging for "httpclient.wire" and I can it does this specifically).

How can I override the header so that HttpClient takes heed?

Roa answered 18/5, 2011 at 13:57 Comment(0)
R
16

After searching some more, and taking a hint from Oleg's answer, I've found the method HttpMethodParams::setVirtualHost().

when HttpClient formats a request, it always creates the "Host" header itself just before sending the request - so it cannot be overridden as a standard header. But before the host name for the "Host" header is generated from the URL, HttpClient checks the HttpMethodParams object to see if the user wants to override the host name. This only overrides the host name and not the port so it would be easier to use, though not as intuitive as I'd like.

The code to use this can look like this:

Method m = new GetMethod("http://some-site/some/path");
m.getParams().setVirtualHost("some-other-site");
client.executeMethod(m);

Because I like one liners, this can also be written as:

client.executeMethod(new GetMethod("http://some-site/some/path") {{
    getParams().setVirtualHost("some-other-site"); }});
Roa answered 20/5, 2011 at 18:29 Comment(0)
A
4

I believe you want http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/HttpHost.html: this lets you configure the host for a specific connection. If I understand it correctly, you can either use the execute method (see http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/client/AbstractHttpClient.html#execute(org.apache.http.HttpHost,%20org.apache.http.HttpRequest)) and pass it a custom HttpHost object, or do this:

  1. Construct an HttpHost instance, passing it your Host header.
  2. Use that to create an HttpRoute instance (see http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/conn/routing/HttpRoute.html)
  3. Pass that to the connection manager when you request a connection (see http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/conn/ClientConnectionManager.html#requestConnection(org.apache.http.conn.routing.HttpRoute,%20java.lang.Object)).
  4. Use the connection with your method: see http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html for more details.

Let me know how that works.

EDIT: principle remains the same. 1. Construct an HttpHost instance, passing it your Host header (see http://hc.apache.org/httpclient-legacy/apidocs/index.html?org/apache/commons/httpclient/HttpHost.html). 2. Create an HttpConfiguration instance and then pass it the HttpHost you created (see http://hc.apache.org/httpclient-legacy/apidocs/index.html?org/apache/commons/httpclient/HostConfiguration.html). 3. Use the execute method on HttpClient with that configuration (see http://hc.apache.org/httpclient-legacy/apidocs/org/apache/commons/httpclient/HttpClient.html#executeMethod(org.apache.commons.httpclient.HostConfiguration,%20org.apache.commons.httpclient.HttpMethod))

Arboriculture answered 18/5, 2011 at 14:38 Comment(1)
I'm using HttpClient 3.1, not HttpComponents. Sorry I didn't mention that before. I've edited my question to make it more clear.Roa
C
3

Following works on android:

System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
InputStream stream_content=null;
try
   {URL url=new URL("http://74.125.28.103/");
    HttpURLConnection conn=(HttpURLConnection)url.openConnection();
    conn.setDoOutput(true);
    conn.setRequestMethod("GET");
    conn.setRequestProperty("Host", "www.google.com");
    stream_content=conn.getInputStream();
   }
catch (Exception e) {}

for https url:

System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
InputStream stream_content=null;
try
   {URL url=new URL("https://74.125.28.103/");
    HttpsURLConnection conn=(HttpsURLConnection)url.openConnection();
    conn.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER );
    conn.setDoOutput(true);
    conn.setRequestMethod("GET");
    conn.setRequestProperty("Host", "www.google.com");
    stream_content=conn.getInputStream();
   }
catch (Exception e) {}
Coligny answered 21/8, 2013 at 5:59 Comment(1)
This solution is using the Java built-in HTTP client (see the sun.net.http name space of the property) and I'd expect it to work on all Java implementations - though it is not useful to me as I'm using Apache's commons HTTP client.Roa
Q
2

One can use the 'http.virtual-host' parameter in order to force an arbitrary (virtual) hostname and port as a value of the Host request header instead of those derived from the actual request URI. This works with the 4.x API only, though.

Quill answered 18/5, 2011 at 15:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.