I m trying to write a unitTest for an endpoint.
This endpoint should take a json object as follow
#PostMapping(value = "/test")
public String endPoint(#RequestBody String obj) {
try {
JSONObject inputJsonObject = new JSONObject(individualJson);
} catch (JSONException | IOException e) {
throw new MyException("JSONObject not valid");
}
......
}
in my unit test I m trying to send an empty string and I m expecting to have a JSONException
mvc.perform(post(url)
.contentType(MediaType.APPLICATION_JSON)
.content(""))
.andReturn().getResponse();
however this my post is not hiting my endpoint... it is like it is not able to evaluate an empty String as a String : "" is not hitting the endpoint however
" " (with a space) is hitting the endpoint ...
Here is the exception returned by the call :
org.springframework.http.converter.HttpMessageNotReadableException:
Required request body is missing: public
com.ba.mypackage.MyController.endPoint(java.lang.String)
How may I access the endpoint by passing an empty string "" ?
You can't, since sending an empty string as body is the same thing as not sending a body in this context, and not sending a body is disallowed by #RequestBody annotation, since default value for its required attribute is true.
Sending an empty string as body is the same thing as not sending a body because in HTTP, a POST request has a header section and body section separated by CRLF, and separating CRLF is required both when having a body and not having it. This is how it is defined in HTTP specification, see https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html for details:
5 Request
A request message from a client to a server includes, within the first line of that message, the method to be applied to the resource, the identifier of the resource, and the protocol version in use.
Request = Request-Line ; Section 5.1
*(( general-header ; Section 4.5
| request-header ; Section 5.3
| entity-header ) CRLF) ; Section 7.1
CRLF
[ message-body ] ; Section 4.3
A header section you provide, and body is something you want to have as empty string. However, you need to anyway have CRLF in place, so request would look something like this:
POST /url HTTP/1.1
Content-Type: application/json; charset=UTF-8
Accept: application/json, application/javascript, text/javascript
Content-Length: 0
Host: localhost:8888
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.3 (Java/1.8.0_112)
Accept-Encoding: gzip,deflate
or, to put [CRLF] on where that character is,
POST /url HTTP/1.1[CRLF]
Content-Type: application/json; charset=UTF-8[CRLF]
Accept: application/json, application/javascript, text/javascript[CRLF]
Content-Length: 0[CRLF]
Host: localhost:8888[CRLF]
Connection: Keep-Alive[CRLF]
User-Agent: Apache-HttpClient/4.5.3 (Java/1.8.0_112)[CRLF]
Accept-Encoding: gzip,deflate[CRLF]
[CRLF]
Since the content-length is zero and the CRLF separator needs to always be there, how would you tell a difference between empty string sent as body and no body sent at all? The thing is you can't, in this context it's the same thing, so what you ask can't be done.
Because empty string is not a valid String and treated similar to Null.
However if you just want to hit the controller and not interested in the empty strings value inside of controller, just mark the parameter as optional.
public String endPoint(#RequestBody(required = false) String obj) {
Related
I am new to Flutter and I am trying to call my ASP.NET server web API.
From the logs on my server, everything goes fine but Android Studio throws an exception: "invalid header field name".
Here is the code in dart:
import 'package:http/http.dart' as http;
...
_getService() async {
String result;
try {
var url = 'http://192.168.1.14:34263/api/Mobile/test/1';
Future<http.Response> response = http.get( url );
result = response.toString();
} catch(exception){
result = exception.toString();
debugPrint(result);
}
...
}
Here is the response header (obtained via Chrome):
Access-Control-Allow-Headers:accept, authorization, Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, PATCH, DELETE
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: WWW-Authenticate
Cache-Control: no-cache
Content-Encoding: deflate
Content-Length:79
Content-Type: application/xml; charset=utf-8
Date: Thu, 08 Mar 2018 01:01:25 GMT
Expires:-1
Pragma:no-cache
Server:MyTestServer
X-Content-Type-Options:NOSNIFF
X-Permitted-Cross-Domain-Policies:master-only
X-SourceFiles:=?UTF-8?BDpcTXlJbmNyZWRpYmxlRHJlc3NpbmdcTXlJbmNyZWRpYmxlRHJlc3NpbmdcTXlJbmNyZWRpYmxlRHJlc3NpbmdcYXBpXE1vYmlsZVxjb3Vjb3VcMQ==?=
X-XSS-Protection:1;mode=block
Here is the answer which is returned:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">test</string>
Can anyone tell me what am I doing wrong?
Many thanks
Ok, I finally found out, by debugging the code.
In fact, my server added a series of field names in the response's header (via the Web.config) and the last character of one of these field names was a space.
As a result, the http_parser.dart threw an exception since spaces are no authorized characters in header field name.
Nothing was detected by Chrome (or any browser) nor by Postman.
I had similar problem and after some heavy debugging
I removed these headers from nginx:
#add_header X−Content−Type−Options nosniff;
#add_header X−Frame−Options SAMEORIGIN;
#add_header X−XSS−Protection 1;
and it works fine. So most likely it's backend - header related issue
I am just trying to make a simple REST request like below
String url = "some url";
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
headers.add(HttpHeaders.AUTHORIZATION, "some authorization");
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Body body = new Body();
body.setRemarks("test");
org.springframework.http.HttpEntity request = new org.springframework.http.HttpEntity(body, headers);
try {
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.PUT, request, String.class);
System.out.println("Status Response: "+ response.getStatusCode() +". Body: "+ response.getBody());
} catch (HttpClientErrorException | HttpServerErrorException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Problem is every time I do this in Java the result is unpredictable I am usually getting this error consistently.
org.springframework.http.InvalidMediaTypeException: Invalid mime type "text/plain, application/json, application/json, application/*+json, application/*+json, */*; charset=UTF-8": Invalid token character ',' in token "plain, application/json, application/json, application/*+json, application/*+json, */*"
at org.springframework.http.MediaType.parseMediaType(MediaType.java:452)
at org.springframework.http.HttpHeaders.getContentType(HttpHeaders.java:745)
at org.springframework.web.client.DefaultResponseErrorHandler.getCharset(DefaultResponseErrorHandler.java:115)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)
However when I try the same request through postman it works. I am missing something very simple and I do not know what.
I checked the response from Postman and the headers, and they seem to hold good like Content-Type →application/json; charset=UTF-8 and the response is also well formed.
I am also not able to make out which part whether the request or the response is on which Rest Template is having a problem.
Short answer in my case was add these extra headers while before making the request.
headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
headers.add(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.name());
Long answer: Thanks to Nikolay Shevchenko's suggestion to use debugger to dig out that when there was an error on the server RestTemplate tried to gather up all headers and body from the response to create sane exception message. While trying to create that message from response it got the mime type
text/plain, application/json, application/json, application/*+json, application/*+json, */*; charset=UTF-8
Yes that entire length of text instead of application/json; charset=UTF-8 as shown for the same request by Postman. So in my case of an older spring rest template version when it tries to parse over the above provided mime type, it fails, producing this message.
org.springframework.http.InvalidMediaTypeException: Invalid mime type "text/plain, application/json, application/json, application/*+json, application/*+json, */*; charset=UTF-8": Invalid token character ',' in token "plain, application/json, application/json, application/*+json, application/*+json, */*"
So instead of a getting a server error, a more fine grained mime type exception bubbles up from deeper stack, making no sense for what you are searching for.
As per this post by M. Deinum RestTemplate was some how ending up using StringHttpMessageConverter although I have specified Jackson to Http Message converter as shown below.
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
As mentioned in aforementioned post having StringHttpMessageConverter causes writeAcceptCharset to be true which brings along the long format of mime type with almost every possible value. In the mentioned post the solutions were either to make writeAcceptCharset as false or not to write plain string but use object and then marshal it as a string.
For my use case I was expecting response type to be application/json with charset of UTF-8 so setting up those accept headers in configuration sorted out my problem.
I'm working on a REST resource that takes in a key and data (value) . I'd like to be robust so this data can be anything. It could range from a string to a file.
To handle this, I have the PUT REST method which is at the end of the post. Nothing fancy, just trying to PUT basic data. If I send data that is a string it works no problem.
However, if I try to send a file across, I get this error: org.jboss.resteasy.spi.UnsupportedMediaTypeException: Cannot consume content type. Here's why this doesn't make sense to me:
If I change the #Consumes from application/octet-stream to #Consumes("multipart/form-data"), I can send a file across just fine. When examining the file that's stored I see something like this:
------WebKitFormBoundaryfuQalizBHtg1BiLJ
Content-Disposition: form-data; name="fileUpload1"; filename="uploadedFile.extension"
Content-Type: application/octet-stream
/* file information here */
------WebKitFormBoundaryfuQalizBHtg1BiLJ--
Notice that the Content-Type is supposedly application/octet-stream which is what I tried consuming before but got the Cannot consume content type exception. I have no idea what would be causing this. I'm using the Advanced Rest Client extension for Chrome to send my request and it looks something like this: https://i.imgur.com/KvKCIkl.jpg
Any thoughts?
#PUT
#Path("{key}")
#Consumes("application/octet-stream")
public Response addData(
final #PathParam("key") String key,
final InputStream data) {
final Service service = new Service();
try {
service.addData(key, data);
} finally {
IOUtils.closeQuietly(data
}
return Response.status(204).build();
}
A multipart/form-data message contains a series of parts divided by a boundary. Every part has its own Content-Type. So in your example Content-Type: application/octet-stream is the Content-Type of one (and probably the only one) part but the Content-Type of the whole message is multipart/form-data. A full message with multiple parts could look like this:
Content-Type: multipart/form-data; boundary=WebKitFormBoundaryfuQalizBHtg1BiLJ
------WebKitFormBoundaryfuQalizBHtg1BiLJ
Content-Disposition: form-data; name="fileUpload1"; filename="uploadedFile.extension"
Content-Type: application/octet-stream
/* file information here */
------WebKitFormBoundaryfuQalizBHtg1BiLJ--
------WebKitFormBoundaryfuQalizBHtg1BiLJ
Content-Type: text/plain
/* some text here */
------WebKitFormBoundaryfuQalizBHtg1BiLJ--
I am trying to send a zipfile from my android application to our server and I keep getting a 411 length required error.
Here is the code that I am using to do that.
HttpPost post = new HttpPost("http://www.xyz.org/upload.json");
post.setHeader(C.constants.HTTP_CONTENT_TYPE, "application/octet-stream");
try {
FileInputStream fis = new FileInputStream("/data/data/org.myapp.appname/app_content.zip");
InputStreamEntity reqEntity = new InputStreamEntity(fis, -1);
post.setEntity(reqEntity);
String response = doPost(post);
Log.v(tag, "response from server " + response);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
What am I doing wrong here and may I also know how I can add more parameters with this post to send them to the server.
You should use a multipart MIME type, and parts for each parameters and for the files. See this old blog post of mine.
As you should know, an HTTP request (and response, too) is made up of two section: a header and a body (also called entity). In the header you specify a Content-Type so that the server script knows how to interpret the following bytes (you can also specify the encoding for textual data on the same line).
After the header, the client sends an empty line and an optional entity. A multipart entity is like a stack of parts separated by a boundary. This is what your desired HTTP request should look like on the wire:
POST /path/to/script.json HTTP/1.1
Host: localhost
Content-Type: multipart/form-data; boundary=a2ksdf0?--
a2ksdf0?--
Content-Disposition: form-data; name="profile_picture"; filename="me.png"
Content-Type: image/png
<content here>
a2ksdf0?--
Content-Disposition: form-data; name="username";
Content-Type: text/plain
Joe Black
BTW, it's the first time I see an upload script named upload.json. What do you use on the server side?
I need to get username and password from HttpServletRequest to process the basic authentication. What I have is CXF endpoint and the basic auth interceptor. The HttpServletRequest I get like this:
public void handleMessage(Message message)
throws Fault {
HttpServletRequest request = (HttpServletRequest) message.get(AbstractHTTPDestination.HTTP_REQUEST);
}
When I tried to debug the code and I see that:
request.getAuthType() is null
request.getRemoteUser() is null
The username and password I am sending with the request from Soap UI. So the question is how am I able to get the username and password from the request?
EDIT
Header looks like this:
POST http://localhost:8011/GradIrelandUserRegistration HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
Authorization: Basic UGF1bGl1czpQYXVsaXVzMTIz
Content-Length: 3170
Host: localhost:8011
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
They say that Authorization is basic, but then why call request.getAuthType() is returning null?
I was able to figure it out my self. In Soap UI I needed to change the Authentication type to:
Preemptive
and then use:
AuthorizationPolicy policy = (AuthorizationPolicy) message.get(AuthorizationPolicy.class.getName());
From the policy object now I am able to get the username and password.
This may be helpful to you
.
I'm bit new in SOAP data parsing so, if not working then let me know brief problem.
.
Also Check this J-Query Plugin for parsing SOAP services with the database. check this Stack Overflow