Files
2020-10-16 15:37:23 -07:00
..
2020-05-29 16:52:39 +02:00
2020-05-07 13:26:43 -05:00

Helidon MP CORS Example

This example shows a simple greeting application, similar to the one from the Helidon MP QuickStart, enhanced with CORS support.

Near the end of the resources/logging.properties file, a commented line would turn on FINE logging that would reveal how the Helidon CORS support makes it decisions. To see that logging, uncomment that line and then package and run the application.

Build and run

mvn package
java -jar target/helidon-examples-microprofile-cors.jar

Using the app endpoints as with the "classic" greeting app

These normal greeting app endpoints work just as in the original greeting app:

curl -X GET http://localhost:8080/greet
{"message":"Hello World!"}

curl -X GET http://localhost:8080/greet/Joe
{"message":"Hello Joe!"}

curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting

curl -X GET http://localhost:8080/greet/Jose
{"message":"Hola Jose!"}

Using CORS

Sending "simple" CORS requests

The following requests illustrate the CORS protocol with the example app.

By setting Origin and Host headers that do not indicate the same system we trigger CORS processing in the server:

# Follow the CORS protocol for GET
curl -i -X GET -H "Origin: http://foo.com" -H "Host: here.com" http://localhost:8080/greet

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Thu, 30 Apr 2020 17:25:51 -0500
Vary: Origin
connection: keep-alive
content-length: 27

{"greeting":"Hola World!"}

Note the new headers Access-Control-Allow-Origin and Vary in the response.

The same happens for a GET requesting a personalized greeting (by passing the name of the person to be greeted):

curl -i -X GET -H "Origin: http://foo.com" -H "Host: here.com" http://localhost:8080/greet/Joe
{"greeting":"Hola Joe!"}

Take a look at GreetResource and in particular the methods named optionsForXXX near the end of the class. There is one for each different subpath that the resource's endpoints handle: no subpath, /{name}, and /greeting. The @CrossOrigin annotation on each defines the CORS behavior for the corresponding path. The optionsForUpdatingGreeting gives specific origins and the HTTP method (PUT) constraints for sharing that resource. The other two optionsForRetrievingXXXGreeting methods use default parameters for the @CrossOrigin annotation: allowing all origins, all methods, etc.

With this in mind, we can see why the two earlier GET curl requests work.

These are what CORS calls "simple" requests; the CORS protocol for these adds headers to the request and response that would be exchanged between the client and server even without CORS.

"Non-simple" CORS requests

The CORS protocol requires the client to send a pre-flight request before sending a request that changes state on the server, such as PUT or DELETE and to check the returned status and headers to make sure the server is willing to accept the actual request. CORS refers to such PUT and DELETE requests as "non-simple" ones.

This command sends a pre-flight OPTIONS request to see if the server will accept a subsequent PUT request from the specified origin to change the greeting:

curl -i -X OPTIONS \
    -H "Access-Control-Request-Method: PUT" \
    -H "Origin: http://foo.com" \
    -H "Host: here.com" \
    http://localhost:8080/greet/greeting

HTTP/1.1 200 OK
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Origin: http://foo.com
Date: Thu, 30 Apr 2020 17:30:59 -0500
transfer-encoding: chunked
connection: keep-alive

The successful status and the returned Access-Control-Allow-xxx headers indicate that the server accepted the pre-flight request. That means it is OK for us to send PUT request to perform the actual change of greeting. (See below for how the server rejects a pre-flight request.)

curl -i -X PUT \
    -H "Origin: http://foo.com" \
    -H "Host: here.com" \
    -H "Access-Control-Allow-Methods: PUT" \
    -H "Access-Control-Allow-Origin: http://foo.com" \
    -H "Content-Type: application/json" \
    -d "{ \"greeting\" : \"Cheers\" }" \
    http://localhost:8080/greet/greeting

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://foo.com
Date: Thu, 30 Apr 2020 17:32:55 -0500
Vary: Origin
connection: keep-alive

And we run one more GET to observe the change in the greeting:

curl -i -X GET -H "Origin: http://foo.com" -H "Host: here.com" http://localhost:8080/greet/Joe
{"greeting":"Cheers Joe!"}

Note that the tests in the example TestCORS class follow these same steps.