Is there a way to "clean" an accept header in Java? - java

So if someone sends in this accept header:
*/*'"!#$^*\/:;.,?{}[]`~-_<sCrIpT>alert(81363)</sCrIpT>
it is returned in the response using Jersey. I need to intercept this and escape it. I have not found any way to do this. Any help?

You could use filters to intercept your request and do the cleanup before they reach your service class. Check this example.

You can read request headers, and modify response headers in this way (you can not modify request headers, it's a read only map):
#Context HttpHeaders headers;
#Path("yourPath")
public Response yourMethod(){
List<String> accept = headers.getRequestHeader(HttpHeaders.ACCEPT);
if ( accept contains invalid characters)) {
do something
}
//If you set a null value, the header is deleted.
//Anyway, deletion is useless, if you have not yet set
// the Accept header on the response.
return Response.ok().header(HttpHeaders.ACCEPT, null).build();
}

Related

GET call with request body - request body not accessible at controller

I am trying to do a get call with request body(JSON) as the request parameter list exceeds the limit. I am able to send the request via postman/insomnia and request is reaching till controller without any error. But the "requstBody" is empty at controller. What i am missing here?
#GET
#Path("\path")
#Consumes(APPLICATION_JSON)
#Produces(APPLICATION_JSON)
public Response getResponse(String requestBody) throws IOException { }
When I replaced #GET with #POST, requestBody has value. For GET call do we need to add anything more?
I am trying to do a get call with request body(JSON) as the request parameter list exceeds the limit. I am able to send the request via postman/insomnia and request is reaching till controller without any error. But the "requstBody" is empty at controller. What i am missing here?
One thing you are missing is the fact that the semantics of a request body with GET are not well defined.
RFC 7231, Section 4.3.1:
A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.
There are two ways for sending parameters in an Http Get method. PathVariable and RequestParam. In this way, sent parameters are visible in the request URL. for example:
www.sampleAddress.com/countries/{parameter1}/get-time?city=someValues
In the above request, parameter1 is a path variable and parameter2 is a request parameter. So an example of a valid URL would be:
www.sampleAddress.com/countries/Germany/get-time?city=berlin
To access these parameters in a java controller, you need to define a specific name for the parameters. For example the following controller will receive this type of requests:
#GetMapping(value = "/countries/{parameter1}/get-time", produces = "application/json; charset=utf-8")
public String getTimeOfCities(
#PathVariable(value = "parameter1") String country,
#RequestParam(value = "city") String city
){
return "the method is not implemented yet";
}
You are able to send RequestBody through a Get request but it is not recommended according to this link.
yes, you can send a body with GET, and no, it is never useful
to do so.
This elaboration in elasticsearch website is nice too:
The HTTP libraries of certain languages (notably JavaScript) don’t allow GET requests to have a request body. In fact, some users are suprised that GET requests are ever allowed to have a body.
The truth is that RFC 7231—the RFC that deals with HTTP semantics and
content—does not define what should happen to a GET request with a
body! As a result, some HTTP servers allow it, and some—especially
caching proxies—don’t.
If you want to use Post method, you are able to have RequestBody too. In the case you want to send data by a post request, an appropriate controller would be like this:
#PostMapping(value = "/countries/{parameter1}/get-time", produces = "application/json; charset=utf-8")
public String getTimeOfCitiesByPost(
#PathVariable(value = "parameter1") String country,
#RequestParam(value = "city") String city,
#RequestBody Object myCustomObject
){
return "the method is not implemented yet";
}
myCustomObject could have any type of data you defined in your code. Note that in this way, you should send request body as a Json string.
put #RequestBody on String requestBody parameter
#RequestMapping("/path/{requestBody}")
public Response getResponse(#PathVariable String requestBody) throws IOException { }

Spring MVC Override Received Content Type

I'm working on a Spring MVC application and have a client that I have no control over. This client is POSTing JSON data but transmitting a application/x-www-form-urlencoded header. Spring naturally trusts this header and tries to receive the data but can't because its JSON. Has anyone had experience overriding the header that Spring receives or just specifying exactly what type of data is coming, regardless of the headers?
You can do two things;
Change the client to send the Content-Type:
application/json header
Write a Servlet Filter or Spring Interceptor which is on top of the Spring Controller and checks for the header Content-Type. If it is not application/json then it changes it to application/json.
Why don't you write a separate controller to handle application/x-www-form-urlencoded requests. If the request is a valid JSON, then you can parse it and forward it to to appropriate service.
This way you can also handle a case in future where you get request of same type which is not a valid JSON.
#RequestMapping(value = "/handleURLEncoded", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public #ResponseBody Object handleURLEncoded(HttpEntity<String> httpEntity) {
String json = httpEntity.getBody();
//now you have your request as a String
//you can manipulate it in any way
if(isJSONValid(json)) {
JSONObject jsonObj = new JSONObject(json);
//forward request or call service directly from here
//...
}
//other cases where it's not a valid JSON
}
Note: isJSONValid() method copied from this answer

Modifying HTTP response body and message

I need to be able to modify the HTTP response body of the response that I am getting when someone hits my Service API. I tried using ConatinerResponseFilter to modify the body, but I believe it will only modify the headers and not the response body. Can someone tell me how I can modify the HTTP response body ,message and the status?
It could be achieved with a WriterInterceptor:
#Provider
public class CustomWriterInterceptor implements WriterInterceptor {
#Override
public void aroundWriteTo(WriterInterceptorContext context)
throws IOException, WebApplicationException {
OutputStream outputStream = context.getOutputStream();
// Manipulate the HTTP entity using the OutputStream
context.setOutputStream(outputStream);
context.proceed();
}
}
In this answer you will find an example of how to modify a JSON sent in the request payload using Jackson (the same idea can be used to manipulate response payload).
The trick is to use a wrapper because body when read as a stream becomes in accessible
Modify HttpServletRequest body
Check this or just check online for modify body in filter
Note :if u are doing a web service then using frameworks like CXF makes it easy modify

How to create endpoint in Jersey for POST requests with or without body

I have an API created with Jersey
There's currently an endpoint to which users can make POST requests. There is no body required, as all the information is in the url.
#POST
#Path("entries")
#Produces(MEDIATYPE_JSON_AND_XML)
public Response createEntry(){
...
}
A new, empty, entry is created and the id is returned.
Content-Type of the request doesn't matter, as there is no request body data.
Now it should also be possible to set specific fields of the new entry during the request, using FormData. For this request a body is necessary, and the Content-Type must be multipart/form-data.
So I've created a second function:
#POST
#Path("entries")
#Consumes("multipart/form-data");
#Produces(MEDIATYPE_JSON_AND_XML)
public Response createEntryWithParam(#FormDataParam('param') String param){
...
}
This second function works te send the parameter in the request. But by adding it, the first stops working.
Sending a request without Content-Type will throw a NullPointerException. Probably because the #Consumes triggers some kind of Content-Type-check, which fails.
Is there a way to have one endpoint accepting POST requests with or without request-body?
edit So, I would like to receive all multipart/form-data requests in the seconds function, and use the first as a kind of catch-all for other POST requests to that endpoint
Currently I have a work-around in place.
If a POST request comes in without MediaType (Content-Type) or request-body, I automatically add an empty JSON object and set the Content-Type accordingly.
#Provider
public class ContentTypeRequestFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext crc) throws IOException {
if (crc.getMethod().equals("POST") && crc.getMediaType() == null && crc.getLength() == -1){
crc.getHeaders().add("content-type", MediaType.APPLICATION_JSON);
InputStream in = IOUtils.toInputStream("{}");
crc.setEntityStream(in);
}
}
}
This works, but is kinda hacky in my opinion. I'm interested to know if there are better ways to achieve my desired result.

How to get header from response in Servlet 2.3 or 2.5

I know that v3.0 has method getHeader() but what about 2.3? Maybe it possible to get from steam?
UPDATE:
Actually, I need the HTTP response header RESTful application. In some reason I have decided to do this in servlet filter... but without success...
Solution #javax.ws.rs.core.Context HttpHeaders requestHeaders.
For example,
#javax.ws.rs.GET
public String invoceRestMethod(#Context HttpHeaders requestHeaders){
MultivaluedMap<String, String> map = headers.getRequestHeaders();
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
// processing header....
}
}
Maybe in will help for someone. But any case, for Servlet issue still is opened
You cannot get the header from the stream*.
What you have to do is insert a proxy response object into the filter chain before your Servlet is called, and have that capture the header.
* Actually, you could potentially capture stuff from the stream using a proxy response and decode the headers. But if you are inserting a proxy response, it is simpler to capture the headers directly.

Categories

Resources