Reputation: 176
I am trying to assign the content-length header in Java but it seems impossible.
Here's my code:
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("URL"))
.header("Content-Type","application/pdf")
.header("Authorization",String.format("Token token=%s",token))
.header("Transfer-Encoding","chunked")
.header("Content-Length",String.valueOf(contentLength))
.POST(HttpRequest.BodyPublishers.ofByteArray(file))
.build();
If I run this, then I get the exception "Restricted Header Name: "Content-Length". So then I remove the line where I set the content-length. At this point I get an IOException saying my request doesn't have a content-length header.
How the hell am I supposed to set the content-length header if the HttpClient throws an exception if I, you know, set the content length header?
EDIT:
I know this doesn't solve the question, but I ended up trying non-system standard HTTP Client Libaries. OkHttp for some reason failed on me, but Apache's HttpClient worked fine. It's not as elegant as Java's built in client, but it actually worked.
Upvotes: 4
Views: 6969
Reputation: 544
HttpClient adds Content-Length
header only for non-empty bodies. As you've noticed, overriding this header is restricted. Hopefully this can be relaxed since JDK 12 by setting a system property jdk.httpclient.allowRestrictedHeaders
, see JDK-8213696.
Upvotes: 4
Reputation: 21640
(This is not really an answer, but the code is too long for a comment)
I tried this code (which is similar to your example), and the response from httpbin.org shows that the Java11 HTTPClient fills in the content-length header with the correct value:
public class HR {
public static void main(String[] args) throws IOException, InterruptedException {
byte[] file = {0, 1, 2, 3, 4, 5, 6, 7};
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/anything"))
.header("Content-Type", "application/pdf")
.header("Authorization", "Token token=xyz")
.header("Transfer-Encoding", "chunked")
// .header("Content-Length", String.valueOf(file.length))
.POST(HttpRequest.BodyPublishers.ofByteArray(file))
.build();
HttpClient client = HttpClient.newHttpClient();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.join();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
The response from httpbin.org is (with some sensitive fields masked)
{
"args": {},
"data": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007",
"files": {},
"form": {},
"headers": {
"Authorization": "Token token=xyz",
"Content-Length": "8",
"Content-Type": "application/pdf",
"Host": "httpbin.org",
"User-Agent": "Java-http-client/15.0.1"
},
"json": null,
"method": "POST",
"origin": "1.2.3.4",
"url": "https://httpbin.org/anything"
}
The response will show up twice (once from the async call, once from the synchronuous call).
I'm therefore not sure on why your code doesn't send the content-length header, the HttpRequest.BodyPublishers.ofByteArray
should do that for you too.
Upvotes: 0