mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Merge HTTP request / response parsing code
This change also fixes a bug so that DNS lookups work correctly when the first answer is a CNAME record.
This commit is contained in:
parent
5a6c0f27c3
commit
a68cc690ff
20 changed files with 561 additions and 616 deletions
|
@ -86,6 +86,7 @@ o/$(MODE)/examples/examples.pkg: \
|
|||
$(EXAMPLES_OBJS) \
|
||||
$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/examples/zodiac.o \
|
||||
o/$(MODE)/examples/unbourne.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_DNS_CONSTS_H_
|
||||
#define COSMOPOLITAN_LIBC_DNS_CONSTS_H_
|
||||
#include "libc/sock/sock.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
#define DNS_TYPE_A 0x01
|
||||
#define DNS_TYPE_PTR 0x0c
|
||||
#define DNS_TYPE_A 1
|
||||
#define DNS_TYPE_NS 2
|
||||
#define DNS_TYPE_CNAME 5
|
||||
#define DNS_TYPE_SOA 6
|
||||
#define DNS_TYPE_PTR 12
|
||||
#define DNS_TYPE_MX 15
|
||||
#define DNS_TYPE_TXT 16
|
||||
|
||||
#define DNS_CLASS_IN 1
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
#define kMinSockaddr4Size \
|
||||
(offsetof(struct sockaddr_in, sin_addr) + sizeof(struct in_addr))
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/consts/ipproto.h"
|
||||
|
@ -49,12 +50,14 @@
|
|||
*/
|
||||
int ResolveDns(const struct ResolvConf *resolvconf, int af, const char *name,
|
||||
struct sockaddr *addr, uint32_t addrsize) {
|
||||
int32_t ttl;
|
||||
int rc, fd, n;
|
||||
struct DnsQuestion q;
|
||||
struct DnsHeader h, h2;
|
||||
struct sockaddr_in *a4;
|
||||
uint8_t *p, *pe, msg[512];
|
||||
uint16_t rtype, rclass, rdlength;
|
||||
if (addrsize < kMinSockaddr4Size) return einval();
|
||||
if (af != AF_INET && af != AF_UNSPEC) return eafnosupport();
|
||||
if (!resolvconf->nameservers.i) return 0;
|
||||
memset(&h, 0, sizeof(h));
|
||||
|
@ -75,38 +78,31 @@ int ResolveDns(const struct ResolvConf *resolvconf, int af, const char *name,
|
|||
DeserializeDnsHeader(&h2, msg);
|
||||
if (h2.id == h.id) {
|
||||
rc = 0;
|
||||
if (h2.ancount) {
|
||||
p = msg + 12;
|
||||
pe = msg + n;
|
||||
while (p < pe && h2.qdcount) {
|
||||
p += strnlen((char *)p, pe - p) + 1 + 4;
|
||||
h2.qdcount--;
|
||||
p = msg + 12;
|
||||
pe = msg + n;
|
||||
while (p < pe && h2.qdcount--) {
|
||||
p += strnlen((char *)p, pe - p) + 1 + 4;
|
||||
}
|
||||
while (p < pe && h2.ancount--) {
|
||||
if ((p[0] & 0xc0) == 0xc0) { /* name pointer */
|
||||
p += 2;
|
||||
} else {
|
||||
p += strnlen((char *)p, pe - p) + 1;
|
||||
}
|
||||
if (p + 1 < pe) {
|
||||
if ((p[0] & 0b11000000) == 0b11000000) { /* name pointer */
|
||||
p += 2;
|
||||
} else {
|
||||
p += strnlen((char *)p, pe - p) + 1;
|
||||
}
|
||||
if (p + 2 + 2 + 4 + 2 < pe) {
|
||||
rtype = READ16BE(p), p += 2;
|
||||
rclass = READ16BE(p), p += 2;
|
||||
/* ttl */ p += 4;
|
||||
rdlength = READ16BE(p), p += 2;
|
||||
if (p + rdlength <= pe && rdlength == 4 &&
|
||||
(rtype == DNS_TYPE_A && rclass == DNS_CLASS_IN)) {
|
||||
rc = 1;
|
||||
if (addrsize) {
|
||||
if (addrsize >= kMinSockaddr4Size) {
|
||||
a4 = (struct sockaddr_in *)addr;
|
||||
a4->sin_family = AF_INET;
|
||||
memcpy(&a4->sin_addr.s_addr, p, 4);
|
||||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p + 10 <= pe) {
|
||||
rtype = READ16BE(p);
|
||||
rclass = READ16BE(p + 2);
|
||||
ttl = READ32BE(p + 4);
|
||||
rdlength = READ16BE(p + 8);
|
||||
if (p + 10 + rdlength <= pe && rdlength == 4 &&
|
||||
rclass == DNS_CLASS_IN && rtype == DNS_TYPE_A) {
|
||||
rc = 1;
|
||||
a4 = (struct sockaddr_in *)addr;
|
||||
a4->sin_family = AF_INET;
|
||||
memcpy(&a4->sin_addr.s_addr, p + 10, 4);
|
||||
break;
|
||||
}
|
||||
p += 10 + rdlength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,11 +125,11 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
|
|||
}
|
||||
|
||||
static int PrintBacktrace(int fd, const struct StackFrame *bp) {
|
||||
if (!IsTiny()) {
|
||||
if (PrintBacktraceUsingAddr2line(fd, bp) != -1) {
|
||||
return 0;
|
||||
}
|
||||
/* if (!IsTiny()) { */
|
||||
if (PrintBacktraceUsingAddr2line(fd, bp) != -1) {
|
||||
return 0;
|
||||
}
|
||||
/* } */
|
||||
return PrintBacktraceUsingSymbols(fd, bp, GetSymbolTable());
|
||||
}
|
||||
|
||||
|
|
|
@ -85,3 +85,11 @@ Uri, kHttpUri
|
|||
Warning, kHttpWarning
|
||||
WWW-Authenticate, kHttpWwwAuthenticate
|
||||
Via, kHttpVia
|
||||
Strict-Transport-Security, kHttpStrictTransportSecurity
|
||||
X-Frame-Options, kHttpXFrameOptions
|
||||
X-Content-Type-Options, kHttpXContentTypeOptions
|
||||
Alt-Svc, kHttpAltSvc
|
||||
Referrer-Policy, kHttpReferrerPolicy
|
||||
X-XSS-Protection, kHttpXXssProtection
|
||||
Accept-Ranges, kHttpAcceptRanges
|
||||
Set-Cookie, kHttpSetCookie
|
||||
|
|
|
@ -38,12 +38,12 @@
|
|||
#line 12 "gethttpheader.gperf"
|
||||
struct thatispacked HttpHeaderSlot { char *name; char code; };
|
||||
|
||||
#define TOTAL_KEYWORDS 73
|
||||
#define TOTAL_KEYWORDS 82
|
||||
#define MIN_WORD_LENGTH 2
|
||||
#define MAX_WORD_LENGTH 32
|
||||
#define MIN_HASH_VALUE 6
|
||||
#define MAX_HASH_VALUE 142
|
||||
/* maximum key range = 137, duplicates = 0 */
|
||||
#define MAX_HASH_VALUE 133
|
||||
/* maximum key range = 128, duplicates = 0 */
|
||||
|
||||
#ifndef GPERF_DOWNCASE
|
||||
#define GPERF_DOWNCASE 1
|
||||
|
@ -72,7 +72,7 @@ static unsigned char gperf_downcase[256] =
|
|||
|
||||
#ifndef GPERF_CASE_STRNCMP
|
||||
#define GPERF_CASE_STRNCMP 1
|
||||
static inline int
|
||||
static int
|
||||
gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
|
||||
{
|
||||
for (; n > 0;)
|
||||
|
@ -102,32 +102,32 @@ hash (register const char *str, register size_t len)
|
|||
{
|
||||
static const unsigned char asso_values[] =
|
||||
{
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 0, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 0, 143, 20, 75, 5,
|
||||
35, 30, 15, 30, 143, 55, 15, 40, 0, 65,
|
||||
30, 143, 35, 20, 0, 50, 10, 30, 55, 45,
|
||||
143, 143, 143, 143, 143, 143, 143, 0, 143, 20,
|
||||
75, 5, 35, 30, 15, 30, 143, 55, 15, 40,
|
||||
0, 65, 30, 143, 35, 20, 0, 50, 10, 30,
|
||||
55, 45, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 20, 134, 134, 134, 134,
|
||||
134, 134, 134, 0, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 0, 134, 20, 95, 5,
|
||||
10, 70, 15, 30, 134, 5, 15, 20, 0, 75,
|
||||
40, 134, 35, 20, 0, 50, 25, 30, 0, 30,
|
||||
134, 134, 134, 134, 134, 134, 134, 0, 134, 20,
|
||||
95, 5, 10, 70, 15, 30, 134, 5, 15, 20,
|
||||
0, 75, 40, 134, 35, 20, 0, 50, 25, 30,
|
||||
0, 30, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134
|
||||
};
|
||||
register unsigned int hval = len;
|
||||
|
||||
|
@ -165,7 +165,7 @@ hash (register const char *str, register size_t len)
|
|||
return hval + asso_values[(unsigned char)str[len - 1]];
|
||||
}
|
||||
|
||||
static inline const struct thatispacked HttpHeaderSlot *
|
||||
static const struct thatispacked HttpHeaderSlot *
|
||||
LookupHttpHeader (register const char *str, register size_t len)
|
||||
{
|
||||
static const struct thatispacked HttpHeaderSlot wordlist[] =
|
||||
|
@ -185,18 +185,31 @@ LookupHttpHeader (register const char *str, register size_t len)
|
|||
{"Authorization", kHttpAuthorization},
|
||||
#line 48 "gethttpheader.gperf"
|
||||
{"Accept-Charset", kHttpAcceptCharset},
|
||||
{""}, {""}, {""}, {""},
|
||||
{""},
|
||||
#line 93 "gethttpheader.gperf"
|
||||
{"X-XSS-Protection", kHttpXXssProtection},
|
||||
#line 34 "gethttpheader.gperf"
|
||||
{"X-CSRF-Token", kHttpXCsrfToken},
|
||||
{""},
|
||||
#line 14 "gethttpheader.gperf"
|
||||
{"Host", kHttpHost},
|
||||
#line 18 "gethttpheader.gperf"
|
||||
{"Accept-Language", kHttpAcceptLanguage},
|
||||
{""}, {""},
|
||||
#line 32 "gethttpheader.gperf"
|
||||
{"X-Forwarded-Host", kHttpXForwardedHost},
|
||||
{""},
|
||||
#line 73 "gethttpheader.gperf"
|
||||
{"Location", kHttpLocation},
|
||||
{""}, {""},
|
||||
#line 72 "gethttpheader.gperf"
|
||||
{"Link", kHttpLink},
|
||||
#line 71 "gethttpheader.gperf"
|
||||
{"Keep-Alive", kHttpKeepAlive},
|
||||
#line 53 "gethttpheader.gperf"
|
||||
{"Access-Control-MaxAge", kHttpAccessControlMaxAge},
|
||||
{""}, {""},
|
||||
#line 91 "gethttpheader.gperf"
|
||||
{"Alt-Svc", kHttpAltSvc},
|
||||
#line 87 "gethttpheader.gperf"
|
||||
{"Via", kHttpVia},
|
||||
#line 35 "gethttpheader.gperf"
|
||||
{"Save-Data", kHttpSaveData},
|
||||
#line 16 "gethttpheader.gperf"
|
||||
|
@ -205,18 +218,21 @@ LookupHttpHeader (register const char *str, register size_t len)
|
|||
{"Cookie", kHttpCookie},
|
||||
#line 42 "gethttpheader.gperf"
|
||||
{"Expires", kHttpExpires},
|
||||
{""}, {""},
|
||||
#line 94 "gethttpheader.gperf"
|
||||
{"Accept-Ranges", kHttpAcceptRanges},
|
||||
#line 29 "gethttpheader.gperf"
|
||||
{"From", kHttpFrom},
|
||||
#line 46 "gethttpheader.gperf"
|
||||
{"Allow", kHttpAllow},
|
||||
#line 25 "gethttpheader.gperf"
|
||||
{"Pragma", kHttpPragma},
|
||||
#line 31 "gethttpheader.gperf"
|
||||
{"X-Requested-With", kHttpXRequestedWith},
|
||||
#line 60 "gethttpheader.gperf"
|
||||
{"Content-Base", kHttpContentBase},
|
||||
#line 47 "gethttpheader.gperf"
|
||||
{"Content-Range", kHttpContentRange},
|
||||
#line 45 "gethttpheader.gperf"
|
||||
{"ETag", kHttpEtag},
|
||||
{""},
|
||||
#line 95 "gethttpheader.gperf"
|
||||
{"Set-Cookie", kHttpSetCookie},
|
||||
#line 63 "gethttpheader.gperf"
|
||||
{"Content-Language", kHttpContentLanguage},
|
||||
#line 81 "gethttpheader.gperf"
|
||||
|
@ -227,8 +243,8 @@ LookupHttpHeader (register const char *str, register size_t len)
|
|||
{"Content-Description", kHttpContentDescription},
|
||||
#line 36 "gethttpheader.gperf"
|
||||
{"Range", kHttpRange},
|
||||
#line 77 "gethttpheader.gperf"
|
||||
{"Proxy-Connection", kHttpProxyConnection},
|
||||
#line 25 "gethttpheader.gperf"
|
||||
{"Pragma", kHttpPragma},
|
||||
#line 28 "gethttpheader.gperf"
|
||||
{"Sec-GPC", kHttpSecGpc},
|
||||
#line 15 "gethttpheader.gperf"
|
||||
|
@ -239,15 +255,15 @@ LookupHttpHeader (register const char *str, register size_t len)
|
|||
{"Access-Control-Request-Methods", kHttpAccessControlRequestMethods},
|
||||
#line 86 "gethttpheader.gperf"
|
||||
{"WWW-Authenticate", kHttpWwwAuthenticate},
|
||||
#line 82 "gethttpheader.gperf"
|
||||
{"Transfer-Encoding", kHttpTransferEncoding},
|
||||
{""},
|
||||
#line 67 "gethttpheader.gperf"
|
||||
{"If-Match", kHttpIfMatch},
|
||||
#line 37 "gethttpheader.gperf"
|
||||
{"Content-Length", kHttpContentLength},
|
||||
{""},
|
||||
#line 78 "gethttpheader.gperf"
|
||||
{"Public", kHttpPublic},
|
||||
#line 22 "gethttpheader.gperf"
|
||||
{"X-Forwarded-For", kHttpXForwardedFor},
|
||||
#line 77 "gethttpheader.gperf"
|
||||
{"Proxy-Connection", kHttpProxyConnection},
|
||||
#line 30 "gethttpheader.gperf"
|
||||
{"If-Modified-Since", kHttpIfModifiedSince},
|
||||
#line 68 "gethttpheader.gperf"
|
||||
|
@ -262,86 +278,87 @@ LookupHttpHeader (register const char *str, register size_t len)
|
|||
{"Upgrade", kHttpUpgrade},
|
||||
#line 50 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Headers", kHttpAccessControlAllowHeaders},
|
||||
#line 70 "gethttpheader.gperf"
|
||||
{"If-Unmodified-Since", kHttpIfUnmodifiedSince},
|
||||
{""},
|
||||
#line 78 "gethttpheader.gperf"
|
||||
{"Public", kHttpPublic},
|
||||
#line 38 "gethttpheader.gperf"
|
||||
{"Content-Type", kHttpContentType},
|
||||
#line 51 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Methods", kHttpAccessControlAllowMethods},
|
||||
#line 62 "gethttpheader.gperf"
|
||||
{"Content-Disposition", kHttpContentDisposition},
|
||||
{""}, {""},
|
||||
#line 49 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Credentials", kHttpAccessControlAllowCredentials},
|
||||
{""},
|
||||
#line 76 "gethttpheader.gperf"
|
||||
{"Proxy-Authorization", kHttpProxyAuthorization},
|
||||
#line 89 "gethttpheader.gperf"
|
||||
{"X-Frame-Options", kHttpXFrameOptions},
|
||||
{""},
|
||||
#line 21 "gethttpheader.gperf"
|
||||
{"Referer", kHttpReferer},
|
||||
#line 75 "gethttpheader.gperf"
|
||||
{"Proxy-Authenticate", kHttpProxyAuthenticate},
|
||||
#line 45 "gethttpheader.gperf"
|
||||
{"ETag", kHttpEtag},
|
||||
{""},
|
||||
#line 23 "gethttpheader.gperf"
|
||||
{"Origin", kHttpOrigin},
|
||||
#line 90 "gethttpheader.gperf"
|
||||
{"X-Content-Type-Options", kHttpXContentTypeOptions},
|
||||
#line 84 "gethttpheader.gperf"
|
||||
{"Uri", kHttpUri},
|
||||
{""}, {""},
|
||||
#line 79 "gethttpheader.gperf"
|
||||
{"Retry-After", kHttpRetryAfter},
|
||||
#line 74 "gethttpheader.gperf"
|
||||
{"Max-Forwards", kHttpMaxForwards},
|
||||
{""}, {""}, {""}, {""},
|
||||
#line 82 "gethttpheader.gperf"
|
||||
{"Transfer-Encoding", kHttpTransferEncoding},
|
||||
{""}, {""}, {""}, {""},
|
||||
#line 33 "gethttpheader.gperf"
|
||||
{"X-Forwarded-Proto", kHttpXForwardedProto},
|
||||
#line 27 "gethttpheader.gperf"
|
||||
{"DNT", kHttpDnt},
|
||||
{""},
|
||||
#line 24 "gethttpheader.gperf"
|
||||
{"Upgrade-Insecure-Requests", kHttpUpgradeInsecureRequests},
|
||||
{""},
|
||||
#line 52 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Origin", kHttpAccessControlAllowOrigin},
|
||||
{""},
|
||||
#line 40 "gethttpheader.gperf"
|
||||
{"Date", kHttpDate},
|
||||
#line 19 "gethttpheader.gperf"
|
||||
{"Accept-Encoding", kHttpAcceptEncoding},
|
||||
#line 43 "gethttpheader.gperf"
|
||||
{"Content-Encoding", kHttpContentEncoding},
|
||||
#line 85 "gethttpheader.gperf"
|
||||
{"Warning", kHttpWarning},
|
||||
#line 75 "gethttpheader.gperf"
|
||||
{"Proxy-Authenticate", kHttpProxyAuthenticate},
|
||||
#line 62 "gethttpheader.gperf"
|
||||
{"Content-Disposition", kHttpContentDisposition},
|
||||
{""},
|
||||
#line 23 "gethttpheader.gperf"
|
||||
{"Origin", kHttpOrigin},
|
||||
#line 49 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Credentials", kHttpAccessControlAllowCredentials},
|
||||
{""},
|
||||
#line 72 "gethttpheader.gperf"
|
||||
{"Link", kHttpLink},
|
||||
#line 71 "gethttpheader.gperf"
|
||||
{"Keep-Alive", kHttpKeepAlive},
|
||||
#line 32 "gethttpheader.gperf"
|
||||
{"X-Forwarded-Host", kHttpXForwardedHost},
|
||||
#line 21 "gethttpheader.gperf"
|
||||
{"Referer", kHttpReferer},
|
||||
#line 27 "gethttpheader.gperf"
|
||||
{"DNT", kHttpDnt},
|
||||
#line 29 "gethttpheader.gperf"
|
||||
{"From", kHttpFrom},
|
||||
{""}, {""},
|
||||
#line 38 "gethttpheader.gperf"
|
||||
{"Content-Type", kHttpContentType},
|
||||
#line 84 "gethttpheader.gperf"
|
||||
{"Uri", kHttpUri},
|
||||
#line 40 "gethttpheader.gperf"
|
||||
{"Date", kHttpDate},
|
||||
{""},
|
||||
#line 79 "gethttpheader.gperf"
|
||||
{"Retry-After", kHttpRetryAfter},
|
||||
{""},
|
||||
#line 51 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Methods", kHttpAccessControlAllowMethods},
|
||||
#line 70 "gethttpheader.gperf"
|
||||
{"If-Unmodified-Since", kHttpIfUnmodifiedSince},
|
||||
{""},
|
||||
#line 31 "gethttpheader.gperf"
|
||||
{"X-Requested-With", kHttpXRequestedWith},
|
||||
#line 52 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Origin", kHttpAccessControlAllowOrigin},
|
||||
{""}, {""}, {""},
|
||||
#line 88 "gethttpheader.gperf"
|
||||
{"Strict-Transport-Security", kHttpStrictTransportSecurity},
|
||||
#line 64 "gethttpheader.gperf"
|
||||
{"Content-Location", kHttpContentLocation},
|
||||
{""}, {""}, {""}, {""},
|
||||
#line 54 "gethttpheader.gperf"
|
||||
{"Access-Control-Method", kHttpAccessControlMethod},
|
||||
{""}, {""}, {""},
|
||||
#line 24 "gethttpheader.gperf"
|
||||
{"Upgrade-Insecure-Requests", kHttpUpgradeInsecureRequests},
|
||||
#line 64 "gethttpheader.gperf"
|
||||
{"Content-Location", kHttpContentLocation},
|
||||
{""}, {""},
|
||||
#line 92 "gethttpheader.gperf"
|
||||
{"Referrer-Policy", kHttpReferrerPolicy},
|
||||
{""}, {""}, {""},
|
||||
#line 56 "gethttpheader.gperf"
|
||||
{"Access-Control-Request-Method", kHttpAccessControlRequestMethod},
|
||||
{""},
|
||||
#line 65 "gethttpheader.gperf"
|
||||
{"Content-MD5", kHttpContentMd5},
|
||||
#line 74 "gethttpheader.gperf"
|
||||
{"Max-Forwards", kHttpMaxForwards},
|
||||
{""}, {""},
|
||||
#line 22 "gethttpheader.gperf"
|
||||
{"X-Forwarded-For", kHttpXForwardedFor},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{""}, {""},
|
||||
#line 34 "gethttpheader.gperf"
|
||||
{"X-CSRF-Token", kHttpXCsrfToken},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{""}, {""}, {""}, {""}, {""}, {""},
|
||||
#line 44 "gethttpheader.gperf"
|
||||
{"Last-Modified", kHttpLastModified},
|
||||
{""}, {""}, {""},
|
||||
#line 33 "gethttpheader.gperf"
|
||||
{"X-Forwarded-Proto", kHttpXForwardedProto}
|
||||
{"Last-Modified", kHttpLastModified}
|
||||
};
|
||||
|
||||
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
||||
|
|
|
@ -168,6 +168,22 @@ const char *GetHttpHeaderName(int h) {
|
|||
return "WWW-Authenticate";
|
||||
case kHttpVia:
|
||||
return "Via";
|
||||
case kHttpStrictTransportSecurity:
|
||||
return "Strict-Transport-Security";
|
||||
case kHttpXFrameOptions:
|
||||
return "X-Frame-Options";
|
||||
case kHttpXContentTypeOptions:
|
||||
return "X-Content-Type-Options";
|
||||
case kHttpAltSvc:
|
||||
return "Alt-Svc";
|
||||
case kHttpReferrerPolicy:
|
||||
return "Referrer-Policy";
|
||||
case kHttpXXssProtection:
|
||||
return "X-XSS-Protection";
|
||||
case kHttpAcceptRanges:
|
||||
return "Accept-Ranges";
|
||||
case kHttpSetCookie:
|
||||
return "Set-Cookie";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
/**
|
||||
* Returns true if standard header has substring.
|
||||
*
|
||||
* @param m is message parsed by ParseHttpRequest
|
||||
* @param b is buffer that ParseHttpRequest parsed
|
||||
* @param m is message parsed by ParseHttpMessage
|
||||
* @param b is buffer that ParseHttpMessage parsed
|
||||
* @param h is known header, e.g. kHttpAcceptEncoding
|
||||
* @param s should not contain comma
|
||||
* @param n is byte length of s where -1 implies strlen
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
#define COSMOPOLITAN_LIBC_HTTP_HTTP_H_
|
||||
#include "libc/time/struct/tm.h"
|
||||
|
||||
#define kHttpRequest 0
|
||||
#define kHttpResponse 1
|
||||
|
||||
#define kHttpGet 1
|
||||
#define kHttpHead 2
|
||||
#define kHttpPost 3
|
||||
|
@ -94,7 +97,15 @@
|
|||
#define kHttpWarning 71
|
||||
#define kHttpWwwAuthenticate 72
|
||||
#define kHttpVia 73
|
||||
#define kHttpHeadersMax 74
|
||||
#define kHttpStrictTransportSecurity 74
|
||||
#define kHttpXFrameOptions 75
|
||||
#define kHttpXContentTypeOptions 76
|
||||
#define kHttpAltSvc 77
|
||||
#define kHttpReferrerPolicy 78
|
||||
#define kHttpXXssProtection 79
|
||||
#define kHttpAcceptRanges 80
|
||||
#define kHttpSetCookie 81
|
||||
#define kHttpHeadersMax 82
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
@ -116,6 +127,7 @@ struct HttpHeaders {
|
|||
struct HttpMessage {
|
||||
int i, a, status;
|
||||
unsigned char t;
|
||||
unsigned char type;
|
||||
unsigned char method;
|
||||
unsigned char version;
|
||||
struct HttpSlice k;
|
||||
|
@ -135,12 +147,9 @@ const char *GetHttpReason(int);
|
|||
const char *GetHttpHeaderName(int);
|
||||
int GetHttpHeader(const char *, size_t);
|
||||
int GetHttpMethod(const char *, size_t);
|
||||
void InitHttpRequest(struct HttpMessage *);
|
||||
void DestroyHttpRequest(struct HttpMessage *);
|
||||
int ParseHttpRequest(struct HttpMessage *, const char *, size_t);
|
||||
void InitHttpResponse(struct HttpMessage *);
|
||||
void DestroyHttpResponse(struct HttpMessage *);
|
||||
int ParseHttpResponse(struct HttpMessage *, const char *, size_t);
|
||||
void InitHttpMessage(struct HttpMessage *, int);
|
||||
void DestroyHttpMessage(struct HttpMessage *);
|
||||
int ParseHttpMessage(struct HttpMessage *, const char *, size_t);
|
||||
bool HeaderHas(struct HttpMessage *, const char *, int, const char *, size_t);
|
||||
int64_t ParseContentLength(const char *, size_t);
|
||||
char *FormatHttpDateTime(char[hasatleast 30], struct tm *);
|
||||
|
|
|
@ -19,11 +19,25 @@
|
|||
#include "net/http/ip.h"
|
||||
|
||||
/**
|
||||
* Returns true if IPv4 address can come from the Internet.
|
||||
* Returns true if IPv4 address is Globally Reachable.
|
||||
*
|
||||
* We intentionally omit TEST-NET here which can be used to simulate
|
||||
* public Internet traffic using non-Internet IPs.
|
||||
*
|
||||
* @return true 92.4499% of the time
|
||||
* @see IANA IPv4 Special-Purpose Address Registry
|
||||
*/
|
||||
bool IsPublicIp(uint32_t x) {
|
||||
return !IsLoopbackIp(x) && !IsPrivateIp(x);
|
||||
return !((x & 0xffffffff) == 0x00000000 /* 0.0.0.0/32 */ ||
|
||||
(x & 0xff000000) == 0x00000000 /* 0.0.0.0/8 */ ||
|
||||
(x & 0xff000000) == 0x0a000000 /* 10.0.0.0/8 */ ||
|
||||
(x & 0xff000000) == 0x7f000000 /* 127.0.0.0/8 */ ||
|
||||
(x & 0xfff00000) == 0xac100000 /* 172.16.0.0/12 */ ||
|
||||
(x & 0xffffff00) == 0xc0000000 /* 192.0.0.0/24 */ ||
|
||||
(x & 0xffff0000) == 0xc0a80000 /* 192.168.0.0/16 */ ||
|
||||
(x & 0xffff0000) == 0xa9fe0000 /* 169.254.0.0/16 */ ||
|
||||
(x & 0xffc00000) == 0x64400000 /* 100.64.0.0/10 */ ||
|
||||
(x & 0xfffe0000) == 0xc6120000 /* 198.18.0.0/15 */ ||
|
||||
(x & 0xf0000000) == 0xf0000000 /* 240.0.0.0/4 */ ||
|
||||
(x & 0xffffffff) == 0xffffffff /* 255.255.255.255/32 */);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/arraylist.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -30,19 +31,34 @@
|
|||
|
||||
#define LIMIT (SHRT_MAX - 2)
|
||||
|
||||
enum { START, METHOD, URI, VERSION, HKEY, HSEP, HVAL, CR1, LF1, LF2 };
|
||||
enum HttpMessageState {
|
||||
START,
|
||||
METHOD,
|
||||
URI,
|
||||
VERSION,
|
||||
STATUS,
|
||||
MESSAGE,
|
||||
HKEY,
|
||||
HSEP,
|
||||
HVAL,
|
||||
CR1,
|
||||
LF1,
|
||||
LF2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes HTTP request parser.
|
||||
* Initializes HTTP message parser.
|
||||
*/
|
||||
void InitHttpRequest(struct HttpMessage *r) {
|
||||
void InitHttpMessage(struct HttpMessage *r, int type) {
|
||||
assert(type == kHttpRequest || type == kHttpResponse);
|
||||
memset(r, 0, sizeof(*r));
|
||||
r->type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys HTTP request parser.
|
||||
* Destroys HTTP message parser.
|
||||
*/
|
||||
void DestroyHttpRequest(struct HttpMessage *r) {
|
||||
void DestroyHttpMessage(struct HttpMessage *r) {
|
||||
if (r->xheaders.p) {
|
||||
free(r->xheaders.p);
|
||||
r->xheaders.p = NULL;
|
||||
|
@ -51,7 +67,7 @@ void DestroyHttpRequest(struct HttpMessage *r) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Parses HTTP request.
|
||||
* Parses HTTP request or response.
|
||||
*
|
||||
* This parser is responsible for determining the length of a message
|
||||
* and slicing the strings inside it. Performance is attained using
|
||||
|
@ -83,7 +99,7 @@ void DestroyHttpRequest(struct HttpMessage *r) {
|
|||
* @see HTTP/1.1 RFC2616 RFC2068
|
||||
* @see HTTP/1.0 RFC1945
|
||||
*/
|
||||
int ParseHttpRequest(struct HttpMessage *r, const char *p, size_t n) {
|
||||
int ParseHttpMessage(struct HttpMessage *r, const char *p, size_t n) {
|
||||
int c, h, i;
|
||||
struct HttpHeader *x;
|
||||
for (n = MIN(n, LIMIT); r->i < n; ++r->i) {
|
||||
|
@ -92,7 +108,7 @@ int ParseHttpRequest(struct HttpMessage *r, const char *p, size_t n) {
|
|||
case START:
|
||||
if (c == '\r' || c == '\n') break; /* RFC7230 § 3.5 */
|
||||
if (!kHttpToken[c]) return ebadmsg();
|
||||
r->t = METHOD;
|
||||
r->t = r->type == kHttpRequest ? METHOD : VERSION;
|
||||
r->a = r->i;
|
||||
break;
|
||||
case METHOD:
|
||||
|
@ -133,17 +149,57 @@ int ParseHttpRequest(struct HttpMessage *r, const char *p, size_t n) {
|
|||
}
|
||||
break;
|
||||
case VERSION:
|
||||
if (c == '\r' || c == '\n') {
|
||||
if (c == ' ' || c == '\r' || c == '\n') {
|
||||
if (r->i - r->a == 8 &&
|
||||
(READ64BE(p + r->a) & 0xFFFFFFFFFF00FF00) == 0x485454502F002E00 &&
|
||||
isdigit(p[r->a + 5]) && isdigit(p[r->a + 7])) {
|
||||
r->version = (p[r->a + 5] - '0') * 10 + (p[r->a + 7] - '0');
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
if (r->type == kHttpRequest) {
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
} else {
|
||||
r->t = STATUS;
|
||||
}
|
||||
} else {
|
||||
return ebadmsg();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATUS:
|
||||
for (;;) {
|
||||
if (c == ' ' || c == '\r' || c == '\n') {
|
||||
if (r->status < 100) return ebadmsg();
|
||||
if (c == ' ') {
|
||||
r->a = r->i + 1;
|
||||
r->t = MESSAGE;
|
||||
} else {
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
}
|
||||
break;
|
||||
} else if ('0' <= c && c <= '9') {
|
||||
r->status *= 10;
|
||||
r->status += c - '0';
|
||||
if (r->status > 999) return ebadmsg();
|
||||
} else {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
}
|
||||
break;
|
||||
case MESSAGE:
|
||||
for (;;) {
|
||||
if (c == '\r' || c == '\n') {
|
||||
r->message.a = r->a;
|
||||
r->message.b = r->i;
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
break;
|
||||
} else if (c < 0x20 || (0x7F <= c && c < 0xA0)) {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
}
|
||||
break;
|
||||
case CR1:
|
||||
if (c != '\n') return ebadmsg();
|
||||
r->t = LF1;
|
|
@ -1,187 +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/bits/bits.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
#define LIMIT (SHRT_MAX - 2)
|
||||
|
||||
enum { START, VERSION, STATUS, MESSAGE, HKEY, HSEP, HVAL, CR1, LF1, LF2 };
|
||||
|
||||
/**
|
||||
* Initializes HTTP response parser.
|
||||
*/
|
||||
void InitHttpResponse(struct HttpMessage *r) {
|
||||
memset(r, 0, sizeof(*r));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys HTTP response parser.
|
||||
*/
|
||||
void DestroyHttpResponse(struct HttpMessage *r) {
|
||||
if (r->xheaders.p) {
|
||||
free(r->xheaders.p);
|
||||
r->xheaders.p = NULL;
|
||||
r->xheaders.n = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses HTTP response.
|
||||
*/
|
||||
int ParseHttpResponse(struct HttpMessage *r, const char *p, size_t n) {
|
||||
int c, h, i;
|
||||
struct HttpHeader *x;
|
||||
for (n = MIN(n, LIMIT); r->i < n; ++r->i) {
|
||||
c = p[r->i] & 0xff;
|
||||
switch (r->t) {
|
||||
case START:
|
||||
if (c == '\r' || c == '\n') break; /* RFC7230 § 3.5 */
|
||||
if (c != 'H') return ebadmsg();
|
||||
r->t = VERSION;
|
||||
r->a = r->i;
|
||||
break;
|
||||
case VERSION:
|
||||
if (c == ' ') {
|
||||
if (r->i - r->a == 8 &&
|
||||
(READ64BE(p + r->a) & 0xFFFFFFFFFF00FF00) == 0x485454502F002E00 &&
|
||||
isdigit(p[r->a + 5]) && isdigit(p[r->a + 7])) {
|
||||
r->version = (p[r->a + 5] - '0') * 10 + (p[r->a + 7] - '0');
|
||||
r->t = STATUS;
|
||||
} else {
|
||||
return ebadmsg();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATUS:
|
||||
for (;;) {
|
||||
if (c == ' ' || c == '\r' || c == '\n') {
|
||||
if (r->status < 100) return ebadmsg();
|
||||
if (c == ' ') {
|
||||
r->a = r->i + 1;
|
||||
r->t = MESSAGE;
|
||||
} else {
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
}
|
||||
break;
|
||||
} else if ('0' <= c && c <= '9') {
|
||||
r->status *= 10;
|
||||
r->status += c - '0';
|
||||
if (r->status > 999) return ebadmsg();
|
||||
} else {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
}
|
||||
break;
|
||||
case MESSAGE:
|
||||
for (;;) {
|
||||
if (c == '\r' || c == '\n') {
|
||||
r->message.a = r->a;
|
||||
r->message.b = r->i;
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
break;
|
||||
} else if (c < 0x20 || (0x7F <= c && c < 0xA0)) {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
}
|
||||
break;
|
||||
case CR1:
|
||||
if (c != '\n') return ebadmsg();
|
||||
r->t = LF1;
|
||||
break;
|
||||
case LF1:
|
||||
if (c == '\r') {
|
||||
r->t = LF2;
|
||||
break;
|
||||
} else if (c == '\n') {
|
||||
return ++r->i;
|
||||
} else if (!kHttpToken[c]) {
|
||||
return ebadmsg(); /* RFC7230 § 3.2.4 */
|
||||
}
|
||||
r->k.a = r->i;
|
||||
r->t = HKEY;
|
||||
break;
|
||||
case HKEY:
|
||||
for (;;) {
|
||||
if (c == ':') {
|
||||
r->k.b = r->i;
|
||||
r->t = HSEP;
|
||||
break;
|
||||
} else if (!kHttpToken[c]) {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
}
|
||||
break;
|
||||
case HSEP:
|
||||
if (c == ' ' || c == '\t') break;
|
||||
r->a = r->i;
|
||||
r->t = HVAL;
|
||||
/* fallthrough */
|
||||
case HVAL:
|
||||
for (;;) {
|
||||
if (c == '\r' || c == '\n') {
|
||||
i = r->i;
|
||||
while (i > r->a && (p[i - 1] == ' ' || p[i - 1] == '\t')) --i;
|
||||
if ((h = GetHttpHeader(p + r->k.a, r->k.b - r->k.a)) != -1 &&
|
||||
(!r->headers[h].a || !kHttpRepeatable[h])) {
|
||||
r->headers[h].a = r->a;
|
||||
r->headers[h].b = i;
|
||||
} else if ((x = realloc(
|
||||
r->xheaders.p,
|
||||
(r->xheaders.n + 1) * sizeof(*r->xheaders.p)))) {
|
||||
x[r->xheaders.n].k = r->k;
|
||||
x[r->xheaders.n].v.a = r->a;
|
||||
x[r->xheaders.n].v.b = i;
|
||||
r->xheaders.p = x;
|
||||
++r->xheaders.n;
|
||||
}
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
break;
|
||||
} else if ((c < 0x20 && c != '\t') || (0x7F <= c && c < 0xA0)) {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
}
|
||||
break;
|
||||
case LF2:
|
||||
if (c == '\n') {
|
||||
return ++r->i;
|
||||
}
|
||||
return ebadmsg();
|
||||
default:
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
if (r->i < LIMIT) {
|
||||
return 0;
|
||||
} else {
|
||||
return ebadmsg();
|
||||
}
|
||||
}
|
35
test/net/http/ismimetype_test.c
Normal file
35
test/net/http/ismimetype_test.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*-*- 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(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"));
|
||||
}
|
||||
|
||||
BENCH(IsMimeType, bench) {
|
||||
EZBENCH2("IsMimeType", donothing,
|
||||
IsMimeType("text/plain; charset=utf-8", -1, "text/plain"));
|
||||
}
|
|
@ -38,41 +38,42 @@ static char *slice(const char *m, struct HttpSlice s) {
|
|||
return p;
|
||||
}
|
||||
|
||||
void SetUp(void) {
|
||||
InitHttpRequest(req);
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
DestroyHttpRequest(req);
|
||||
DestroyHttpMessage(req);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, soLittleState) {
|
||||
TEST(ParseHttpMessage, soLittleState) {
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
ASSERT_LE(sizeof(struct HttpMessage), 512);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testEmpty_tooShort) {
|
||||
EXPECT_EQ(0, ParseHttpRequest(req, "", 0));
|
||||
TEST(ParseHttpMessage, testEmpty_tooShort) {
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(0, ParseHttpMessage(req, "", 0));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testTooShort) {
|
||||
EXPECT_EQ(0, ParseHttpRequest(req, "\r\n", 2));
|
||||
TEST(ParseHttpMessage, testTooShort) {
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(0, ParseHttpMessage(req, "\r\n", 2));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testNoHeaders) {
|
||||
TEST(ParseHttpMessage, testNoHeaders) {
|
||||
static const char m[] = "GET /foo HTTP/1.0\r\n\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpGet, req->method);
|
||||
EXPECT_STREQ("/foo", gc(slice(m, req->uri)));
|
||||
EXPECT_EQ(10, req->version);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testSomeHeaders) {
|
||||
TEST(ParseHttpMessage, testSomeHeaders) {
|
||||
static const char m[] = "\
|
||||
POST /foo?bar%20hi HTTP/1.0\r\n\
|
||||
Host: foo.example\r\n\
|
||||
Content-Length: 0\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpPost, req->method);
|
||||
EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri)));
|
||||
EXPECT_EQ(10, req->version);
|
||||
|
@ -81,101 +82,113 @@ Content-Length: 0\r\n\
|
|||
EXPECT_STREQ("", gc(slice(m, req->headers[kHttpEtag])));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testHttp101) {
|
||||
TEST(ParseHttpMessage, testHttp101) {
|
||||
static const char m[] = "GET / HTTP/1.1\r\n\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpGet, req->method);
|
||||
EXPECT_STREQ("/", gc(slice(m, req->uri)));
|
||||
EXPECT_EQ(11, req->version);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testHttp100) {
|
||||
TEST(ParseHttpMessage, testHttp100) {
|
||||
static const char m[] = "GET / HTTP/1.0\r\n\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpGet, req->method);
|
||||
EXPECT_STREQ("/", gc(slice(m, req->uri)));
|
||||
EXPECT_EQ(10, req->version);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testUnknownMethod_canBeUsedIfYouWant) {
|
||||
TEST(ParseHttpMessage, testUnknownMethod_canBeUsedIfYouWant) {
|
||||
static const char m[] = "#%*+_^ / HTTP/1.0\r\n\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_FALSE(req->method);
|
||||
EXPECT_STREQ("WUT", kHttpMethod[req->method]);
|
||||
EXPECT_STREQ("#%*+_^", gc(slice(m, req->xmethod)));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testIllegalMethod) {
|
||||
TEST(ParseHttpMessage, testIllegalMethod) {
|
||||
static const char m[] = "ehd@oruc / HTTP/1.0\r\n\r\n";
|
||||
EXPECT_EQ(-1, ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_STREQ("WUT", kHttpMethod[req->method]);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testIllegalMethodCasing_weAllowItAndPreserveIt) {
|
||||
TEST(ParseHttpMessage, testIllegalMethodCasing_weAllowItAndPreserveIt) {
|
||||
static const char m[] = "get / HTTP/1.0\r\n\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_STREQ("GET", kHttpMethod[req->method]);
|
||||
EXPECT_STREQ("get", gc(slice(m, req->xmethod)));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testEmptyMethod_isntAllowed) {
|
||||
TEST(ParseHttpMessage, testEmptyMethod_isntAllowed) {
|
||||
static const char m[] = " / HTTP/1.0\r\n\r\n";
|
||||
EXPECT_EQ(-1, ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_STREQ("WUT", kHttpMethod[req->method]);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testEmptyUri_isntAllowed) {
|
||||
TEST(ParseHttpMessage, testEmptyUri_isntAllowed) {
|
||||
static const char m[] = "GET HTTP/1.0\r\n\r\n";
|
||||
EXPECT_EQ(-1, ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_STREQ("GET", kHttpMethod[req->method]);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testHttp09) {
|
||||
TEST(ParseHttpMessage, testHttp09) {
|
||||
static const char m[] = "GET /\r\n\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpGet, req->method);
|
||||
EXPECT_STREQ("/", gc(slice(m, req->uri)));
|
||||
EXPECT_EQ(9, req->version);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testLeadingLineFeeds_areIgnored) {
|
||||
TEST(ParseHttpMessage, testLeadingLineFeeds_areIgnored) {
|
||||
static const char m[] = "\
|
||||
\r\n\
|
||||
GET /foo?bar%20hi HTTP/1.0\r\n\
|
||||
User-Agent: hi\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri)));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testLineFolding_isRejected) {
|
||||
TEST(ParseHttpMessage, testLineFolding_isRejected) {
|
||||
static const char m[] = "\
|
||||
GET /foo?bar%20hi HTTP/1.0\r\n\
|
||||
User-Agent: hi\r\n\
|
||||
there\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(-1, ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(EBADMSG, errno);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testEmptyHeaderName_isRejected) {
|
||||
TEST(ParseHttpMessage, testEmptyHeaderName_isRejected) {
|
||||
static const char m[] = "\
|
||||
GET /foo?bar%20hi HTTP/1.0\r\n\
|
||||
User-Agent: hi\r\n\
|
||||
: hi\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(-1, ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(EBADMSG, errno);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testUnixNewlines) {
|
||||
TEST(ParseHttpMessage, testUnixNewlines) {
|
||||
static const char m[] = "\
|
||||
POST /foo?bar%20hi HTTP/1.0\n\
|
||||
Host: foo.example\n\
|
||||
Content-Length: 0\n\
|
||||
\n\
|
||||
\n";
|
||||
EXPECT_EQ(strlen(m) - 1, ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m) - 1, ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpPost, req->method);
|
||||
EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri)));
|
||||
EXPECT_EQ(10, req->version);
|
||||
|
@ -184,7 +197,7 @@ Content-Length: 0\n\
|
|||
EXPECT_STREQ("", gc(slice(m, req->headers[kHttpEtag])));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testChromeMessage) {
|
||||
TEST(ParseHttpMessage, testChromeMessage) {
|
||||
static const char m[] = "\
|
||||
GET /tool/net/redbean.png HTTP/1.1\r\n\
|
||||
Host: 10.10.10.124:8080\r\n\
|
||||
|
@ -196,7 +209,8 @@ Referer: http://10.10.10.124:8080/\r\n\
|
|||
Accept-Encoding: gzip, deflate\r\n\
|
||||
Accept-Language: en-US,en;q=0.9\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(kHttpGet, req->method);
|
||||
EXPECT_STREQ("/tool/net/redbean.png", gc(slice(m, req->uri)));
|
||||
EXPECT_EQ(11, req->version);
|
||||
|
@ -207,35 +221,38 @@ Accept-Language: en-US,en;q=0.9\r\n\
|
|||
EXPECT_STREQ("", gc(slice(m, req->headers[kHttpExpect])));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testExtendedHeaders) {
|
||||
TEST(ParseHttpMessage, testExtendedHeaders) {
|
||||
static const char m[] = "\
|
||||
GET /foo?bar%20hi HTTP/1.0\r\n\
|
||||
X-User-Agent: hi\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
ASSERT_EQ(1, req->xheaders.n);
|
||||
EXPECT_STREQ("X-User-Agent", gc(slice(m, req->xheaders.p[0].k)));
|
||||
EXPECT_STREQ("hi", gc(slice(m, req->xheaders.p[0].v)));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testNormalHeaderOnMultipleLines_getsOverwritten) {
|
||||
TEST(ParseHttpMessage, 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)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_STREQ("text/plain", gc(slice(m, req->headers[kHttpContentType])));
|
||||
ASSERT_EQ(0, req->xheaders.n);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testCommaSeparatedOnMultipleLines_becomesLinear) {
|
||||
TEST(ParseHttpMessage, 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)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(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)));
|
||||
|
@ -249,7 +266,8 @@ 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)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_TRUE(HeaderHas(req, m, kHttpAcceptEncoding, "gzip", -1));
|
||||
EXPECT_TRUE(HeaderHas(req, m, kHttpAcceptEncoding, "deflate", -1));
|
||||
EXPECT_FALSE(HeaderHas(req, m, kHttpAcceptEncoding, "funzip", -1));
|
||||
|
@ -260,67 +278,116 @@ TEST(HeaderHas, testHeaderOnSameLIne) {
|
|||
GET / HTTP/1.1\r\n\
|
||||
Accept-Encoding: deflate, gzip, bzip2\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_TRUE(HeaderHas(req, m, kHttpAcceptEncoding, "gzip", -1));
|
||||
EXPECT_TRUE(HeaderHas(req, m, kHttpAcceptEncoding, "deflate", -1));
|
||||
EXPECT_FALSE(HeaderHas(req, m, kHttpAcceptEncoding, "funzip", -1));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testHeaderValuesWithWhitespace_getsTrimmed) {
|
||||
TEST(ParseHttpMessage, testHeaderValuesWithWhitespace_getsTrimmed) {
|
||||
static const char m[] = "\
|
||||
OPTIONS * HTTP/1.0\r\n\
|
||||
User-Agent: \t hi there \t \r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_STREQ("hi there", gc(slice(m, req->headers[kHttpUserAgent])));
|
||||
EXPECT_STREQ("*", gc(slice(m, req->uri)));
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testAbsentHost_setsSliceToZero) {
|
||||
TEST(ParseHttpMessage, testAbsentHost_setsSliceToZero) {
|
||||
static const char m[] = "\
|
||||
GET / HTTP/1.1\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(0, req->headers[kHttpHost].a);
|
||||
EXPECT_EQ(0, req->headers[kHttpHost].b);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testEmptyHost_setsSliceToNonzeroValue) {
|
||||
TEST(ParseHttpMessage, testEmptyHost_setsSliceToNonzeroValue) {
|
||||
static const char m[] = "\
|
||||
GET / HTTP/1.1\r\n\
|
||||
Host:\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_NE(0, req->headers[kHttpHost].a);
|
||||
EXPECT_EQ(req->headers[kHttpHost].a, req->headers[kHttpHost].b);
|
||||
}
|
||||
|
||||
TEST(ParseHttpRequest, testEmptyHost2_setsSliceToNonzeroValue) {
|
||||
TEST(ParseHttpMessage, testEmptyHost2_setsSliceToNonzeroValue) {
|
||||
static const char m[] = "\
|
||||
GET / HTTP/1.1\r\n\
|
||||
Host: \r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpRequest(req, m, strlen(m)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_NE(0, req->headers[kHttpHost].a);
|
||||
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"));
|
||||
TEST(ParseHttpResponse, testEmpty_tooShort) {
|
||||
InitHttpMessage(req, kHttpResponse);
|
||||
EXPECT_EQ(0, ParseHttpMessage(req, "", 0));
|
||||
}
|
||||
|
||||
TEST(ParseHttpResponse, testTooShort) {
|
||||
InitHttpMessage(req, kHttpResponse);
|
||||
EXPECT_EQ(0, ParseHttpMessage(req, "\r\n", 2));
|
||||
}
|
||||
|
||||
TEST(ParseHttpResponse, testNoHeaders) {
|
||||
static const char m[] = "HTTP/1.0 200 OK\r\n\r\n";
|
||||
InitHttpMessage(req, kHttpResponse);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(200, req->status);
|
||||
EXPECT_STREQ("OK", gc(slice(m, req->message)));
|
||||
EXPECT_EQ(10, req->version);
|
||||
}
|
||||
|
||||
TEST(ParseHttpResponse, testSomeHeaders) {
|
||||
static const char m[] = "\
|
||||
HTTP/1.0 200 OK\r\n\
|
||||
Host: foo.example\r\n\
|
||||
Content-Length: 0\r\n\
|
||||
\r\n";
|
||||
InitHttpMessage(req, kHttpResponse);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(200, req->status);
|
||||
EXPECT_STREQ("OK", gc(slice(m, req->message)));
|
||||
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])));
|
||||
}
|
||||
|
||||
TEST(ParseHttpResponse, testHttp101) {
|
||||
static const char m[] = "HTTP/1.1 300 OMG\r\n\r\n";
|
||||
InitHttpMessage(req, kHttpResponse);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(300, req->status);
|
||||
EXPECT_STREQ("OMG", gc(slice(m, req->message)));
|
||||
EXPECT_EQ(11, req->version);
|
||||
}
|
||||
|
||||
TEST(ParseHttpResponse, testHttp100) {
|
||||
static const char m[] = "HTTP/1.0 404 Not Found\r\n\r\n";
|
||||
InitHttpMessage(req, kHttpResponse);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EXPECT_EQ(404, req->status);
|
||||
EXPECT_STREQ("Not Found", gc(slice(m, req->message)));
|
||||
EXPECT_EQ(10, req->version);
|
||||
}
|
||||
|
||||
void DoTiniestHttpRequest(void) {
|
||||
static const char m[] = "\
|
||||
GET /\r\n\
|
||||
\r\n";
|
||||
InitHttpRequest(req);
|
||||
ParseHttpRequest(req, m, sizeof(m));
|
||||
DestroyHttpRequest(req);
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
ParseHttpMessage(req, m, sizeof(m));
|
||||
DestroyHttpMessage(req);
|
||||
}
|
||||
|
||||
void DoTinyHttpRequest(void) {
|
||||
|
@ -328,9 +395,9 @@ void DoTinyHttpRequest(void) {
|
|||
GET /\r\n\
|
||||
Accept-Encoding: gzip\r\n\
|
||||
\r\n";
|
||||
InitHttpRequest(req);
|
||||
ParseHttpRequest(req, m, sizeof(m));
|
||||
DestroyHttpRequest(req);
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
ParseHttpMessage(req, m, sizeof(m));
|
||||
DestroyHttpMessage(req);
|
||||
}
|
||||
|
||||
void DoStandardChromeRequest(void) {
|
||||
|
@ -345,9 +412,9 @@ Referer: http://10.10.10.124:8080/\r\n\
|
|||
Accept-Encoding: gzip, deflate\r\n\
|
||||
Accept-Language: en-US,en;q=0.9\r\n\
|
||||
\r\n";
|
||||
InitHttpRequest(req);
|
||||
CHECK_EQ(sizeof(m) - 1, ParseHttpRequest(req, m, sizeof(m)));
|
||||
DestroyHttpRequest(req);
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
CHECK_EQ(sizeof(m) - 1, ParseHttpMessage(req, m, sizeof(m)));
|
||||
DestroyHttpMessage(req);
|
||||
}
|
||||
|
||||
void DoUnstandardChromeRequest(void) {
|
||||
|
@ -362,16 +429,88 @@ X-Referer: http://10.10.10.124:8080/\r\n\
|
|||
X-Accept-Encoding: gzip, deflate\r\n\
|
||||
X-Accept-Language: en-US,en;q=0.9\r\n\
|
||||
\r\n";
|
||||
InitHttpRequest(req);
|
||||
CHECK_EQ(sizeof(m) - 1, ParseHttpRequest(req, m, sizeof(m)));
|
||||
DestroyHttpRequest(req);
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
CHECK_EQ(sizeof(m) - 1, ParseHttpMessage(req, m, sizeof(m)));
|
||||
DestroyHttpMessage(req);
|
||||
}
|
||||
|
||||
BENCH(ParseHttpRequest, bench) {
|
||||
void DoTiniestHttpResponse(void) {
|
||||
static const char m[] = "\
|
||||
HTTP/1.0 200\r\n\
|
||||
\r\n";
|
||||
InitHttpMessage(req, kHttpResponse);
|
||||
ParseHttpMessage(req, m, sizeof(m));
|
||||
DestroyHttpMessage(req);
|
||||
}
|
||||
|
||||
void DoTinyHttpResponse(void) {
|
||||
static const char m[] = "\
|
||||
HTTP/1.0 200\r\n\
|
||||
Accept-Encoding: gzip\r\n\
|
||||
\r\n";
|
||||
InitHttpMessage(req, kHttpResponse);
|
||||
ParseHttpMessage(req, m, sizeof(m));
|
||||
DestroyHttpMessage(req);
|
||||
}
|
||||
|
||||
void DoStandardHttpResponse(void) {
|
||||
static const char m[] = "\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
Server: nginx\r\n\
|
||||
Date: Sun, 27 Jun 2021 19:09:59 GMT\r\n\
|
||||
Content-Type: text/html; charset=utf-8\r\n\
|
||||
Transfer-Encoding: chunked\r\n\
|
||||
Connection: keep-alive\r\n\
|
||||
Vary: Accept-Encoding\r\n\
|
||||
Cache-Control: private; max-age=0\r\n\
|
||||
X-Frame-Options: DENY\r\n\
|
||||
X-Content-Type-Options: nosniff\r\n\
|
||||
X-XSS-Protection: 1; mode=block\r\n\
|
||||
Referrer-Policy: origin\r\n\
|
||||
Strict-Transport-Security: max-age=31556900\r\n\
|
||||
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://cdnjs.cloudflare.com/; frame-src 'self' https://www.google.com/recaptcha/; style-src 'self' 'unsafe-inline'\r\n\
|
||||
\r\n";
|
||||
InitHttpMessage(req, kHttpResponse);
|
||||
CHECK_EQ(sizeof(m) - 1, ParseHttpMessage(req, m, sizeof(m)));
|
||||
DestroyHttpMessage(req);
|
||||
}
|
||||
|
||||
void DoUnstandardHttpResponse(void) {
|
||||
static const char m[] = "\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
date: Sun, 27 Jun 2021 19:00:36 GMT\r\n\
|
||||
server: Apache\r\n\
|
||||
x-frame-options: SAMEORIGIN\r\n\
|
||||
x-xss-protection: 0\r\n\
|
||||
vary: Accept-Encoding\r\n\
|
||||
referrer-policy: no-referrer\r\n\
|
||||
x-slack-backend: r\r\n\
|
||||
strict-transport-security: max-age=31536000; includeSubDomains; preload\r\n\
|
||||
set-cookie: b=5aboacm0axrlzntx5wfec7r42; expires=Fri, 27-Jun-2031 19:00:36 GMT; Max-Age=315532800; path=/; domain=.slack.com; secure; SameSite=None\r\n\
|
||||
set-cookie: x=5aboacm0axrlzntx5wfec7r42.1624820436; expires=Sun, 27-Jun-2021 19:15:36 GMT; Max-Age=900; path=/; domain=.slack.com; secure; SameSite=None\r\n\
|
||||
content-type: text/html; charset=utf-8\r\n\
|
||||
x-envoy-upstream-service-time: 19\r\n\
|
||||
x-backend: main_normal main_canary_with_overflow main_control_with_overflow\r\n\
|
||||
x-server: slack-www-hhvm-main-iad-a9ic\r\n\
|
||||
x-via: envoy-www-iad-qd3r, haproxy-edge-pdx-klqo\r\n\
|
||||
x-slack-shared-secret-outcome: shared-secret\r\n\
|
||||
via: envoy-www-iad-qd3r\r\n\
|
||||
transfer-encoding: chunked\r\n\
|
||||
\r\n";
|
||||
InitHttpMessage(req, kHttpResponse);
|
||||
CHECK_EQ(sizeof(m) - 1, ParseHttpMessage(req, m, sizeof(m)));
|
||||
DestroyHttpMessage(req);
|
||||
}
|
||||
|
||||
BENCH(ParseHttpMessage, bench) {
|
||||
EZBENCH2("DoTiniestHttpRequest", donothing, DoTiniestHttpRequest());
|
||||
EZBENCH2("DoTinyHttpRequest", donothing, DoTinyHttpRequest());
|
||||
EZBENCH2("DoStandardChromeRequest", donothing, DoStandardChromeRequest());
|
||||
EZBENCH2("DoUnstandardChromeRequest", donothing, DoUnstandardChromeRequest());
|
||||
EZBENCH2("DoTiniestHttpResponse", donothing, DoTiniestHttpResponse());
|
||||
EZBENCH2("DoTinyHttpResponse", donothing, DoTinyHttpResponse());
|
||||
EZBENCH2("DoStandardHttpResponse", donothing, DoStandardHttpResponse());
|
||||
EZBENCH2("DoUnstandardHttpResponse", donothing, DoUnstandardHttpResponse());
|
||||
}
|
||||
|
||||
BENCH(HeaderHas, bench) {
|
||||
|
@ -384,13 +523,12 @@ 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)));
|
||||
InitHttpMessage(req, kHttpRequest);
|
||||
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m)));
|
||||
EZBENCH2("HeaderHas text/plain", donothing,
|
||||
HeaderHas(req, m, kHttpAccept, "text/plain", 7));
|
||||
EZBENCH2("HeaderHas deflate", donothing,
|
||||
HeaderHas(req, m, kHttpAcceptEncoding, "deflate", 7));
|
||||
EZBENCH2("HeaderHas gzip", donothing,
|
||||
HeaderHas(req, m, kHttpAcceptEncoding, "gzip", 4));
|
||||
EZBENCH2("IsMimeType", donothing,
|
||||
IsMimeType("text/plain; charset=utf-8", -1, "text/plain"));
|
||||
}
|
|
@ -1,175 +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/log/check.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
struct HttpMessage req[1];
|
||||
|
||||
static char *slice(const char *m, struct HttpSlice s) {
|
||||
char *p;
|
||||
p = xmalloc(s.b - s.a + 1);
|
||||
memcpy(p, m + s.a, s.b - s.a);
|
||||
p[s.b - s.a] = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
void SetUp(void) {
|
||||
InitHttpResponse(req);
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
DestroyHttpResponse(req);
|
||||
}
|
||||
|
||||
TEST(ParseHttpResponse, soLittleState) {
|
||||
ASSERT_LE(sizeof(struct HttpMessage), 512);
|
||||
}
|
||||
|
||||
TEST(ParseHttpResponse, testEmpty_tooShort) {
|
||||
EXPECT_EQ(0, ParseHttpResponse(req, "", 0));
|
||||
}
|
||||
|
||||
TEST(ParseHttpResponse, testTooShort) {
|
||||
EXPECT_EQ(0, ParseHttpResponse(req, "\r\n", 2));
|
||||
}
|
||||
|
||||
TEST(ParseHttpResponse, testNoHeaders) {
|
||||
static const char m[] = "HTTP/1.0 200 OK\r\n\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpResponse(req, m, strlen(m)));
|
||||
EXPECT_EQ(200, req->status);
|
||||
EXPECT_STREQ("OK", gc(slice(m, req->message)));
|
||||
EXPECT_EQ(10, req->version);
|
||||
}
|
||||
|
||||
TEST(ParseHttpResponse, testSomeHeaders) {
|
||||
static const char m[] = "\
|
||||
HTTP/1.0 200 OK\r\n\
|
||||
Host: foo.example\r\n\
|
||||
Content-Length: 0\r\n\
|
||||
\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpResponse(req, m, strlen(m)));
|
||||
EXPECT_EQ(200, req->status);
|
||||
EXPECT_STREQ("OK", gc(slice(m, req->message)));
|
||||
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])));
|
||||
}
|
||||
|
||||
TEST(ParseHttpResponse, testHttp101) {
|
||||
static const char m[] = "HTTP/1.1 300 OMG\r\n\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpResponse(req, m, strlen(m)));
|
||||
EXPECT_EQ(300, req->status);
|
||||
EXPECT_STREQ("OMG", gc(slice(m, req->message)));
|
||||
EXPECT_EQ(11, req->version);
|
||||
}
|
||||
|
||||
TEST(ParseHttpResponse, testHttp100) {
|
||||
static const char m[] = "HTTP/1.0 404 Not Found\r\n\r\n";
|
||||
EXPECT_EQ(strlen(m), ParseHttpResponse(req, m, strlen(m)));
|
||||
EXPECT_EQ(404, req->status);
|
||||
EXPECT_STREQ("Not Found", gc(slice(m, req->message)));
|
||||
EXPECT_EQ(10, req->version);
|
||||
}
|
||||
|
||||
void DoTiniestHttpResponse(void) {
|
||||
static const char m[] = "\
|
||||
HTTP/1.0 200\r\n\
|
||||
\r\n";
|
||||
InitHttpResponse(req);
|
||||
ParseHttpResponse(req, m, sizeof(m));
|
||||
DestroyHttpResponse(req);
|
||||
}
|
||||
|
||||
void DoTinyHttpResponse(void) {
|
||||
static const char m[] = "\
|
||||
HTTP/1.0 200\r\n\
|
||||
Accept-Encoding: gzip\r\n\
|
||||
\r\n";
|
||||
InitHttpResponse(req);
|
||||
ParseHttpResponse(req, m, sizeof(m));
|
||||
DestroyHttpResponse(req);
|
||||
}
|
||||
|
||||
void DoStandardChromeResponse(void) {
|
||||
static const char m[] = "\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
Host: 10.10.10.124:8080\r\n\
|
||||
Connection: keep-alive\r\n\
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36\r\n\
|
||||
DNT: \t1 \r\n\
|
||||
Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8\r\n\
|
||||
Referer: http://10.10.10.124:8080/\r\n\
|
||||
Accept-Encoding: gzip, deflate\r\n\
|
||||
Accept-Language: en-US,en;q=0.9\r\n\
|
||||
\r\n";
|
||||
InitHttpResponse(req);
|
||||
CHECK_EQ(sizeof(m) - 1, ParseHttpResponse(req, m, sizeof(m)));
|
||||
DestroyHttpResponse(req);
|
||||
}
|
||||
|
||||
void DoUnstandardChromeResponse(void) {
|
||||
static const char m[] = "\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
X-Host: 10.10.10.124:8080\r\n\
|
||||
X-Connection: keep-alive\r\n\
|
||||
X-User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36\r\n\
|
||||
X-DNT: \t1 \r\n\
|
||||
X-Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8\r\n\
|
||||
X-Referer: http://10.10.10.124:8080/\r\n\
|
||||
X-Accept-Encoding: gzip, deflate\r\n\
|
||||
X-Accept-Language: en-US,en;q=0.9\r\n\
|
||||
\r\n";
|
||||
InitHttpResponse(req);
|
||||
CHECK_EQ(sizeof(m) - 1, ParseHttpResponse(req, m, sizeof(m)));
|
||||
DestroyHttpResponse(req);
|
||||
}
|
||||
|
||||
BENCH(ParseHttpResponse, bench) {
|
||||
EZBENCH2("DoTiniestHttpResponse", donothing, DoTiniestHttpResponse());
|
||||
EZBENCH2("DoTinyHttpResponse", donothing, DoTinyHttpResponse());
|
||||
EZBENCH2("DoStandardChromeResponse", donothing, DoStandardChromeResponse());
|
||||
EZBENCH2("DoUnstandardChromeResponse", donothing,
|
||||
DoUnstandardChromeResponse());
|
||||
}
|
||||
|
||||
BENCH(HeaderHas, bench) {
|
||||
static const char m[] = "\
|
||||
HTTP/1.1 200 OK\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), ParseHttpResponse(req, m, strlen(m)));
|
||||
EZBENCH2("HeaderHas text/plain", donothing,
|
||||
HeaderHas(req, m, kHttpAccept, "text/plain", 7));
|
||||
EZBENCH2("HeaderHas deflate", donothing,
|
||||
HeaderHas(req, m, kHttpAcceptEncoding, "deflate", 7));
|
||||
EZBENCH2("HeaderHas gzip", donothing,
|
||||
HeaderHas(req, m, kHttpAcceptEncoding, "gzip", 4));
|
||||
EZBENCH2("IsMimeType", donothing,
|
||||
IsMimeType("text/plain; charset=utf-8", -1, "text/plain"));
|
||||
}
|
|
@ -21,12 +21,17 @@ TEST_NET_HTTP_CHECKS = \
|
|||
|
||||
TEST_NET_HTTP_DIRECTDEPS = \
|
||||
NET_HTTP \
|
||||
LIBC_LOG \
|
||||
LIBC_TESTLIB \
|
||||
THIRD_PARTY_MBEDTLS
|
||||
|
||||
TEST_NET_HTTP_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TEST_NET_HTTP_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/test/net/http/joyent_test.o: \
|
||||
OVERRIDE_CPPFLAGS += \
|
||||
-DSTACK_FRAME_UNLIMITED
|
||||
|
||||
o/$(MODE)/test/net/http/http.pkg: \
|
||||
$(TEST_NET_HTTP_OBJS) \
|
||||
$(foreach x,$(TEST_NET_HTTP_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
|
|
@ -24,11 +24,14 @@
|
|||
#include "net/http/escape.h"
|
||||
|
||||
TEST(VisualizeControlCodes, test) {
|
||||
size_t n;
|
||||
EXPECT_STREQ("hello", gc(VisualizeControlCodes("hello", -1, 0)));
|
||||
EXPECT_STREQ("hello\r\n", gc(VisualizeControlCodes("hello\r\n", -1, 0)));
|
||||
EXPECT_STREQ("hello␁␂␡", gc(VisualizeControlCodes("hello\1\2\177", -1, 0)));
|
||||
EXPECT_STREQ("hello\\u0085",
|
||||
gc(VisualizeControlCodes("hello\302\205", -1, 0)));
|
||||
EXPECT_STREQ("hi", gc(VisualizeControlCodes("hi", -1, &n)));
|
||||
EXPECT_EQ(2, n);
|
||||
}
|
||||
|
||||
TEST(VisualizeControlCodes, testOom_returnsNullAndSetsSizeToZero) {
|
||||
|
|
|
@ -76,6 +76,7 @@ void lookup(const char *name) {
|
|||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
showcrashreports();
|
||||
for (i = 1; i < argc; ++i) lookup(argv[i]);
|
||||
lookup("time-a.timefreq.bldrdoc.gov");
|
||||
/* for (i = 1; i < argc; ++i) lookup(argv[i]); */
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ TOOL_NET_BINS = \
|
|||
$(TOOL_NET_COMS:%=%.dbg)
|
||||
|
||||
TOOL_NET_COMS = \
|
||||
o/$(MODE)/tool/net/dig.com \
|
||||
o/$(MODE)/tool/net/echoserver.com \
|
||||
o/$(MODE)/tool/net/redbean.com \
|
||||
o/$(MODE)/tool/net/redbean-demo.com \
|
||||
o/$(MODE)/tool/net/redbean-static.com \
|
||||
|
@ -127,10 +129,10 @@ o/$(MODE)/tool/net/redbean-demo.com: \
|
|||
tool/net/demo/seekable.txt \
|
||||
tool/net/demo/virtualbean.html \
|
||||
tool/net/redbean.c \
|
||||
net/http/parsehttprequest.c \
|
||||
net/http/parsehttpmessage.c \
|
||||
net/http/parseurl.c \
|
||||
net/http/encodeurl.c \
|
||||
test/net/http/parsehttprequest_test.c \
|
||||
test/net/http/parsehttpmessage_test.c \
|
||||
test/net/http/parseurl_test.c
|
||||
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
|
||||
@$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/.redbean-demo
|
||||
|
@ -143,7 +145,7 @@ o/$(MODE)/tool/net/redbean-demo.com: \
|
|||
@echo "<-- check out this lua server page" | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -cqj $@ tool/net/demo/redbean.lua
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -qj $@ tool/net/demo/404.html tool/net/favicon.ico tool/net/redbean.png tool/net/demo/redbean-form.lua tool/net/demo/redbean-xhr.lua
|
||||
@echo Uncompressed for HTTP Range requests | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -cqj0 $@ tool/net/demo/seekable.txt
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -q $@ tool/net/ tool/net/demo/ tool/net/demo/index.html tool/net/demo/redbean.css tool/net/redbean.c net/http/parsehttprequest.c net/http/parseurl.c net/http/encodeurl.c test/net/http/parsehttprequest_test.c test/net/http/parseurl_test.c
|
||||
@$(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -q $@ tool/net/ tool/net/demo/ tool/net/demo/index.html tool/net/demo/redbean.css tool/net/redbean.c net/http/parsehttpmessage.c net/http/parseurl.c net/http/encodeurl.c test/net/http/parsehttpmessage_test.c test/net/http/parseurl_test.c
|
||||
@printf "<p>This is a live instance of <a href=https://justine.lol/redbean/>redbean</a>: a tiny multiplatform webserver that <a href=https://news.ycombinator.com/item?id=26271117>went viral</a> on hacker news a few months ago.\r\nSince then, we've added Lua dynamic serving, which also goes as fast as 1,000,000 requests per second on a core i9 (rather than a cheap virtual machine like this)\nin addition to SQLite and SSL. The text you're reading now is a PKZIP End Of Central Directory comment.\r\n<p>redbean aims to be production worthy across six operating systems, using a single executable file (this demo is hosted on FreeBSD 13). redbean has been enhanced to restore the APE header after startup.\r\nIt automatically generates this listing page based on your zip contents. If you use redbean as an application server / web development environment,\r\nthen you'll find other new and useful features like function call logging so you can get that sweet sweet microsecond scale latency." | $(COMPILE) -AZIP -T$@ o/$(MODE)/host/third_party/infozip/zip.com -z $@
|
||||
@$(COMPILE) -AMKDIR -T$@ mkdir -p o/$(MODE)/tool/net/virtualbean.justine.lol/
|
||||
@$(COMPILE) -ACP -T$@ cp tool/net/redbean.png o/$(MODE)/tool/net/virtualbean.justine.lol/redbean.png
|
||||
|
|
|
@ -552,7 +552,7 @@ static void UnmapLater(int f, void *p, size_t n) {
|
|||
}
|
||||
|
||||
static void CollectGarbage(void) {
|
||||
DestroyHttpRequest(&msg);
|
||||
DestroyHttpMessage(&msg);
|
||||
while (freelist.n) {
|
||||
free(freelist.p[--freelist.n]);
|
||||
}
|
||||
|
@ -3058,8 +3058,8 @@ static void GetDosLocalTime(int64_t utcunixts, uint16_t *out_time,
|
|||
static bool IsUtf8(const void *data, size_t size) {
|
||||
const unsigned char *p, *pe;
|
||||
for (p = data, pe = p + size; p + 2 <= pe; ++p) {
|
||||
if (*p >= 0300) {
|
||||
if (*p >= 0200 && *p < 0300) {
|
||||
if (p[0] >= 0300) {
|
||||
if (p[1] >= 0200 && p[1] < 0300) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -5236,7 +5236,7 @@ static bool HandleMessage(void) {
|
|||
struct iovec iov[4];
|
||||
long actualcontentlength;
|
||||
g_syscount = 0;
|
||||
if ((rc = ParseHttpRequest(&msg, inbuf.p, amtread)) != -1) {
|
||||
if ((rc = ParseHttpMessage(&msg, inbuf.p, amtread)) != -1) {
|
||||
if (!rc) return false;
|
||||
hdrsize = rc;
|
||||
if (logmessages) LogMessage("received", inbuf.p, hdrsize);
|
||||
|
@ -5317,7 +5317,7 @@ static void InitRequest(void) {
|
|||
outbuf.n = 0;
|
||||
luaheaderp = 0;
|
||||
contentlength = 0;
|
||||
InitHttpRequest(&msg);
|
||||
InitHttpMessage(&msg, kHttpRequest);
|
||||
}
|
||||
|
||||
static void HandleMessages(void) {
|
||||
|
|
Loading…
Reference in a new issue