diff --git a/moco-doc/apis.md b/moco-doc/apis.md index a88008418..711520d78 100644 --- a/moco-doc/apis.md +++ b/moco-doc/apis.md @@ -55,6 +55,7 @@ Table of Contents - [Secure](#secure) - [HTTP Only](#http-only) - [Max Age](#max-age) + - [Same Site](#same-site) - [CORS](#cors) - [Default All CORS](#default-all-cors) - [CORS with allowOrigin/Access-Control-Allow-Origin](#cors-with-alloworiginaccess-control-allow-origin) @@ -108,6 +109,7 @@ Table of Contents - [Log](#log) - [Log with verifier](#log-with-verifier) + ## Composite Java API Design Moco Java API is designed in functional fashion which means you can composite any request or response easily. @@ -1757,6 +1759,16 @@ You can add default all CORS to your response with `cors` operator without any a server.response(cors()); ``` +* JSON API +```json +{ + "response" : + { + "cors" : true + } +} +``` + #### CORS with allowOrigin/Access-Control-Allow-Origin You can allow CORS with specific origin with `cors` operator with `allowOrigin` argument, which provides `Access-Control-Allow-Origin` header. diff --git a/moco-runner/src/main/java/com/github/dreamhead/moco/parser/deserializer/CorsContainerDeserializer.java b/moco-runner/src/main/java/com/github/dreamhead/moco/parser/deserializer/CorsContainerDeserializer.java new file mode 100644 index 000000000..1dfa0e03a --- /dev/null +++ b/moco-runner/src/main/java/com/github/dreamhead/moco/parser/deserializer/CorsContainerDeserializer.java @@ -0,0 +1,55 @@ +package com.github.dreamhead.moco.parser.deserializer; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.github.dreamhead.moco.parser.model.CorsContainer; + +import java.io.IOException; +import java.util.List; + +public class CorsContainerDeserializer extends JsonDeserializer { + @Override + public CorsContainer deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException { + JsonToken currentToken = jp.getCurrentToken(); + if (currentToken == JsonToken.VALUE_TRUE) { + return CorsContainer.newContainer(); + } + + if (currentToken == JsonToken.START_OBJECT) { + jp.nextToken(); + CorsContainerDeserializer.InternalCorsContainer container = jp.readValueAs(CorsContainerDeserializer.InternalCorsContainer.class); + return container.toContainer(); + } + + return (CorsContainer) ctxt.handleUnexpectedToken(CorsContainer.class, jp); + } + + @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) + static class InternalCorsContainer { + @JsonAlias("Access-Control-Allow-Origin") + private String allowOrigin; + + @JsonAlias("Access-Control-Allow-Methods") + private List allowMethods; + + @JsonAlias("Access-Control-Allow-Headers") + private List allowHeaders; + + @JsonAlias("Access-Control-Max-Age") + private Long maxAge; + + @JsonAlias("Access-Control-Expose-Headers") + private List exposeHeaders; + + @JsonAlias("Access-Control-Allow-Credentials") + private Boolean allowCredentials; + + public CorsContainer toContainer() { + return CorsContainer.newContainer(allowOrigin, allowMethods, allowHeaders, maxAge, exposeHeaders, allowCredentials); + } + } +} diff --git a/moco-runner/src/main/java/com/github/dreamhead/moco/parser/model/CorsContainer.java b/moco-runner/src/main/java/com/github/dreamhead/moco/parser/model/CorsContainer.java index 2137218df..6c4d004c3 100644 --- a/moco-runner/src/main/java/com/github/dreamhead/moco/parser/model/CorsContainer.java +++ b/moco-runner/src/main/java/com/github/dreamhead/moco/parser/model/CorsContainer.java @@ -2,7 +2,10 @@ import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.github.dreamhead.moco.handler.cors.CorsConfig; +import com.github.dreamhead.moco.parser.deserializer.CookieContainerDeserializer; +import com.github.dreamhead.moco.parser.deserializer.CorsContainerDeserializer; import com.google.common.base.MoreObjects; import java.util.ArrayList; @@ -16,6 +19,7 @@ import static com.github.dreamhead.moco.MocoCors.maxAge; @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +@JsonDeserialize(using = CorsContainerDeserializer.class) public final class CorsContainer { @JsonAlias("Access-Control-Allow-Origin") private String allowOrigin; @@ -35,6 +39,26 @@ public final class CorsContainer { @JsonAlias("Access-Control-Allow-Credentials") private Boolean allowCredentials; + public static CorsContainer newContainer() { + return new CorsContainer(); + } + + public static CorsContainer newContainer(final String allowOrigin, + final List allowMethods, + final List allowHeaders, + final long maxAge, + final List exposeHeaders, + final Boolean allowCredentials) { + CorsContainer container = new CorsContainer(); + container.allowOrigin = allowOrigin; + container.allowMethods = allowMethods; + container.allowHeaders = allowHeaders; + container.maxAge = maxAge; + container.exposeHeaders = exposeHeaders; + container.allowCredentials = allowCredentials; + return container; + } + public CorsConfig[] getConfigs() { List configs = new ArrayList<>(); if (allowOrigin != null) { diff --git a/moco-runner/src/test/java/com/github/dreamhead/moco/MocoCorsStandaloneTest.java b/moco-runner/src/test/java/com/github/dreamhead/moco/MocoCorsStandaloneTest.java index db20b152a..5ccfc4561 100644 --- a/moco-runner/src/test/java/com/github/dreamhead/moco/MocoCorsStandaloneTest.java +++ b/moco-runner/src/test/java/com/github/dreamhead/moco/MocoCorsStandaloneTest.java @@ -12,6 +12,14 @@ import static org.hamcrest.MatcherAssert.assertThat; public class MocoCorsStandaloneTest extends AbstractMocoStandaloneTest { + @Test + public void should_support_default_cors() throws IOException, ProtocolException { + runWithConfiguration("cors.json"); + ClassicHttpResponse response = helper.putForResponseWithHeaders(remoteUrl("/default-cors"), "", of("Origin", "https://www.github.com/")); + assertThat(response.getHeader("Access-Control-Allow-Origin").getValue(), is("*")); + assertThat(response.getHeader("Access-Control-Allow-Methods").getValue(), is("*")); + assertThat(response.getHeader("Access-Control-Allow-Headers").getValue(), is("*")); + } @Test public void should_support_cors() throws IOException, ProtocolException { runWithConfiguration("cors.json"); diff --git a/moco-runner/src/test/resources/cors.json b/moco-runner/src/test/resources/cors.json index b51b5f050..3fc2b5001 100644 --- a/moco-runner/src/test/resources/cors.json +++ b/moco-runner/src/test/resources/cors.json @@ -1,4 +1,12 @@ [ + { + "request": { + "uri": "/default-cors" + }, + "response": { + "cors": true + } + }, { "request": { "uri": "/cors"