OPTIONS request for restful cross-domain using CORS - rest

On client side I'm using Ajax.post (jquery 1.5) with json. On server side I'm using rest resteasy-jaxrs-2.0.1.GA. I found somewhere that i should add couple of headers to server response and I've done with following filter:
public void doFilter( ServletRequest req,
ServletResponse res,
FilterChain filterChain)
throws IOException, ServletException {
MyServletRequestWrapper httpReq = new MyServletRequestWrapper((HttpServletRequest)req);
HttpServletResponse httpRes = (HttpServletResponse)res;
HttpSession session = httpReq.getSession();
httpRes.addHeader(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
httpRes.addHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
if (((HttpServletRequest) req).getMethod().equals("OPTIONS")){
httpRes.addHeader(ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, OPTIONS, PUT, DELETE");
httpRes.addHeader(ACCESS_CONTROL_ALLOW_HEADERS, "content-type, x-requested-with, x-requested-by");
}
filterChain.doFilter(httpReq, httpRes);
}
It works fine cause to every single GET response above headers are added. Problem appears when I want to use POST request. When I use Ajax.post, at first server gets OPTIONS request and I've got following error:
Failed executing OPTIONS [REST_PATH]
org.jboss.resteasy.spi.DefaultOptionsMethodException: No resource method found for options, return OK with Allow header
To solve above error I was trying to add method invoke with the same path as POST ([REST_PATH]) but with #OPTION annotation. In that case javac told me that symbol :class OPTIONS could not be found, even there is a OPTION.class in attached jaxrs library.
Any ideas to fix it? I would be very grateful for any clues.

This question is quite old, but as a reference for others with similar problems - just recently i came across a nice "CORS Filter" you may want to consider using. It's just a matter of adding the following lines to your web.xml and it works like a charm.
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<servlet-name>MyServletNameGoesHere</servlet-name>
</filter-mapping>
and the maven dependency:
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>1.5.1</version>
</dependency>

When I was trying to call my service with an Angular 2 client RestEasy was responding to the preflight requests with the HTTP status 500 and the following error.
RESTEASY003655: No resource method found for options, return OK with
Allow header
I tried RestEasy's CorsFilter but I'd like to propose a simple alternative. What if you don't want to write code handling the OPTIONS call for each of your endpoints ?
I implemented a simple filter that:
Applies the CORS header you need to the response.
Returns the HTTP status code 200 when calling an endpoint with the OPTIONS method. You tell the client that its CORS preflight requests were accepted.
Here is the code. Feel free to refine the filter if you only want to send back a 200 when querying a "real" endpoint.
#Provider
public class CorsFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
headers.add("Access-Control-Allow-Origin", "*"); // If you want to be more restrictive it could be localhost:4200
headers.add("Access-Control-Allow-Methods", "GET, PUT, POST, OPTIONS"); // You can add HEAD, DELETE, TRACE, PATCH
headers.add("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, Accept-Language"); // You can add many more
if (requestContext.getMethod().equals("OPTIONS"))
responseContext.setStatus(200);
}}
Make sure to understand CORS too.

The CORS filter may be fine. I would like to point out as you wrote "To solve above error I was trying to add method invoke with the same path as POST ([REST_PATH]) but with #OPTION annotation. In that case javac told me that symbol :class OPTIONS could not be found, " that you had a typo there instead of #OPTIONS you wrote #OPTION without the S :)

There is a built in CORS filter in tomcat.
http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Related

SOAP-UI Http Status: 405 - The HTTP method 'GET' of the incoming request... is not allowed

I'm doing a POST from SOAP-UI to a IIS C# REST/JSON web service. I had it working, then changed my web.config to require SSL and this problem began.
Also changed IIS webservice to SSL required instead of accepted.
Now I'm getting the error in RAW view of SOAP-UI:
HTTP/1.1 405 Method Not Allowed
Allow: POST
Content-Length: 1565
Content-Type: text/html; charset=UTF-8
Server: Microsoft-IIS/7.5
From Trace Listener:
<ExceptionString>System.InvalidOperationException: The HTTP method 'GET' of the incoming request (with URI 'https://mysite/MyApp/SQRTREST.svc/placeOrderSQRT/') is not allowed.</ExceptionString>
<StackTrace> at System.Runtime.Diagnostics.EtwDiagnosticTrace.WriteExceptionToTraceString(XmlTextWriter xml, Exception exception, Int32 remainingLength, Int32 remainingAllowedRecursionDepth)
at System.Runtime.Diagnostics.EtwDiagnosticTrace.ExceptionToTraceString(Exception exception, Int32 maxTraceStringLength)
at System.Runtime.Diagnostics.EtwDiagnosticTrace.GetSerializedPayload(Object source, TraceRecord traceRecord, Exception exception, Boolean getServiceReference)
at System.Runtime.TraceCore.HandledExceptionWarning(EtwDiagnosticTrace trace, String param0, Exception exception)
at System.ServiceModel.Dispatcher.HttpUnhandledOperationInvoker.Invoke(Object instance, Object[] inputs, Object[]&amp; outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&amp; rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(IAsyncResult result)
So if SOAP-UI is doing a POST, why is the error related to an HTTP "GET" method?
This is happening in with SOAP-UI in Production too, but yet the external client seems to still be able to call the webservice using whatever software they are using.
I see other posts about 405 on StackOveflow, but nothing that addresses a SOAP-UI post.
Updates on next day after posting the above:
1) I got setup with Debug/Trace - and when running SOAP-UI, the trace never enters the method
2) I set up a C# client program that does the Post, and it does get into the method and I'm able to use Debug/Trace (it's ending with another issue I have to untangle).
Update 2: Some research makes me think it might have to do with the fact that the HTTP Headers are encrypted. Someone in the SOAP-Ui forum mentioned having a missing HTTP Header; but not sure where that leads me...
This lead me to the solution:
https://forums.iis.net/t/1152122.aspx?HTTP+1+1+405+Method+Not+Allowed+Allow+OPTIONS+TRACE+GET+HEAD
I simply added a trailing slash on my method name.
I have the Endpoint set to the xxx.svc.
Then I had the Resource set to a value such as /Resource1.
By changing it to /Resource1/ it worked.
The above link suggests that it tries to read the directory or something.

Jersey Grizzly Rest How to extract "form-data" parameters

Consider following function:
#POST
#Path("/handle_response")
#Produces(MediaType.APPLICATION_JSON)
public ResponseJsonBean handle(#FormParam("first") Integer first, #FormParam("second") Integer second)
{
////// bla bla
}
The above function is called when I make a POST x-www-form-urlencoded request. But the function is not called when I make POST form data request. Why it is not called in the latter case? and how can I make such function which works for latter request.
Yeah application/x-www-form-urlencoded and multipart/form-data are complete different types and formats. The correct provider to read the request is discovered through the type sent.
For multipart support, you should add the Jersey multipart dependency
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey2.version}</version>
</dependency>
Then in your resource method do something like
#POST
#Path("/upload")
#Produces(MediaType.APPLICATION_JSON)
#Consumes({MediaType.MULTIPART_FORM_DATA})
public Response uploadFile(
#FormDataParam("file") InputStream fileInputStream,
#FormDataParam("file") FormDataContentDisposition cdh) throws Exception{
}
See Also:
An example with the client side also
Jersey Multipart Documentation
In case you are using Jersey 1.x

CSRF Filtering using GWT RequestFactoryServlet

I am implementing a token based system to prevent CSRF attacks in my Request Factory based GWT App.
To implement my filter on the server side I have overridden the doPost method on RequestFactoryServlet, thus:
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String sessionToken = CsrfTokenManager.getToken(request.getSession());
String requestToken = request.getHeader(CsrfTokenManager.CSRF_TOKEN_NAME);
if (sessionToken.equals(requestToken)) {
super.doPost(request, response);
} else {
logger.error(String.format("Received unsafe http request [%s]", getFullRequest(request)));
response.sendError(401,"Unsafe HTTP Request");
}
}
This works in that it does not allow requests without a valid token to be processed, and my logs contain a suitable message, but the error I get back is a 500-Internal Server Error rather than a 401.
Can anyone shed light on why this is and what I should be doing differently?
There is very little information provided by you on the reason for 500 internal server error. Please share the exception stack trace ( 500 internal server error would have thrown one).
Also avoid implementing a custom one if it is not based on GWT recommendation. Read this stackoverflow query on CSRF with RequestFactory.

Jetty custom status message ??

I am writing a service in clojure (using ring and compojure) which should change the status message. It is running on embedded Jetty 8. For example I have
200 OK
and I would like to have something like
200 <custome message>
In the EJB world there was possibility to set up header "X-Http-Status-Message" which does some magic behind the scene and changed message in response.
Is there any header in Jetty which allow me to do the same thing??
or Is there any other way in clojure to do it??
Not with a magic header like that.
The status reason has to be set along with the status code in the same call in Jetty.
You can use either javax.servlet.http.HttpServletResponse.setStatus(int, String) or org.eclipse.jetty.server.Response.setStatus(int, String).
Example:
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setStatus(HttpServletResponse.SC_OK, "Alrighty");
}
Note that some error conditions this status reason cannot be overridden. But generally, use of HttpServletResponse.sendError(int, String) will behave as you expect.
According to Ring documentation, you can only set the status code, not message:
https://github.com/mmcgrana/ring/wiki/Concepts
Also, the ring.util.servlet/set-status function invokes javax.servlet.http.HttpServletResponse .setStatus(int):
(defn set-status
"Update a HttpServletResponse with a status code."
[^HttpServletResponse response, status]
(.setStatus response status))
Whole implementation is here: https://github.com/ring-clojure/ring/blob/master/ring-servlet/src/ring/util/servlet.clj#L64
It should be fairly trivial to change Ring to add optional support for status message.
I suppose that the change could be introduced to the ring.util.servlet/update-servlet-response function:
(defn update-servlet-response
"Update the HttpServletResponse using a response map."
[^HttpServletResponse response, {:keys [status headers body]}]
(when-not response
(throw (Exception. "Null response given.")))
(when status
(set-status response status))
(doto response
(set-headers headers)
(set-body body)))
For example by adding status-message key to the response map.
https://github.com/ring-clojure/ring/blob/master/ring-servlet/src/ring/util/servlet.clj#L105

Using a default method for unmatched REST methods in Jersey

I know this is not quite "restful" but, I want to learn if and how I can handle all requests which do not match any of the methods in my REST resource (I want to proxy these requests to another server). For example, it could be a method like:
#GET
#Path("*")
public Response defaultMethod(#Context HttpServletRequest request, #Context HttpServletResponse response)
{
// do proxying here
}
how can I achieve this?
BR,
SerkanC
#Path("/{default: .*}")
This works for:
http://example.com/someUnexpectedPath
http://example.com/someUnexpectedPath/withAdditionalSubPaths
http://example.com/someUnexpectedPath/withAdditionalSubPaths?andParams=whatever
One possible option would be to define a custom 404 mapping. Since 404s handles all unmatched requests it should catch all undefined urls.
I added the following this to my web.xml file
<error-page>
<error-code>404</error-code>
<location>/error/404</location>
</error-page>
Where location is the path you want to direct the request to. Then just define that the call as normal.