How to customise "host" header in Java http client
Asked Answered
V

2

19

Here's my code:

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("http://127.0.0.1:8081/"))
    .header("Host", "test.example.com")
    .build();
client.send(request, HttpResponse.BodyHandlers.ofString());

As a result I see that the above code sends:

GET / HTTP/1.1
Connection: Upgrade, HTTP2-Settings
Content-Length: 0
Host: 127.0.0.1:8081
HTTP2-Settings: AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA
Upgrade: h2c
User-Agent: Java-http-client/10
Host: test.example.com

As you can see it sends two Host headers (the one from URI and the one I specified), but I would like it to send the Host header that I specified, not the one from the URI. Is it possible with this client?

EDIT: In Java 11, it gets even worse (you need to change the client.send line to: client.send(request, HttpResponse.BodyHandlers.ofString());):

java.lang.IllegalArgumentException: restricted header name: "Host"

How can I customize that header (needed for testing of virtual hosts)?

I also tried the setHeader and get exactly the same problem (either double Host headers, or the exception).

EDIT: I reported a JDK bug.

Verile answered 13/9, 2018 at 14:3 Comment(0)
V
22

As of Java 12 (EA build 22) it has been solved by additional property jdk.httpclient.allowRestrictedHeaders (see https://bugs.openjdk.java.net/browse/JDK-8213696).

So now one can override Host (or any other restricted header) by executing the code with:

java -Djdk.httpclient.allowRestrictedHeaders=host ...

Allowing multiple restricted headers are as follows:

java -Djdk.httpclient.allowRestrictedHeaders=connection,content-length,host

and you can set it up in the eclipse menu > Run > Run Cunfigurations enter image description here

Verile answered 4/12, 2018 at 16:6 Comment(1)
Also important, you must remove whitespaces from the list of values despite what is specified in the documentation: names are case-insensitive and whitespace is ignored.Interdigitate
L
3

The behavior from the Java11 client code seems correct. The Host section elaborates on the details. By the way, from the documentation of HttpRequest builder header(String name, String value) :

*    @throws IllegalArgumentException if the header name or value is not
*    valid, see <a href="https://www.rfc-editor.org/rfc/rfc7230#section-3.2">
*    RFC 7230 section-3.2</a>, or the header name or value is restricted
*    by the implementation.

Update: See this, for answer pertaining to JDK/12.

Lauderdale answered 13/9, 2018 at 14:16 Comment(4)
Yes, but e.g. Apache HttpClient allows customization of that header since some time: #6046411 similarly curl allows customization of Host header (it takes precedence over the URL). So it is a reasonable expectation have same functionality in this http client.Halfmoon
@KrzysztofKrasoń Though I am not in the position to define the reason why the implementation of the other clients differs. Yet to what I could further dig into is that RFC2616 specifies the same and the answer to what is the http host header also emphasizes on the note that the URI should be such that the host and the port should be read from it.Lauderdale
While you are correct according to the RFC, but almost all web clients allow some level of customization - which is very convenient thing for developers, e.g. I would expect to be able to override all headers that are produced by given http client - this allows easy debugging of the applications being developed.Halfmoon
It is the correct answer for java 11, let's hope it will change in some next release.Halfmoon

© 2022 - 2024 — McMap. All rights reserved.