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

(bug with ready fix!) "OPTIONS" request returns 400 (Bad Request) and fails to respond proper CORS headers #574

Closed
1 of 2 tasks
gilad-bendor opened this issue Mar 25, 2019 · 5 comments

Comments

@gilad-bendor
Copy link

You want to:

  • report a bug
  • request a feature

Current behaviour

My situation is this:

  1. I have to pass the "Authorization" HTTP-header
  2. My socket.io server and my client are on different domains
    Thus, the browser performs an "OPTIONS" pre-flight request.

The "OPTIONS" pre-flight request fails in two ways:

  1. It returns HTTP status of 400 (Bad Request)
  2. It returns the CORS header "Access-Control-Allow-Headers: Content-Type"
    while it should have taken the header's value from the request-header "Access-Control-Request-Headers"

This relates to bug #279.

Steps to reproduce

  1. Clone: https://github.com/gilad-bendor/socket.io-fiddle.git
  2. Execute:
    $ npm install
    $ npm start
  3. The client has to be in the browser - because this is a CORS problem.
    Just open (double-click) the file "client-demo.html" in any modern browser

Expected behaviour

Socket.io should connect...

Setup

  • OS: Windows 10
  • browser: Chrome 72
  • socket.io version: 2.2.0

Other information (e.g. stacktraces, related issues, suggestions how to fix)

I have made a fix, and tested it. There are two fixes in engine.io:

Fix 1: engine.io/lib/transports/polling-xhr.js in XHR.prototype.onRequest
Replace this line:
headers['Access-Control-Allow-Headers'] = 'Content-Type';
with this:
const accessControlRequestHeaders = req.headers['access-control-request-headers'];
if (accessControlRequestHeaders) headers['Access-Control-Allow-Headers'] = accessControlRequestHeaders;

Fix 2: engine.io/lib/server.js in Server.prototype.verify
Replace this line:
if ('GET' !== req.method) return fn(Server.errors.BAD_HANDSHAKE_METHOD, false);
with this:
if (('GET' !== req.method) && ('OPTIONS' !== req.method)) return fn(Server.errors.BAD_HANDSHAKE_METHOD, false);

@darrachequesne
Copy link
Member

Hi! I'm not sure what's the best way to fix that. Couldn't you use the handlePreflightRequest option?

const io = require('socket.io')(server, {
  handlePreflightRequest: (req, res) => {
    res.writeHead(200, {
      'Access-Control-Allow-Headers': 'Authorization',
      'Access-Control-Allow-Methods': 'GET',
      'Access-Control-Allow-Origin': 'null', // served from file system
      'Access-Control-Allow-Credentials': true
    });
    res.end();
  }
});

@gilad-bendor
Copy link
Author

This worked perfectly, thanks!
However, my guess is that I am not the first one to encounter this - why not establish a generic solution?
:-)

@stephen-dahl
Copy link

stephen-dahl commented Aug 21, 2019

options requests should be allowed before the handshake since the purpose of the options request is to ask if I am allowed to perform the handshake request

@darrachequesne
Copy link
Member

Please note that the handlePreflightRequest has been removed in Engine.IO v4, and replaced by the cors module.

const { Server } = require('engine.io');

// before
new Server({
  handlePreflightRequest: (req, res) => {
    res.writeHead(200, {
      "Access-Control-Allow-Origin": 'https://example.com',
      "Access-Control-Allow-Methods": 'GET,POST',
      "Access-Control-Allow-Headers": 'Authorization',
      "Access-Control-Allow-Credentials": true
    });
    res.end();
  }
});

// after
new Server({
  cors: {
    origin: "https://example.com",
    methods: ["GET","POST"],
    allowedHeaders: ["Authorization"],
    credentials: true
  }
});

@danicunhac
Copy link

Thank you, this saved my life.

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

No branches or pull requests

4 participants