Skip to content

Commit

Permalink
changed: [router] string pattern should be served when full path matc…
Browse files Browse the repository at this point in the history
…hes (#32)
  • Loading branch information
keroxp authored Oct 10, 2019
1 parent 042fc6d commit c8f5d5b
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 105 deletions.
177 changes: 85 additions & 92 deletions agent_test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Copyright 2019 Yusuke Sakurai. All rights reserved. MIT license.
import { runIfMain, test } from "./vendor/https/deno.land/std/testing/mod.ts";
import { defer, Deferred } from "./promises.ts";
import { encode } from "./vendor/https/deno.land/std/strings/encode.ts";
import { createAgent } from "./agent.ts";
import { createRouter } from "./router.ts";
Expand All @@ -11,16 +10,16 @@ import {
import Reader = Deno.Reader;
import Buffer = Deno.Buffer;
import copy = Deno.copy;
import { it } from "./testing.ts";
import { ServeListener } from "./server.ts";

async function readString(r: Reader) {
const buf = new Buffer();
await copy(buf, r);
return buf.toString();
}

let _port = 8700;
function setupRouter(port: number): Deferred {
const d = defer();
function setupRouter(port: number): ServeListener {
const router = createRouter();
router.handle("/get", async req => {
return req.respond({
Expand All @@ -35,103 +34,97 @@ function setupRouter(port: number): Deferred {
body: req.body
});
});
router.listen(
{
hostname: "127.0.0.1",
port
},
{ cancel: d.promise }
);
return d;
return router.listen({
hostname: "127.0.0.1",
port
});
}

test(async function agent() {
const router = setupRouter(++_port);
const agent = createAgent(`http://127.0.0.1:${_port}`);
try {
{
const res = await agent.send({
path: "/get",
method: "GET"
});
assertEquals(res.status, 200);
assertEquals(await readString(res.body), "ok");
}
{
const res = await agent.send({
path: "/post",
method: "POST",
body: encode("denoland")
});
assertEquals(res.status, 200);
assertEquals(await readString(res.body), "denoland");
it("agent", t => {
let port = 8700;
t.beforeAfterAll(() => {
const listener = setupRouter(port);
return () => listener.close();
});
t.run("agent", async () => {
const agent = createAgent(`http://127.0.0.1:${port}`);
try {
{
const res = await agent.send({
path: "/get",
method: "GET"
});
assertEquals(res.status, 200);
assertEquals(await readString(res.body), "ok");
}
{
const res = await agent.send({
path: "/post",
method: "POST",
body: encode("denoland")
});
assertEquals(res.status, 200);
assertEquals(await readString(res.body), "denoland");
}
} catch (e) {
console.error(e);
} finally {
agent.conn.close();
}
} catch (e) {
console.error(e);
} finally {
agent.conn.close();
router.resolve();
}
});

test(async function agentTls() {
const router = setupRouter(++_port);
const agent = createAgent(`https://httpbin.org`);
try {
{
const res = await agent.send({
path: "/get?deno=land",
method: "GET"
});
assertEquals(res.status, 200);
const resp = JSON.parse(await readString(res.body));
assertEquals(resp["args"]["deno"], "land");
});
t.run("agentTls", async () => {
const agent = createAgent(`https://httpbin.org`);
try {
{
const res = await agent.send({
path: "/get?deno=land",
method: "GET"
});
assertEquals(res.status, 200);
const resp = JSON.parse(await readString(res.body));
assertEquals(resp["args"]["deno"], "land");
}
{
const res = await agent.send({
path: "/post",
method: "POST",
headers: new Headers({
"content-type": "application/x-www-form-urlencoded; charset=UTF-8"
}),
body: "deno=land"
});
assertEquals(res.status, 200);
const body = await readString(res.body);
const resp = JSON.parse(body);
assertEquals(resp["form"]["deno"], "land");
}
} catch (e) {
console.error(e);
} finally {
agent.conn.close();
}
{
const res = await agent.send({
});
t.run("agent unread body", async () => {
const agent = createAgent(`http://127.0.0.1:${port}`);
try {
await agent.send({ path: "/get", method: "GET" });
await agent.send({ path: "/post", method: "POST", body: encode("ko") });
const { body } = await agent.send({
path: "/post",
method: "POST",
headers: new Headers({
"content-type": "application/x-www-form-urlencoded; charset=UTF-8"
}),
body: "deno=land"
body: encode("denoland")
});
assertEquals(res.status, 200);
const body = await readString(res.body);
const resp = JSON.parse(body);
assertEquals(resp["form"]["deno"], "land");
assertEquals(await readString(body), "denoland");
} catch (e) {
console.error(e);
} finally {
agent.conn.close();
}
} catch (e) {
console.error(e);
} finally {
agent.conn.close();
router.resolve();
}
});

test(async function agentUnreadBody() {
const router = setupRouter(++_port);
const agent = createAgent(`http://127.0.0.1:${_port}`);
try {
await agent.send({ path: "/get", method: "GET" });
await agent.send({ path: "/post", method: "POST", body: encode("ko") });
const { body } = await agent.send({
path: "/post",
method: "POST",
body: encode("denoland")
});
t.run("agent invalid scheme", async () => {
assertThrows(() => {
createAgent("ftp://127.0.0.1");
});
assertEquals(await readString(body), "denoland");
} catch (e) {
console.error(e);
} finally {
agent.conn.close();
router.resolve();
}
});

test(async function agentInvalidScheme() {
assertThrows(() => {
createAgent("ftp://127.0.0.1");
});
});

Expand Down
1 change: 1 addition & 0 deletions logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export enum Loglevel {
ERROR,
NONE
}

export type Logger = (level: Loglevel, msg: string, ...args: any[]) => void;
let logLevel = Loglevel.INFO;
export function setLevel(level: Loglevel) {
Expand Down
4 changes: 2 additions & 2 deletions router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export function createRouter(
}
): HttpRouter {
const middlewares: HttpHandler[] = [];
const routes: { pattern: string | RegExp; handlers: HttpHandler[] }[] = [];
const { info, error } = namedLogger("servest:router", opts.logger);
const finalErrorHandler = async (e: any, req: RoutedServerRequest) => {
if (e instanceof RoutingError) {
Expand All @@ -80,11 +81,10 @@ export function createRouter(
}
}
};
let errorHandler: ErrorHandler = finalErrorHandler;
const logRouteStatus = (req: ServerRequest, status: number) => {
info(`${status} ${req.method} ${req.url}`);
};
let errorHandler: ErrorHandler = finalErrorHandler;
const routes: { pattern: string | RegExp; handlers: HttpHandler[] }[] = [];
function handlerToString(handlers: HttpHandler[]): string {
return handlers.map(v => v.name).join(" ");
}
Expand Down
11 changes: 5 additions & 6 deletions router_util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
export function findLongestAndNearestMatch(
pathname: string,
patterns: (string | RegExp)[]
): { index: number; match: RegExpMatchArray } {
): { index: number; match: RegExpMatchArray | null } {
let lastMatchIndex = pathname.length;
let lastMatchLength = 0;
let match: RegExpMatchArray | null = null;
Expand All @@ -15,7 +15,9 @@ export function findLongestAndNearestMatch(
const pattern = patterns[i];
if (pattern instanceof RegExp) {
const m = pathname.match(pattern);
if (!m) continue;
if (!m || m.index === undefined) {
continue;
}
if (
m.index < lastMatchIndex ||
(m.index === lastMatchIndex && m[0].length > lastMatchLength)
Expand All @@ -25,10 +27,7 @@ export function findLongestAndNearestMatch(
lastMatchIndex = m.index;
lastMatchLength = m[0].length;
}
} else if (
pathname.startsWith(pattern) &&
pattern.length > lastMatchLength
) {
} else if (pathname === pattern && pattern.length > lastMatchLength) {
index = i;
match = [pattern];
lastMatchIndex = 0;
Expand Down
10 changes: 6 additions & 4 deletions router_util_test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
// Copyright 2019 Yusuke Sakurai. All rights reserved. MIT license.
import { findLongestAndNearestMatch } from "./router_util.ts";
import { test } from "./vendor/https/deno.land/std/testing/mod.ts";
import { runIfMain, test } from "./vendor/https/deno.land/std/testing/mod.ts";
import { assertEquals } from "./vendor/https/deno.land/std/testing/asserts.ts";

([
["/foo", ["/foo", "/bar", "/f"], 0],
["/foo", ["/foo", "/foo/bar"], 0],
["/foo/bar", ["/", "/foo", "/hoo", "/hoo/foo/bar", "/foo/bar"], 4],
["/foo/bar/foo", ["/foo", "/foo/bar", "/bar/foo"], 1],
["/foo", ["/", "/hoo", "/hoo/foo"], 0],
["/foo/bar/foo", ["/foo", "/foo/bar", "/bar/foo", "/foo/bar/foo"], 3],
["/foo", ["/", "/hoo", "/hoo/foo"], -1],
["/deno/land", [/d(.+?)o/, /d(.+?)d/], 1],
["/foo", ["/", "/a/foo"], 0],
["/foo", ["/", "/a/foo", "/foo"], 2],
["/foo", [/\/foo/, /\/bar\/foo/], 0],
["/foo", [/\/a\/foo/, /\/foo/], 1]
] as [string, (string | RegExp)[], number][]).forEach(([path, pat, idx]) => {
test("findLongestAndNearestMatch:" + path, () => {
assertEquals(findLongestAndNearestMatch(path, pat).index, idx);
});
});

runIfMain(import.meta);
3 changes: 2 additions & 1 deletion site/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import content from "./content.ts";
const router = createRouter({ logLevel: Loglevel.INFO });
const port = Deno.env()["PORT"] || "8899";
const { pathname } = new URL("./public", import.meta.url);
router.get("/", serveStatic(pathname), async req => {
router.use(serveStatic(pathname));
router.get("/", async req => {
return req.respond({
status: 200,
headers: new Headers({
Expand Down

0 comments on commit c8f5d5b

Please sign in to comment.