///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2020 Oracle and/or its affiliates.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

///////////////////////////////////////////////////////////////////////////////

= Using Configuration for CORS
:javadoc-base-url-api: {javadoc-base-url}io.helidon.webserver.cors/io/helidon/webserver/cors
:javadoc-base-url-webserver: {javadoc-base-url}io.helidon.webserver/io/helidon/webserver
:h1Prefix: SE
:pagename: cors-configuration
:description: Helidon CORS Configuration
:keywords: helidon, java, cors, configuration
:cors-se-intro: 01_introduction.adoc
:mapped-config-top-key: my-cors
:helidon-tag: https://github.com/oracle/helidon/tree/{helidon-version}
:helidon-se-cors-example: {helidon-tag}/examples/cors
:mapped-config-id-callout: Assigns a unique identifier for this mapped CORS config section.
:common-page-prefix-inc: ../../shared/cors/common_shared.adoc
:cors-config-table-exclude-methods:
:!cors-config-table-exclude-keys:
:basic-table-intro: The table below lists the configuration keys that identify the CORS characteristics.
:helidon-variant: SE

You can use configuration in combination with the Helidon CORS SE API to add CORS support to your resources by
replacing some Java code with declarative configuration. This also gives your users a way to override the
CORS behavior of your services without requiring the code to change.  

include::{common-page-prefix-inc}[tag=cors-configuration-formats-intro]

include::{common-page-prefix-inc}[tag=basic-cross-origin-config]


=== Mapped Cross-Origin Configuration
In some cases, you or your users might want to configure CORS behavior based on URL path matching.
// We want to use the following to insert the SE or MP callout 1 text; we need to use the blank, plus,
// and subs because the MP attribute value contains backticks, and this is the only way we've found
// to for the substitution in the callout to work the way we want. And this works when
// rendered in our editing tools and via the asciidoctor command to HTML but not on our built site.
//
// <1> {blank}
// +
// [subs=attributes+]
// {mapped-config-id-callout}
//
// So instead we have the prefix and suffix tags and the including document provides its own callout 1.
// If at some point the rendering for our site handles this, we can just remove the tag and end
// for the prefix and suffix and just have the including file include the mapped-config instead of
// include the prefix, then provide its own callout 1, then include the suffix.
//
include::{common-page-prefix-inc}[tag=mapped-config-prefix]
<1>  {mapped-config-id-callout}
include::{common-page-prefix-inc}[tag=mapped-config-suffix]

[[using-config-from-app]]
== Using CORS Configuration in the Application
You use configuration in combination with the Helidon CORS SE API
to add CORS support to your resources. The example in <<se/cors/02_using-the-api.adoc#se-api-routing-example,Sample Routing Setup Using the `CrossOriginConfig` API>>
uses the low-level Helidon CORS SE API to create
a `CrossOriginConfig` instance that is then used as part of a `CorsSupport` instance to create the routing rules.
As an alternative to using the low-level API, this example uses config to create the
`CrossOriginConfig` instance instead.


[source,java]
----
    private static Routing createRouting(Config config) {

        MetricsSupport metrics = MetricsSupport.create();
        GreetService greetService = new GreetService(config);
        HealthSupport health = HealthSupport.builder()
                .addLiveness(HealthChecks.healthChecks())   // Adds a convenient set of checks
                .build();
        CorsSupport.Builder builder = CorsSupport.builder();

        Config config = Config.create(); // Created from the current config sources
        config.get("my-cors") // <1>
                .ifExists(builder::mappedConfig);
        config.get("restrictive-cors") // <2>
                .ifExists(builder::config);
        builder.addCrossOriginConfig(CrossOriginConfig.create()); // <3>

        CorsSupport corsSupport = builder.build(); // <4>

        // Note: Add the CORS routing *before* registering the GreetService routing.
        return Routing.builder()
                .register(JsonSupport.create())
                .register(health)                   // Health at "/health"
                .register(metrics)                 // Metrics at "/metrics"
                .register("/greet", corsSupport, greetService) // <5>
                .build();
    }
----
<1> If `my-cors` exists in the configuration, use it to add mapped CORS config to the `CorsSupport` builder.
<2> If `restrictive-cors` exists in the configuration, use it to add basic (not mapped) config to the builder.
<3> Provide default CORS handling for requests that do not match earlier entries.
<4> Obtain the finished `CorsSupport` instance.
<5> Use `corsSupport` in constructing the routing rules.


As each request arrives, Helidon checks it against the cross-origin config instances in the order that your application
added them to the `CorsSupport.Builder`.
The `my-cors` mapped configuration acts as an override because the application added it to the builder first.

If the `my-cors` config key does not appear in the configuration, then the code skips creating a `CrossOriginConfig`
instance based on that configuration, and no overriding occurs. The CORS behavior
that is established by the other `CrossOriginConfig` instance based on the `restrictive-cors` config (if present)
prevails.

NOTE: Remember that if you set configuration in a file that you include as part of your application JAR file, then you need to
rebuild and restart your application for any changes to take effect.

== Next Steps

* Use these same configuration techniques to control the behavior of the CORS-enabled built-in services.
<<se/cors/04_support-in-builtin-services.adoc, Learn more.>>
* See the Helidon CORS support in action by building and running the link:{helidon-se-cors-example}[CORS example].
