-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Update OptionsFilter to not emit duplicate headers #10126
Conversation
OptionsFilter is updated to act upon the response and ensure that the `Allow` header is only written one time.
Kudos, SonarCloud Quality Gate passed! |
mutableHttpResponse.header(HttpHeaders.ALLOW, HttpMethod.OPTIONS.toString()); | ||
return mutableHttpResponse; | ||
if (HttpStatus.METHOD_NOT_ALLOWED.equals(response.getStatus())) { | ||
List<String> allowedMethods = response.getHeaders().get(HttpHeaders.ALLOW, String[].class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't we have a getAll method to simplify this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, getAll
makes it more complicated because it does not do any parsing of the values, it just returns the raw value strings. So in this case, the header has already been written in RequestLifecycle
as something like Allow: GET,POST,HEAD
. getAll
then returns a list with a single String
value of "GET,POST,HEAD"
. Thus to produce this same result we would need conditional logic to check whether that String
is empty to determine whether to add a comma before appending OPTIONS
to it.
I had to disable the OptionsFilterTest on for the servlet TCK on micronaut-projects/micronaut-servlet#588. That should be re-enabled once this is merged. |
.forEach(allow -> mutableHttpResponse.header(HttpHeaders.ALLOW, allow)); | ||
mutableHttpResponse.header(HttpHeaders.ALLOW, HttpMethod.OPTIONS.toString()); | ||
return mutableHttpResponse; | ||
if (HttpStatus.METHOD_NOT_ALLOWED.equals(response.getStatus())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
at this point might as well move the entire logic into RequestLifecycle or wherever METHOD_NOT_ALLOWED is thrown...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yawkat Yes, I had that same thought. It happens in RequestLifecycle#onRouteMiss.
My main concern, and reason for not doing that yet, is that onRouteMiss
executes before runWithFilters
and the original intention of this filter to avoid conflicting with the CORS filter.
That said, it occurs to me now that the onRouteMiss
logic must be getting executed anyway (and the Allow
header getting populated) even in the case of CORS being enabled. Thus in a Servlet environment, we are likely sending the Allow
header even in response to a CORS pre-flight request (alongside all the other headers that CORS adds) because of the same issue of not being able to create a new ServletResponse in the middle of request processing.
OptionsFilter is updated to act upon the response and ensure that the
Allow
header is only written one time.The filter was previously not working as expected with any of the Servlet implementations (including cloud
functions). The problem being that an initial response has already been generated in the
onRouteMiss
methodof
RequestLifecycle
and theAllow
header has already been set using the same route lookup logic that wasimplemented in this filter. The result was that there would be multiple
Allow
headers emitted, containing mostlyduplicate values.
The approach I've taken is to turn this filter into a
ResponseFilter
that relies on the fact that the allowedmethods have already been set in the
RequestLifecycle
if there is not any explicitOptions
route implemented bythe user.
Ultimately this simplifies things a bit, as we no longer need to look up the allowed routes here in the filter.
Additionally, this ensures that the
Allow
header will only be emitted once, with a comma separated list ofacceptable methods. The implementation was previously writing out multiple
Allow
headers each with a single methodvalue. While this is technically allowed by the HTTP spec, I think single multi-valued header format is
cleaner and less surprising.
This should clear the way further for being able to successfully update the Micronaut Core dependency to 4.2.x in Servlet, GCP, AWS, etc.