summaryrefslogtreecommitdiff
path: root/http/server.ts
diff options
context:
space:
mode:
authorYusuke Sakurai <kerokerokerop@gmail.com>2019-02-19 08:32:31 +0900
committerRyan Dahl <ry@tinyclouds.org>2019-02-18 18:32:31 -0500
commitbdeb6c43afceab913cb02f00e74ebe43377c2fff (patch)
tree1110965322df504a689ea17e54386546ea244733 /http/server.ts
parent954fe83f62770257ea516396feb31ba961bc0967 (diff)
fix: url match logic of http server (denoland/deno_std#199)
Original: https://github.com/denoland/deno_std/commit/da188a7d30cbf71317b46015ee63a06437c09aeb
Diffstat (limited to 'http/server.ts')
-rw-r--r--http/server.ts58
1 files changed, 39 insertions, 19 deletions
diff --git a/http/server.ts b/http/server.ts
index a5c5677c2..a80becbd5 100644
--- a/http/server.ts
+++ b/http/server.ts
@@ -152,25 +152,15 @@ class HttpServerImpl implements HttpServer {
async listen(addr: string, cancel: Deferred = defer()) {
for await (const { req, res } of serve(addr, cancel)) {
- let lastMatch: RegExpMatchArray;
- let lastHandler: HttpHandler;
- for (const { pattern, handler } of this.handlers) {
- const match = req.url.match(pattern);
- if (!match) {
- continue;
- }
- if (!lastMatch) {
- lastMatch = match;
- lastHandler = handler;
- } else if (match[0].length > lastMatch[0].length) {
- // use longest match
- lastMatch = match;
- lastHandler = handler;
- }
- }
- req.match = lastMatch;
- if (lastHandler) {
- await lastHandler(req, res);
+ let { pathname } = new URL(req.url, addr);
+ const { index, match } = findLongestAndNearestMatch(
+ pathname,
+ this.handlers.map(v => v.pattern)
+ );
+ req.match = match;
+ if (index > -1) {
+ const { handler } = this.handlers[index];
+ await handler(req, res);
if (!res.isResponded) {
await res.respond({
status: 500,
@@ -187,6 +177,36 @@ class HttpServerImpl implements HttpServer {
}
}
+/**
+ * Find the match that appeared in the nearest position to the beginning of word.
+ * If positions are same, the longest one will be picked.
+ * Return -1 and null if no match found.
+ * */
+export function findLongestAndNearestMatch(
+ pathname: string,
+ patterns: (string | RegExp)[]
+): { index: number; match: RegExpMatchArray } {
+ let lastMatchIndex = pathname.length;
+ let lastMatchLength = 0;
+ let match: RegExpMatchArray = null;
+ let index = -1;
+ for (let i = 0; i < patterns.length; i++) {
+ const pattern = patterns[i];
+ const m = pathname.match(pattern);
+ if (!m) continue;
+ if (
+ m.index < lastMatchIndex ||
+ (m.index === lastMatchIndex && m[0].length > lastMatchLength)
+ ) {
+ index = i;
+ match = m;
+ lastMatchIndex = m.index;
+ lastMatchLength = m[0].length;
+ }
+ }
+ return { index, match };
+}
+
class ServerResponderImpl implements ServerResponder {
constructor(private w: Writer) {}