Skip to content

Commit a8c0600

Browse files
committedOct 13, 2020
feat: remove the 'origins' option
The underlying Engine.IO server now supports a 'cors' option, which will be forwarded to the cors module. Breaking change: the 'origins' option is removed Before: ```js new Server(3000, { origins: ["https://example.com"] }); ``` The 'origins' option was used in the allowRequest method, in order to determine whether the request should pass or not. And the Engine.IO server would implicitly add the necessary Access-Control-Allow-xxx headers. After: ```js new Server(3000, { cors: { origin: "https://example.com", methods: ["GET", "POST"], allowedHeaders: ["content-type"] } }); ``` The already existing 'allowRequest' option can be used for validation: ```js new Server(3000, { allowRequest: (req, callback) => { callback(null, req.headers.referer.startsWith("https://example.com")); } }); ```
1 parent 8b6b100 commit a8c0600

File tree

4 files changed

+34
-234
lines changed

4 files changed

+34
-234
lines changed
 

‎dist/index.d.ts

-19
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ interface ServerOptions extends EngineAttachOptions {
9797
* the adapter to use. Defaults to an instance of the Adapter that ships with socket.io which is memory based.
9898
*/
9999
adapter: any;
100-
/**
101-
* the allowed origins (*:*)
102-
*/
103-
origins: string | string[] | ((origin: string, cb: (err: Error, allow: boolean) => void) => void);
104100
/**
105101
* the parser to use. Defaults to an instance of the Parser that ships with socket.io.
106102
*/
@@ -115,7 +111,6 @@ export declare class Server extends EventEmitter {
115111
nsps: Map<string, Namespace>;
116112
private parentNsps;
117113
private _adapter;
118-
private _origins;
119114
private _serveClient;
120115
private eio;
121116
private engine;
@@ -130,13 +125,6 @@ export declare class Server extends EventEmitter {
130125
constructor(opts?: Partial<ServerOptions>);
131126
constructor(srv: http.Server, opts?: Partial<ServerOptions>);
132127
constructor(srv: number, opts?: Partial<ServerOptions>);
133-
/**
134-
* Server request verification function, that checks for allowed origins
135-
*
136-
* @param {http.IncomingMessage} req request
137-
* @param {Function} fn callback to be called with the result: `fn(err, success)`
138-
*/
139-
private checkRequest;
140128
/**
141129
* Sets/gets whether client code is being served.
142130
*
@@ -168,13 +156,6 @@ export declare class Server extends EventEmitter {
168156
* @return {Server|Adapter} self when setting or value when getting
169157
*/
170158
adapter(v: any): any;
171-
/**
172-
* Sets the allowed origins for requests.
173-
*
174-
* @param {String|String[]} v origins
175-
* @return {Server|Adapter} self when setting or value when getting
176-
*/
177-
origins(v: any): any;
178159
/**
179160
* Attaches socket.io to a server or port.
180161
*

‎dist/index.js

-47
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ const namespace_1 = require("./namespace");
3333
const parent_namespace_1 = require("./parent-namespace");
3434
const socket_io_adapter_1 = require("socket.io-adapter");
3535
const parser = __importStar(require("socket.io-parser"));
36-
const url_1 = __importDefault(require("url"));
3736
const debug_1 = __importDefault(require("debug"));
3837
const debug = debug_1.default("socket.io:server");
3938
const clientVersion = require("socket.io-client/package.json").version;
@@ -56,42 +55,10 @@ class Server extends events_1.EventEmitter {
5655
this.parser = opts.parser || parser;
5756
this.encoder = new this.parser.Encoder();
5857
this.adapter(opts.adapter || socket_io_adapter_1.Adapter);
59-
this.origins(opts.origins || "*:*");
6058
this.sockets = this.of("/");
6159
if (srv)
6260
this.attach(srv, opts);
6361
}
64-
/**
65-
* Server request verification function, that checks for allowed origins
66-
*
67-
* @param {http.IncomingMessage} req request
68-
* @param {Function} fn callback to be called with the result: `fn(err, success)`
69-
*/
70-
checkRequest(req, fn) {
71-
let origin = req.headers.origin || req.headers.referer;
72-
// file:// URLs produce a null Origin which can't be authorized via echo-back
73-
if ("null" == origin || null == origin)
74-
origin = "*";
75-
if (!!origin && typeof this._origins == "function")
76-
return this._origins(origin, fn);
77-
if (this._origins.indexOf("*:*") !== -1)
78-
return fn(null, true);
79-
if (origin) {
80-
try {
81-
const parts = url_1.default.parse(origin);
82-
const defaultPort = "https:" == parts.protocol ? 443 : 80;
83-
parts.port = parts.port != null ? parts.port : defaultPort;
84-
const ok = ~this._origins.indexOf(parts.protocol + "//" + parts.hostname + ":" + parts.port) ||
85-
~this._origins.indexOf(parts.hostname + ":" + parts.port) ||
86-
~this._origins.indexOf(parts.hostname + ":*") ||
87-
~this._origins.indexOf("*:" + parts.port);
88-
debug("origin %s is %svalid", origin, !!ok ? "" : "not ");
89-
return fn(null, !!ok);
90-
}
91-
catch (ex) { }
92-
}
93-
fn(null, false);
94-
}
9562
/**
9663
* Sets/gets whether client code is being served.
9764
*
@@ -176,18 +143,6 @@ class Server extends events_1.EventEmitter {
176143
}
177144
return this;
178145
}
179-
/**
180-
* Sets the allowed origins for requests.
181-
*
182-
* @param {String|String[]} v origins
183-
* @return {Server|Adapter} self when setting or value when getting
184-
*/
185-
origins(v) {
186-
if (!arguments.length)
187-
return this._origins;
188-
this._origins = v;
189-
return this;
190-
}
191146
listen(srv, opts = {}) {
192147
return this.attach(srv, opts);
193148
}
@@ -212,8 +167,6 @@ class Server extends events_1.EventEmitter {
212167
}
213168
// set engine.io path to `/socket.io`
214169
opts.path = opts.path || this._path;
215-
// set origins verification
216-
opts.allowRequest = opts.allowRequest || this.checkRequest.bind(this);
217170
this.initEngine(srv, opts);
218171
return this;
219172
}

‎lib/index.ts

-62
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { ParentNamespace } from "./parent-namespace";
99
import { Adapter, Room, SocketId } from "socket.io-adapter";
1010
import * as parser from "socket.io-parser";
1111
import { Encoder } from "socket.io-parser";
12-
import url from "url";
1312
import debugModule from "debug";
1413
import { Socket } from "./socket";
1514
import { CookieSerializeOptions } from "cookie";
@@ -122,13 +121,6 @@ interface ServerOptions extends EngineAttachOptions {
122121
* the adapter to use. Defaults to an instance of the Adapter that ships with socket.io which is memory based.
123122
*/
124123
adapter: any;
125-
/**
126-
* the allowed origins (*:*)
127-
*/
128-
origins:
129-
| string
130-
| string[]
131-
| ((origin: string, cb: (err: Error, allow: boolean) => void) => void);
132124
/**
133125
* the parser to use. Defaults to an instance of the Parser that ships with socket.io.
134126
*/
@@ -155,7 +147,6 @@ export class Server extends EventEmitter {
155147
ParentNamespace
156148
> = new Map();
157149
private _adapter;
158-
private _origins;
159150
private _serveClient: boolean;
160151
private eio;
161152
private engine;
@@ -182,48 +173,10 @@ export class Server extends EventEmitter {
182173
this.parser = opts.parser || parser;
183174
this.encoder = new this.parser.Encoder();
184175
this.adapter(opts.adapter || Adapter);
185-
this.origins(opts.origins || "*:*");
186176
this.sockets = this.of("/");
187177
if (srv) this.attach(srv, opts);
188178
}
189179

190-
/**
191-
* Server request verification function, that checks for allowed origins
192-
*
193-
* @param {http.IncomingMessage} req request
194-
* @param {Function} fn callback to be called with the result: `fn(err, success)`
195-
*/
196-
private checkRequest(
197-
req: http.IncomingMessage,
198-
fn: (err: Error, success: boolean) => void
199-
) {
200-
let origin = req.headers.origin || req.headers.referer;
201-
202-
// file:// URLs produce a null Origin which can't be authorized via echo-back
203-
if ("null" == origin || null == origin) origin = "*";
204-
205-
if (!!origin && typeof this._origins == "function")
206-
return this._origins(origin, fn);
207-
if (this._origins.indexOf("*:*") !== -1) return fn(null, true);
208-
if (origin) {
209-
try {
210-
const parts: any = url.parse(origin);
211-
const defaultPort = "https:" == parts.protocol ? 443 : 80;
212-
parts.port = parts.port != null ? parts.port : defaultPort;
213-
const ok =
214-
~this._origins.indexOf(
215-
parts.protocol + "//" + parts.hostname + ":" + parts.port
216-
) ||
217-
~this._origins.indexOf(parts.hostname + ":" + parts.port) ||
218-
~this._origins.indexOf(parts.hostname + ":*") ||
219-
~this._origins.indexOf("*:" + parts.port);
220-
debug("origin %s is %svalid", origin, !!ok ? "" : "not ");
221-
return fn(null, !!ok);
222-
} catch (ex) {}
223-
}
224-
fn(null, false);
225-
}
226-
227180
/**
228181
* Sets/gets whether client code is being served.
229182
*
@@ -319,19 +272,6 @@ export class Server extends EventEmitter {
319272
return this;
320273
}
321274

322-
/**
323-
* Sets the allowed origins for requests.
324-
*
325-
* @param {String|String[]} v origins
326-
* @return {Server|Adapter} self when setting or value when getting
327-
*/
328-
public origins(v) {
329-
if (!arguments.length) return this._origins;
330-
331-
this._origins = v;
332-
return this;
333-
}
334-
335275
/**
336276
* Attaches socket.io to a server or port.
337277
*
@@ -379,8 +319,6 @@ export class Server extends EventEmitter {
379319

380320
// set engine.io path to `/socket.io`
381321
opts.path = opts.path || this._path;
382-
// set origins verification
383-
opts.allowRequest = opts.allowRequest || this.checkRequest.bind(this);
384322

385323
this.initEngine(srv, opts);
386324

‎test/socket.io.ts

+34-106
Original file line numberDiff line numberDiff line change
@@ -124,121 +124,61 @@ describe("socket.io", () => {
124124
describe("handshake", () => {
125125
const request = require("superagent");
126126

127-
it("should disallow request when origin defined and none specified", done => {
128-
const sockets = new Server({ origins: "http://foo.example:*" }).listen(
129-
54013
130-
);
131-
request
132-
.get("http://localhost:54013/socket.io/default/")
133-
.query({ transport: "polling" })
134-
.end((err, res) => {
135-
expect(res.status).to.be(403);
136-
done();
137-
});
138-
});
139-
140-
it("should disallow request when origin defined and a different one specified", done => {
141-
const sockets = new Server({ origins: "http://foo.example:*" }).listen(
142-
54014
143-
);
144-
request
145-
.get("http://localhost:54014/socket.io/default/")
146-
.query({ transport: "polling" })
147-
.set("origin", "http://herp.derp")
148-
.end((err, res) => {
149-
expect(res.status).to.be(403);
150-
done();
151-
});
152-
});
153-
154-
it("should allow request when origin defined an the same is specified", done => {
155-
const sockets = new Server({ origins: "http://foo.example:*" }).listen(
156-
54015
157-
);
158-
request
159-
.get("http://localhost:54015/socket.io/default/")
160-
.set("origin", "http://foo.example")
161-
.query({ transport: "polling" })
162-
.end((err, res) => {
163-
expect(res.status).to.be(200);
164-
done();
165-
});
166-
});
167-
168-
it("should allow request when origin defined as function and same is supplied", done => {
169-
const sockets = new Server({
170-
origins: (origin, callback) => {
171-
if (origin == "http://foo.example") {
172-
return callback(null, true);
173-
}
174-
return callback(null, false);
127+
it("should send the Access-Control-Allow-xxx headers on OPTIONS request", done => {
128+
const sockets = new Server(54013, {
129+
cors: {
130+
origin: "http://localhost:54023",
131+
methods: ["GET", "POST"],
132+
allowedHeaders: ["content-type"],
133+
credentials: true
175134
}
176-
}).listen(54016);
135+
});
177136
request
178-
.get("http://localhost:54016/socket.io/default/")
179-
.set("origin", "http://foo.example")
137+
.options("http://localhost:54013/socket.io/default/")
180138
.query({ transport: "polling" })
139+
.set("Origin", "http://localhost:54023")
181140
.end((err, res) => {
182-
expect(res.status).to.be(200);
183-
done();
184-
});
185-
});
141+
expect(res.status).to.be(204);
186142

187-
it("should allow request when origin defined as function and different is supplied", done => {
188-
const sockets = new Server({
189-
origins: (origin, callback) => {
190-
if (origin == "http://foo.example") {
191-
return callback(null, true);
192-
}
193-
return callback(null, false);
194-
}
195-
}).listen(54017);
196-
request
197-
.get("http://localhost:54017/socket.io/default/")
198-
.set("origin", "http://herp.derp")
199-
.query({ transport: "polling" })
200-
.end((err, res) => {
201-
expect(res.status).to.be(403);
143+
expect(res.headers["access-control-allow-origin"]).to.be(
144+
"http://localhost:54023"
145+
);
146+
expect(res.headers["access-control-allow-methods"]).to.be("GET,POST");
147+
expect(res.headers["access-control-allow-headers"]).to.be(
148+
"content-type"
149+
);
150+
expect(res.headers["access-control-allow-credentials"]).to.be("true");
202151
done();
203152
});
204153
});
205154

206-
it("should allow request when origin defined as function and no origin is supplied", done => {
207-
const sockets = new Server({
208-
origins: (origin, callback) => {
209-
if (origin == "*") {
210-
return callback(null, true);
211-
}
212-
return callback(null, false);
155+
it("should send the Access-Control-Allow-xxx headers on GET request", done => {
156+
const sockets = new Server(54014, {
157+
cors: {
158+
origin: "http://localhost:54024",
159+
methods: ["GET", "POST"],
160+
allowedHeaders: ["content-type"],
161+
credentials: true
213162
}
214-
}).listen(54021);
163+
});
215164
request
216-
.get("http://localhost:54021/socket.io/default/")
165+
.get("http://localhost:54014/socket.io/default/")
217166
.query({ transport: "polling" })
167+
.set("Origin", "http://localhost:54024")
218168
.end((err, res) => {
219169
expect(res.status).to.be(200);
220-
done();
221-
});
222-
});
223170

224-
it("should default to port 443 when protocol is https", done => {
225-
const sockets = new Server({ origins: "https://foo.example:443" }).listen(
226-
54036
227-
);
228-
request
229-
.get("http://localhost:54036/socket.io/default/")
230-
.set("origin", "https://foo.example")
231-
.query({ transport: "polling" })
232-
.end((err, res) => {
233-
expect(res.status).to.be(200);
171+
expect(res.headers["access-control-allow-origin"]).to.be(
172+
"http://localhost:54024"
173+
);
174+
expect(res.headers["access-control-allow-credentials"]).to.be("true");
234175
done();
235176
});
236177
});
237178

238179
it("should allow request if custom function in opts.allowRequest returns true", done => {
239180
const sockets = new Server(createServer().listen(54022), {
240-
allowRequest: (req, callback) => callback(null, true),
241-
origins: "http://foo.example:*"
181+
allowRequest: (req, callback) => callback(null, true)
242182
});
243183

244184
request
@@ -263,18 +203,6 @@ describe("socket.io", () => {
263203
done();
264204
});
265205
});
266-
267-
it("should allow request when using an array of origins", done => {
268-
new Server({ origins: ["http://foo.example:54024"] }).listen(54024);
269-
request
270-
.get("http://localhost:54024/socket.io/default/")
271-
.set("origin", "http://foo.example:54024")
272-
.query({ transport: "polling" })
273-
.end((err, res) => {
274-
expect(res.status).to.be(200);
275-
done();
276-
});
277-
});
278206
});
279207

280208
describe("close", () => {

0 commit comments

Comments
 (0)
Please sign in to comment.