Kong / unirest-java

Unirest in Java: Simplified, lightweight HTTP client library.
http://kong.github.io/unirest-java/
MIT License
2.58k stars 591 forks source link

Default header is not overrided #448

Closed TimeInvestor closed 1 year ago

TimeInvestor commented 1 year ago

I am testing a bunch of APIs. Most APIs need the header "Content-Type" = "application/json" and OAuth 2.0. So I do such setup

Unirest.config().setDefaultHeader("Accept", "application/json")
                .setDefaultHeader("Content-Type", "application/json")
                .setDefaultHeader("Authorization", "Bearer xxx-abc-123");

However, there is a special API which requires basic authentication and form data (multipart/form-data), so in the test I put

Unirest.post("http://www.example.com/api")
        .basicAuth("username", "password")
        .field("username", "xxx")
        .field("token", "abc")
        .field("grant_type", "password");

In the final request set out, the Authorization header is replaced/override to Authorization: Basic YXBwUG9yabc123== but the "Content-Type" header is still Content-Type: application/json.

ryber commented 1 year ago

Hi @TimeInvestor there are a few things going on here, and one bug that that fixed although it might not be what you think.

So, the internet is a weird and wacky place, and not everyone behaves the way you think. One of Unirest's rules is that it will let you do things in non-standard ways, because the world has non-standard things. So, I would not expect that if you set a default header for Content-Type that it would get automatically changed. Somewhere in the world is a API that wants form vars and a Content-Type of Cheese

The one exception to this is multipart forms where the header and boundary must be defined in specific ways. However your request is NOT a multipart form on the surface. By default without a default header the Content-Type would be set to application/x-www-form-urlencoded. Unirest would only change to multipart if you truly had different types like with a File or Octet-Stream

You could have attempted to do a headerReplace on the content, but this won't quite work with multi-part forms. It would indeed change the header, but it would not have made the form an ACTUAL multipart request, it would have been a lie.

There is a way to FORCE multipart on a request with the .multiPartContent() method like this:

Unirest.post("http://www.example.com/api")
                .basicAuth("username", "password")
                .multiPartContent()
                .field("username", "xxx")
                .field("token", "abc")
                .field("grant_type", "password")

Now the bug is that in the last version this still didn't override the default header, so I've just released version 3.13.11 that does just that.

Here are some tests documenting further :https://github.com/Kong/unirest-java/blob/main/unirest/src/test/java/BehaviorTests/MultiPartFormPostingTest.java#L59-L75

TimeInvestor commented 1 year ago

@ryber The solution solved my issue perfectly 😄 Thanks for the prompt help 👍