mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-28 00:02:28 +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
|
@ -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"));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue