mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-28 15:28:30 +00:00
Make more major improvements to redbean
- POSIX regular expressions for Lua - Improved protocol parsing and encoding - Additional APIs for ZIP storage retrieval - Fix st_mode issue on NT for regular files - Generalized APIs for URL and Host handling - Worked out the kinks in resource resolution - Allow for custom error pages like /404.html
This commit is contained in:
parent
26ac6871da
commit
4effa23528
74 changed files with 3710 additions and 14246 deletions
|
@ -25,29 +25,29 @@
|
|||
|
||||
char *escapeparam(const char *s) {
|
||||
struct EscapeResult r;
|
||||
r = EscapeUrlParam(s, -1);
|
||||
r = EscapeParam(s, -1);
|
||||
ASSERT_EQ(strlen(r.data), r.size);
|
||||
return r.data;
|
||||
}
|
||||
|
||||
TEST(EscapeUrlParam, test) {
|
||||
TEST(EscapeParam, test) {
|
||||
EXPECT_STREQ("abc%20%26%3C%3E%22%27%01%02",
|
||||
gc(escapeparam("abc &<>\"'\1\2")));
|
||||
}
|
||||
|
||||
TEST(EscapeUrlParam, testLargeGrowth) {
|
||||
TEST(EscapeParam, testLargeGrowth) {
|
||||
EXPECT_STREQ("%22%22%22", gc(escapeparam("\"\"\"")));
|
||||
}
|
||||
|
||||
TEST(EscapeUrlParam, testEmpty) {
|
||||
TEST(EscapeParam, testEmpty) {
|
||||
EXPECT_STREQ("", gc(escapeparam("")));
|
||||
}
|
||||
|
||||
TEST(EscapeUrlParam, testAstralPlanes_usesUtf8HexEncoding) {
|
||||
TEST(EscapeParam, testAstralPlanes_usesUtf8HexEncoding) {
|
||||
EXPECT_STREQ("%F0%90%8C%B0", escapeparam("𐌰"));
|
||||
}
|
||||
|
||||
BENCH(EscapeUrlParam, bench) {
|
||||
EZBENCH2("EscapeUrlParam", donothing,
|
||||
free(EscapeUrlParam(kHyperion, kHyperionSize).data));
|
||||
BENCH(EscapeParam, bench) {
|
||||
EZBENCH2("EscapeParam", donothing,
|
||||
free(EscapeParam(kHyperion, kHyperionSize).data));
|
||||
}
|
||||
|
|
96
test/net/http/isacceptablehost_test.c
Normal file
96
test/net/http/isacceptablehost_test.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
TEST(IsAcceptableHost, test) {
|
||||
EXPECT_TRUE(IsAcceptableHost("", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("0.0.0.0", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost("1.2.3", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("1.2.3.4", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost("1.2.3.4.5", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("1.2.3.4.5.arpa", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("255.255.255.255", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost("255.255.255", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost("256.255.255.255", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("hello.example", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost("hello..example", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("hello", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost("hello\177", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost("hello.example\300\200", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost(".", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost(".e", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost("e.", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost(".hi.example", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost("hi..example", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("hi-there.example", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("_there.example", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("-there.example", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("there-.example", -1));
|
||||
EXPECT_FALSE(IsAcceptableHost("ther#e.example", -1));
|
||||
EXPECT_TRUE(IsAcceptableHost("localhost", -1));
|
||||
}
|
||||
|
||||
TEST(IsAcceptablePort, test) {
|
||||
EXPECT_TRUE(IsAcceptablePort("", -1));
|
||||
EXPECT_TRUE(IsAcceptablePort("0", -1));
|
||||
EXPECT_TRUE(IsAcceptablePort("65535", -1));
|
||||
EXPECT_FALSE(IsAcceptablePort("65536", -1));
|
||||
EXPECT_FALSE(IsAcceptablePort("-1", -1));
|
||||
EXPECT_FALSE(IsAcceptablePort("http", -1));
|
||||
}
|
||||
|
||||
TEST(ParseIp, test) {
|
||||
EXPECT_EQ(-1, ParseIp("", -1));
|
||||
EXPECT_EQ(0x00000000, ParseIp("0.0.0.0", -1));
|
||||
EXPECT_EQ(0x01020304, ParseIp("1.2.3.4", -1));
|
||||
EXPECT_EQ(0x80020304, ParseIp("128.2.3.4", -1));
|
||||
EXPECT_EQ(0xFFFFFFFF, ParseIp("255.255.255.255", -1));
|
||||
EXPECT_EQ(0xcb007100, ParseIp("203.0.113.0", -1));
|
||||
EXPECT_EQ(0x00000000, ParseIp("...", -1)); /* meh */
|
||||
EXPECT_EQ(-1, ParseIp("128.2..3.4", -1));
|
||||
EXPECT_EQ(-1, ParseIp("1.2.3", -1));
|
||||
EXPECT_EQ(-1, ParseIp("256.255.255.255", -1));
|
||||
EXPECT_EQ(-1, ParseIp("1.2.3.4.5", -1));
|
||||
EXPECT_EQ(-1, ParseIp("1.2.3.4.5.arpa", -1));
|
||||
EXPECT_EQ(-1, ParseIp("255.255.255", -1));
|
||||
EXPECT_EQ(-1, ParseIp("hello", -1));
|
||||
EXPECT_EQ(-1, ParseIp("hello\177", -1));
|
||||
EXPECT_EQ(-1, ParseIp("hello.example\300\200", -1));
|
||||
EXPECT_EQ(-1, ParseIp(".", -1));
|
||||
EXPECT_EQ(-1, ParseIp(".e", -1));
|
||||
EXPECT_EQ(-1, ParseIp("e.", -1));
|
||||
EXPECT_EQ(-1, ParseIp(".hi.example", -1));
|
||||
EXPECT_EQ(-1, ParseIp("hi..example", -1));
|
||||
EXPECT_EQ(-1, ParseIp("hi-there.example", -1));
|
||||
EXPECT_EQ(-1, ParseIp("_there.example", -1));
|
||||
EXPECT_EQ(-1, ParseIp("-there.example", -1));
|
||||
EXPECT_EQ(-1, ParseIp("there-.example", -1));
|
||||
EXPECT_EQ(-1, ParseIp("ther#e.example", -1));
|
||||
EXPECT_EQ(-1, ParseIp("localhost", -1));
|
||||
EXPECT_EQ(-1, ParseIp("hello.example", -1));
|
||||
EXPECT_EQ(-1, ParseIp("hello..example", -1));
|
||||
}
|
||||
|
||||
BENCH(IsAcceptableHost, bench) {
|
||||
EZBENCH2("IsAcceptableHost 127.0.0.1", donothing,
|
||||
IsAcceptableHost("127.0.0.1", 9));
|
||||
EZBENCH2("IsAcceptablePort 80", donothing, IsAcceptablePort("80", 2));
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
TEST(IsAcceptableHostPort, test) {
|
||||
EXPECT_FALSE(IsAcceptableHostPort("", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort(":", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort(":80", -1));
|
||||
EXPECT_TRUE(IsAcceptableHostPort("0.0.0.0", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("1.2.3", -1));
|
||||
EXPECT_TRUE(IsAcceptableHostPort("1.2.3.4", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("1.2.3.4.5", -1));
|
||||
EXPECT_TRUE(IsAcceptableHostPort("1.2.3.4.5.arpa", -1));
|
||||
EXPECT_TRUE(IsAcceptableHostPort("255.255.255.255", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("255.255.255", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("256.255.255.255", -1));
|
||||
EXPECT_TRUE(IsAcceptableHostPort("hello.example", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("hello..example", -1));
|
||||
EXPECT_TRUE(IsAcceptableHostPort("hello.example:80", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("hello.example:80:", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("hello.example::80", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("hello.example:-80", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort(":80", -1));
|
||||
EXPECT_TRUE(IsAcceptableHostPort("hello.example:65535", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("hello.example:65536", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("hello.example:-80", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort(" hello .example:80", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("hello.example:80h", -1));
|
||||
EXPECT_TRUE(IsAcceptableHostPort("hello", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("hello\177", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("hello.example\300\200:80", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort(".", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort(".e", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("e.", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort(".hi.example", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("hi..example", -1));
|
||||
EXPECT_TRUE(IsAcceptableHostPort("hi-there.example", -1));
|
||||
EXPECT_TRUE(IsAcceptableHostPort("_there.example", -1));
|
||||
EXPECT_TRUE(IsAcceptableHostPort("-there.example", -1));
|
||||
EXPECT_TRUE(IsAcceptableHostPort("there-.example", -1));
|
||||
EXPECT_FALSE(IsAcceptableHostPort("ther#e.example", -1));
|
||||
}
|
|
@ -20,13 +20,16 @@
|
|||
#include "net/http/http.h"
|
||||
|
||||
TEST(ParseContentLength, test) {
|
||||
EXPECT_EQ(0, ParseContentLength("", 0));
|
||||
EXPECT_EQ(-1, ParseContentLength(0, 0));
|
||||
EXPECT_EQ(-1, ParseContentLength("", 0));
|
||||
EXPECT_EQ(-1, ParseContentLength("-1", 2));
|
||||
EXPECT_EQ(-1, ParseContentLength("-2", 2));
|
||||
EXPECT_EQ(-1, ParseContentLength("e", -1));
|
||||
EXPECT_EQ(-1, ParseContentLength(",", -1));
|
||||
EXPECT_EQ(-1, ParseContentLength("\0", 1));
|
||||
EXPECT_EQ(0, ParseContentLength("0", 1));
|
||||
EXPECT_EQ(1, ParseContentLength("1", 1));
|
||||
EXPECT_EQ(0x7fffffff, ParseContentLength("2147483647", 10));
|
||||
EXPECT_EQ(-1, ParseContentLength("2147483648", 10));
|
||||
EXPECT_EQ(-1, ParseContentLength("9223372036854775808", 19));
|
||||
EXPECT_EQ(-1, ParseContentLength("88223372036854775808", 20));
|
||||
EXPECT_EQ(42, ParseContentLength("42, 42", -1)); /* RFC7230 § 3.3.2 */
|
||||
EXPECT_EQ(0x000000ffffffffff, ParseContentLength("1099511627775", -1));
|
||||
EXPECT_EQ(-1, ParseContentLength("1099511627776", -1));
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
TEST(ParseHttpRange, testEmptyHack) {
|
||||
TEST(ParseHttpRange, testEmptyHack_refusedBecauseItWontEncodeInContentRange) {
|
||||
long start, length;
|
||||
const char *s = "bytes=-0";
|
||||
EXPECT_TRUE(ParseHttpRange(s, strlen(s), 100, &start, &length));
|
||||
EXPECT_EQ(100, start);
|
||||
EXPECT_FALSE(ParseHttpRange(s, strlen(s), 100, &start, &length));
|
||||
EXPECT_EQ(0, start);
|
||||
EXPECT_EQ(0, length);
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,22 @@ TEST(ParseHttpRange, testEmptyRange_isntEmpty) {
|
|||
EXPECT_EQ(1, length);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRange, testEmptyRangeOfOneByteFile_itWorks) {
|
||||
long start, length;
|
||||
const char *s = "bytes=0-0";
|
||||
EXPECT_TRUE(ParseHttpRange(s, strlen(s), 1, &start, &length));
|
||||
EXPECT_EQ(0, start);
|
||||
EXPECT_EQ(1, length);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRange, testEmptyRangeOfEmptyFile_outOfRange) {
|
||||
long start, length;
|
||||
const char *s = "bytes=0-0";
|
||||
EXPECT_FALSE(ParseHttpRange(s, strlen(s), 0, &start, &length));
|
||||
EXPECT_EQ(0, start);
|
||||
EXPECT_EQ(0, length);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRange, testInclusiveIndexing) {
|
||||
long start, length;
|
||||
const char *s = "bytes=0-10";
|
||||
|
@ -81,7 +97,7 @@ TEST(ParseHttpRange, testOutOfRange) {
|
|||
const char *s = "bytes=0-100";
|
||||
EXPECT_FALSE(ParseHttpRange(s, strlen(s), 100, &start, &length));
|
||||
EXPECT_EQ(0, start);
|
||||
EXPECT_EQ(101, length);
|
||||
EXPECT_EQ(0, length);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRange, testInvalidRange) {
|
||||
|
@ -104,6 +120,14 @@ TEST(ParseHttpRange, testOverflow_duringAddition_setsErrorRange) {
|
|||
long start, length;
|
||||
const char *s = "bytes=4611686018427387904-4611686018427387915";
|
||||
EXPECT_FALSE(ParseHttpRange(s, strlen(s), 100, &start, &length));
|
||||
EXPECT_EQ(4611686018427387904, start);
|
||||
EXPECT_EQ(12, length);
|
||||
EXPECT_EQ(0, start);
|
||||
EXPECT_EQ(0, length);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRange, testMultipartRange_notImplemented) {
|
||||
long start, length;
|
||||
const char *s = "bytes=0-100,200-300";
|
||||
EXPECT_FALSE(ParseHttpRange(s, strlen(s), 100, &start, &length));
|
||||
EXPECT_EQ(0, start);
|
||||
EXPECT_EQ(0, length);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/http.h"
|
||||
#include "net/http/uri.h"
|
||||
|
||||
struct HttpRequest req[1];
|
||||
|
||||
|
@ -39,10 +38,6 @@ static char *slice(const char *m, struct HttpRequestSlice s) {
|
|||
return p;
|
||||
}
|
||||
|
||||
static unsigned version(const char *m) {
|
||||
return ParseHttpVersion(m + req->version.a, req->version.b - req->version.a);
|
||||
}
|
||||
|
||||
void SetUp(void) {
|
||||
InitHttpRequest(req);
|
||||
}
|
||||
|
@ -51,9 +46,9 @@ void TearDown(void) {
|
|||
DestroyHttpRequest(req);
|
||||
}
|
||||
|
||||
/* TEST(ParseHttpRequest, soLittleState) { */
|
||||
/* ASSERT_EQ(280, sizeof(struct HttpRequest)); */
|
||||
/* } */
|
||||
TEST(ParseHttpRequest, soLittleState) {
|
||||
ASSERT_LE(sizeof(struct HttpRequest), 512);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testEmpty_tooShort) {
|
||||
EXPECT_EQ(0, ParseHttpRequest(req, "", 0));
|
||||
|
@ -68,7 +63,7 @@ TEST(ParseHttpRequest, testNoHeaders) {
|
|||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpGet, req->method);
|
||||
EXPECT_STREQ("/foo", gc(slice(m, req->uri)));
|
||||
EXPECT_STREQ("HTTP/1.0", gc(slice(m, req->version)));
|
||||
EXPECT_EQ(10, req->version);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testSomeHeaders) {
|
||||
|
@ -80,7 +75,7 @@ Content-Length: 0\r\n\
|
|||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpPost, req->method);
|
||||
EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri)));
|
||||
EXPECT_STREQ("HTTP/1.0", gc(slice(m, req->version)));
|
||||
EXPECT_EQ(10, req->version);
|
||||
EXPECT_STREQ("foo.example", gc(slice(m, req->headers[kHttpHost])));
|
||||
EXPECT_STREQ("0", gc(slice(m, req->headers[kHttpContentLength])));
|
||||
EXPECT_STREQ("", gc(slice(m, req->headers[kHttpEtag])));
|
||||
|
@ -91,8 +86,7 @@ TEST(ParseHttpRequest, testHttp101) {
|
|||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpGet, req->method);
|
||||
EXPECT_STREQ("/", gc(slice(m, req->uri)));
|
||||
EXPECT_STREQ("HTTP/1.1", gc(slice(m, req->version)));
|
||||
EXPECT_EQ(101, version(m));
|
||||
EXPECT_EQ(11, req->version);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testHttp100) {
|
||||
|
@ -100,17 +94,48 @@ TEST(ParseHttpRequest, testHttp100) {
|
|||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpGet, req->method);
|
||||
EXPECT_STREQ("/", gc(slice(m, req->uri)));
|
||||
EXPECT_STREQ("HTTP/1.0", gc(slice(m, req->version)));
|
||||
EXPECT_EQ(100, version(m));
|
||||
EXPECT_EQ(10, req->version);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testHttp009) {
|
||||
TEST(ParseHttpRequest, testUnknownMethod_canBeUsedIfYouWant) {
|
||||
static const char m[] = "#%*+_^ / HTTP/1.0\r\n\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_FALSE(req->method);
|
||||
EXPECT_STREQ("WUT", kHttpMethod[req->method]);
|
||||
EXPECT_STREQ("#%*+_^", gc(slice(m, req->xmethod)));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testIllegalMethod) {
|
||||
static const char m[] = "ehd@oruc / HTTP/1.0\r\n\r\n";
|
||||
EXPECT_EQ(-1, ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_STREQ("WUT", kHttpMethod[req->method]);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testIllegalMethodCasing_weAllowItAndPreserveIt) {
|
||||
static const char m[] = "get / HTTP/1.0\r\n\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_STREQ("GET", kHttpMethod[req->method]);
|
||||
EXPECT_STREQ("get", gc(slice(m, req->xmethod)));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testEmptyMethod_isntAllowed) {
|
||||
static const char m[] = " / HTTP/1.0\r\n\r\n";
|
||||
EXPECT_EQ(-1, ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_STREQ("WUT", kHttpMethod[req->method]);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testEmptyUri_isntAllowed) {
|
||||
static const char m[] = "GET HTTP/1.0\r\n\r\n";
|
||||
EXPECT_EQ(-1, ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_STREQ("GET", kHttpMethod[req->method]);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testHttp09) {
|
||||
static const char m[] = "GET /\r\n\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpGet, req->method);
|
||||
EXPECT_STREQ("/", gc(slice(m, req->uri)));
|
||||
EXPECT_STREQ("", gc(slice(m, req->version)));
|
||||
EXPECT_EQ(9, version(m));
|
||||
EXPECT_EQ(9, req->version);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testLeadingLineFeeds_areIgnored) {
|
||||
|
@ -153,7 +178,7 @@ Content-Length: 0\n\
|
|||
EXPECT_EQ(strlen(m) - 1, ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpPost, req->method);
|
||||
EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri)));
|
||||
EXPECT_STREQ("HTTP/1.0", gc(slice(m, req->version)));
|
||||
EXPECT_EQ(10, req->version);
|
||||
EXPECT_STREQ("foo.example", gc(slice(m, req->headers[kHttpHost])));
|
||||
EXPECT_STREQ("0", gc(slice(m, req->headers[kHttpContentLength])));
|
||||
EXPECT_STREQ("", gc(slice(m, req->headers[kHttpEtag])));
|
||||
|
@ -174,7 +199,7 @@ Accept-Language: en-US,en;q=0.9\r\n\
|
|||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpGet, req->method);
|
||||
EXPECT_STREQ("/tool/net/redbean.png", gc(slice(m, req->uri)));
|
||||
EXPECT_STREQ("HTTP/1.1", gc(slice(m, req->version)));
|
||||
EXPECT_EQ(11, req->version);
|
||||
EXPECT_STREQ("10.10.10.124:8080", gc(slice(m, req->headers[kHttpHost])));
|
||||
EXPECT_STREQ("1", gc(slice(m, req->headers[kHttpDnt])));
|
||||
EXPECT_STREQ("", gc(slice(m, req->headers[kHttpExpect])));
|
||||
|
@ -193,6 +218,54 @@ X-User-Agent: hi\r\n\
|
|||
EXPECT_STREQ("hi", gc(slice(m, req->xheaders.p[0].v)));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testNormalHeaderOnMultipleLines_getsOverwritten) {
|
||||
static const char m[] = "\
|
||||
GET / HTTP/1.1\r\n\
|
||||
Content-Type: text/html\r\n\
|
||||
Content-Type: text/plain\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_STREQ("text/plain", gc(slice(m, req->headers[kHttpContentType])));
|
||||
ASSERT_EQ(0, req->xheaders.n);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testCommaSeparatedOnMultipleLines_becomesLinear) {
|
||||
static const char m[] = "\
|
||||
GET / HTTP/1.1\r\n\
|
||||
Accept: text/html\r\n\
|
||||
Accept: text/plain\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_STREQ("text/html", gc(slice(m, req->headers[kHttpAccept])));
|
||||
ASSERT_EQ(1, req->xheaders.n);
|
||||
EXPECT_STREQ("Accept", gc(slice(m, req->xheaders.p[0].k)));
|
||||
EXPECT_STREQ("text/plain", gc(slice(m, req->xheaders.p[0].v)));
|
||||
}
|
||||
|
||||
TEST(HeaderHasSubstring, testHeaderSpansMultipleLines) {
|
||||
static const char m[] = "\
|
||||
GET / HTTP/1.1\r\n\
|
||||
Accept-Encoding: deflate\r\n\
|
||||
ACCEPT-ENCODING: gzip\r\n\
|
||||
ACCEPT-encoding: bzip2\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_TRUE(HeaderHasSubstring(req, m, kHttpAcceptEncoding, "gzip", -1));
|
||||
EXPECT_TRUE(HeaderHasSubstring(req, m, kHttpAcceptEncoding, "deflate", -1));
|
||||
EXPECT_FALSE(HeaderHasSubstring(req, m, kHttpAcceptEncoding, "funzip", -1));
|
||||
}
|
||||
|
||||
TEST(HeaderHasSubstring, testHeaderOnSameLIne) {
|
||||
static const char m[] = "\
|
||||
GET / HTTP/1.1\r\n\
|
||||
Accept-Encoding: deflate, gzip, bzip2\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EXPECT_TRUE(HeaderHasSubstring(req, m, kHttpAcceptEncoding, "gzip", -1));
|
||||
EXPECT_TRUE(HeaderHasSubstring(req, m, kHttpAcceptEncoding, "deflate", -1));
|
||||
EXPECT_FALSE(HeaderHasSubstring(req, m, kHttpAcceptEncoding, "funzip", -1));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testHeaderValuesWithWhitespace_getsTrimmed) {
|
||||
static const char m[] = "\
|
||||
OPTIONS * HTTP/1.0\r\n\
|
||||
|
@ -231,6 +304,15 @@ Host: \r\n\
|
|||
EXPECT_EQ(req->headers[kHttpHost].a, req->headers[kHttpHost].b);
|
||||
}
|
||||
|
||||
TEST(IsMimeType, test) {
|
||||
ASSERT_TRUE(IsMimeType("text/plain", -1, "text/plain"));
|
||||
ASSERT_TRUE(IsMimeType("TEXT/PLAIN", -1, "text/plain"));
|
||||
ASSERT_TRUE(IsMimeType("TEXT/PLAIN ", -1, "text/plain"));
|
||||
ASSERT_TRUE(IsMimeType("text/plain; charset=utf-8", -1, "text/plain"));
|
||||
ASSERT_FALSE(IsMimeType("TEXT/PLAI ", -1, "text/plain"));
|
||||
ASSERT_FALSE(IsMimeType("", -1, "text/plain"));
|
||||
}
|
||||
|
||||
void DoTiniestHttpRequest(void) {
|
||||
static const char m[] = "\
|
||||
GET /\r\n\
|
||||
|
@ -290,3 +372,24 @@ BENCH(ParseHttpRequest, bench) {
|
|||
EZBENCH2("DoStandardChromeRequest", donothing, DoStandardChromeRequest());
|
||||
EZBENCH2("DoUnstandardChromeRequest", donothing, DoUnstandardChromeRequest());
|
||||
}
|
||||
|
||||
BENCH(HeaderHasSubstring, bench) {
|
||||
static const char m[] = "\
|
||||
GET / HTTP/1.1\r\n\
|
||||
X-In-Your-Way-A: a\r\n\
|
||||
X-In-Your-Way-B: b\r\n\
|
||||
X-In-Your-Way-C: b\r\n\
|
||||
Accept-Encoding: deflate\r\n\
|
||||
ACCEPT-ENCODING: gzip\r\n\
|
||||
ACCEPT-encoding: bzip2\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
EZBENCH2("HeaderHasSubstring text/plain", donothing,
|
||||
HeaderHasSubstring(req, m, kHttpAccept, "text/plain", 7));
|
||||
EZBENCH2("HeaderHasSubstring deflate", donothing,
|
||||
HeaderHasSubstring(req, m, kHttpAcceptEncoding, "deflate", 7));
|
||||
EZBENCH2("HeaderHasSubstring gzip", donothing,
|
||||
HeaderHasSubstring(req, m, kHttpAcceptEncoding, "gzip", 4));
|
||||
EZBENCH2("IsMimeType", donothing,
|
||||
IsMimeType("text/plain; charset=utf-8", -1, "text/plain"));
|
||||
}
|
||||
|
|
|
@ -24,122 +24,135 @@
|
|||
#include "libc/testlib/testlib.h"
|
||||
#include "net/http/url.h"
|
||||
|
||||
TEST(ParseRequestUri, testEmpty) {
|
||||
TEST(ParseUrl, testEmpty) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri(0, 0, &h));
|
||||
gc(ParseUrl(0, 0, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(0, h.params.n);
|
||||
ASSERT_STREQ("", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testFragment) {
|
||||
TEST(ParseUrl, testFragment) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("#x", -1, &h));
|
||||
gc(ParseUrl("#x", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(0, h.path.n);
|
||||
ASSERT_EQ(1, h.fragment.n);
|
||||
ASSERT_BINEQ(u"x", h.fragment.p);
|
||||
ASSERT_STREQ("#x", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testFragmentAbsent_isNull) {
|
||||
TEST(ParseUrl, testFragmentAbsent_isNull) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("", -1, &h));
|
||||
gc(ParseUrl("", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(0, h.fragment.p);
|
||||
ASSERT_EQ(0, h.fragment.n);
|
||||
ASSERT_STREQ("", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testFragmentEmpty_isNonNull) {
|
||||
TEST(ParseUrl, testFragmentEmpty_isNonNull) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("#", -1, &h));
|
||||
gc(ParseUrl("#", -1, &h)); /* python's uri parser is wrong here */
|
||||
gc(h.params.p);
|
||||
ASSERT_NE(0, h.fragment.p);
|
||||
ASSERT_EQ(0, h.fragment.n);
|
||||
ASSERT_STREQ("#", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testPathFragment) {
|
||||
TEST(ParseUrl, testPathFragment) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("x#y", -1, &h));
|
||||
gc(ParseUrl("x#y", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.path.n);
|
||||
ASSERT_EQ('x', h.path.p[0]);
|
||||
ASSERT_EQ(1, h.fragment.n);
|
||||
ASSERT_EQ('y', h.fragment.p[0]);
|
||||
ASSERT_STREQ("x#y", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testAbsolutePath) {
|
||||
TEST(ParseUrl, testAbsolutePath) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("/x/y", -1, &h));
|
||||
gc(ParseUrl("/x/y", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(4, h.path.n);
|
||||
ASSERT_BINEQ(u"/x/y", h.path.p);
|
||||
ASSERT_STREQ("/x/y", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testRelativePath1) {
|
||||
TEST(ParseUrl, testRelativePath1) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("x", -1, &h));
|
||||
gc(ParseUrl("x", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.path.n);
|
||||
ASSERT_EQ('x', h.path.p[0]);
|
||||
ASSERT_STREQ("x", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testOptions) {
|
||||
TEST(ParseUrl, testOptions) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("*", -1, &h));
|
||||
gc(ParseUrl("*", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.path.n);
|
||||
ASSERT_EQ('*', h.path.p[0]);
|
||||
ASSERT_STREQ("*", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testRelativePath2) {
|
||||
TEST(ParseUrl, testRelativePath2) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("x/y", -1, &h));
|
||||
gc(ParseUrl("x/y", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(3, h.path.n);
|
||||
ASSERT_BINEQ(u"x/y", h.path.p);
|
||||
ASSERT_STREQ("x/y", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testRoot) {
|
||||
TEST(ParseUrl, testRoot) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("/", -1, &h));
|
||||
gc(ParseUrl("/", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.path.n);
|
||||
ASSERT_EQ('/', h.path.p[0]);
|
||||
ASSERT_STREQ("/", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testSchemePath) {
|
||||
TEST(ParseUrl, testSchemePath) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("x:y", -1, &h));
|
||||
gc(ParseUrl("x:y", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.scheme.n);
|
||||
ASSERT_BINEQ(u"x", h.scheme.p);
|
||||
ASSERT_EQ(1, h.path.n);
|
||||
ASSERT_BINEQ(u"y", h.path.p);
|
||||
ASSERT_STREQ("x:y", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testSchemeAuthority) {
|
||||
TEST(ParseUrl, testSchemeAuthority) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("x://y", -1, &h));
|
||||
gc(ParseUrl("x://y", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.scheme.n);
|
||||
ASSERT_EQ('x', h.scheme.p[0]);
|
||||
ASSERT_EQ(1, h.host.n);
|
||||
ASSERT_EQ('y', h.host.p[0]);
|
||||
ASSERT_STREQ("x://y", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testParamsQuestion_doesntTurnIntoSpace) {
|
||||
TEST(ParseUrl, testParamsQuestion_doesntTurnIntoSpace) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("x?+", -1, &h));
|
||||
gc(ParseUrl("x?+", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.path.n);
|
||||
ASSERT_BINEQ(u"x", h.path.p);
|
||||
ASSERT_EQ(1, h.params.n);
|
||||
ASSERT_EQ(1, h.params.p[0].key.n);
|
||||
ASSERT_EQ('+', h.params.p[0].key.p[0]);
|
||||
ASSERT_STREQ("x?%2B", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testUrl) {
|
||||
TEST(ParseUrl, testUrl) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("a://b:B@c:C/d?e#f", -1, &h));
|
||||
gc(ParseUrl("a://b:B@c:C/d?e#f", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.scheme.n);
|
||||
ASSERT_EQ('a', h.scheme.p[0]);
|
||||
|
@ -156,14 +169,40 @@ TEST(ParseRequestUri, testUrl) {
|
|||
ASSERT_EQ(1, h.params.n);
|
||||
ASSERT_EQ(1, h.params.p[0].key.n);
|
||||
ASSERT_BINEQ(u"e", h.params.p[0].key.p);
|
||||
ASSERT_EQ(SIZE_MAX, h.params.p[0].val.n);
|
||||
ASSERT_EQ(0, h.params.p[0].val.n);
|
||||
ASSERT_EQ(0, h.params.p[0].val.p);
|
||||
ASSERT_EQ(1, h.fragment.n);
|
||||
ASSERT_BINEQ(u"f", h.fragment.p);
|
||||
ASSERT_STREQ("a://b:B@c:C/d?e#f", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testUrlWithoutScheme) {
|
||||
TEST(ParseUrl, testEmptyQueryKeyVal_decodesToEmptyStrings) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("//b@c/d?e#f", -1, &h));
|
||||
gc(ParseUrl("?=", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.params.n);
|
||||
ASSERT_EQ(0, h.params.p[0].key.n);
|
||||
ASSERT_NE(0, h.params.p[0].key.p);
|
||||
ASSERT_EQ(0, h.params.p[0].val.n);
|
||||
ASSERT_NE(0, h.params.p[0].val.p);
|
||||
ASSERT_STREQ("?=", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testMultipleEquals_goesIntoValue) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("?==", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.params.n);
|
||||
ASSERT_EQ(0, h.params.p[0].key.n);
|
||||
ASSERT_NE(0, h.params.p[0].key.p);
|
||||
ASSERT_EQ(1, h.params.p[0].val.n);
|
||||
ASSERT_EQ('=', h.params.p[0].val.p[0]);
|
||||
ASSERT_STREQ("?=%3D", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testUrlWithoutScheme) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("//b@c/d?e#f", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(0, h.scheme.n);
|
||||
ASSERT_EQ(1, h.user.n);
|
||||
|
@ -175,14 +214,16 @@ TEST(ParseRequestUri, testUrlWithoutScheme) {
|
|||
ASSERT_EQ(1, h.params.n);
|
||||
ASSERT_EQ(1, h.params.p[0].key.n);
|
||||
ASSERT_BINEQ(u"e", h.params.p[0].key.p);
|
||||
ASSERT_EQ(SIZE_MAX, h.params.p[0].val.n);
|
||||
ASSERT_EQ(0, h.params.p[0].val.n);
|
||||
ASSERT_EQ(0, h.params.p[0].val.p);
|
||||
ASSERT_EQ(1, h.fragment.n);
|
||||
ASSERT_BINEQ(u"f", h.fragment.p);
|
||||
ASSERT_STREQ("//b@c/d?e#f", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testUrlWithoutUser) {
|
||||
TEST(ParseUrl, testUrlWithoutUser) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("a://c/d?e#f", -1, &h));
|
||||
gc(ParseUrl("a://c/d?e#f", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.scheme.n);
|
||||
ASSERT_EQ('a', h.scheme.p[0]);
|
||||
|
@ -196,24 +237,159 @@ TEST(ParseRequestUri, testUrlWithoutUser) {
|
|||
ASSERT_EQ(1, h.params.n);
|
||||
ASSERT_EQ(1, h.params.p[0].key.n);
|
||||
ASSERT_EQ('e', h.params.p[0].key.p[0]);
|
||||
ASSERT_EQ(SIZE_MAX, h.params.p[0].val.n);
|
||||
ASSERT_EQ(0, h.params.p[0].val.n);
|
||||
ASSERT_EQ(0, h.params.p[0].val.p);
|
||||
ASSERT_EQ(1, h.fragment.n);
|
||||
ASSERT_EQ('f', h.fragment.p[0]);
|
||||
ASSERT_STREQ("a://c/d?e#f", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testLolv6) {
|
||||
TEST(ParseUrl, testEmptyParams_absentCanBeDiscerned) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("//[::1]:31337", -1, &h));
|
||||
gc(ParseUrl("", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(0, h.params.n);
|
||||
ASSERT_EQ(NULL, h.params.p);
|
||||
gc(ParseUrl("?", -1, &h)); /* python's uri parser is wrong here */
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(0, h.params.n);
|
||||
ASSERT_NE(NULL, h.params.p);
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testWeirdAmps_areReprodicible) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("?&&", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(3, h.params.n);
|
||||
ASSERT_EQ(0, h.params.p[0].key.n);
|
||||
ASSERT_NE(0, h.params.p[0].key.p);
|
||||
ASSERT_EQ(0, h.params.p[0].val.n);
|
||||
ASSERT_EQ(0, h.params.p[0].val.p);
|
||||
ASSERT_EQ(0, h.params.p[1].key.n);
|
||||
ASSERT_NE(0, h.params.p[1].key.p);
|
||||
ASSERT_EQ(0, h.params.p[1].val.n);
|
||||
ASSERT_EQ(0, h.params.p[1].val.p);
|
||||
ASSERT_EQ(0, h.params.p[2].key.n);
|
||||
ASSERT_NE(0, h.params.p[2].key.p);
|
||||
ASSERT_EQ(0, h.params.p[2].val.n);
|
||||
ASSERT_EQ(0, h.params.p[2].val.p);
|
||||
ASSERT_STREQ("?&&", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testOpaquePart_canLetQuestionMarkGoInPath) {
|
||||
struct Url h; /* python's uri parser is wrong here */
|
||||
gc(ParseUrl("s:o!$%&'()*+,-./09:;=?@AZ_az#fragged", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(26, h.path.n);
|
||||
ASSERT_EQ(0, memcmp(h.path.p, "o!$%&'()*+,-./09:;=?@AZ_az", 26));
|
||||
ASSERT_EQ(0, h.params.n);
|
||||
ASSERT_EQ(NULL, h.params.p);
|
||||
ASSERT_STREQ("s:o!$%25&'()*+,-./09:;=%3F@AZ_az#fragged",
|
||||
gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testSchemePathWithoutAuthority_paramsAreAllowed) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("s:/o!$%&'()*+,-./09:;=?@AZ_az#fragged", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(20, h.path.n);
|
||||
ASSERT_EQ(0, memcmp(h.path.p, "/o!$%&'()*+,-./09:;=", 20));
|
||||
ASSERT_EQ(1, h.params.n);
|
||||
ASSERT_STREQ("s:/o!$%25&'()*+,-./09:;=?%40AZ_az#fragged",
|
||||
gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testOpaquePart_permitsPercentEncoding) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("s:%2Fo!$%&'()*+,-./09:;=?@AZ_az#fragged", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(27, h.path.n);
|
||||
ASSERT_EQ(0, memcmp(h.path.p, "/o!$%&'()*+,-./09:;=?@AZ_az", 27));
|
||||
ASSERT_EQ(0, h.params.n);
|
||||
ASSERT_STREQ("s:/o!$%25&\'()*+,-./09:;=%3F@AZ_az#fragged",
|
||||
gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testTelephone) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("tel:+1-212-867-5309", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(15, h.path.n);
|
||||
ASSERT_BINEQ(u"+1-212-867-5309", h.path.p);
|
||||
ASSERT_STREQ("tel:+1-212-867-5309", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testLolv6) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("//[::1]:31337", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(3, h.host.n);
|
||||
ASSERT_BINEQ(u"::1", h.host.p);
|
||||
ASSERT_EQ(5, h.port.n);
|
||||
ASSERT_BINEQ(u"31337", h.port.p);
|
||||
ASSERT_STREQ("//[::1]:31337", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testUrlWithoutParams) {
|
||||
TEST(ParseUrl, testLolV6_withoutPort) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("a://b@c/d#f", -1, &h));
|
||||
gc(ParseUrl("//[::1]", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_STREQ("//[::1]", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testLolv7) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("//[vf.::1]", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(6, h.host.n);
|
||||
ASSERT_BINEQ(u"vf.::1", h.host.p);
|
||||
ASSERT_EQ(0, h.port.n);
|
||||
ASSERT_EQ(0, h.port.p);
|
||||
ASSERT_STREQ("//[vf.::1]", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testLolv7WithoutColon_weCantProduceLegalEncodingSadly) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("//[v7.7.7.7]", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_STREQ("//v7.7.7.7", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testObviouslyIllegalIpLiteral_getsTreatedAsRegName) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("//[vf.::1%00]", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_STREQ("//vf.%3A%3A1%00", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseHost, test) {
|
||||
struct Url h = {0};
|
||||
gc(ParseHost("foo.example:80", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(11, h.host.n);
|
||||
ASSERT_BINEQ(u"foo.example", h.host.p);
|
||||
ASSERT_EQ(2, h.port.n);
|
||||
ASSERT_BINEQ(u"80", h.port.p);
|
||||
ASSERT_STREQ("//foo.example:80", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseHost, testObviouslyIllegalIpLiteral_getsTreatedAsRegName) {
|
||||
struct Url h = {0};
|
||||
gc(ParseHost("[vf.::1%00]", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_STREQ("//vf.%3A%3A1%00", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(EncodeUrl, testHostPortPlacedInHostField_ungoodIdea) {
|
||||
struct Url h = {0};
|
||||
h.host.n = strlen("foo.example:80");
|
||||
h.host.p = "foo.example:80";
|
||||
ASSERT_STREQ("//foo.example%3A80", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testUrlWithoutParams) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("a://b@c/d#f", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.scheme.n);
|
||||
ASSERT_EQ('a', h.scheme.p[0]);
|
||||
|
@ -226,6 +402,7 @@ TEST(ParseRequestUri, testUrlWithoutParams) {
|
|||
ASSERT_EQ(0, h.params.n);
|
||||
ASSERT_EQ(1, h.fragment.n);
|
||||
ASSERT_EQ('f', h.fragment.p[0]);
|
||||
ASSERT_STREQ("a://b@c/d#f", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testLatin1_doesNothing) {
|
||||
|
@ -235,6 +412,7 @@ TEST(ParseUrl, testLatin1_doesNothing) {
|
|||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.path.n);
|
||||
ASSERT_EQ(0, memcmp("\377", h.path.p, 1));
|
||||
ASSERT_STREQ("%FF", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testLatin1_expandsMemoryToUtf8) {
|
||||
|
@ -246,40 +424,202 @@ TEST(ParseRequestUri, testLatin1_expandsMemoryToUtf8) {
|
|||
ASSERT_EQ(0, memcmp("\303\277", h.path.p, 2));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testPercentShrinkingMemory) {
|
||||
TEST(ParseUrl, testPercentShrinkingMemory) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("%Ff", 3, &h));
|
||||
gc(ParseUrl("%Ff", 3, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.path.n);
|
||||
ASSERT_EQ(0, memcmp("\377", h.path.p, 1));
|
||||
ASSERT_STREQ("%FF", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testBadPercent_getsIgnored) {
|
||||
TEST(ParseUrl, testEscapingWontOverrun) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("%FZ", 3, &h));
|
||||
char b[1] = {'%'};
|
||||
gc(ParseUrl(b, 1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(1, h.path.n);
|
||||
ASSERT_EQ(0, memcmp("%", h.path.p, 1));
|
||||
ASSERT_STREQ("%25", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testBadPercent_getsIgnored) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("%FZ", 3, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(3, h.path.n);
|
||||
ASSERT_EQ(0, memcmp("%FZ", h.path.p, 3));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testFileUrl) {
|
||||
TEST(ParseUrl, testFileUrl) {
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("file:///etc/passwd", -1, &h));
|
||||
gc(ParseUrl("file:///etc/passwd", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(4, h.scheme.n);
|
||||
ASSERT_BINEQ(u"file", h.scheme.p);
|
||||
ASSERT_EQ(0, h.host.n);
|
||||
ASSERT_NE(0, h.host.p);
|
||||
ASSERT_EQ(0, h.port.n);
|
||||
ASSERT_EQ(0, h.port.p);
|
||||
ASSERT_EQ(11, h.path.n);
|
||||
ASSERT_BINEQ(u"/etc/passwd", h.path.p);
|
||||
ASSERT_STREQ("file:///etc/passwd", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseRequestUri, testZipUri2) {
|
||||
TEST(EncodeUrl, testModifyingParseResultAndReencoding_addsStructure) {
|
||||
size_t n;
|
||||
struct Url h;
|
||||
gc(ParseRequestUri("zip:etc/passwd", -1, &h));
|
||||
gc(ParseUrl("rel", -1, &h));
|
||||
gc(h.params.p);
|
||||
h.host.n = 7;
|
||||
h.host.p = "justine";
|
||||
ASSERT_STREQ("//justine/rel", gc(EncodeUrl(&h, &n)));
|
||||
ASSERT_EQ(13, n);
|
||||
}
|
||||
|
||||
TEST(EncodeUrl, testTortureCharacters_doesWhatYouAskItToDoButSchemeCantEscape) {
|
||||
size_t n;
|
||||
struct Url h;
|
||||
memset(&h, 0, sizeof(h));
|
||||
h.scheme.n = 1;
|
||||
h.scheme.p = "/";
|
||||
h.user.n = 1;
|
||||
h.user.p = "";
|
||||
h.pass.n = 1;
|
||||
h.pass.p = "";
|
||||
h.host.n = 1;
|
||||
h.host.p = "";
|
||||
h.port.n = 1;
|
||||
h.port.p = "";
|
||||
h.path.n = 1;
|
||||
h.path.p = "";
|
||||
h.params = (struct UrlParams){.n = 1,
|
||||
.p = (struct UrlParam[]){{
|
||||
.key = (struct UrlView){.n = 1, .p = ""},
|
||||
.val = (struct UrlView){.n = 1, .p = ""},
|
||||
}}};
|
||||
h.fragment.n = 1;
|
||||
h.fragment.p = "";
|
||||
ASSERT_STREQ("/://%00:%00@%00:%00/%00?%00=%00#%00", gc(EncodeUrl(&h, &n)));
|
||||
ASSERT_EQ(35, n);
|
||||
}
|
||||
|
||||
TEST(EncodeUrl, testUserPassPort_allDependOnHostNonAbsence) {
|
||||
size_t n;
|
||||
struct Url h;
|
||||
memset(&h, 0, sizeof(h));
|
||||
h.scheme.n = 1;
|
||||
h.scheme.p = "/";
|
||||
h.user.n = 1;
|
||||
h.user.p = "";
|
||||
h.pass.n = 1;
|
||||
h.pass.p = "";
|
||||
h.host.n = 0;
|
||||
h.host.p = 0;
|
||||
h.port.n = 1;
|
||||
h.port.p = "";
|
||||
h.path.n = 1;
|
||||
h.path.p = "";
|
||||
h.params = (struct UrlParams){.n = 1,
|
||||
.p = (struct UrlParam[]){{
|
||||
.key = (struct UrlView){.n = 1, .p = ""},
|
||||
.val = (struct UrlView){.n = 1, .p = ""},
|
||||
}}};
|
||||
h.fragment.n = 1;
|
||||
h.fragment.p = "";
|
||||
ASSERT_STREQ("/:%00?%00=%00#%00", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(EncodeUrl, testEmptyRegName_isLegal) {
|
||||
size_t n;
|
||||
struct Url h;
|
||||
memset(&h, 0, sizeof(h));
|
||||
h.scheme.n = 1;
|
||||
h.scheme.p = "/";
|
||||
h.user.n = 1;
|
||||
h.user.p = "";
|
||||
h.pass.n = 1;
|
||||
h.pass.p = "";
|
||||
h.host.n = 0;
|
||||
h.host.p = "";
|
||||
h.port.n = 1;
|
||||
h.port.p = "";
|
||||
h.path.n = 1;
|
||||
h.path.p = "";
|
||||
h.params = (struct UrlParams){.n = 1,
|
||||
.p = (struct UrlParam[]){{
|
||||
.key = (struct UrlView){.n = 1, .p = ""},
|
||||
.val = (struct UrlView){.n = 1, .p = ""},
|
||||
}}};
|
||||
h.fragment.n = 1;
|
||||
h.fragment.p = "";
|
||||
ASSERT_STREQ("/://%00:%00@:%00/%00?%00=%00#%00", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testEmptyScheme_isNotPossible) {
|
||||
struct Url h;
|
||||
gc(ParseUrl(":", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(0, h.scheme.n);
|
||||
ASSERT_EQ(0, h.scheme.p);
|
||||
ASSERT_EQ(1, h.path.n);
|
||||
ASSERT_EQ(':', h.path.p[0]);
|
||||
ASSERT_STREQ(":", gc(EncodeUrl(&h, 0)));
|
||||
gc(ParseUrl("://hi", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(0, h.scheme.n);
|
||||
ASSERT_EQ(0, h.scheme.p);
|
||||
ASSERT_EQ(5, h.path.n);
|
||||
ASSERT_BINEQ(u"://hi", h.path.p);
|
||||
ASSERT_STREQ("://hi", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testZipUri2) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("zip:etc/passwd", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(3, h.scheme.n);
|
||||
ASSERT_BINEQ(u"zip", h.scheme.p);
|
||||
ASSERT_EQ(10, h.path.n);
|
||||
ASSERT_BINEQ(u"etc/passwd", h.path.p);
|
||||
ASSERT_STREQ("zip:etc/passwd", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testZipUri3) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("zip:/etc/passwd", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(0, h.host.n);
|
||||
ASSERT_EQ(0, h.host.p);
|
||||
ASSERT_EQ(3, h.scheme.n);
|
||||
ASSERT_BINEQ(u"zip", h.scheme.p);
|
||||
ASSERT_EQ(11, h.path.n);
|
||||
ASSERT_BINEQ(u"/etc/passwd", h.path.p);
|
||||
ASSERT_STREQ("zip:/etc/passwd", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testDataUri) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("data:image/png;base64,09AZaz+/==", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(0, h.host.n);
|
||||
ASSERT_EQ(0, h.host.p);
|
||||
ASSERT_EQ(4, h.scheme.n);
|
||||
ASSERT_BINEQ(u"data", h.scheme.p);
|
||||
ASSERT_EQ(27, h.path.n);
|
||||
ASSERT_BINEQ(u"image/png;base64,09AZaz+/==", h.path.p);
|
||||
ASSERT_STREQ("data:image/png;base64,09AZaz+/==", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseUrl, testBadSchemeCharacter_parserAssumesItsPath) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("fil\e://hi", -1, &h));
|
||||
gc(h.params.p);
|
||||
ASSERT_EQ(0, h.scheme.n);
|
||||
ASSERT_EQ(0, h.scheme.p);
|
||||
ASSERT_EQ(9, h.path.n);
|
||||
ASSERT_BINEQ(u"fil←://hi", h.path.p);
|
||||
ASSERT_STREQ("fil%1B://hi", gc(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
||||
TEST(ParseParams, testEmpty) {
|
||||
|
@ -297,7 +637,9 @@ TEST(ParseParams, test) {
|
|||
ASSERT_EQ(1, h.p[0].key.n);
|
||||
ASSERT_EQ(1, h.p[0].val.n);
|
||||
ASSERT_EQ(1, h.p[1].key.n);
|
||||
ASSERT_EQ(SIZE_MAX, h.p[1].val.n);
|
||||
ASSERT_NE(0, h.p[1].key.p);
|
||||
ASSERT_EQ(0, h.p[1].val.n);
|
||||
ASSERT_EQ(0, h.p[1].val.p);
|
||||
ASSERT_EQ(4, h.p[2].key.n);
|
||||
ASSERT_EQ(0, h.p[2].val.n);
|
||||
EXPECT_EQ('a', h.p[0].key.p[0]);
|
||||
|
@ -344,14 +686,28 @@ void A(void) {
|
|||
free(h.p);
|
||||
}
|
||||
|
||||
BENCH(url, bench) {
|
||||
BENCH(ParseUrl, bench) {
|
||||
struct Url h;
|
||||
EZBENCH2("ParseParams", donothing, A());
|
||||
EZBENCH2("URI a", donothing, free(ParseRequestUri("a", -1, &h)));
|
||||
EZBENCH2("URI a://b@c/d#f", donothing,
|
||||
free(ParseRequestUri("a://b@c/d#f", -1, &h)));
|
||||
EZBENCH2("URI a://b@c/d?z#f", donothing, ({
|
||||
free(ParseRequestUri("a://b@c/?zd#f", -1, &h));
|
||||
EZBENCH2("ParseParams hyperion", donothing, A());
|
||||
EZBENCH2("ParseUrl a", donothing, free(ParseUrl("a", -1, &h)));
|
||||
EZBENCH2("ParseUrl a://b@c/d#f", donothing,
|
||||
free(ParseUrl("a://b@c/d#f", -1, &h)));
|
||||
EZBENCH2("ParseUrl a://b@c/d?z#f", donothing, ({
|
||||
free(ParseUrl("a://b@c/?zd#f", -1, &h));
|
||||
free(h.params.p);
|
||||
}));
|
||||
}
|
||||
|
||||
BENCH(EncodeUrl, bench) {
|
||||
struct Url h;
|
||||
gc(ParseUrl("a", -1, &h));
|
||||
EZBENCH2("EncodeUrl a", donothing, free(EncodeUrl(&h, 0)));
|
||||
gc(ParseUrl("a://b@c/d#f", -1, &h));
|
||||
EZBENCH2("EncodeUrl a://b@c/d#f", donothing, free(EncodeUrl(&h, 0)));
|
||||
gc(ParseUrl("a://b@c/?zd#f", -1, &h));
|
||||
gc(h.params.p);
|
||||
EZBENCH2("EncodeUrl a://b@c/d?z#f", donothing, free(EncodeUrl(&h, 0)));
|
||||
gc(ParseUrl(kHyperion, kHyperionSize, &h));
|
||||
gc(h.params.p);
|
||||
EZBENCH2("EncodeUrl hyperion", donothing, free(EncodeUrl(&h, 0)));
|
||||
}
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "net/http/uri.h"
|
||||
|
||||
_Alignas(32) const char kWinsockIcoPngBase64[] = "\
|
||||
base64,iVBORw0KGgoAAAANSUhEUgAAAJcAAACXCAYAAAAYn8l5AAAABmJLR0QA/\
|
||||
wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4woLByMP6uwgW\
|
||||
QAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAMeSURBVHja7\
|
||||
d1BcuIwEAVQPMW94GbAzeBkZJepUXpw01ixDO+tE0PML+lHtsV0v9/vO+jgj1OAc\
|
||||
CFcIFwIF8IFP+wrvzRNkzP3y7a4YmTkQrgQLnitc/XqA3GX+9SrU/+ei8vl8uMnT\
|
||||
qeTkQvTIggXwoVC36mOJhZa3Upm5ALhQrjQuV6jT2HkQrgQLhAuNlLo+96Z6q5XI\
|
||||
xcIF8KFzrXbWTDt0jTf4AkrIxfChXCBcCFcCBcIF8LFO9iP/gajx9jXMvrj80Yuh\
|
||||
AuEC52r2q9G6jnRxWQX7Y1cCBfCBcLFxxb6tsBH5f12uz08xvV6Lb328Xh8+nfO5\
|
||||
/NsyVfwjVwIF8IFa3auzALpXL96pRst0dWinta+loVWIxfChXCBcCFcCBcIF8LFe\
|
||||
xn+6Z+5xc5oYTOzQJr5mcrFbYxcCBfCBcKFQv9AexdC9U7UueMueWwjFwgXwoVwO\
|
||||
QUIF8IFwkV3e6dgfdETQ5knmIxcmBZBuBAuUOgH1Rb6LRZ8IxfChXDBt+le2N9nq\
|
||||
a0a222VRn/aJrp5sO1CS22XlPkC9fa1R/tuIiMXwoVwgXDx5oV+ruCPJlrI7LXfa\
|
||||
XsuMouo1YXWXv8IGLkwLSJcMGbnyrzWmqK/s31/Ue+pdJr2uNECbrvoXP0cen2eR\
|
||||
i5MiwgXCBf9DX8n6ta+lCmzkFkp+FGhb89N9Yu52uMs9eVYRi5MiwgXbKdzba0TV\
|
||||
h7NjzpY5i7Tpb78tD1OZrE408GMXJgWES4QLhT6zRf8qAxXFlqXKu+Vgp/5xyX6u\
|
||||
41cmBYRLvg7dS5xJyqPzW2HFH0Ev9mxKjJ3wRq5MC0iXCBc9FdaRM38DzD6o/kjF\
|
||||
frRy7uRC+FCuOBlpUVUnjzJhQvXo+8PaxEV0yLCBU9xs+Cg2ies1+5g0RPfRi5Mi\
|
||||
wgXCBcK/UeYe3Ims6ia2RN1zfJu5MK0iHDBQy5cj/AhFLZd6inarskWSpgWES4QL\
|
||||
sZkEXUAS227VJU5ti2UMC0iXKBzfUIPW3vbqrm96qP3Z+TCtIhwgXCh0POfAt1T5\
|
||||
i6Nw+Ew+/6MXJgWES7Quejf74xcdPMFQQsgQ0YEZnUAAAAASUVORK5CYII=";
|
||||
|
||||
size_t size;
|
||||
|
||||
void SetUp(void) {
|
||||
size = strlen(kWinsockIcoPngBase64);
|
||||
}
|
||||
BENCH(strlen, bench) {
|
||||
EZBENCH(donothing, (size = strlen(kWinsockIcoPngBase64)));
|
||||
}
|
||||
TEST(uricspn, test) {
|
||||
EXPECT_EQ(size, uricspn(kWinsockIcoPngBase64, size));
|
||||
}
|
||||
BENCH(uricspn, bench) {
|
||||
EZBENCH(donothing, uricspn(kWinsockIcoPngBase64, size));
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/initializer.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/uri.h"
|
||||
|
||||
#define URIPARSE(URI) uriparse(&uri, (p = URI), (size = sizeof(URI) - 1))
|
||||
|
||||
static const char kHttpCosmopolitanVideoUrl[] =
|
||||
"http://cosmopolitan.storage.googleapis.com/pub/vid/blankspace.mpg";
|
||||
|
||||
static const char kSipPriceIsTortureUri[] =
|
||||
"sip:bob%20barker:priceisright@[dead:beef::666]:5060;isup-oli=00";
|
||||
|
||||
static const char kWinsockIcoPngBase64[] = "\
|
||||
base64,iVBORw0KGgoAAAANSUhEUgAAAJcAAACXCAYAAAAYn8l5AAAABmJLR0QA/\
|
||||
wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4woLByMP6uwgW\
|
||||
QAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAMeSURBVHja7\
|
||||
d1BcuIwEAVQPMW94GbAzeBkZJepUXpw01ixDO+tE0PML+lHtsV0v9/vO+jgj1OAc\
|
||||
CFcIFwIF8IFP+wrvzRNkzP3y7a4YmTkQrgQLnitc/XqA3GX+9SrU/+ei8vl8uMnT\
|
||||
qeTkQvTIggXwoVC36mOJhZa3Upm5ALhQrjQuV6jT2HkQrgQLhAuNlLo+96Z6q5XI\
|
||||
xcIF8KFzrXbWTDt0jTf4AkrIxfChXCBcCFcCBcIF8LFO9iP/gajx9jXMvrj80Yuh\
|
||||
AuEC52r2q9G6jnRxWQX7Y1cCBfCBcLFxxb6tsBH5f12uz08xvV6Lb328Xh8+nfO5\
|
||||
/NsyVfwjVwIF8IFa3auzALpXL96pRst0dWinta+loVWIxfChXCBcCFcCBcIF8LFe\
|
||||
xn+6Z+5xc5oYTOzQJr5mcrFbYxcCBfCBcKFQv9AexdC9U7UueMueWwjFwgXwoVwO\
|
||||
QUIF8IFwkV3e6dgfdETQ5knmIxcmBZBuBAuUOgH1Rb6LRZ8IxfChXDBt+le2N9nq\
|
||||
a0a222VRn/aJrp5sO1CS22XlPkC9fa1R/tuIiMXwoVwgXDx5oV+ruCPJlrI7LXfa\
|
||||
XsuMouo1YXWXv8IGLkwLSJcMGbnyrzWmqK/s31/Ue+pdJr2uNECbrvoXP0cen2eR\
|
||||
i5MiwgXCBf9DX8n6ta+lCmzkFkp+FGhb89N9Yu52uMs9eVYRi5MiwgXbKdzba0TV\
|
||||
h7NjzpY5i7Tpb78tD1OZrE408GMXJgWES4QLhT6zRf8qAxXFlqXKu+Vgp/5xyX6u\
|
||||
41cmBYRLvg7dS5xJyqPzW2HFH0Ev9mxKjJ3wRq5MC0iXCBc9FdaRM38DzD6o/kjF\
|
||||
frRy7uRC+FCuOBlpUVUnjzJhQvXo+8PaxEV0yLCBU9xs+Cg2ies1+5g0RPfRi5Mi\
|
||||
wgXCBcK/UeYe3Ims6ia2RN1zfJu5MK0iHDBQy5cj/AhFLZd6inarskWSpgWES4QL\
|
||||
sZkEXUAS227VJU5ti2UMC0iXKBzfUIPW3vbqrm96qP3Z+TCtIhwgXCh0POfAt1T5\
|
||||
i6Nw+Ew+/6MXJgWES7Quejf74xcdPMFQQsgQ0YEZnUAAAAASUVORK5CYII=";
|
||||
|
||||
static size_t size;
|
||||
static const char *p;
|
||||
static struct Uri uri;
|
||||
static struct UriMem {
|
||||
struct UriSlice segs[8];
|
||||
struct UriRef paramsegs[8];
|
||||
struct UriKeyval params[4], queries[4];
|
||||
} urimem_;
|
||||
|
||||
static textstartup void init() {
|
||||
uri.segs.n = ARRAYLEN(urimem_.segs);
|
||||
uri.segs.p = urimem_.segs;
|
||||
uri.params.n = ARRAYLEN(urimem_.params);
|
||||
uri.params.p = urimem_.params;
|
||||
uri.queries.n = ARRAYLEN(urimem_.queries);
|
||||
uri.queries.p = urimem_.queries;
|
||||
uri.paramsegs.n = ARRAYLEN(urimem_.paramsegs);
|
||||
uri.paramsegs.p = urimem_.paramsegs;
|
||||
}
|
||||
|
||||
const void *const g_name_ctor[] initarray = {init};
|
||||
|
||||
TEST(uriparse, sipPstnUri) {
|
||||
EXPECT_NE(-1, URIPARSE("sip:+12125650666"));
|
||||
EXPECT_STREQ("sip", gc(strndup(p + uri.scheme.i, uri.scheme.n)));
|
||||
EXPECT_STREQ("+12125650666", gc(strndup(p + uri.host.i, uri.host.n)));
|
||||
EXPECT_STREQ("", gc(strndup(p + uri.opaque.i, uri.opaque.n)));
|
||||
}
|
||||
|
||||
TEST(uriparse, printVideoUrl) {
|
||||
EXPECT_NE(-1, URIPARSE(kHttpCosmopolitanVideoUrl));
|
||||
EXPECT_STREQ("http", gc(strndup(p + uri.scheme.i, uri.scheme.n)));
|
||||
EXPECT_STREQ("cosmopolitan.storage.googleapis.com",
|
||||
gc(strndup(p + uri.host.i, uri.host.n)));
|
||||
EXPECT_STREQ("", gc(strndup(p + uri.port.i, uri.port.n)));
|
||||
EXPECT_STREQ("/pub/vid/blankspace.mpg",
|
||||
gc(strndup(p + uri.segs.p[0].i,
|
||||
(uri.segs.p[uri.segs.i - 1].n +
|
||||
(uri.segs.p[uri.segs.i - 1].i - uri.segs.p[0].i)))));
|
||||
}
|
||||
|
||||
TEST(uriparse, localRelativeFile) {
|
||||
EXPECT_NE(-1, URIPARSE("blankspace.mpg"));
|
||||
EXPECT_STREQ("", gc(strndup(p + uri.scheme.i, uri.scheme.n)));
|
||||
EXPECT_STREQ("", gc(strndup(p + uri.host.i, uri.host.n)));
|
||||
EXPECT_STREQ("", gc(strndup(p + uri.port.i, uri.port.n)));
|
||||
EXPECT_STREQ("blankspace.mpg",
|
||||
gc(strndup(p + uri.segs.p[0].i,
|
||||
(uri.segs.p[uri.segs.i - 1].n +
|
||||
(uri.segs.p[uri.segs.i - 1].i - uri.segs.p[0].i)))));
|
||||
}
|
||||
|
||||
TEST(uriparse, badPort_einval) {
|
||||
EXPECT_EQ(-1, URIPARSE("http://hello.example:http/"));
|
||||
EXPECT_EQ(EINVAL, errno);
|
||||
}
|
||||
|
||||
TEST(uriparse, datauri) {
|
||||
size = strlen((p = gc(xstrcat("data:image/png;", kWinsockIcoPngBase64))));
|
||||
EXPECT_NE(-1, uriparse(&uri, p, size));
|
||||
EXPECT_EQ(5, uri.opaque.i);
|
||||
EXPECT_EQ(size - 5, uri.opaque.n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BENCH(uriparse, bench) {
|
||||
EZBENCH(donothing, URIPARSE("sip:+12125650666"));
|
||||
EZBENCH(donothing, URIPARSE("http://hello.example"));
|
||||
EZBENCH(donothing, URIPARSE(kHttpCosmopolitanVideoUrl));
|
||||
EZBENCH(donothing, URIPARSE(kSipPriceIsTortureUri));
|
||||
}
|
||||
|
||||
BENCH(uriparse, bigWinsockIcoPngUri) {
|
||||
const char *BigDataIconUri;
|
||||
BigDataIconUri = gc(xstrcat("data:image/png;", kWinsockIcoPngBase64));
|
||||
size = strlen(kWinsockIcoPngBase64);
|
||||
EZBENCH(donothing, uriparse(&uri, BigDataIconUri, size));
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "net/http/uri.h"
|
||||
|
||||
TEST(urischeme, test) {
|
||||
EXPECT_EQ(kUriSchemeSip, urischeme((struct UriSlice){0, 3}, "sips"));
|
||||
}
|
||||
|
||||
BENCH(urischeme, bench) {
|
||||
EZBENCH(donothing, urischeme((struct UriSlice){0, 3}, "sips"));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue