diff --git a/lib/server.ts b/lib/server.ts index c99f8ef8..e0e975bd 100644 --- a/lib/server.ts +++ b/lib/server.ts @@ -31,6 +31,12 @@ export interface AttachOptions { * @default 1000 */ destroyUpgradeTimeout?: number; + + /** + * Whether we should add a trailing slash to the request path. + * @default true + */ + addTrailingSlash?: boolean; } export interface ServerOptions { @@ -181,6 +187,22 @@ export abstract class BaseServer extends EventEmitter { protected abstract init(); + /** + * Compute the pathname of the requests that are handled by the server + * @param options + * @protected + */ + protected _computePath(options: AttachOptions) { + let path = (options.path || "/engine.io").replace(/\/$/, ""); + + if (options.addTrailingSlash !== false) { + // normalize path + path += "/"; + } + + return path; + } + /** * Returns a list of available transports for upgrade given a certain transport. * @@ -635,14 +657,11 @@ export class Server extends BaseServer { * @api public */ public attach(server: HttpServer, options: AttachOptions = {}) { - let path = (options.path || "/engine.io").replace(/\/$/, ""); - + const path = this._computePath(options); const destroyUpgradeTimeout = options.destroyUpgradeTimeout || 1000; - // normalize path - path += "/"; - function check(req) { + // TODO use `path === new URL(...).pathname` in the next major release (ref: https://nodejs.org/api/url.html) return path === req.url.slice(0, path.length); } diff --git a/lib/userver.ts b/lib/userver.ts index 66fa4041..82fdd5bd 100644 --- a/lib/userver.ts +++ b/lib/userver.ts @@ -65,7 +65,7 @@ export class uServer extends BaseServer { app /* : TemplatedApp */, options: AttachOptions & uOptions = {} ) { - const path = (options.path || "/engine.io").replace(/\/$/, "") + "/"; + const path = this._computePath(options); (app as TemplatedApp) .any(path, this.handleRequest.bind(this)) // diff --git a/test/server.js b/test/server.js index 6bb461a9..5d741022 100644 --- a/test/server.js +++ b/test/server.js @@ -745,6 +745,36 @@ describe("server", () => { }); }); }); + + it("should support requests without trailing slash", done => { + listen({ addTrailingSlash: false }, port => { + const partialDone = createPartialDone(done, 2); + + request + .get(`http://localhost:${port}/engine.io`) + .query({ transport: "polling" }) + .end((err, res) => { + expect(err).to.be(null); + expect(res.status).to.be(200); + partialDone(); + }); + + request + .get(`http://localhost:${port}/engine.io/foo/bar/`) + .query({ transport: "polling" }) + .end((err, res) => { + if (process.env.EIO_WS_ENGINE === "uws") { + expect(err).to.not.be(null); + expect(err.message).to.be("socket hang up"); + } else { + expect(err).to.be(null); + // this should not work, but it is kept for backward-compatibility + expect(res.status).to.be(200); + } + partialDone(); + }); + }); + }); }); describe("close", () => {