Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bundled CORS-support #236

Open
ikitommi opened this issue Mar 11, 2019 · 8 comments
Open

Bundled CORS-support #236

ikitommi opened this issue Mar 11, 2019 · 8 comments

Comments

@ikitommi
Copy link
Member

Currently, a third party mw/interceptor is needed for CORS. There should be a fast default mw & interceptor for this. Those could be configured either via route data or via mw/interceptor options. Example data format from #143 (comment):

{:access-control
 {:allow-origin "http://foo.example"
  :allow-methods #{:get :post :put}
  :allow-credentials true
  :allow-headers #{"X-PINGOTHER" "Content-Type"}
  :expose-headers #{"X-My-Custom-Header" "X-Another-Custom-Header"}
  :max-age 86400}}

Some prior work:

Related issues:

@lilactown
Copy link
Contributor

Just putting in my 2 cents: it would be useful to have :allow-origin (at the very least) be a RegEx or function. Depending on the case, users might want to modify the other headers as well depending on parts of the request (e.g. origin).

@kennyjwilli
Copy link

I needed CORS to get my local dev setup with a SPA and backend API working. Ended up writing this interceptor that uses ring-cors.

(s/def ::allow-origin string?)
(s/def ::allow-methods (s/coll-of keyword? :kind set?))
(s/def ::allow-credentials boolean?)
(s/def ::allow-headers (s/coll-of string? :kind set?))
(s/def ::expose-headers (s/coll-of string? :kind set?))
(s/def ::max-age nat-int?)
(s/def ::access-control
  (s/keys :opt-un [::allow-origin
                   ::allow-methods
                   ::allow-credentials
                   ::allow-headers
                   ::expose-headers
                   ::max-age]))

(s/def ::cors-interceptor
  (s/keys :opt-un [::access-control]))

(def cors-interceptor
  {:name    ::cors
   :spec    ::access-control
   :compile (fn [{:keys [access-control]} _]
              (when access-control
                (let [access-control (cors/normalize-config (mapcat identity access-control))]
                  {:enter (fn cors-interceptor-enter
                            [ctx]
                            (let [request (:request ctx)]
                              (if (or (and (cors/preflight? request)
                                           (cors/allow-request? request access-control)))
                                (let [resp (cors/add-access-control
                                             request
                                             access-control
                                             cors/preflight-complete-response)]
                                  (assoc ctx
                                    :response resp
                                    :queue nil))
                                ctx)))
                   :leave (fn cors-interceptor-leave
                            [ctx]
                            (let [request (:request ctx)]
                              (if (and (cors/origin request)
                                       (cors/allow-request? request access-control))
                                (if-let [response (:response ctx)]
                                  (assoc ctx
                                    :response
                                    (cors/add-access-control
                                      request
                                      access-control
                                      response)))
                                ctx)))})))})

Happy to submit a PR if interested.

@thenonameguy
Copy link
Contributor

@kennyjwilli, cleaned up your example a little bit:

(def cors-interceptor
  {:name    ::cors
   :spec    ::access-control
   :compile (fn [{:keys [access-control]} _]
              (when access-control
                (let [access-control (cors/normalize-config (mapcat identity access-control))]
                  {:enter (fn cors-interceptor-enter
                            [{:keys [request] :as ctx}]
                            (if (and (cors/preflight? request)
                                     (cors/allow-request? request access-control))
                              (let [resp (cors/add-access-control
                                          request
                                          access-control
                                          cors/preflight-complete-response)]
                                (assoc ctx
                                       :response resp
                                       :queue nil))
                              ctx))
                   :leave (fn cors-interceptor-leave
                            [{:keys [request response] :as ctx}]
                            (cond-> ctx
                              (and (cors/origin request)
                                   (cors/allow-request? request access-control)
                                   response)
                              (assoc :response
                                     (cors/add-access-control
                                      request
                                      access-control
                                      response))))})))})

@wpcarro
Copy link

wpcarro commented May 11, 2020

What's the status of this? I like the idea of reitit supporting CORS configuration. I've been searching for an idiomatic way to whitelist origins for my ring server and stumbled upon this thread.

@onetom
Copy link

onetom commented May 11, 2021

So, will this support be included into reitit?
I just tried to use ring-cors today, but couldn't make it work.

It seems like the casing of the content-type header makes it fail to allow a method on this line:
https://github.com/r0man/ring-cors/blob/e762decdd4778f70da0dec2b840c5632da559271/src/ring/middleware/cors.cljc#L72
where the access-control-request-method header is looked up simply with get-in, instead of the get-header function within the same file (copied from ring-core's ring.util.reponse.

Since such (presumed) bugs are still present in ring-cors, it might make sense delaying its inclusion into reitit, but it feels like such a common use-case, it would be great to include it...

@brancusi
Copy link

brancusi commented Sep 8, 2021

Would really like this to be a default option.

@fuadsaud
Copy link

fuadsaud commented Mar 7, 2023

What are the current limitations with the :reitit.ring/default-options-endpoint solution? I understand it allows for arbitrary logic to be injected. Is the limitation the fact that it needs to be applied to the entire router instead of individual routes (e.g. via route middleware)?

Edit: I guess the missing piece would be adding the headers to the non-preflight requests.

@WorldsEndless
Copy link

WorldsEndless commented Feb 21, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Development

No branches or pull requests

9 participants