How to found out url with which the request arrived at error handler? - spring-mvc

I send following http request:
http://localhost:8081/member/createCompany/getSmallThumbnail/
On server side I hit into controller method:
#RequestMapping("/error")
public String error(Model model, HttpServletRequest request){
if(request.getRequestURI().contains("thumbnail")){
System.out.println("thumbnail accepted");
}
request.toString();
model.addAttribute("message", "page not found");
return "errorPage";
}
At this method I want to know url with which the request arrived.
If in debug I stop inside this method I see information needed for me:
But I cannot find method in request which will return this.
Please help to return url which I want.
P.S.
Actually I have not mapped controller in my spring mvc application(url is broken) for http://localhost:8081/member/createCompany/getSmallThumbnail/. This url("/error") configured in web.xml as error page.

Your request got redispatched to /error (presumably for error processing).
If this framework follows the normal Servlet error dispatching behavior, then your original request can be found in the HttpServletRequest.getAttributes() under the various javax.servlet.RequestDispatcher.ERROR_* keys.
ERROR_EXCEPTION - The exception object
ERROR_EXCEPTION_TYPE - The type of exception object
ERROR_MESSAGE - the exception message
ERROR_REQUEST_URI - the original request uri that caused the error dispatch
ERROR_SERVLET_NAME - the name of the servlet that caused the error
ERROR_STATUS_CODE - the response status code determined for this error dispatch
What you want is
String originalUri = (String) request.getAttribute(
RequestDispatcher.ERROR_REQUEST_URI)

Related

400 when passing url in #PathVariable to Spring MVC controller method

I'm trying to pass a url in to a Spring MVC controller method in a #PathVariable but am getting a 400 http response code, and the request is rejected before it reaches the controller method.
My request is being issued as:
curl 'https://127.0.0.1:8443//myapi/page/http%3A%2F%2Fwww.example.co.uk%2Ffolder%2Fpage_n0/info' -k -w "\nResponse code: %{http_code}\n"
The controller method, and UTF-8 filter, is:
#Bean
public FilterRegistrationBean filterRegistrationBean()
{
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(filter);
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
#RequestMapping(value = {"/myapi/page/{url}/info"}, method = RequestMethod.GET)
public ResponseEntity<?> test(HttpServletRequest request, HttpServletResponse response, #PathVariable("url") String webPage)
{
ResponseEntity<?> results = new ResponseEntity<Map<String, Object>>(HttpStatus.OK);
// Do something here
return results;
}
I am using Tomcat 8.5.5, and nothing is present in the log files (logging has been set at DEBUG level) except for the following entry in localhost_access_log.2016-10-04.txt:
127.0.0.1 - - [04/Oct/2016:09:04:24 +0100] "GET //myapi/page/http%/info HTTP/1.1" 400 -
In my test code, the url being passed into is being encoded using URLEncoder.encode(), so should be being encoded correctly.
In the remote debugger, I can see that the CharacterEncodingFilter registration code above is being entered so the filter should be being registered.
I have also addedURIEncoding="UTF-8" to each of the Connectors in the server.xml file in $CATALINA_HOME/conf.
I am going round in circles with this and keep on thinking there's something obvious I'm missing. I've never had any issues using a #PathVariable before so I presume I'm encountering some sort of encoding issue, probably relating to the % sign.
I'd be grateful for any help with this!
Update:
I think the issue is that Spring, inside AbstractHandlerMethodMapping and UriUtils, is decoding the entire url, including the #PathVariable portion. It then cannot find a request mapping for the decoded url which is unsurprising since the decoded url includes the decoded url in the #PathVariable. I need to find some way of telling Spring not to decode the application/x-www.form-urlencoded portion of the url.
Any ideas?

How to use custom (non-standard) HTTP status codes in ZF2

I'm trying to send response with a custom http status code 498 - Token Invalid in a Zend Framework 2 application. This is obviously not working as standard Zend Response class does not allow for custom http codes.
So I have created my own response class that handles this http code and return it in my action:
$response = new CustomResponse();
$response->setStatusCode(498); //basic zend response objects throws InvalidArgumentException
return $response;
Although no exception is thrown, the browser says it returned 500 error.
How to get this working?
The HTTP Response class in ZF2 strictly follows the RFC 2616 for the status codes. This is a good practice and an exception will be thrown by setStatusCode() method when you pass an unknown status code.
Anyway, you don't need to create a custom response object to return a non-standard HTTP status code. There is a setCustomStatusCode() method exists for this requirement.
Try this in any controller action:
public function myAction()
{
$response = $this->getResponse();
$response->setCustomStatusCode(498);
$response->setReasonPhrase('Invalid token!');
return $response;
}

Spring MVC binding request parameters

I wrote a spring-mvc controller method to get an array of values in the request parameter.The method looks like below
/**
Trying to get the value for request param foo which passes multiple values
**/
#RequestMapping(method=RequestMethod.GET)
public void performActionXX(HttpServletRequest request,
HttpServletResponse response,
#RequestParam("foo") String[] foo) {
......
......
}
The above method works fine when the request url is in below format
...?foo=1234&foo=0987&foo=5674.
However when the request url is in below format the server returns 400 error
...?foo[0]=1234&foo[1]=0987&foo[2]=5674
Any idea how to fix the method to cater to the second format request url?
This is not possible with #RequestParam. What you can do is implement and register your own HandlerMethodArgumentResolver to perform to resolve request parameters like
...?foo[0]=1234&foo[1]=0987&foo[2]=5674
into an array. You can always checkout the code of RequestParamMethodArgumentResolver to see how Spring does it.
Note that I recommend you change how the client creates the URL.
The server is supposed to define an API and the client is meant to follow it, that's why we have the 400 Bad Request status code.
I resolved this issue using the request.getParameterMap().Below is code.
Map<String,String> parameterMap= request.getParameterMap();
for(String key :parameterMap.keySet()){
if(key.startsWith("nameEntry")){
nameEntryLst.add(request.getParameter(key));
}
}

ASP.NET Web API removing HttpError from responses

I'm building RESTful service using Microsoft ASP.NET Web API.
My problem concerns HttpErrors that Web API throws back to user when something go wrong (e.g. 400 Bad Request or 404 Not Found).
The problem is, that I don't want to get serialized HttpError in response content, as it sometimes provides too much information, therefore it violates OWASP security rules, for example:
Request:
http://localhost/Service/api/something/555555555555555555555555555555555555555555555555555555555555555555555
As a response, I get 400 of course, but with following content information:
{
"$id": "1",
"Message": "The request is invalid.",
"MessageDetail": "The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'MyNamespaceAndMethodHere(Int32)' in 'Service.Controllers.MyController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}
Something like this not only indicates that my WebService is based on ASP.NET WebAPI technology (which isn't that bad), but also it gives some information about my namespaces, method names, parameters, etc.
I tried to set IncludeErrorDetailPolicy in Global.asax
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Never;
Yeah, that did somehow good, now the result doesn't contain MessageDetail section, but still, I don't want to get this HttpError at all.
I also built my custom DelegatingHandler, but it also affects 400s and 404s that I myself generate in controllers, which I don't want to happen.
My question is:
Is there any convinient way to get rid of serialized HttpError from response content? All I want user to get back for his bad requests is response code.
What about using a custom IHttpActionInvoker ?
Basically, you just have to send an empty HttpResponseMessage.
Here is a very basic example :
public class MyApiControllerActionInvoker : ApiControllerActionInvoker
{
public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
{
var result = base.InvokeActionAsync(actionContext, cancellationToken);
if (result.Exception != null)
{
//Log critical error
Debug.WriteLine("unhandled Exception ");
return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.InternalServerError));
}
else if (result.Result.StatusCode!= HttpStatusCode.OK)
{
//Log critical error
Debug.WriteLine("invalid response status");
return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(result.Result.StatusCode));
}
return result;
}
}
In Global.asax
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionInvoker), new MyApiControllerActionInvoker());
One other important thing you could do, not related to Web Api, is to remove excessive asp.net & IIS HTTP headers. Here is a good explanation.
I believe your approach of using the message handler is correct because regardless of the component in the Web API pipeline that sets the status code to 4xx, message handler can clear out response body. However, you do want to differentiate between the ones you explicitly set versus the ones set by the other components. Here is my suggestion and I admit it is a bit hacky. If you don't get any other better solution, give this a try.
In your ApiController classes, when you throw a HttpResponseException, set a flag in request properties, like so.
Request.Properties["myexception"] = true;
throw new HttpResponseException(...);
In the message handler, check for the property and do not clear the response body, if the property is set.
var response = await base.SendAsync(request, cancellationToken);
if((int)response.StatusCode > 399 && !request.Properties.Any(p => p.Key == "myException"))
response.Content = null;
return response;
You can package this a bit nicely by adding an extension method to HttpRequestMessage so that neither the ApiController nor the message handler knows anything about the hard-coded string "myException" that I use above.

How to customize #RequestParam error 400 response in Spring MVC

Is there a way to customize what gets displayed when a required #RequestParam is not sent to the request handler? I always get HTTP Status 400 with a description "The request sent by the client was syntactically incorrect ()." in this case.
Yes, there is a way you should catch MissingServletRequestParameterException
You can do it in several ways:
1)
#ExceptionHandler(MissingServletRequestParameterException.class)
public String handleMyException(Exception exception) {
return "yourErrorViewName";
}
2)
<error-page>
<exception-type>org.springframework.web.bind.MissingServletRequestParameterException</exception-type>
<location>/WEB-INF/pages/myError.jsp</location>
</error-page>
Hope it helps.
How I solved my problem:
#ResponseBody
#ExceptionHandler(MissingServletRequestParameterException.class)
public Object missingParamterHandler(Exception exception) {
// exception handle while specified arguments are not available requested service only. it handle when request is as api json service
return new HashMap() {{ put("result", "failed"); put("type", "required_parameter_missing");}};
}

Resources