aws / serverless-application-model

The AWS Serverless Application Model (AWS SAM) transform is a AWS CloudFormation macro that transforms SAM templates into CloudFormation templates.
https://aws.amazon.com/serverless/sam
Apache License 2.0
9.35k stars 2.38k forks source link

BinaryMediaTypes and CORS do not work together #1344

Open espenjanson opened 4 years ago

espenjanson commented 4 years ago

We cannot get CORS to work with BinaryMediaTypes

Error message:


OPTIONS https://URL 500

Access to XMLHttpRequest at 'https://URL' from origin 'http://localhost:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access- 
Control-Allow-Origin' header is present on the requested resource.

This is our sam template:


Resources:
  ApiName:
    Type: AWS::Serverless::Api
    Properties:
      StageName: development
      BinaryMediaTypes:
        - '*~1*'
      Cors:
        AllowMethods: "'*'"
        AllowHeaders: "'*'"
        AllowOrigin: "'*'"
      Auth:
        DefaultAuthorizer: CognitoAuthorizer
        AddDefaultAuthorizerToCorsPreflight: false
        Authorizers:
          CognitoAuthorizer:
            UserPoolArn: 'USER_POOL'

As soon as we remove the "BinaryMediaTypes" option, the request works.

SAM CLI, version 0.37.0

averydev commented 4 years ago

Did you ever figure out the problem here? I'm having the same issue.

rcermeno commented 4 years ago

I have the same issue, please somebody help us!!!

rcermeno commented 4 years ago

@espenjanson @averydev I could solve it.

Just put the mime types you need in the BinaryMediaTypes property. i.e:

BinaryMediaTypes:
        - 'text~1html'
        - 'application~1xhtml+xml'
        - 'application~1xml;q=0.9'
        - 'image~1*'

The reason: If you set the property to / , then ApiGateway tries to convert all responses to Binary, even json responses, and throws an error.

danbanecker commented 3 years ago

SAM should support content handling for CORS OPTIONS requests. For example in AWS::Serverless::Api Please add an option under the Cors: section to be able to convert to text so this binary problem is fixed. contentHandling: CONVERT_TO_TEXT

  Cors:
    AllowMethods: "'OPTIONS,HEAD,GET,POST,PUT,DELETE'"
    AllowHeaders: "'Access-Control-Request-Headers,Access-Control-Request-Method,Access-Control-Allow-Origin,x-api-key,Accept,Content-Type'"
    AllowOrigin: "'*'"
    contentHandling: CONVERT_TO_TEXT
marinaglancy commented 3 years ago

There are situations when it is necessary to specify

BinaryMediaTypes:
  - '*.*'

Because this is the "Accept" header that browsers and curl send and the BinaryMediaTypes must match it.

Unfortunately workaround suggested by @rcermeno does not help in this case. More discussion here: https://github.com/aws/aws-sam-cli/issues/312

hhowe29 commented 3 years ago

Is it possible to configure SAM to defer all CORS logic to the lambda proxy? Our lambda is implemented with flask, so dealing with CORS on that level isn't too bad.

We are setting BinaryMediaTypes to */* to work around a variety of issues. It worked beautifully until we realized it broke CORS.

luizwhite commented 3 years ago

any workaround to serve binaries (like when Content-Type is application/pdf) and not require "Accept" header in the request, while working with CORS?

matzeso commented 3 years ago

Having the same issue - damn I just thought I finally have a solution for handling binary files in the browser with the */* mediaType and then had to realize it broke CORS.

psudocode commented 2 years ago

I have a slightly different problem. I tried to upload files via Lamba to S3, its works only on the non-browser environment but not the browser.

Postman -> lambda (can upload - without cors) Browser -> lambda (can't upload)

I solved it by adding "multipart/form-data" to "Binary Media Types" or "BinaryMediaTypes".

I hope this comment can help someone in the future.

choutkamartin commented 1 year ago

4 years later, still troublesome

martinber commented 11 months ago

I lost many hours to this. It doesn't help that the lambda powertools documentation example uses BinaryMediaTypes and CORS together. I copied this part thinking that these are "recommended" for lambda-powertools, I wonder now if that documentation example is wrong

Also it doesn't help that I tested locally using sam local start-api and there it works, but when it is deployed it does not work

payros commented 7 months ago

I also lost many hours trying to resolve this issue. Can anyone explain to me why API Gateway must look at the Accept header to encode/decode binary data? Wouldn't it be sufficient to simply look at the Content-Type request header and match it with BinaryMediaTypes for requests?

As I see it, ignoring the Accept header when making the decision to encode/decode binary data would solve this issue.