Add /statusz page to redbean plus other enhancements

redbean improvements:

- Explicitly disable corking
- Simulate Python regex API for Lua
- Send warmup requests in main process on startup
- Add Class-A granular IPv4 network classification
- Add /statusz page so you can monitor your redbean's health
- Fix regressions on OpenBSD/NetBSD caused by recent changes
- Plug Authorization header into Lua GetUser and GetPass APIs
- Recognize X-Forwarded-{For,Host} from local reverse proxies
- Add many additional functions to redbean Lua server page API
- Report resource usage of child processes on `/` listing page
- Introduce `-a` flag for logging child process resource usage
- Introduce `-t MILLIS` flag and `ProgramTimeout(ms)` init API
- Introduce `-H "Header: value"` flag and `ProgramHeader(k,v)` API

Cosmopolitan Libc improvements:

- Make strerror() simpler
- Make inet_pton() not depend on sscanf()
- Fix OpenExecutable() which broke .data section earlier
- Fix stdio in cases where it overflows kernel tty buffer
- Fix bugs in crash reporting w/o .com.dbg binary present
- Add polyfills for SO_LINGER, SO_RCVTIMEO, and SO_SNDTIMEO
- Polyfill TCP_CORK on BSD and XNU using TCP_NOPUSH magnums

New netcat clone in examples/nc.c:

While testing some of the failure conditions for redbean, I noticed that
BusyBox's `nc` command is pretty busted, if you use it as an interactive
tool, rather than having it be part of a pipeline. Unfortunately this'll
only work on UNIX since Windows doesn't let us poll on stdio and sockets
at the same time because I don't think they want tools like this running
on their platform. So if you want forbidden fruit, it's here so enjoy it
This commit is contained in:
Justine Tunney 2021-04-23 10:45:19 -07:00
parent 4effa23528
commit b107d2709f
163 changed files with 4425 additions and 2104 deletions

View file

@ -1,11 +0,0 @@
#ifndef COSMOPOLITAN_NET_HTTP_BASE64_H_
#define COSMOPOLITAN_NET_HTTP_BASE64_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
char *EncodeBase64(const void *, size_t, size_t *);
void *DecodeBase64(const char *, size_t, size_t *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_NET_HTTP_BASE64_H_ */

50
net/http/categorizeip.c Normal file
View file

@ -0,0 +1,50 @@
/*-*- 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 "net/http/ip.h"
/**
* Classifies IP address.
*
* @return integer e.g. kIpLoopback, kIpPrivate, etc.
* @see GetIpCategoryName()
*/
int CategorizeIp(uint32_t x) {
int a;
if (IsAnonymousIp(x)) return kIpAnonymous;
if (IsMulticastIp(x)) return kIpMulticast;
if (IsLoopbackIp(x)) return kIpLoopback;
if (IsPrivateIp(x)) return kIpPrivate;
if (IsTestnetIp(x)) return kIpTestnet;
if (IsAfrinicIp(x)) return kIpAfrinic;
if (IsLacnicIp(x)) return kIpLacnic;
if (IsApnicIp(x)) return kIpApnic;
if (IsArinIp(x)) return kIpArin;
if (IsRipeIp(x)) return kIpRipe;
if (IsDodIp(x)) return kIpDod;
a = (x & 0xff000000) >> 24;
if (a == 12) return kIpAtt;
if (a == 17) return kIpApple;
if (a == 19) return kIpFord;
if (a == 38) return kIpCogent;
if (a == 48) return kIpPrudential;
if (a == 56) return kIpUsps;
if (a == 73) return kIpComcast;
if (a >= 240) return kIpFuture;
return kIpUnknown;
}

View file

@ -18,7 +18,7 @@
*/
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "net/http/base64.h"
#include "net/http/escape.h"
static const signed char kBase64[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00
@ -47,7 +47,7 @@ static const signed char kBase64[256] = {
* @param out_size if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
void *DecodeBase64(const char *data, size_t size, size_t *out_size) {
char *DecodeBase64(const char *data, size_t size, size_t *out_size) {
size_t n;
char *r, *q;
int a, b, c, d, w;

View file

@ -20,28 +20,35 @@
#include "libc/intrin/pmovmskb.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "net/http/http.h"
#include "net/http/escape.h"
/**
* Decodes ISO-8859-1 to UTF-8.
*
* @param data is input value
* @param size if -1 implies strlen
* @param out_size if non-NULL receives output length
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
char *DecodeLatin1(const char *data, size_t size, size_t *out_size) {
char *DecodeLatin1(const char *p, size_t n, size_t *z) {
int c;
size_t n;
size_t i;
char *r, *q;
const char *p, *e;
if (size == -1) size = data ? strlen(data) : 0;
if ((r = malloc(size * 2 + 1))) {
q = r;
p = data;
e = p + size;
while (p < e) {
c = *p++ & 0xff;
int8_t v1[16], v2[16], vz[16];
if (z) *z = 0;
if (n == -1) n = p ? strlen(p) : 0;
if ((q = r = malloc(n * 2 + 1))) {
for (i = 0; i < n;) {
memset(vz, 0, 16); /* 3x speedup for ASCII */
while (i + 16 < n) {
memcpy(v1, p + i, 16);
pcmpgtb(v2, v1, vz);
if (pmovmskb((void *)v2) != 0xFFFF) break;
memcpy(q, v1, 16);
q += 16;
i += 16;
}
c = p[i++] & 0xff;
if (c < 0200) {
*q++ = c;
} else {
@ -49,14 +56,9 @@ char *DecodeLatin1(const char *data, size_t size, size_t *out_size) {
*q++ = 0200 | c & 077;
}
}
n = q - r;
if (z) *z = q - r;
*q++ = '\0';
if ((q = realloc(r, n + 1))) r = q;
} else {
n = 0;
}
if (out_size) {
*out_size = n;
if ((q = realloc(r, q - r))) r = q;
}
return r;
}

View file

@ -18,7 +18,7 @@
*/
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "net/http/base64.h"
#include "net/http/escape.h"
#define CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
@ -30,7 +30,7 @@
* @param out_size if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
char *EncodeBase64(const void *data, size_t size, size_t *out_size) {
char *EncodeBase64(const char *data, size_t size, size_t *out_size) {
size_t n;
unsigned w;
char *r, *q;
@ -39,7 +39,7 @@ char *EncodeBase64(const void *data, size_t size, size_t *out_size) {
if ((n = size) % 3) n += 3 - size % 3;
n /= 3, n *= 4;
if ((r = malloc(n + 1))) {
for (q = r, p = data, pe = p + size; p < pe; p += 3) {
for (q = r, p = (void *)data, pe = p + size; p < pe; p += 3) {
w = p[0] << 020;
if (p + 1 < pe) w |= p[1] << 010;
if (p + 2 < pe) w |= p[2] << 000;

View file

@ -20,7 +20,7 @@
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/str/thompike.h"
#include "net/http/http.h"
#include "net/http/escape.h"
/**
* Encodes HTTP header value.

72
net/http/encodelatin1.c Normal file
View file

@ -0,0 +1,72 @@
/*-*- 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/errno.h"
#include "libc/intrin/pcmpgtb.h"
#include "libc/intrin/pmovmskb.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "net/http/escape.h"
/**
* Encodes UTF-8 to ISO-8859-1.
*
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @param f can kControlC0, kControlC1 to forbid
* @return allocated NUL-terminated buffer, or NULL w/ errno
* @error EILSEQ means UTF-8 found we can't or won't re-encode
* @error ENOMEM means malloc() failed
*/
char *EncodeLatin1(const char *p, size_t n, size_t *z, int f) {
int c;
size_t i;
char *r, *q;
if (z) *z = 0;
if (n == -1) n = p ? strlen(p) : 0;
if ((q = r = malloc(n + 1))) {
for (i = 0; i < n;) {
c = p[i++] & 0xff;
if (c >= 0300) {
if ((c <= 0303) && i < n && (p[i] & 0300) == 0200) {
c = (c & 037) << 6 | p[i++] & 077;
} else {
goto Invalid;
}
}
if (((f & kControlC1) && 0x80 <= c && c < 0xA0) ||
((f & kControlC0) && (c < 32 || c == 0x7F) &&
!(c == '\t' || c == '\r' || c == '\n' || c == '\v')) ||
((f & kControlWs) &&
(c == '\t' || c == '\r' || c == '\n' || c == '\v'))) {
goto Invalid;
}
*q++ = c;
}
if (z) *z = q - r;
*q++ = '\0';
if ((q = realloc(r, q - r))) r = q;
}
return r;
Invalid:
free(r);
errno = EILSEQ;
return NULL;
}

View file

@ -1,13 +1,13 @@
#ifndef COSMOPOLITAN_NET_HTTP_ESCAPE_H_
#define COSMOPOLITAN_NET_HTTP_ESCAPE_H_
#define kControlWs 1
#define kControlC0 2
#define kControlC1 4
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct EscapeResult {
char *data;
size_t size;
};
extern const signed char kHexToInt[256];
extern const char kEscapeAuthority[256];
extern const char kEscapeIp[256];
@ -16,17 +16,27 @@ extern const char kEscapeSegment[256];
extern const char kEscapeParam[256];
extern const char kEscapeFragment[256];
struct EscapeResult EscapeHtml(const char *, size_t);
struct EscapeResult EscapeUrl(const char *, size_t, const char[hasatleast 256]);
struct EscapeResult EscapeUser(const char *, size_t);
struct EscapeResult EscapePass(const char *, size_t);
struct EscapeResult EscapeIp(const char *, size_t);
struct EscapeResult EscapeHost(const char *, size_t);
struct EscapeResult EscapePath(const char *, size_t);
struct EscapeResult EscapeParam(const char *, size_t);
struct EscapeResult EscapeFragment(const char *, size_t);
struct EscapeResult EscapeSegment(const char *, size_t);
struct EscapeResult EscapeJsStringLiteral(const char *, size_t);
char *EscapeHtml(const char *, size_t, size_t *);
char *EscapeUrl(const char *, size_t, size_t *, const char[256]);
char *EscapeUser(const char *, size_t, size_t *);
char *EscapePass(const char *, size_t, size_t *);
char *EscapeIp(const char *, size_t, size_t *);
char *EscapeHost(const char *, size_t, size_t *);
char *EscapePath(const char *, size_t, size_t *);
char *EscapeParam(const char *, size_t, size_t *);
char *EscapeFragment(const char *, size_t, size_t *);
char *EscapeSegment(const char *, size_t, size_t *);
char *EscapeJsStringLiteral(const char *, size_t, size_t *);
bool HasControlCodes(const char *, size_t, int);
char *Underlong(const char *, size_t, size_t *);
char *DecodeLatin1(const char *, size_t, size_t *);
char *EncodeLatin1(const char *, size_t, size_t *, int);
char *EncodeHttpHeaderValue(const char *, size_t, size_t *);
char *VisualizeControlCodes(const char *, size_t, size_t *);
char *IndentLines(const char *, size_t, size_t *, size_t);
char *EncodeBase64(const char *, size_t, size_t *);
char *DecodeBase64(const char *, size_t, size_t *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -21,8 +21,11 @@
/**
* Escapes URL fragment.
*
* @param size if -1 implies strlen
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
struct EscapeResult EscapeFragment(const char *data, size_t size) {
return EscapeUrl(data, size, kEscapeFragment);
char *EscapeFragment(const char *p, size_t n, size_t *z) {
return EscapeUrl(p, n, z, kEscapeFragment);
}

View file

@ -21,8 +21,11 @@
/**
* Escapes URL host or registry name.
*
* @param size if -1 implies strlen
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
struct EscapeResult EscapeHost(const char *data, size_t size) {
return EscapeUrl(data, size, kEscapeAuthority);
char *EscapeHost(const char *p, size_t n, size_t *z) {
return EscapeUrl(p, n, z, kEscapeAuthority);
}

View file

@ -23,63 +23,67 @@
/**
* Escapes HTML entities.
*
* @param size if -1 implies strlen
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
struct EscapeResult EscapeHtml(const char *data, size_t size) {
char *EscapeHtml(const char *p, size_t n, size_t *z) {
int c;
char *p;
size_t i;
struct EscapeResult r;
if (size == -1) size = data ? strlen(data) : 0;
p = r.data = xmalloc(size * 6 + 1);
for (i = 0; i < size; ++i) {
switch ((c = data[i])) {
case '&':
p[0] = '&';
p[1] = 'a';
p[2] = 'm';
p[3] = 'p';
p[4] = ';';
p += 5;
break;
case '<':
p[0] = '&';
p[1] = 'l';
p[2] = 't';
p[3] = ';';
p += 4;
break;
case '>':
p[0] = '&';
p[1] = 'g';
p[2] = 't';
p[3] = ';';
p += 4;
break;
case '"':
p[0] = '&';
p[1] = 'q';
p[2] = 'u';
p[3] = 'o';
p[4] = 't';
p[5] = ';';
p += 6;
break;
case '\'':
p[0] = '&';
p[1] = '#';
p[2] = '3';
p[3] = '9';
p[4] = ';';
p += 5;
break;
default:
*p++ = c;
break;
char *q, *r;
if (z) *z = 0;
if (n == -1) n = p ? strlen(p) : 0;
if ((q = r = malloc(n * 6 + 1))) {
for (i = 0; i < n; ++i) {
switch ((c = p[i])) {
case '&':
q[0] = '&';
q[1] = 'a';
q[2] = 'm';
q[3] = 'p';
q[4] = ';';
q += 5;
break;
case '<':
q[0] = '&';
q[1] = 'l';
q[2] = 't';
q[3] = ';';
q += 4;
break;
case '>':
q[0] = '&';
q[1] = 'g';
q[2] = 't';
q[3] = ';';
q += 4;
break;
case '"':
q[0] = '&';
q[1] = 'q';
q[2] = 'u';
q[3] = 'o';
q[4] = 't';
q[5] = ';';
q += 6;
break;
case '\'':
q[0] = '&';
q[1] = '#';
q[2] = '3';
q[3] = '9';
q[4] = ';';
q += 5;
break;
default:
*q++ = c;
break;
}
}
if (z) *z = q - r;
*q++ = '\0';
if ((q = realloc(r, q - r))) r = q;
}
r.size = p - r.data;
r.data = xrealloc(r.data, r.size + 1);
r.data[r.size] = '\0';
return r;
}

View file

@ -23,8 +23,11 @@
*
* This is the same as EscapeHost except colon is permitted.
*
* @param size if -1 implies strlen
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
struct EscapeResult EscapeIp(const char *data, size_t size) {
return EscapeUrl(data, size, kEscapeAuthority);
char *EscapeIp(const char *p, size_t n, size_t *z) {
return EscapeUrl(p, n, z, kEscapeAuthority);
}

View file

@ -31,186 +31,192 @@
* can't be encoded will use invalid codepoint markers. This function is
* agnostic to numbers that have been used with malicious intent in the
* past under buggy software. Noncanonical encodings such as overlong
* NUL are canonicalized as NUL.
* NUL are canonicalized as NUL. Therefore it isn't necessary to say
* EscapeJsStringLiteral(Underlong(𝑥)) since EscapeJsStringLiteral(𝑥)
* will do the same thing.
*
* @param p is input value
* @param n if -1 implies strlen
* @param out_size if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
struct EscapeResult EscapeJsStringLiteral(const char *data, size_t size) {
char *p;
char *EscapeJsStringLiteral(const char *p, size_t n, size_t *z) {
uint64_t w;
unsigned i, n;
char *q, *r;
size_t i, j, m;
wint_t x, a, b;
const char *d, *e;
struct EscapeResult r;
d = data;
e = data + size;
p = r.data = xmalloc(size * 6 + 6 + 1);
while (d < e) {
x = *d++ & 0xff;
if (x >= 0300) {
a = ThomPikeByte(x);
n = ThomPikeLen(x) - 1;
if (d + n <= e) {
for (i = 0;;) {
b = d[i] & 0xff;
if (!ThomPikeCont(b)) break;
a = ThomPikeMerge(a, b);
if (++i == n) {
x = a;
d += i;
break;
if (z) *z = 0;
if (n == -1) n = p ? strlen(p) : 0;
if ((q = r = malloc(n * 6 + 6 + 1))) {
for (i = 0; i < n;) {
x = p[i++] & 0xff;
if (x >= 0300) {
a = ThomPikeByte(x);
m = ThomPikeLen(x) - 1;
if (i + m <= n) {
for (j = 0;;) {
b = p[i + j] & 0xff;
if (!ThomPikeCont(b)) break;
a = ThomPikeMerge(a, b);
if (++j == m) {
x = a;
i += j;
break;
}
}
}
}
switch (x) {
case ' ':
case '!':
case '#':
case '$':
case '%':
case '(':
case ')':
case '*':
case '+':
case ',':
case '-':
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case ':':
case ';':
case '?':
case '@':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '[':
case ']':
case '^':
case '_':
case '`':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
case '{':
case '|':
case '}':
case '~':
*q++ = x;
break;
case '\t':
q[0] = '\\';
q[1] = 't';
q += 2;
break;
case '\n':
q[0] = '\\';
q[1] = 'n';
q += 2;
break;
case '\r':
q[0] = '\\';
q[1] = 'r';
q += 2;
break;
case '\f':
q[0] = '\\';
q[1] = 'f';
q += 2;
break;
case '\\':
q[0] = '\\';
q[1] = '\\';
q += 2;
break;
case '/':
q[0] = '\\';
q[1] = '/';
q += 2;
break;
case '"':
q[0] = '\\';
q[1] = '"';
q += 2;
break;
case '\'':
q[0] = '\\';
q[1] = '\'';
q += 2;
break;
case '<':
case '>':
case '&':
case '=':
default:
w = EncodeUtf16(x);
do {
q[0] = '\\';
q[1] = 'u';
q[2] = "0123456789abcdef"[(w & 0xF000) >> 014];
q[3] = "0123456789abcdef"[(w & 0x0F00) >> 010];
q[4] = "0123456789abcdef"[(w & 0x00F0) >> 004];
q[5] = "0123456789abcdef"[(w & 0x000F) >> 000];
q += 6;
} while ((w >>= 16));
break;
}
}
switch (x) {
case ' ':
case '!':
case '#':
case '$':
case '%':
case '(':
case ')':
case '*':
case '+':
case ',':
case '-':
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case ':':
case ';':
case '?':
case '@':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '[':
case ']':
case '^':
case '_':
case '`':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
case '{':
case '|':
case '}':
case '~':
*p++ = x;
break;
case '\t':
p[0] = '\\';
p[1] = 't';
p += 2;
break;
case '\n':
p[0] = '\\';
p[1] = 'n';
p += 2;
break;
case '\r':
p[0] = '\\';
p[1] = 'r';
p += 2;
break;
case '\f':
p[0] = '\\';
p[1] = 'f';
p += 2;
break;
case '\\':
p[0] = '\\';
p[1] = '\\';
p += 2;
break;
case '/':
p[0] = '\\';
p[1] = '/';
p += 2;
break;
case '"':
p[0] = '\\';
p[1] = '"';
p += 2;
break;
case '\'':
p[0] = '\\';
p[1] = '\'';
p += 2;
break;
case '<':
case '>':
case '&':
case '=':
default:
w = EncodeUtf16(x);
do {
p[0] = '\\';
p[1] = 'u';
p[2] = "0123456789abcdef"[(w & 0xF000) >> 014];
p[3] = "0123456789abcdef"[(w & 0x0F00) >> 010];
p[4] = "0123456789abcdef"[(w & 0x00F0) >> 004];
p[5] = "0123456789abcdef"[(w & 0x000F) >> 000];
p += 6;
} while ((w >>= 16));
break;
}
if (z) *z = q - r;
*q++ = '\0';
if ((q = realloc(r, q - r))) r = q;
}
r.size = p - r.data;
r.data = xrealloc(r.data, r.size + 1);
r.data[r.size] = '\0';
return r;
}

View file

@ -21,8 +21,11 @@
/**
* Escapes query/form name/parameter.
*
* @param size if -1 implies strlen
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
struct EscapeResult EscapeParam(const char *data, size_t size) {
return EscapeUrl(data, size, kEscapeParam);
char *EscapeParam(const char *p, size_t n, size_t *z) {
return EscapeUrl(p, n, z, kEscapeParam);
}

View file

@ -21,8 +21,11 @@
/**
* Escapes URL password.
*
* @param size if -1 implies strlen
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
struct EscapeResult EscapePass(const char *data, size_t size) {
return EscapeUrl(data, size, kEscapeAuthority);
char *EscapePass(const char *p, size_t n, size_t *z) {
return EscapeUrl(p, n, z, kEscapeAuthority);
}

View file

@ -23,8 +23,11 @@
*
* This is the same as EscapePathSegment() except slash is allowed.
*
* @param size if -1 implies strlen
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
struct EscapeResult EscapePath(const char *data, size_t size) {
return EscapeUrl(data, size, kEscapePath);
char *EscapePath(const char *p, size_t n, size_t *z) {
return EscapeUrl(p, n, z, kEscapePath);
}

View file

@ -24,8 +24,11 @@
* Please note this will URI encode the slash character. That's because
* segments are the labels between the slashes in a path.
*
* @param size if -1 implies strlen
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
struct EscapeResult EscapeSegment(const char *data, size_t size) {
return EscapeUrl(data, size, kEscapeSegment);
char *EscapeSegment(const char *p, size_t n, size_t *z) {
return EscapeUrl(p, n, z, kEscapeSegment);
}

View file

@ -26,7 +26,10 @@
* This function is agnostic to the underlying charset.
* Always using UTF-8 is a good idea.
*
* @param size if -1 implies strlen
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
* @see kEscapeAuthority
* @see kEscapeIpLiteral
* @see kEscapePath
@ -34,16 +37,17 @@
* @see kEscapeParam
* @see kEscapeFragment
*/
struct EscapeResult EscapeUrl(const char *data, size_t size,
const char xlat[hasatleast 256]) {
char *EscapeUrl(const char *p, size_t n, size_t *z, const char T[256]) {
char *r, *q;
struct UrlView v;
struct EscapeResult r;
if (size == -1) size = data ? strlen(data) : 0;
v.p = data;
v.n = size;
r.data = xmalloc(size * 6 + 1);
r.size = EscapeUrlView(r.data, &v, xlat) - r.data;
r.data = xrealloc(r.data, r.size + 1);
r.data[r.size] = '\0';
if (n == -1) n = p ? strlen(p) : 0;
if (z) *z = 0;
if ((q = r = malloc(n * 6 + 1))) {
v.p = p, v.n = n;
q = EscapeUrlView(r, &v, T);
if (z) *z = q - r;
*q++ = '\0';
if ((q = realloc(r, q - r))) r = q;
}
return r;
}

View file

@ -21,8 +21,11 @@
/**
* Escapes URL user name.
*
* @param size if -1 implies strlen
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
struct EscapeResult EscapeUser(const char *data, size_t size) {
return EscapeUrl(data, size, kEscapeAuthority);
char *EscapeUser(const char *p, size_t n, size_t *z) {
return EscapeUrl(p, n, z, kEscapeAuthority);
}

View file

@ -9,63 +9,70 @@
%readonly-tables
%struct-type
%define lookup-function-name LookupHttpHeader
struct HttpHeaderSlot { char *name; char code; };
struct thatispacked HttpHeaderSlot { char *name; char code; };
%%
Accept, kHttpAccept
Accept-Charset, kHttpAcceptCharset
Accept-Encoding, kHttpAcceptEncoding
Accept-Language, kHttpAcceptLanguage
Age, kHttpAge
Allow, kHttpAllow
Authorization, kHttpAuthorization
Cache-Control, kHttpCacheControl
Chunked, kHttpChunked
Link, kHttpLink
Connection, kHttpConnection
Content-Base, kHttpContentBase
Content-Encoding, kHttpContentEncoding
Content-Language, kHttpContentLanguage
Content-Length, kHttpContentLength
Content-Location, kHttpContentLocation
Content-MD5, kHttpContentMd5
Content-Range, kHttpContentRange
Content-Type, kHttpContentType
Date, kHttpDate
ETag, kHttpEtag
Expires, kHttpExpires
From, kHttpFrom
Host, kHttpHost
If-Match, kHttpIfMatch
If-Modified-Since, kHttpIfModifiedSince
If-None-Match, kHttpIfNoneMatch
If-Range, kHttpIfRange
If-Unmodified-Since, kHttpIfUnmodifiedSince
Keep-Alive, kHttpKeepAlive
Max-Forwards, kHttpMaxForwards
Pragma, kHttpPragma
Proxy-Authenticate, kHttpProxyAuthenticate
Proxy-Authorization, kHttpProxyAuthorization
Proxy-Connection, kHttpProxyConnection
Range, kHttpRange
Referer, kHttpReferer
Transfer-Encoding, kHttpTransferEncoding
Upgrade, kHttpUpgrade
User-Agent, kHttpUserAgent
Via, kHttpVia
Location, kHttpLocation
Public, kHttpPublic
Retry-After, kHttpRetryAfter
Server, kHttpServer
Vary, kHttpVary
Warning, kHttpWarning
WWW-Authenticate, kHttpWwwAuthenticate
Last-Modified, kHttpLastModified
Trailer, kHttpTrailer
TE, kHttpTe
DNT, kHttpDnt
Expect, kHttpExpect
Content-Disposition, kHttpContentDisposition
Content-Description, kHttpContentDescription
Origin, kHttpOrigin
Upgrade-Insecure-Requests, kHttpUpgradeInsecureRequests
URI, kHttpUri
Accept, kHttpAccept
Accept-Charset, kHttpAcceptCharset
Accept-Encoding, kHttpAcceptEncoding
Accept-Language, kHttpAcceptLanguage
Age, kHttpAge
Allow, kHttpAllow
Authorization, kHttpAuthorization
Cache-Control, kHttpCacheControl
Chunked, kHttpChunked
Link, kHttpLink
Connection, kHttpConnection
Content-Base, kHttpContentBase
Content-Encoding, kHttpContentEncoding
Content-Language, kHttpContentLanguage
Content-Length, kHttpContentLength
Content-Location, kHttpContentLocation
Content-MD5, kHttpContentMd5
Content-Range, kHttpContentRange
Content-Type, kHttpContentType
Date, kHttpDate
ETag, kHttpEtag
Expires, kHttpExpires
From, kHttpFrom
Host, kHttpHost
If-Match, kHttpIfMatch
If-Modified-Since, kHttpIfModifiedSince
If-None-Match, kHttpIfNoneMatch
If-Range, kHttpIfRange
If-Unmodified-Since, kHttpIfUnmodifiedSince
Keep-Alive, kHttpKeepAlive
Max-Forwards, kHttpMaxForwards
Pragma, kHttpPragma
Proxy-Authenticate, kHttpProxyAuthenticate
Proxy-Authorization, kHttpProxyAuthorization
Proxy-Connection, kHttpProxyConnection
Range, kHttpRange
Referer, kHttpReferer
Transfer-Encoding, kHttpTransferEncoding
Upgrade, kHttpUpgrade
User-Agent, kHttpUserAgent
Via, kHttpVia
Location, kHttpLocation
Public, kHttpPublic
Retry-After, kHttpRetryAfter
Server, kHttpServer
Vary, kHttpVary
Warning, kHttpWarning
WWW-Authenticate, kHttpWwwAuthenticate
Last-Modified, kHttpLastModified
Trailer, kHttpTrailer
TE, kHttpTe
DNT, kHttpDnt
Expect, kHttpExpect
Content-Disposition, kHttpContentDisposition
Content-Description, kHttpContentDescription
Origin, kHttpOrigin
Upgrade-Insecure-Requests, kHttpUpgradeInsecureRequests
URI, kHttpUri
X-Csrf-Token, kHttpXCsrfToken
X-Forwarded-For, kHttpXForwardedFor
X-Forwarded-Host, kHttpXForwardedHost
X-Forwarded-Proto, kHttpXForwardedProto
X-Requested-With, kHttpXRequestedWith
Access-Control-Request-Method, kHttpAccessControlRequestMethod
Access-Control-Request-Headers, kHttpAccessControlRequestHeaders

View file

@ -35,14 +35,14 @@
#include "net/http/http.h"
#define GPERF_DOWNCASE
#line 12 "gethttpheader.gperf"
struct HttpHeaderSlot { char *name; char code; };
struct thatispacked HttpHeaderSlot { char *name; char code; };
#define TOTAL_KEYWORDS 58
#define TOTAL_KEYWORDS 65
#define MIN_WORD_LENGTH 2
#define MAX_WORD_LENGTH 25
#define MAX_WORD_LENGTH 30
#define MIN_HASH_VALUE 2
#define MAX_HASH_VALUE 97
/* maximum key range = 96, duplicates = 0 */
#define MAX_HASH_VALUE 102
/* maximum key range = 101, duplicates = 0 */
#ifndef GPERF_DOWNCASE
#define GPERF_DOWNCASE 1
@ -101,32 +101,32 @@ hash (register const char *str, register size_t len)
{
static const unsigned char asso_values[] =
{
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 30, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 5, 0, 30, 55, 0,
0, 10, 5, 30, 98, 0, 0, 15, 0, 15,
51, 98, 30, 55, 10, 5, 35, 20, 25, 10,
98, 98, 98, 98, 98, 98, 98, 5, 0, 30,
55, 0, 0, 10, 5, 30, 98, 0, 0, 15,
0, 15, 51, 98, 30, 55, 10, 5, 35, 20,
25, 10, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 30, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 10, 0, 10, 0, 5,
0, 15, 25, 30, 103, 0, 0, 5, 0, 45,
65, 103, 20, 55, 0, 30, 15, 10, 10, 40,
103, 103, 103, 103, 103, 103, 103, 10, 0, 10,
0, 5, 0, 15, 25, 30, 103, 0, 0, 5,
0, 45, 65, 103, 20, 55, 0, 30, 15, 10,
10, 40, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103
};
register unsigned int hval = len;
@ -152,146 +152,157 @@ hash (register const char *str, register size_t len)
return hval;
}
const struct HttpHeaderSlot *
const struct thatispacked HttpHeaderSlot *
LookupHttpHeader (register const char *str, register size_t len)
{
static const struct HttpHeaderSlot wordlist[] =
static const struct thatispacked HttpHeaderSlot wordlist[] =
{
{""}, {""},
#line 64 "gethttpheader.gperf"
{"TE", kHttpTe},
#line 18 "gethttpheader.gperf"
{"Age", kHttpAge},
{"TE", kHttpTe},
#line 65 "gethttpheader.gperf"
{"DNT", kHttpDnt},
#line 23 "gethttpheader.gperf"
{"Link", kHttpLink},
{"Link", kHttpLink},
{""},
#line 56 "gethttpheader.gperf"
{"Public", kHttpPublic},
#line 50 "gethttpheader.gperf"
{"Referer", kHttpReferer},
#line 54 "gethttpheader.gperf"
{"Via", kHttpVia},
{"Public", kHttpPublic},
{""},
#line 24 "gethttpheader.gperf"
{"Connection", kHttpConnection},
{""},
#line 22 "gethttpheader.gperf"
{"Chunked", kHttpChunked},
#line 65 "gethttpheader.gperf"
{"DNT", kHttpDnt},
#line 18 "gethttpheader.gperf"
{"Age", kHttpAge},
#line 33 "gethttpheader.gperf"
{"Date", kHttpDate},
#line 49 "gethttpheader.gperf"
{"Range", kHttpRange},
{""}, {""}, {""},
#line 34 "gethttpheader.gperf"
{"ETag", kHttpEtag},
#line 19 "gethttpheader.gperf"
{"Allow", kHttpAllow},
#line 45 "gethttpheader.gperf"
{"Pragma", kHttpPragma},
#line 51 "gethttpheader.gperf"
{"Transfer-Encoding", kHttpTransferEncoding},
{""},
#line 28 "gethttpheader.gperf"
{"Content-Length", kHttpContentLength},
{""},
{"Date", kHttpDate},
#line 24 "gethttpheader.gperf"
{"Connection", kHttpConnection},
#line 30 "gethttpheader.gperf"
{"Content-MD5", kHttpContentMd5},
#line 50 "gethttpheader.gperf"
{"Referer", kHttpReferer},
#line 54 "gethttpheader.gperf"
{"Via", kHttpVia},
{""}, {""},
#line 26 "gethttpheader.gperf"
{"Content-Encoding", kHttpContentEncoding},
{"Content-Encoding", kHttpContentEncoding},
{""}, {""},
#line 28 "gethttpheader.gperf"
{"Content-Length", kHttpContentLength},
#line 49 "gethttpheader.gperf"
{"Range", kHttpRange},
#line 14 "gethttpheader.gperf"
{"Accept", kHttpAccept},
#line 25 "gethttpheader.gperf"
{"Content-Base", kHttpContentBase},
{"Content-Base", kHttpContentBase},
#line 31 "gethttpheader.gperf"
{"Content-Range", kHttpContentRange},
{"Content-Range", kHttpContentRange},
#line 68 "gethttpheader.gperf"
{"Content-Description", kHttpContentDescription},
{"Content-Description", kHttpContentDescription},
{""},
#line 27 "gethttpheader.gperf"
{"Content-Language", kHttpContentLanguage},
#line 32 "gethttpheader.gperf"
{"Content-Type", kHttpContentType},
#line 71 "gethttpheader.gperf"
{"URI", kHttpUri},
#line 36 "gethttpheader.gperf"
{"From", kHttpFrom},
{""},
#line 14 "gethttpheader.gperf"
{"Accept", kHttpAccept},
{"Content-Language", kHttpContentLanguage},
#line 60 "gethttpheader.gperf"
{"Warning", kHttpWarning},
#line 20 "gethttpheader.gperf"
{"Authorization", kHttpAuthorization},
{""}, {""},
#line 29 "gethttpheader.gperf"
{"Content-Location", kHttpContentLocation},
#line 63 "gethttpheader.gperf"
{"Trailer", kHttpTrailer},
{"Warning", kHttpWarning},
#line 55 "gethttpheader.gperf"
{"Location", kHttpLocation},
#line 59 "gethttpheader.gperf"
{"Vary", kHttpVary},
{"Location", kHttpLocation},
#line 34 "gethttpheader.gperf"
{"ETag", kHttpEtag},
#line 17 "gethttpheader.gperf"
{"Accept-Language", kHttpAcceptLanguage},
#line 69 "gethttpheader.gperf"
{"Origin", kHttpOrigin},
#line 52 "gethttpheader.gperf"
{"Upgrade", kHttpUpgrade},
#line 40 "gethttpheader.gperf"
{"If-None-Match", kHttpIfNoneMatch},
#line 15 "gethttpheader.gperf"
{"Accept-Charset", kHttpAcceptCharset},
{"Accept-Language", kHttpAcceptLanguage},
#line 45 "gethttpheader.gperf"
{"Pragma", kHttpPragma},
#line 51 "gethttpheader.gperf"
{"Transfer-Encoding", kHttpTransferEncoding},
#line 71 "gethttpheader.gperf"
{"URI", kHttpUri},
{""},
#line 53 "gethttpheader.gperf"
{"User-Agent", kHttpUserAgent},
{"User-Agent", kHttpUserAgent},
#line 57 "gethttpheader.gperf"
{"Retry-After", kHttpRetryAfter},
{""},
#line 38 "gethttpheader.gperf"
{"If-Match", kHttpIfMatch},
#line 42 "gethttpheader.gperf"
{"If-Unmodified-Since", kHttpIfUnmodifiedSince},
{""},
#line 48 "gethttpheader.gperf"
{"Proxy-Connection", kHttpProxyConnection},
#line 66 "gethttpheader.gperf"
{"Expect", kHttpExpect},
#line 21 "gethttpheader.gperf"
{"Cache-Control", kHttpCacheControl},
#line 67 "gethttpheader.gperf"
{"Content-Disposition", kHttpContentDisposition},
{""},
#line 43 "gethttpheader.gperf"
{"Keep-Alive", kHttpKeepAlive},
#line 39 "gethttpheader.gperf"
{"If-Modified-Since", kHttpIfModifiedSince},
#line 46 "gethttpheader.gperf"
{"Proxy-Authenticate", kHttpProxyAuthenticate},
#line 47 "gethttpheader.gperf"
{"Proxy-Authorization", kHttpProxyAuthorization},
#line 70 "gethttpheader.gperf"
{"Upgrade-Insecure-Requests", kHttpUpgradeInsecureRequests},
#line 61 "gethttpheader.gperf"
{"WWW-Authenticate", kHttpWwwAuthenticate},
{""},
#line 41 "gethttpheader.gperf"
{"If-Range", kHttpIfRange},
#line 37 "gethttpheader.gperf"
{"Host", kHttpHost},
{""},
#line 58 "gethttpheader.gperf"
{"Server", kHttpServer},
{""}, {""}, {""},
{"Retry-After", kHttpRetryAfter},
#line 22 "gethttpheader.gperf"
{"Chunked", kHttpChunked},
#line 20 "gethttpheader.gperf"
{"Authorization", kHttpAuthorization},
#line 15 "gethttpheader.gperf"
{"Accept-Charset", kHttpAcceptCharset},
#line 16 "gethttpheader.gperf"
{"Accept-Encoding", kHttpAcceptEncoding},
#line 30 "gethttpheader.gperf"
{"Content-MD5", kHttpContentMd5},
{"Accept-Encoding", kHttpAcceptEncoding},
#line 58 "gethttpheader.gperf"
{"Server", kHttpServer},
#line 52 "gethttpheader.gperf"
{"Upgrade", kHttpUpgrade},
#line 38 "gethttpheader.gperf"
{"If-Match", kHttpIfMatch},
#line 77 "gethttpheader.gperf"
{"Access-Control-Request-Method", kHttpAccessControlRequestMethod},
#line 78 "gethttpheader.gperf"
{"Access-Control-Request-Headers", kHttpAccessControlRequestHeaders},
#line 76 "gethttpheader.gperf"
{"X-Requested-With", kHttpXRequestedWith},
#line 63 "gethttpheader.gperf"
{"Trailer", kHttpTrailer},
#line 21 "gethttpheader.gperf"
{"Cache-Control", kHttpCacheControl},
#line 67 "gethttpheader.gperf"
{"Content-Disposition", kHttpContentDisposition},
#line 19 "gethttpheader.gperf"
{"Allow", kHttpAllow},
#line 69 "gethttpheader.gperf"
{"Origin", kHttpOrigin},
#line 32 "gethttpheader.gperf"
{"Content-Type", kHttpContentType},
#line 40 "gethttpheader.gperf"
{"If-None-Match", kHttpIfNoneMatch},
#line 36 "gethttpheader.gperf"
{"From", kHttpFrom},
{""},
#line 61 "gethttpheader.gperf"
{"WWW-Authenticate", kHttpWwwAuthenticate},
#line 39 "gethttpheader.gperf"
{"If-Modified-Since", kHttpIfModifiedSince},
#line 41 "gethttpheader.gperf"
{"If-Range", kHttpIfRange},
#line 37 "gethttpheader.gperf"
{"Host", kHttpHost},
#line 70 "gethttpheader.gperf"
{"Upgrade-Insecure-Requests", kHttpUpgradeInsecureRequests},
#line 29 "gethttpheader.gperf"
{"Content-Location", kHttpContentLocation},
{""}, {""},
#line 59 "gethttpheader.gperf"
{"Vary", kHttpVary},
#line 73 "gethttpheader.gperf"
{"X-Forwarded-For", kHttpXForwardedFor},
#line 74 "gethttpheader.gperf"
{"X-Forwarded-Host", kHttpXForwardedHost},
#line 75 "gethttpheader.gperf"
{"X-Forwarded-Proto", kHttpXForwardedProto},
#line 62 "gethttpheader.gperf"
{"Last-Modified", kHttpLastModified},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
#line 35 "gethttpheader.gperf"
{"Expires", kHttpExpires},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{"Last-Modified", kHttpLastModified},
{""}, {""},
#line 48 "gethttpheader.gperf"
{"Proxy-Connection", kHttpProxyConnection},
#line 44 "gethttpheader.gperf"
{"Max-Forwards", kHttpMaxForwards}
{"Max-Forwards", kHttpMaxForwards},
{""}, {""}, {""},
#line 66 "gethttpheader.gperf"
{"Expect", kHttpExpect},
#line 72 "gethttpheader.gperf"
{"X-Csrf-Token", kHttpXCsrfToken},
{""},
#line 42 "gethttpheader.gperf"
{"If-Unmodified-Since", kHttpIfUnmodifiedSince},
{""}, {""}, {""}, {""}, {""},
#line 43 "gethttpheader.gperf"
{"Keep-Alive", kHttpKeepAlive},
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
{""}, {""}, {""},
#line 46 "gethttpheader.gperf"
{"Proxy-Authenticate", kHttpProxyAuthenticate},
#line 47 "gethttpheader.gperf"
{"Proxy-Authorization", kHttpProxyAuthorization},
{""}, {""},
#line 35 "gethttpheader.gperf"
{"Expires", kHttpExpires}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)

View file

@ -136,6 +136,20 @@ const char *GetHttpHeaderName(int h) {
return "Upgrade-Insecure-Requests";
case kHttpUri:
return "URI";
case kHttpXCsrfToken:
return "X-Csrf-Token";
case kHttpXForwardedFor:
return "X-Forwarded-For";
case kHttpXForwardedHost:
return "X-Forwarded-Host";
case kHttpXForwardedProto:
return "X-Forwarded-Proto";
case kHttpXRequestedWith:
return "X-Requested-With";
case kHttpAccessControlRequestMethod:
return "Access-Control-Request-Method";
case kHttpAccessControlRequestHeaders:
return "Access-Control-Request-Headers";
default:
return NULL;
}

View file

@ -0,0 +1,68 @@
/*-*- 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 "net/http/ip.h"
/**
* Describes IP address.
* @see CategorizeIp()
*/
const char *GetIpCategoryName(int c) {
switch (c) {
case kIpMulticast:
return "MULTICAST";
case kIpLoopback:
return "LOOPBACK";
case kIpPrivate:
return "PRIVATE";
case kIpTestnet:
return "TESTNET";
case kIpAfrinic:
return "AFRINIC";
case kIpLacnic:
return "LACNIC";
case kIpApnic:
return "APNIC";
case kIpArin:
return "ARIN";
case kIpRipe:
return "RIPE";
case kIpDod:
return "DOD";
case kIpAtt:
return "AT&T";
case kIpApple:
return "APPLE";
case kIpFord:
return "FORD";
case kIpCogent:
return "COGENT";
case kIpPrudential:
return "PRUDENTIAL";
case kIpUsps:
return "USPS";
case kIpComcast:
return "COMCAST";
case kIpFuture:
return "FUTURE";
case kIpAnonymous:
return "ANONYMOUS";
default:
return NULL;
}
}

View file

@ -0,0 +1,69 @@
/*-*- 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/errno.h"
#include "libc/intrin/pcmpgtb.h"
#include "libc/intrin/pmovmskb.h"
#include "libc/mem/mem.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/str/thompike.h"
#include "net/http/escape.h"
/**
* Returns true if C0 or C1 control codes are present
*
* @param p is input value
* @param n if -1 implies strlen
* @param f can have kControlWs, kControlC0, kControlC1 to forbid
* @return true if forbidden characters were found
* @see VisualizeControlCodes()
*/
bool HasControlCodes(const char *p, size_t n, int f) {
int c;
wint_t x, a, b;
size_t i, j, m;
if (n == -1) n = p ? strlen(p) : 0;
for (i = 0; i < n;) {
x = p[i++] & 0xff;
if (x >= 0300) {
a = ThomPikeByte(x);
m = ThomPikeLen(x) - 1;
if (i + m <= n) {
for (j = 0;;) {
b = p[i + j] & 0xff;
if (!ThomPikeCont(b)) break;
a = ThomPikeMerge(a, b);
if (++j == m) {
x = a;
i += j;
break;
}
}
}
}
if (((f & kControlC1) && 0x80 <= x && x < 0xA0) ||
((f & kControlC0) && (x < 32 || x == 0x7F) &&
!(x == '\t' || x == '\r' || x == '\n' || x == '\v')) ||
((f & kControlWs) &&
(x == '\t' || x == '\r' || x == '\n' || x == '\v'))) {
return true;
}
}
return false;
}

View file

@ -30,8 +30,8 @@
* @param n is byte length of s where -1 implies strlen
* @return true if substring present
*/
bool HeaderHasSubstring(struct HttpRequest *m, const char *b, int h,
const char *s, size_t n) {
bool HeaderHas(struct HttpRequest *m, const char *b, int h, const char *s,
size_t n) {
size_t i;
assert(0 <= h && h < kHttpHeadersMax);
if (n == -1) n = s ? strlen(s) : 0;

View file

@ -1,6 +1,5 @@
#ifndef COSMOPOLITAN_LIBC_HTTP_HTTP_H_
#define COSMOPOLITAN_LIBC_HTTP_HTTP_H_
#include "libc/alg/alg.h"
#include "libc/time/struct/tm.h"
#define kHttpGet 1
@ -21,65 +20,72 @@
#define kHttpReport 16
#define kHttpUnlock 17
#define kHttpAccept 0
#define kHttpAcceptCharset 1
#define kHttpAcceptEncoding 2
#define kHttpAcceptLanguage 3
#define kHttpAge 4
#define kHttpAllow 5
#define kHttpAuthorization 6
#define kHttpCacheControl 7
#define kHttpChunked 8
#define kHttpLink 9
#define kHttpConnection 10
#define kHttpContentBase 11
#define kHttpContentEncoding 12
#define kHttpContentLanguage 13
#define kHttpContentLength 14
#define kHttpContentLocation 15
#define kHttpContentMd5 16
#define kHttpContentRange 17
#define kHttpContentType 18
#define kHttpDate 19
#define kHttpEtag 20
#define kHttpExpires 21
#define kHttpFrom 22
#define kHttpHost 23
#define kHttpIfMatch 24
#define kHttpIfModifiedSince 25
#define kHttpIfNoneMatch 26
#define kHttpIfRange 27
#define kHttpIfUnmodifiedSince 28
#define kHttpKeepAlive 29
#define kHttpMaxForwards 30
#define kHttpPragma 31
#define kHttpProxyAuthenticate 32
#define kHttpProxyAuthorization 33
#define kHttpProxyConnection 34
#define kHttpRange 35
#define kHttpReferer 36
#define kHttpTransferEncoding 37
#define kHttpUpgrade 38
#define kHttpUserAgent 39
#define kHttpVia 40
#define kHttpLocation 41
#define kHttpPublic 42
#define kHttpRetryAfter 43
#define kHttpServer 44
#define kHttpVary 45
#define kHttpWarning 46
#define kHttpWwwAuthenticate 47
#define kHttpLastModified 48
#define kHttpTrailer 49
#define kHttpTe 50
#define kHttpDnt 51
#define kHttpExpect 52
#define kHttpContentDisposition 53
#define kHttpContentDescription 54
#define kHttpOrigin 55
#define kHttpUpgradeInsecureRequests 56
#define kHttpUri 57
#define kHttpHeadersMax 58
#define kHttpAccept 0
#define kHttpAcceptCharset 1
#define kHttpAcceptEncoding 2
#define kHttpAcceptLanguage 3
#define kHttpAge 4
#define kHttpAllow 5
#define kHttpAuthorization 6
#define kHttpCacheControl 7
#define kHttpChunked 8
#define kHttpLink 9
#define kHttpConnection 10
#define kHttpContentBase 11
#define kHttpContentEncoding 12
#define kHttpContentLanguage 13
#define kHttpContentLength 14
#define kHttpContentLocation 15
#define kHttpContentMd5 16
#define kHttpContentRange 17
#define kHttpContentType 18
#define kHttpDate 19
#define kHttpEtag 20
#define kHttpExpires 21
#define kHttpFrom 22
#define kHttpHost 23
#define kHttpIfMatch 24
#define kHttpIfModifiedSince 25
#define kHttpIfNoneMatch 26
#define kHttpIfRange 27
#define kHttpIfUnmodifiedSince 28
#define kHttpKeepAlive 29
#define kHttpMaxForwards 30
#define kHttpPragma 31
#define kHttpProxyAuthenticate 32
#define kHttpProxyAuthorization 33
#define kHttpProxyConnection 34
#define kHttpRange 35
#define kHttpReferer 36
#define kHttpTransferEncoding 37
#define kHttpUpgrade 38
#define kHttpUserAgent 39
#define kHttpVia 40
#define kHttpLocation 41
#define kHttpPublic 42
#define kHttpRetryAfter 43
#define kHttpServer 44
#define kHttpVary 45
#define kHttpWarning 46
#define kHttpWwwAuthenticate 47
#define kHttpLastModified 48
#define kHttpTrailer 49
#define kHttpTe 50
#define kHttpDnt 51
#define kHttpExpect 52
#define kHttpContentDisposition 53
#define kHttpContentDescription 54
#define kHttpOrigin 55
#define kHttpUpgradeInsecureRequests 56
#define kHttpUri 57
#define kHttpXCsrfToken 58
#define kHttpXForwardedFor 59
#define kHttpXForwardedHost 60
#define kHttpXForwardedProto 61
#define kHttpXRequestedWith 62
#define kHttpAccessControlRequestMethod 63
#define kHttpAccessControlRequestHeaders 64
#define kHttpHeadersMax 65
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -111,30 +117,25 @@ extern const char kHttpToken[256];
extern const char kHttpMethod[18][8];
extern const bool kHttpRepeatable[kHttpHeadersMax];
const char *GetHttpReason(int);
const char *GetHttpHeaderName(int);
int GetHttpHeader(const char *, size_t);
int GetHttpMethod(const char *, size_t);
void InitHttpRequest(struct HttpRequest *);
void DestroyHttpRequest(struct HttpRequest *);
int ParseHttpRequest(struct HttpRequest *, const char *, size_t);
bool HeaderHasSubstring(struct HttpRequest *, const char *, int, const char *,
size_t);
int NegotiateHttpRequest(int, const char *, uint32_t *, char *, uint32_t *,
uint32_t *, bool, long double);
bool HeaderHas(struct HttpRequest *, const char *, int, const char *, size_t);
int64_t ParseContentLength(const char *, size_t);
char *FormatHttpDateTime(char[hasatleast 30], struct tm *);
bool ParseHttpRange(const char *, size_t, long, long *, long *);
int64_t ParseHttpDateTime(const char *, size_t);
const char *GetHttpReason(int);
const char *GetHttpHeaderName(int);
char *DecodeLatin1(const char *, size_t, size_t *);
bool IsValidHttpToken(const char *, size_t);
char *EncodeHttpHeaderValue(const char *, size_t, size_t *);
char *VisualizeControlCodes(const char *, size_t, size_t *);
char *IndentLines(const char *, size_t, size_t *, size_t);
bool IsAcceptablePath(const char *, size_t);
bool IsAcceptableHost(const char *, size_t);
bool IsAcceptablePort(const char *, size_t);
bool IsReasonablePath(const char *, size_t);
int64_t ParseIp(const char *, size_t);
int ParseForwarded(const char *, size_t, uint32_t *, uint16_t *);
bool IsMimeType(const char *, size_t, const char *);
COSMOPOLITAN_C_END_

View file

@ -53,6 +53,21 @@ $(NET_HTTP_A).pkg: \
$(NET_HTTP_A_OBJS) \
$(foreach x,$(NET_HTTP_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/net/http/categorizeip.o \
o/$(MODE)/net/http/getipcategoryname.o \
o/$(MODE)/net/http/isafrinicip.o \
o/$(MODE)/net/http/isanonymousip.o \
o/$(MODE)/net/http/isapnicip.o \
o/$(MODE)/net/http/isarinip.o \
o/$(MODE)/net/http/isdodip.o \
o/$(MODE)/net/http/islacnicip.o \
o/$(MODE)/net/http/isloopbackip.o \
o/$(MODE)/net/http/ismulticastip.o \
o/$(MODE)/net/http/isripeip.o \
o/$(MODE)/net/http/istestnetip.o: \
OVERRIDE_CFLAGS += \
-Os
o/$(MODE)/net/http/formathttpdatetime.o: \
OVERRIDE_CFLAGS += \
-O3

View file

@ -18,42 +18,46 @@
*/
#include "libc/str/str.h"
#include "libc/x/x.h"
#include "net/http/http.h"
#include "net/http/escape.h"
/**
* Inserts spaces before lines.
*
* @param data is input value
* @param size if -1 implies strlen
* @param out_size if non-NULL receives output length
* @param amt is number of spaces to use
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @param j is number of spaces to use
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
char *IndentLines(const char *data, size_t size, size_t *out_size, size_t amt) {
char *r;
const char *p;
size_t i, n, m, a;
if (size == -1) size = data ? strlen(data) : 0;
char *IndentLines(const char *p, size_t n, size_t *z, size_t j) {
char *r, *q;
const char *l;
size_t i, t, m, a;
if (n == -1) n = p ? strlen(p) : 0;
r = 0;
n = 0;
t = 0;
do {
if ((p = memchr(data, '\n', size))) {
m = p + 1 - data;
a = *data != '\r' && *data != '\n' ? amt : 0;
if ((l = memchr(p, '\n', n))) {
m = l + 1 - p;
a = *p != '\r' && *p != '\n' ? j : 0;
} else {
m = size;
a = size ? amt : 0;
m = n;
a = n ? j : 0;
}
r = xrealloc(r, n + a + m + 1);
memset(r + n, ' ', a);
memcpy(r + n + a, data, m);
n += a + m;
data += m;
size -= m;
} while (p);
if (out_size) {
*out_size = n;
}
r[n] = '\0';
if ((q = realloc(r, t + a + m + 1))) {
r = q;
} else {
free(r);
if (z) *z = 0;
return 0;
}
memset(r + t, ' ', a);
memcpy(r + t + a, p, m);
t += a + m;
p += m;
n -= m;
} while (l);
if (z) *z = t;
r[t] = '\0';
return r;
}

45
net/http/ip.h Normal file
View file

@ -0,0 +1,45 @@
#ifndef COSMOPOLITAN_NET_HTTP_IP_H_
#define COSMOPOLITAN_NET_HTTP_IP_H_
#define kIpUnknown 0
#define kIpMulticast 1
#define kIpLoopback 2
#define kIpPrivate 3
#define kIpTestnet 4
#define kIpAfrinic 5
#define kIpLacnic 6
#define kIpApnic 7
#define kIpArin 8
#define kIpRipe 9
#define kIpDod 10
#define kIpAtt 11
#define kIpApple 12
#define kIpFord 13
#define kIpCogent 14
#define kIpPrudential 15
#define kIpUsps 16
#define kIpComcast 17
#define kIpFuture 18
#define kIpAnonymous 19
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
bool IsDodIp(uint32_t);
bool IsArinIp(uint32_t);
bool IsRipeIp(uint32_t);
bool IsApnicIp(uint32_t);
bool IsLacnicIp(uint32_t);
bool IsPublicIp(uint32_t);
bool IsPrivateIp(uint32_t);
bool IsAfrinicIp(uint32_t);
bool IsTestnetIp(uint32_t);
bool IsLoopbackIp(uint32_t);
bool IsMulticastIp(uint32_t);
bool IsAnonymousIp(uint32_t);
int CategorizeIp(uint32_t);
const char *GetIpCategoryName(int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_NET_HTTP_IP_H_ */

View file

@ -29,9 +29,11 @@
*
* It is assumed that the URI parser already took care of percent
* escape decoding as well as ISO-8859-1 decoding. The input needs
* to be a UTF-8 string.
* to be a UTF-8 string. This function takes overlong encodings into
* consideration, so you don't need to call Underlong() beforehand.
*
* @param size if -1 implies strlen
* @see IsReasonablePath()
*/
bool IsAcceptablePath(const char *data, size_t size) {
const char *p, *e;

28
net/http/isafrinicip.c Normal file
View file

@ -0,0 +1,28 @@
/*-*- 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 "net/http/ip.h"
/**
* Returns true if IPv4 address is managed by AFRINIC.
*/
bool IsAfrinicIp(uint32_t x) {
int a = (x & 0xff000000) >> 24;
return a == 41 || a == 102 || a == 105 || a == 154 || a == 196 || a == 197 ||
(x & 0xffffe000) == 0xca7b0000 /* 202.123.0.0/19 */;
}

41
net/http/isanonymousip.c Normal file
View file

@ -0,0 +1,41 @@
/*-*- 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 "net/http/ip.h"
/**
* Returns true if IPv4 address is anonymous proxy provider.
*/
bool IsAnonymousIp(uint32_t x) {
return (x & 0xffffffff) == 0x1f0e8527 || (x & 0xffffff00) == 0x2e138900 ||
(x & 0xffffff00) == 0x2e138f00 || (x & 0xfffffffe) == 0x32074e58 ||
(x & 0xfffffe00) == 0x3e490800 || (x & 0xffffffff) == 0x3feb9bd2 ||
(x & 0xffffffff) == 0x400c7617 || (x & 0xffffffff) == 0x400c7658 ||
(x & 0xffffff00) == 0x432b9c00 || (x & 0xffffff00) == 0x450a8b00 ||
(x & 0xffffff00) == 0x46e8f500 || (x & 0xffffffff) == 0x4a5209e0 ||
(x & 0xfffffe00) == 0x50fe4a00 || (x & 0xfffffe00) == 0x5d735200 ||
(x & 0xfffffe00) == 0x5d735400 || (x & 0xffffffff) == 0x602fe214 ||
(x & 0xffffff00) == 0x93cb7800 || (x & 0xffffffff) == 0xb0094b2b ||
(x & 0xffffffff) == 0xb9246491 || (x & 0xffffff00) == 0xc0ee1500 ||
(x & 0xffffffff) == 0xc16b1147 || (x & 0xffffffff) == 0xc6906958 ||
(x & 0xffffff00) == 0xc772df00 || (x & 0xffffff00) == 0xc7bcec00 ||
(x & 0xffffffff) == 0xc8c8c8c8 || (x & 0xffffff00) == 0xce47a200 ||
(x & 0xffffff00) == 0xcec46700 || (x & 0xffffffff) == 0xd02be134 ||
(x & 0xffffff00) == 0xd1d8c600 || (x & 0xfffffffc) == 0xd43fa9e8 ||
(x & 0xffffffff) == 0xd5eaf973 || (x & 0xffffff00) == 0xd897b400;
}

35
net/http/isapnicip.c Normal file
View 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 "net/http/ip.h"
/**
* Returns true if IPv4 address is managed by APNIC.
*/
bool IsApnicIp(uint32_t x) {
int a = (x & 0xff000000) >> 24;
return a == 1 || a == 14 || a == 27 || a == 36 || a == 39 || a == 42 ||
a == 43 || a == 49 || a == 58 || a == 59 || a == 60 || a == 61 ||
a == 101 || a == 103 || a == 106 || a == 110 || a == 111 || a == 112 ||
a == 113 || a == 114 || a == 115 || a == 116 || a == 117 || a == 118 ||
a == 119 || a == 120 || a == 121 || a == 122 || a == 123 || a == 124 ||
a == 125 || a == 126 || a == 133 || a == 150 || a == 153 || a == 163 ||
a == 171 || a == 175 || a == 180 || a == 182 || a == 183 || a == 202 ||
a == 203 || a == 210 || a == 211 || a == 218 || a == 219 || a == 220 ||
a == 221 || a == 222 || a == 223;
}

42
net/http/isarinip.c Normal file
View file

@ -0,0 +1,42 @@
/*-*- 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 "net/http/ip.h"
/**
* Returns true if IPv4 address is managed by ARIN.
*/
bool IsArinIp(uint32_t x) {
int a = (x & 0xff000000) >> 24;
return a == 3 || a == 4 || a == 8 || a == 9 || a == 13 || a == 15 ||
a == 16 || a == 18 || a == 20 || a == 23 || a == 24 || a == 32 ||
a == 34 || a == 35 || a == 40 || a == 44 || a == 45 || a == 47 ||
a == 50 || a == 52 || a == 54 || a == 63 || a == 64 || a == 65 ||
a == 66 || a == 67 || a == 68 || a == 69 || a == 70 || a == 71 ||
a == 72 || a == 74 || a == 75 || a == 76 || a == 96 || a == 97 ||
a == 98 || a == 99 || a == 100 || a == 104 || a == 107 || a == 108 ||
a == 128 || a == 129 || a == 130 || a == 131 || a == 132 || a == 134 ||
a == 135 || a == 136 || a == 137 || a == 138 || a == 139 || a == 140 ||
a == 142 || a == 143 || a == 144 || a == 146 || a == 147 || a == 148 ||
a == 149 || a == 152 || a == 155 || a == 156 || a == 157 || a == 158 ||
a == 159 || a == 160 || a == 161 || a == 162 || a == 164 || a == 165 ||
a == 166 || a == 167 || a == 168 || a == 169 || a == 170 || a == 172 ||
a == 173 || a == 174 || a == 184 || a == 192 || a == 198 || a == 199 ||
a == 204 || a == 205 || a == 206 || a == 207 || a == 208 || a == 209 ||
a == 216;
}

29
net/http/isdodip.c Normal file
View file

@ -0,0 +1,29 @@
/*-*- 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 "net/http/ip.h"
/**
* Returns true if IP is owned by the U.S. Department of Defense.
*/
bool IsDodIp(uint32_t x) {
int a = (x & 0xff000000) >> 24;
return a == 6 || a == 7 || a == 11 || a == 21 || a == 22 || a == 26 ||
a == 28 || a == 29 || a == 30 || a == 33 || a == 55 || a == 214 ||
a == 215;
}

28
net/http/islacnicip.c Normal file
View file

@ -0,0 +1,28 @@
/*-*- 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 "net/http/ip.h"
/**
* Returns true if IPv4 address is managed by LACNIC.
*/
bool IsLacnicIp(uint32_t x) {
int a = (x & 0xff000000) >> 24;
return a == 177 || a == 179 || a == 181 || a == 186 || a == 187 || a == 189 ||
a == 190 || a == 191 || a == 200 || a == 201;
}

26
net/http/isloopbackip.c Normal file
View file

@ -0,0 +1,26 @@
/*-*- 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 "net/http/ip.h"
/**
* Returns true if IPv4 address is used for localhost.
*/
bool IsLoopbackIp(uint32_t x) {
return (x >> 24) == 127; /* 127.0.0.0/8 */
}

26
net/http/ismulticastip.c Normal file
View file

@ -0,0 +1,26 @@
/*-*- 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 "net/http/ip.h"
/**
* Returns true if IPv4 address is used for multicast.
*/
bool IsMulticastIp(uint32_t x) {
return (x >> 28) == 0xE; /* 224.0.0.0/4 */
}

28
net/http/isprivateip.c Normal file
View file

@ -0,0 +1,28 @@
/*-*- 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 "net/http/ip.h"
/**
* Returns true if IPv4 address is intended for private networks.
*/
bool IsPrivateIp(uint32_t x) {
return (x >> 24) == 10 /* 10.0.0.0/8 */
|| (x & 0xfff00000) == 0xac100000 /* 172.16.0.0/12 */
|| (x & 0xffff0000) == 0xc0a80000 /* 192.168.0.0/16 */;
}

26
net/http/ispublicip.c Normal file
View file

@ -0,0 +1,26 @@
/*-*- 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 "net/http/ip.h"
/**
* Returns true if IPv4 address can come from the Internet.
*/
bool IsPublicIp(uint32_t x) {
return !IsLoopbackIp(x) && !IsPrivateIp(x) && !IsTestnetIp(x);
}

View file

@ -0,0 +1,67 @@
/*-*- 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/str/str.h"
#include "libc/str/thompike.h"
#include "net/http/http.h"
/**
* Returns true if path doesn't contain "." or ".." segments.
*
* @param size if -1 implies strlen
* @see IsAcceptablePath()
*/
bool IsReasonablePath(const char *data, size_t size) {
const char *p, *e;
int x, y, z, a, b, i, n;
if (size == -1) size = data ? strlen(data) : 0;
z = '/';
y = '/';
x = '/';
p = data;
e = p + size;
while (p < e) {
x = *p++ & 0xff;
if (x >= 0300) {
a = ThomPikeByte(x);
n = ThomPikeLen(x) - 1;
if (p + n <= e) {
for (i = 0;;) {
b = p[i] & 0xff;
if (!ThomPikeCont(b)) break;
a = ThomPikeMerge(a, b);
if (++i == n) {
x = a;
p += i;
break;
}
}
}
}
if (x == '\\') {
x = '/';
}
if (z == '/' && y == '.' && x == '/') return false;
if (z == '/' && y == '.' && x == '.') return false;
z = y;
y = x;
}
if (y == '/' && x == '.') return false;
if (z == '/' && y == '.' && x == '.') return false;
return true;
}

34
net/http/isripeip.c Normal file
View file

@ -0,0 +1,34 @@
/*-*- 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 "net/http/ip.h"
/**
* Returns true if IPv4 address is managed by RIPE NCC.
*/
bool IsRipeIp(uint32_t x) {
int a = (x & 0xff000000) >> 24;
return a == 2 || a == 5 || a == 25 || a == 31 || a == 37 || a == 46 ||
a == 51 || a == 53 || a == 57 || a == 62 || a == 77 || a == 78 ||
a == 79 || a == 80 || a == 81 || a == 82 || a == 83 || a == 84 ||
a == 85 || a == 86 || a == 87 || a == 88 || a == 89 || a == 90 ||
a == 91 || a == 92 || a == 93 || a == 94 || a == 95 || a == 109 ||
a == 141 || a == 145 || a == 151 || a == 176 || a == 178 || a == 185 ||
a == 188 || a == 193 || a == 194 || a == 195 || a == 212 || a == 213 ||
a == 217;
}

29
net/http/istestnetip.c Normal file
View file

@ -0,0 +1,29 @@
/*-*- 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 "net/http/ip.h"
/**
* Returns true if IPv4 address is intended for documentation.
* @see RFC5737
*/
bool IsTestnetIp(uint32_t x) {
return (((x & 0xFFFFFF00u) == 0xC0000200u) /* 192.0.2.0/24 */ ||
((x & 0xFFFFFF00u) == 0xC0000200u) /* 198.51.100.0/24 */ ||
((x & 0xFFFFFF00u) == 0xCB007100u) /* 203.0.113.0/24 */);
}

View file

@ -1,106 +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/calls/calls.h"
#include "libc/macros.internal.h"
#include "libc/math.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/shut.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/time.h"
#include "net/http/http.h"
static pureconst long AsMilliseconds(long double ts) {
return ts * 1e3 + .5;
}
/**
* Negotiates HTTP request.
*
* This function blocks until a response header is consumed. We assume
* the response header is smaller than *inout_respsize. We're agnostic
* to the various different i/o paradigms. Goal is really good latency.
*
* @param singleshot should be true w/ connection: close
* @return 0 on success, or -1 w/ errno
*/
int NegotiateHttpRequest(int sock, const char *req, uint32_t *inout_reqsize,
char *resp, uint32_t *inout_respsize,
uint32_t *out_resphdrsize, bool singleshot,
long double timeout) {
ssize_t rc;
struct pollfd fd;
const char *body;
long double start, now, deadline;
uint32_t transmitted, received, exchanged, remaining;
fd.fd = sock;
received = 0;
transmitted = 0;
fd.events = POLLOUT | POLLIN;
deadline = (start = now = nowl()) + timeout;
do {
if ((rc = poll(&fd, 1, MAX(0, AsMilliseconds(deadline - now)))) == 1) {
if (fd.revents & POLLHUP) {
econnreset();
break;
}
if (fd.revents & (POLLIN | POLLERR)) {
remaining = *inout_respsize - received - 1;
if ((rc = recv(fd.fd, resp + received, remaining, 0)) != -1) {
exchanged = rc;
body = memmem(resp + (received >= 4 ? received - 4 : 0), exchanged,
"\r\n\r\n", 4);
received += exchanged;
if (body) {
resp[received] = '\0';
*inout_respsize = received;
*inout_reqsize = transmitted;
*out_resphdrsize = body - resp;
return 0;
}
if (exchanged == remaining) {
emsgsize();
break;
}
} else {
break;
}
}
if (fd.revents & POLLOUT) {
remaining = *inout_reqsize - transmitted;
if ((rc = send(fd.fd, req + transmitted, remaining, 0)) != -1) {
exchanged = rc;
transmitted += exchanged;
if (exchanged == remaining) {
if (singleshot) shutdown(fd.fd, SHUT_WR);
fd.events &= ~POLLOUT;
}
} else {
break;
}
}
} else {
if (!rc) etimedout();
break;
}
} while ((now = nowl()) < deadline);
close(fd.fd);
return -1;
}

76
net/http/parseforwarded.c Normal file
View file

@ -0,0 +1,76 @@
/*-*- 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/str/str.h"
#include "net/http/http.h"
/**
* Parses X-Forwarded-For.
*
* This header is used by reverse proxies. For example:
*
* X-Forwarded-For: 203.0.113.42:31337
*
* @param s is input data
* @param n if -1 implies strlen
* @param ip receives ip on success if not NULL
* @param port receives port on success if not NULL
* @return 0 on success or -1 on failure
* @see RFC7239's poorly designed Forwarded header
*/
int ParseForwarded(const char *s, size_t n, uint32_t *ip, uint16_t *port) {
size_t i;
uint32_t x;
int c, j, t;
if (n == -1) n = s ? strlen(s) : 0;
for (t = x = j = i = 0; i < n;) {
c = s[i++] & 255;
if (isdigit(c)) {
t *= 10;
t += c - '0';
if (t > 255) return -1;
} else if (c == '.') {
x <<= 8;
x |= t;
t = 0;
++j;
} else if (c == ':') {
x <<= 8;
x |= t;
t = 0;
if (j != 3) return -1;
while (i < n) {
c = s[i++] & 255;
if (isdigit(c)) {
t *= 10;
t += c - '0';
if (t > 65535) return -1;
} else {
return -1;
}
}
if (!x || !t) return -1;
if (ip) *ip = x;
if (port) *port = t;
return 0;
} else {
return -1;
}
}
return -1;
}

View file

@ -60,14 +60,24 @@ void DestroyHttpRequest(struct HttpRequest *r) {
* that fragmented messages can be handled efficiently. A limitation on
* message size is imposed to make the header data structures smaller.
*
* This parser assumes ISO-8859-1 and guarantees no C0 or C1 control
* codes are present in message fields, with the exception of tab.
* Please note that fields like URI may use UTF-8 percent encoding. This
* parser doesn't care if you choose ASA X3.4-1963 or MULTICS newlines.
*
* kHttpRepeatable defines which standard header fields are O(1) and
* which ones may have comma entries spilled over into xheaders. For
* most headers it's sufficient to simply check the static slice. If
* r->headers[kHttpFoo].a is zero then the header is totally absent.
*
* This parser takes about 300 nanoseconds (900 cycles) to parse a 403
* byte Chrome HTTP request under MODE=rel on a Core i9 which is about
* gigabyte per second of throughput per core.
* This parser has linear complexity. Each character only needs to be
* considered a single time. That's the case even if messages are
* fragmented. If a message is valid but incomplete, this function will
* return zero so that it can be resumed as soon as more data arrives.
*
* This parser takes about 500 nanoseconds to parse a 403 byte Chrome
* HTTP request under MODE=rel on a Core i9 which is about three cycles
* per byte or a gigabyte per second of throughput per core.
*
* @note we assume p points to a buffer that has >=SHRT_MAX bytes
* @see HTTP/1.1 RFC2616 RFC2068

View file

@ -127,25 +127,28 @@ static bool ParseScheme(struct UrlParser *u, struct Url *h) {
}
static void ParseAuthority(struct UrlParser *u, struct Url *h) {
bool b = false;
int t = 0;
const char *c = NULL;
while (u->i < u->size) {
u->c = u->data[u->i++] & 0xff;
if (u->c == '/' || u->c == '#' || u->c == '?') {
break;
} else if (u->c == '[') {
b = true;
t = -1;
} else if (u->c == ']') {
b = false;
} else if (u->c == ':' && !b) {
t = 0;
} else if (u->c == ':' && t >= 0) {
*u->p++ = ':';
c = u->p;
++t;
} else if (u->c == '@') {
if (c) {
h->user.p = u->q;
h->user.n = c - u->q;
h->user.n = c - 1 - u->q;
h->pass.p = c;
h->pass.n = u->p - c;
c = NULL;
t = 0;
} else {
h->user.p = u->q;
h->user.n = u->p - u->q;
@ -159,9 +162,9 @@ static void ParseAuthority(struct UrlParser *u, struct Url *h) {
*u->p++ = u->c;
}
}
if (c) {
if (t == 1) {
h->host.p = u->q;
h->host.n = c - u->q;
h->host.n = c - 1 - u->q;
h->port.p = c;
h->port.n = u->p - c;
c = NULL;

85
net/http/underlong.c Normal file
View file

@ -0,0 +1,85 @@
/*-*- 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/intrin/pcmpgtb.h"
#include "libc/intrin/pmovmskb.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/str/thompike.h"
#include "libc/str/tpenc.h"
#include "net/http/escape.h"
/**
* Canonicalizes overlong Thompson-Pike encodings.
*
* Please note that the IETF banned these numbers, so if you want to
* enforce their ban you can simply strcmp() the result to check for
* the existence of banned numbers.
*
* @param p is input value
* @param n if -1 implies strlen
* @param z if non-NULL receives output length
* @return allocated NUL-terminated buffer, or NULL w/ errno
*/
char *Underlong(const char *p, size_t n, size_t *z) {
uint64_t w;
char *r, *q;
size_t i, j, m;
wint_t x, a, b;
int8_t v1[16], v2[16], vz[16];
if (z) *z = 0;
if (n == -1) n = p ? strlen(p) : 0;
if ((q = r = malloc(n + 1))) {
for (i = 0; i < n;) {
memset(vz, 0, 16); /* 50x speedup for ASCII */
while (i + 16 < n) {
memcpy(v1, p + i, 16);
pcmpgtb(v2, v1, vz);
if (pmovmskb((void *)v2) != 0xFFFF) break;
memcpy(q, v1, 16);
q += 16;
i += 16;
}
x = p[i++] & 0xff;
if (x >= 0300) {
a = ThomPikeByte(x);
m = ThomPikeLen(x) - 1;
if (i + m <= n) {
for (j = 0;;) {
b = p[i + j] & 0xff;
if (!ThomPikeCont(b)) break;
a = ThomPikeMerge(a, b);
if (++j == m) {
x = a;
i += j;
break;
}
}
}
}
w = tpenc(x);
do {
*q++ = w;
} while ((w >>= 8));
}
if (z) *z = q - r;
*q++ = '\0';
if ((q = realloc(r, q - r))) r = q;
}
return r;
}

View file

@ -20,7 +20,7 @@
#include "libc/str/str.h"
#include "libc/str/thompike.h"
#include "libc/str/tpenc.h"
#include "net/http/http.h"
#include "net/http/escape.h"
/**
* Filters out control codes from string.
@ -29,6 +29,10 @@
* want full blown C string literal escaping, but we don't want things
* like raw ANSI control codes from untrusted devices in our terminals.
*
* This function also canonicalizes overlong encodings. Therefore it
* isn't necessary to say VisualizeControlCodes(Underlong(𝑥))) since
* VisualizeControlCodes(𝑥) will do the same thing.
*
* @param data is input value
* @param size if -1 implies strlen
* @param out_size if non-NULL receives output length