Cross-site request and Sever configuration

While developing REST web service, we came across an error “No ‘Access-Control-Allow-Origin’ header is present on the requested resource” with Http Status code 403, after exploring more on it, found the details of CORS and how browser supports it. Obviously as a user (mostly developer) I can disable the security and can make the request, but lets understand the ideal way of handling it.

What is CORS?

This document defines a mechanism to enable client-side cross-origin requests. Specifications that enable an API to make cross-origin requests to resources can use the algorithms defined by this specification. If such an API is used on http://example.org resources, a resource on http://hello-world.example can opt in using the mechanism described by this specification (e.g., specifying Access-Control-Allow-Origin: http://example.org as response header), which would allow that resource to be fetched cross-origin from http://example.org.

You can find more details on : http://www.w3.org/TR/cors/

So if you are making request to same server but the URL is different, the request will be treated as the cross-domain, e.g. http://localhost and http://120.0.0.1 will be treated as the cross-domain. Specification is implemented by the browser to support same-origin policy and security. When browser makes a request, it check for the origin and the URL of the request made to, if it wont match (protocol+domain+port number should be same) then a pre-flight request is made to the server, which is nothing but a same request with HTTP method OPTION. e.g. if you are making a call from localhost:8080/app/index.html to 127.0.0.1:8080/app/hello then request is made to 127.0.0.1:8080/app/hello with OPTION http method.

Pre-flight Request 

OPTIONS /app/home HTTP/1.1 
Host: 127.0.0.1:8080 
Connection: keep-alive 
Cache-Control: max-age=0 
Access-Control-Request-Method: GET 
Origin: http://localhost:8080 
Access-Control-Request-Headers: accept, content-type 
Accept: */* 
Referer: http://localhost:8080/app/index.html 
  

Response

HTTP/1.1 200 OK 
Access-Control-Allow-Origin: http://localhost:8080 
Access-Control-Allow-Credentials: true 
Access-Control-Max-Age: 1800 
Access-Control-Allow-Methods: GET 
Access-Control-Allow-Headers: content-type,access-control-request-headers,access-control-request-method,accept,origin,x-requested-with 
Content-Length: 0
  

 

If your server returns the Access-Control-Allow-Origin headers then only client can access the targeted site content, when the preflight request is successful then browser makes the original request. Once the request is successful, browser cache the details of the origin, url (request made to), max-age and header details, so for subsequent requests to same URL will be served directly and in that case preflight request will be not sent.

On Server Side, How I can support the cross-site request

We do use Tomcat, from Tomact version 7.0.40 by default CorsFilter is included, you just need to enable it for your application, the minimal configuration is

	<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>
 

you can specify the optional parameters by adding init parameters, follow this link for more details.

e.g.

		<init-param>
			<param-name>cors.allowed.origins</param-name>
			<param-value>http://localhost:8080, http://127.0.0.1:8080</param-value>
		</init-param>
		<init-param>
			<param-name>cors.allowed.methods</param-name>
			<param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
		</init-param>

If you have Apache or any other HTTP server between client and you application server, then make sure you have implemented cross-site support on those servers.
if your application is used or open for limited applications, it is recommended to use specific domain names list for “Allowed Origin”, if you have a global web API then you can use *.
More on OPTION method

This method allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval. Mostly option do not have the body, but specification is open and in future option body may be supported to make detailed query on server.

BTW : WebSocket won’t fall under same-origin or cross-site policy, so if you create a WebSocket to different URL it will work.

Download code from GIT

Advertisements
Cross-site request and Sever configuration

Running Embedded Tomcat

While searching for Tomcat 8, I came across a term called “Embedded Tomcat”, so I was wondering what it’s all about. With Embedded Tomcat, one can write a standalone application which can have a embedded web server, so when you run the standalone java application, tomcat embedded server will also start with it. I was surprised to see it has all the features which are available with Tomcat, including WebSocket. Spring Boot is using this API for starting the Spring Boot application. Even you can start your Spring web application by registering Springs DispatcherServlet in below example (but why need to reinvent the wheel, Spring Boot has done that for us).

Maven :

 <dependency> 
  <groupId>org.apache.tomcat.embed</groupId> 
  <artifactId>tomcat-embed-core</artifactId> 
  <version>8.0.14</version>
</dependency> 

<dependency> 
  <groupId>org.apache.tomcat.embed</groupId> 
  <artifactId>tomcat-embed-logging-juli</artifactId> 
  <version>8.0.14</version> 
</dependency>      

Java Code :

		Tomcat tomcat = new Tomcat();
		tomcat.setPort(8080);
		File base = new File(&amp;amp;quot;./staticContent&amp;amp;quot;);
		
		Context rootCtx = tomcat.addWebapp(&amp;amp;quot;/app&amp;amp;quot;, base.getAbsolutePath());
		
		Tomcat.addServlet(rootCtx, &amp;amp;quot;home&amp;amp;quot;, new SimpleServlet());
		rootCtx.addServletMapping(&amp;amp;quot;/home&amp;amp;quot;, &amp;amp;quot;home&amp;amp;quot;);
		
		tomcat.start();
		tomcat.getServer().await();

In above code, setPort sets the port to listen on for embedded Tomcat, I have added a folder “staticContent”, which has my html and to simplify the tomcat configuration I have added simpleWEB-INF/ web.xml in same folder. you can call it from main method.

tomcat.addWebApp method is called with two arguments, first is the context root, and second is the folder path.

if you observer addServlet is Static method of Tomcat class, which registers the servlet class. SimpleServlet is a simple servlet class.

tomcat.start will start the server. That’s all and your embedded Tomcat server is started. you can access your resources by hitting http://localhost:8080/app/home

One of the possible use (Other than running it as tomcat server) I can see is, if you have a web based tool or utility and you want user to quick start and try your product, with minimal setup i.e. just unzipping the package to folder, user can start exploring functionality.

Download Code

Running Embedded Tomcat