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

Preflight/OPTIONS request return 405 for groups with cors/middleware #1040

Closed
lornasong opened this issue Dec 8, 2017 · 16 comments
Closed
Labels

Comments

@lornasong
Copy link

The 405 I am seeing happens when:

  • Making a preflight/options request to an endpoint
  • This endpoint is part of a group
  • This group has cors/middleware attached
  • The main route does not have cors/middleware

I want to acknowledge that this is very similar to #228. However, it seems recently other people have commented that they are experiencing a similar issue and did not see a response.

To reproduce, example when CORS is added to a group only and OPTIONS returns 405

e := echo.New()
e.Use(middleware.Logger())

g := e.Group("/group")
g.Use(middleware.CORSWithConfig(middleware.CORSConfig{
    AllowOrigins:     []string{"*"},
    AllowHeaders:     []string{"authorization", "Content-Type"},
    AllowCredentials: true,
    AllowMethods:     []string{echo.OPTIONS, echo.GET, echo.HEAD, echo.PUT, echo.PATCH, echo.POST, echo.DELETE},
}))

g.GET("/test", func(c echo.Context) error {
    return c.String(http.StatusOK, "200")
})

curl -i -X OPTIONS http://localhost:8083/group/test

HTTP/1.1 405 Method Not Allowed
Content-Type: application/json; charset=UTF-8
Date: Fri, 08 Dec 2017 22:06:02 GMT
Content-Length: 32

However, if the CORS is added at the main route level (this is not what we want to do), OPTIONS returns ideal response:

e := echo.New()
e.Use(middleware.Logger())

e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
    AllowOrigins:     []string{"*"},
    AllowHeaders:     []string{"authorization", "Content-Type"},
    AllowCredentials: true,
    AllowMethods:     []string{echo.OPTIONS, echo.GET, echo.HEAD, echo.PUT, echo.PATCH, echo.POST, echo.DELETE},
}))

g := e.Group("/group")

g.GET("/test", func(c echo.Context) error {
    return c.String(http.StatusOK, "200")
})

curl -i -X OPTIONS http://localhost:8083/group/test

HTTP/1.1 204 No Content
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: authorization,Content-Type
Access-Control-Allow-Methods: OPTIONS,GET,HEAD,PUT,PATCH,POST,DELETE
Access-Control-Allow-Origin: *
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Date: Fri, 08 Dec 2017 22:05:49 GMT

Ideally, it would be nice when adding CORS at the group level only (see code in first example), that a 204 and all of the access-control headers is returned for preflight/options requests (see curl response in second example).

Note: using Echo version 3

@lornasong
Copy link
Author

Hello, just wanted to follow up on this issue. Is this a valid concern? Or is there a recommended alternative approach? Thank you.

@michaeloverton
Copy link

I am having the same issue. Requests to the grouped endpoint are failing the preflight when they shouldn't be.

@eduardotang
Copy link

same issue , any news?

@stale
Copy link

stale bot commented Nov 30, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Nov 30, 2018
@stale stale bot closed this as completed Dec 7, 2018
@rskumar
Copy link

rskumar commented Dec 20, 2018

I too am having same issue. any workaround?

@lcd1232
Copy link

lcd1232 commented Mar 15, 2019

Me too. Any workaround?

@h3l
Copy link

h3l commented Jun 21, 2019

Got this too

@mgnsk
Copy link

mgnsk commented Jun 25, 2019

There seems to be an issue with echo's trailing slashes
If we do
curl -i -X OPTIONS http://localhost:8083/group/test/ (note the trailing slash)
on the first example we get the correct response.

@mgnsk
Copy link

mgnsk commented Jun 25, 2019

There seems to be an issue with echo's trailing slashes
If we do
curl -i -X OPTIONS http://localhost:8083/group/test/ (note the trailing slash)
on the first example we get the correct response.

The solution is to use e.Pre(middleware.AddTrailingSlash()). That way your first example works regardless of the slash.

@vishr vishr removed the wontfix label Jun 25, 2019
@vishr vishr reopened this Jun 25, 2019
@stale
Copy link

stale bot commented Aug 24, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Aug 24, 2019
@stale stale bot closed this as completed Aug 31, 2019
@freshteapot
Copy link

Adding

e.Pre(middleware.AddTrailingSlash()

Is not a fix for me.
I am happy to try and contribute, but i might need some pointers on where to start on the debugging front.

@freshteapot
Copy link

  • I can now confirm, when you pass cors in as a middleware to "GET", it doesnt get called.
  • As mentioned above, if cors is set on the highest level via Use, it works.

I am yet to understand where this goes wrong :)

@freshteapot
Copy link

What I can conclude, so far.

  • middleware support on the actual route, cant handle cors, as the cors middleware expects OPTIONS. Which if you are using GET or POST etc, it will never be.
  • cors middleware should be used on the highest level, the variable where you create the server from
e := echo.New()

At this level, it will always get called as part of the highest level middleware.

The simplest, just add it there and be happy. Anything else, will make you frustrated and not help.
The middleware, only adds to the headers, if a pre-flight has been requested.

I think where I went wrong and perhaps others, is the concept, that middleware via Use can be used at the top level and in groups etc, however this particular middleware only works correctly in one spot.

@vishr is that fair to say?

@jwgcarlson
Copy link

@freshteapot This is my understanding as well. There are basically two distinct types of middleware in Echo:

  1. Top-level middlewares, i.e. e.Use(m...), are applied to every request, regardless of routing.
  2. Route-level middlewares, e.g. e.GET(path, h, m...), are only applied to matching routes.

Despite the similarity between e.Use(m...) and g.Use(m...), groups are actually just syntactic convenience for route-level middlewares. And the CORS middleware doesn't work correctly at route level, because it relies on intercepting OPTIONS requests for which no handler has been defined.

My workaround has been to just declare a dummy OPTIONS handler for every route where I know I may need CORS. As long as some handler is defined, group middlewares for OPTIONS requests will be applied, allowing the CORS middleware to intercept the request and return the correct response. So it looks something like this:

g := e.Group("")
g.Use(middleware.CORSWithConfig(...))  // CORS middleware applied to group
g.GET("/foo", myHandler)  // Normal handler
g.OPTIONS("/foo", echo.MethodNotAllowedHandler)  // Dummy handler

If you have lots of routes, you can define a new type that wraps echo.Group and sets the dummy handler for you:

type CORSGroup struct {
    g *echo.Group
}
func (cg *CORSGroup) GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) {
    cg.g.GET(path, h, m...)  // Normal handler
    cg.g.OPTIONS(path, echo.MethodNotAllowedHandler)  // Dummy handler
}
// POST, DELETE, etc.

@amitavaghosh1
Copy link

You can always migrate to fiber v2. :D because curl -I host:port/ -v still return 405 . There is no shortage of routers

@aldas
Copy link
Contributor

aldas commented Jan 26, 2022

Linking it here #2039 adds Allow header handling. This kicks in when there is no OPTIONS handler set for that path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests