400 Bad request on Java Webclient multipart/formdata post request - java

Im having problems on posting a multipart/formdata request to a REST api. The request returns an 400 Bad Request response.
This is how the request should look like. The link shows you a screenshot captured on a successful request by the web interface.
Successful request
This is the Java code I created.
public void importModel(String projectId, String modelId, MultipartFile file, String fileName) throws IOException {
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("data", file.getBytes(), MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "form-data; name=data; filename=" + fileName);
MultiValueMap<String, HttpEntity<?>> parts = builder.build();
WebClient webClient = WebClient.builder()
.filters(exchangeFilterFunctions -> {
exchangeFilterFunctions.add(logRequest());
exchangeFilterFunctions.add(logResponse());
})
.build();
String request = webClient.post()
.uri(getBaseUriBuilder()
.pathSegment(getTeamSlug())
.path(API_PATH_PROJECTS)
.pathSegment(projectId)
.path(API_PATH_MODEL)
.pathSegment(modelId)
.path("/importasync")
.build())
.contentType(MediaType.MULTIPART_FORM_DATA)
.contentLength(file.getSize())
.header(HttpHeaders.AUTHORIZATION, getPrefixedAuthToken())
.body(BodyInserters.fromMultipartData(parts))
.exchange()
.flatMap(FlatService::apply)
.block();
return;
}
Any help is much appreciated. Thank in advance!

Have you tried to send the request with alternative Software like POSTMAN.
There you can check for the request properties that are being sent with the request
a 400 error can occur due to the following issues with your request
Wrong URL: Same as 404-Error a Bad Request is generated, when the user types in a wrong internet address or he adds special chars to the address.
Error full Cookies: If the Cookie inside your browser is to old or broken it can also be a 400.
Old outdated DNS-Entries: In your DNS-Cache could lie files that point to wrong or outdated IP- addresses
Too big files: when you try to upload very large files, the server can deny the request.
Too long header lines: the communication between the client and server is done with header information about the request. some servers set a limit to the header length.
Also if you can find out the more specific 400 error like this:
400.1: Invalid Destination Header
400.2: Invalid Depth Header
400.3: Invalid If Header
400.4: Invalid Overwrite Header
400.5: Invalid Translate Header
400.6: Invalid Request Body
400.7: Invalid Content
400.8: Invalid Timeout
400.9: Invalid Lock Token
If you are not the server admin you could ask him about specifications of the server. or use tools like postman where you can try to send requests to the server and find out more specific error codes.

Related

Response had HTTP status code 500, no 'Access-Control-Allow-Origin' header

I have a simple java web service deployed(say /diagnosis). When i hit the URL(/diagnosis) i am getting the JSON output. When i try to hit the rest service(/diagnosis) through Angular JS i am getting:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4201' is therefore not allowed access. The response had HTTP status code 500.
My Java code is:
#GET
#Path("/DiagnosisSortProviderCost")
#Produces(MediaType.APPLICATION_JSON)
public Response DiagnosisSortProviderCost() throws Exception {
// String path_name = "C:\\Users\\526761\\Desktop\\PioDel\\";
JSONArray jsonArr = jsonread.json_extract_provider(path_name);
System.out.println("--");
System.out.println(jsonArr);
Response response = Response.status(200).entity(jsonread.pro_DiagProvCost(jsonArr))
.header("Access-Control-Allow-Origin", "*").build();
return response;
}
I added the code to resolve CORS Filter issue, i even replaced the * with IP and port. Yet i couldn't get the issue resolved.
Please help me!!!
#GET
#Path("/DiagnosisSortProviderCost")
#Produces(MediaType.APPLICATION_JSON)
Because your mapping will never work. It only support GET method, in case of different http method like OPTIONS (for CORS), it will not serve.
All browser will send OPTIONS firstly to detect which method is allowed before sending actually request. If OPTIONS is not support or http method is not supported, browser will prevent it.
Change it to #RequestMaping with method option: The HTTP request methods to map to, narrowing the primary mapping: GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.

Rest assured testing - API request 401 bad request

I have a problem with sending API request via postman or Java lib "io.restassured".
When I do the same action on UI the request returns correct response, but when I try the same thing via postman or java code I get:
401 Bad request Your browser sent an invalid
request.
The java code
public static void main(String[] args) {
String requestUrl = "exampleBaseUrl/app/reports/api/rest/v1/graphs?context=shipper&reports_type=freights";
Response response = RestAssured.given().relaxedHTTPSValidation().header("x-csrf-token", "18ea65e740eb0ddddadf0ef435d92564").
when().
get(requestUrl);
}
I assume something is wrong with the authentication, because in dev tools i can see a Get request for CSRF_token, and it looks like this:
the endpoint for the token:
/login?get_csrf_token
and for this request I get following response:
{"csrf_token":"18ea65e740eb0ddddadf0ef435d92564"}
I am not sure how to solve this, I have also tried to get the token via java code by sending a get request to the token's endpoint /login?get_csrf_token
and this one gets my a HTML response with empty username and password input.
Error 401 means your request isn't authorized.
For authorization, usually while logging in you are given a token, which you will have to keep in your cache/local-memory and whenever you communicate with the server you have to add that in your request header (for your own introduction to the server)
It seems like in your case you can get a token from /login?get_csrf_token after logging in. Note that you don't need authorization for a login service.
Now, after getting token from the server, how to add it as a request header? See REST Assured Documentation

Unable to send `multipart/form-data` request with python requests module

I have Java spring server that requires the Content-Type of the requests being sent to the server to be multipart/form-data.
I can correctly send requests to the server with postman:
However, I got The current request is not a multipart request error when trying to send the request with requests module in python3.
My python code is:
import requests
headers = {
'Authorization': 'Bearer auth_token'
}
data = {
'myKey': 'myValue'
}
response = requests.post('http://127.0.0.1:8080/apiUrl', data=data, headers=headers)
print(response.text)
If I add 'Content-Type': 'multipart/form-data' to the header of the request, the error message then becomes Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found.
How can I make the same request as postman sends with python?
requests's author thinks this situation is not pythonic, so requests doesn't support this usage natively.
You need to use requests_toolbelt which is an extension maintained by members of the requests core development team, doc, example:
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
m = MultipartEncoder(
fields={'field0': 'value', 'field1': 'value',
'field2': ('filename', open('file.py', 'rb'), 'text/plain')}
)
r = requests.post('http://httpbin.org/post', data=m,
headers={'Content-Type': m.content_type})

File upload in case of HTTP 307

I am writing a Spring controller that handles the HTTP PUT request from client, and generates S3 pre-signed url and issues a HTTP 307 status (Temp redirect) code. So basically I am authenticating the client and if it succeeds then I am asking him to write to a s3 folder. The client is able to write to signed url location.
Now my concern is the client will have to do upload two times. Once to my application server and then to s3, so the operation will take double the time.
Is my understanding correct?Does the client actually does 2 write in this case? Or is the client smart enough and just pushes the part of payload first and if it succeeds then pushes entire payload?
I read about HTTP 100 status code, but looks like the app server/tomcat already issues it and is not in my control.
Here is my spring controller
#RequestMapping("/upload")
public ResponseEntity<Void> execute(HttpServletRequest request) throws IOException, ServletException {
HttpHeaders headers = new HttpHeaders();
String redirectUrl = getRedirectUrl(requestURI, request.getMethod());
headers.setLocation(new URI(redirectUrl));
ResponseEntity<Void> redirectEntity = new ResponseEntity<Void>(null,headers,HttpStatus.TEMPORARY_REDIRECT);
return redirectEntity;
}
How can i prevent clint from uploading the entire payload to my app server?
So my understanding correct?
Answer is YES. Server will send the response of PUT request after reading the full request including body. when you client will repeat the request, in response 307 (Temporary Redirect), it will be like a new http request.
Also an important point on using 307 response code from spec(see below) should be considered for this approach.
If the 307 status code is received in response to a request other
than GET or HEAD, the user agent MUST NOT automatically redirect the
request unless it can be confirmed by the user, since this might
change the conditions under which the request was issued.
On point
How can i prevent client from uploading the entire payload to my app server?
You may do upload to s3 in background from your controller and return the redirect response (301?) point to an URL which will return the status of upload request.
This just isn’t how HTTP works, HTTP has no mechanism to halt a file upload other than closing the connection, but if you close the connection you cant return the redirect information.
If you want the client to upload directly to S3, you will need to do it in two steps.
Have the client request the URL for the file transfer, then have them initiate the transfer with the desired URL.

Spring RestTemplate HTTP POST with non standard HTTP header causes 400 bad request error

I am sending a POST request to a service with custom header and payload, via RestTemplate. On executing 'exchange' method, I am getting 400 Bad request error. However, same request works fine when sent from Chrome Postman plugin.
After so much debugging, I have found the root cause for it, it's happening due to non standard http header being present in headers. Below is the code to create header object:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "token");
headers.set("X-User-name", "user");
Request with this header results in 400. Now, if I comment out the last line, I get 500 error from server, asking for header. However, this means request is valid.
Can anyone please help?
Update
I tried removing hyphens from header name (e.g. tried with XUsername) and got the message from server, saying X-User-name is required. So, it has something to do with hyphen symbol.
Thanks in advance.

Categories