mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 23:08:31 +00:00
Make more major improvements to redbean
- POSIX regular expressions for Lua - Improved protocol parsing and encoding - Additional APIs for ZIP storage retrieval - Fix st_mode issue on NT for regular files - Generalized APIs for URL and Host handling - Worked out the kinks in resource resolution - Allow for custom error pages like /404.html
This commit is contained in:
parent
26ac6871da
commit
4effa23528
74 changed files with 3710 additions and 14246 deletions
144
net/http/encodeurl.c
Normal file
144
net/http/encodeurl.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*-*- 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/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "net/http/escape.h"
|
||||
#include "net/http/url.h"
|
||||
|
||||
static size_t DimensionUrl(struct Url *h) {
|
||||
size_t i, n;
|
||||
n = 0;
|
||||
n += h->scheme.n;
|
||||
n += 1;
|
||||
n += 2;
|
||||
n += h->user.n * 3;
|
||||
n += 1;
|
||||
n += h->pass.n * 3;
|
||||
n += 1;
|
||||
n += 1;
|
||||
n += h->host.n * 3;
|
||||
n += 1;
|
||||
n += 1;
|
||||
n += h->port.n * 3;
|
||||
n += 1;
|
||||
n += h->path.n * 3;
|
||||
n += 1;
|
||||
n += h->params.n;
|
||||
for (i = 0; i < h->params.n; ++i) {
|
||||
n += h->params.p[i].key.n * 3;
|
||||
n += 1;
|
||||
n += h->params.p[i].val.n * 3;
|
||||
}
|
||||
n += 1;
|
||||
n += h->fragment.n * 3;
|
||||
n += 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
static bool NeedsSquareBrackets(struct Url *h) {
|
||||
int c;
|
||||
size_t i;
|
||||
if (!memchr(h->host.p, ':', h->host.n)) return false;
|
||||
if (h->pass.p) return true;
|
||||
if (h->host.n >= 4 && h->host.p[0] == 'v' && h->host.p[2] == '.' &&
|
||||
kHexToInt[h->host.p[1] & 0xFF] != -1) {
|
||||
for (i = 3; i < h->host.n; ++i) {
|
||||
if (kEscapeIp[h->host.p[i] & 0xFF]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < h->host.n; ++i) {
|
||||
c = h->host.p[i] & 0xFF;
|
||||
if (!(kHexToInt[c] || c == '.' || c == ':')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes URL.
|
||||
*
|
||||
* @param z if not null receives string length of result
|
||||
* @return nul-terminated url string needing free
|
||||
* @see ParseUrl()
|
||||
*/
|
||||
char *EncodeUrl(struct Url *h, size_t *z) {
|
||||
size_t i, n;
|
||||
char *m, *p;
|
||||
if ((p = m = malloc(DimensionUrl(h)))) {
|
||||
if (h->scheme.n) {
|
||||
p = mempcpy(p, h->scheme.p, h->scheme.n);
|
||||
*p++ = ':';
|
||||
}
|
||||
if (h->host.p) {
|
||||
*p++ = '/';
|
||||
*p++ = '/';
|
||||
if (h->user.p) {
|
||||
p = EscapeUrlView(p, &h->user, kEscapeAuthority);
|
||||
if (h->pass.p) {
|
||||
*p++ = ':';
|
||||
p = EscapeUrlView(p, &h->pass, kEscapeAuthority);
|
||||
}
|
||||
*p++ = '@';
|
||||
}
|
||||
if (h->host.p) {
|
||||
if (NeedsSquareBrackets(h)) {
|
||||
*p++ = '[';
|
||||
p = EscapeUrlView(p, &h->host, kEscapeIp);
|
||||
*p++ = ']';
|
||||
} else {
|
||||
p = EscapeUrlView(p, &h->host, kEscapeAuthority);
|
||||
}
|
||||
if (h->port.p) {
|
||||
*p++ = ':';
|
||||
p = EscapeUrlView(p, &h->port, kEscapeAuthority);
|
||||
}
|
||||
}
|
||||
if (h->path.n && h->path.p[0] != '/') {
|
||||
*p++ = '/';
|
||||
}
|
||||
}
|
||||
p = EscapeUrlView(p, &h->path, kEscapePath);
|
||||
if (h->params.p) {
|
||||
*p++ = '?';
|
||||
for (i = 0; i < h->params.n; ++i) {
|
||||
if (i) *p++ = '&';
|
||||
p = EscapeUrlView(p, &h->params.p[i].key, kEscapeParam);
|
||||
if (h->params.p[i].val.p) {
|
||||
*p++ = '=';
|
||||
p = EscapeUrlView(p, &h->params.p[i].val, kEscapeParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (h->fragment.p) {
|
||||
*p++ = '#';
|
||||
p = EscapeUrlView(p, &h->fragment, kEscapeFragment);
|
||||
}
|
||||
n = p - m;
|
||||
*p++ = '\0';
|
||||
if ((p = realloc(m, p - m))) m = p;
|
||||
} else {
|
||||
n = 0;
|
||||
}
|
||||
if (z) *z = n;
|
||||
return m;
|
||||
}
|
|
@ -8,12 +8,24 @@ struct EscapeResult {
|
|||
size_t size;
|
||||
};
|
||||
|
||||
extern const signed char kHexToInt[256];
|
||||
extern const char kEscapeAuthority[256];
|
||||
extern const char kEscapeIp[256];
|
||||
extern const char kEscapePath[256];
|
||||
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 EscapeUrlPath(const char *, size_t);
|
||||
struct EscapeResult EscapeUrlParam(const char *, size_t);
|
||||
struct EscapeResult EscapeUrlFragment(const char *, size_t);
|
||||
struct EscapeResult EscapeUrlPathSegment(const char *, size_t);
|
||||
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);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 │
|
||||
│ 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 │
|
||||
|
@ -16,15 +16,13 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "net/http/uri.h"
|
||||
#include "net/http/escape.h"
|
||||
|
||||
struct UriSlice uripath(const struct Uri *uri) {
|
||||
if (uri->segs.i) {
|
||||
return (struct UriSlice){
|
||||
uri->segs.p[0].i,
|
||||
(uri->segs.p[uri->segs.i - 1].n +
|
||||
(uri->segs.p[uri->segs.i - 1].i - uri->segs.p[0].i))};
|
||||
} else {
|
||||
return (struct UriSlice){0, 0};
|
||||
}
|
||||
/**
|
||||
* Escapes URL fragment.
|
||||
*
|
||||
* @param size if -1 implies strlen
|
||||
*/
|
||||
struct EscapeResult EscapeFragment(const char *data, size_t size) {
|
||||
return EscapeUrl(data, size, kEscapeFragment);
|
||||
}
|
28
net/http/escapehost.c
Normal file
28
net/http/escapehost.c
Normal 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/escape.h"
|
||||
|
||||
/**
|
||||
* Escapes URL host or registry name.
|
||||
*
|
||||
* @param size if -1 implies strlen
|
||||
*/
|
||||
struct EscapeResult EscapeHost(const char *data, size_t size) {
|
||||
return EscapeUrl(data, size, kEscapeAuthority);
|
||||
}
|
|
@ -16,17 +16,21 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
|
||||
/**
|
||||
* Escapes HTML entities.
|
||||
*
|
||||
* @param size if -1 implies strlen
|
||||
*/
|
||||
struct EscapeResult EscapeHtml(const char *data, size_t size) {
|
||||
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])) {
|
||||
|
|
30
net/http/escapeip.c
Normal file
30
net/http/escapeip.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- 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/escape.h"
|
||||
|
||||
/**
|
||||
* Escapes URL IP-literal.
|
||||
*
|
||||
* This is the same as EscapeHost except colon is permitted.
|
||||
*
|
||||
* @param size if -1 implies strlen
|
||||
*/
|
||||
struct EscapeResult EscapeIp(const char *data, size_t size) {
|
||||
return EscapeUrl(data, size, kEscapeAuthority);
|
||||
}
|
28
net/http/escapeparam.c
Normal file
28
net/http/escapeparam.c
Normal 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/escape.h"
|
||||
|
||||
/**
|
||||
* Escapes query/form name/parameter.
|
||||
*
|
||||
* @param size if -1 implies strlen
|
||||
*/
|
||||
struct EscapeResult EscapeParam(const char *data, size_t size) {
|
||||
return EscapeUrl(data, size, kEscapeParam);
|
||||
}
|
28
net/http/escapepass.c
Normal file
28
net/http/escapepass.c
Normal 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/escape.h"
|
||||
|
||||
/**
|
||||
* Escapes URL password.
|
||||
*
|
||||
* @param size if -1 implies strlen
|
||||
*/
|
||||
struct EscapeResult EscapePass(const char *data, size_t size) {
|
||||
return EscapeUrl(data, size, kEscapeAuthority);
|
||||
}
|
30
net/http/escapepath.c
Normal file
30
net/http/escapepath.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- 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/escape.h"
|
||||
|
||||
/**
|
||||
* Escapes URL path.
|
||||
*
|
||||
* This is the same as EscapePathSegment() except slash is allowed.
|
||||
*
|
||||
* @param size if -1 implies strlen
|
||||
*/
|
||||
struct EscapeResult EscapePath(const char *data, size_t size) {
|
||||
return EscapeUrl(data, size, kEscapePath);
|
||||
}
|
31
net/http/escapesegment.c
Normal file
31
net/http/escapesegment.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*-*- 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/escape.h"
|
||||
|
||||
/**
|
||||
* Escapes URL path segment.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
struct EscapeResult EscapeSegment(const char *data, size_t size) {
|
||||
return EscapeUrl(data, size, kEscapeSegment);
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
#include "net/http/url.h"
|
||||
|
||||
/**
|
||||
* Escapes URL component using generic table.
|
||||
|
@ -26,29 +27,22 @@
|
|||
* Always using UTF-8 is a good idea.
|
||||
*
|
||||
* @param size if -1 implies strlen
|
||||
* @see EscapeUrlParam
|
||||
* @see EscapeUrlFragment
|
||||
* @see EscapeUrlPathSegment
|
||||
* @see kEscapeAuthority
|
||||
* @see kEscapeIpLiteral
|
||||
* @see kEscapePath
|
||||
* @see kEscapePathSegment
|
||||
* @see kEscapeParam
|
||||
* @see kEscapeFragment
|
||||
*/
|
||||
struct EscapeResult EscapeUrl(const char *data, size_t size,
|
||||
const char xlat[hasatleast 256]) {
|
||||
int c;
|
||||
char *p;
|
||||
size_t i;
|
||||
struct UrlView v;
|
||||
struct EscapeResult r;
|
||||
if (size == -1) size = data ? strlen(data) : 0;
|
||||
p = r.data = xmalloc(size * 6 + 1);
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (!xlat[(c = data[i] & 0xff)]) {
|
||||
*p++ = c;
|
||||
} else {
|
||||
p[0] = '%';
|
||||
p[1] = "0123456789ABCDEF"[(c & 0xF0) >> 4];
|
||||
p[2] = "0123456789ABCDEF"[(c & 0x0F) >> 0];
|
||||
p += 3;
|
||||
}
|
||||
}
|
||||
r.size = p - r.data;
|
||||
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';
|
||||
return r;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 │
|
||||
│ 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 │
|
||||
|
@ -16,20 +16,23 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "net/http/geturischeme.inc"
|
||||
#include "net/http/uri.h"
|
||||
#include "net/http/url.h"
|
||||
|
||||
/**
|
||||
* Returns nonzero numeric code for resource paradigms we like.
|
||||
*
|
||||
* Lookups are case-insensitive and performed using a hash table that's
|
||||
* literally perfect.
|
||||
* Escapes URL component using generic table w/ stpcpy() api.
|
||||
*/
|
||||
enum UriScheme urischeme(struct UriSlice scheme, const char *str) {
|
||||
const struct UriSchemeSlot *slot;
|
||||
if ((slot = in_word_set(str + scheme.i, scheme.n))) {
|
||||
return slot->code;
|
||||
} else {
|
||||
return 0;
|
||||
char *EscapeUrlView(char *p, struct UrlView *v, const char T[256]) {
|
||||
int c;
|
||||
size_t i;
|
||||
for (i = 0; i < v->n; ++i) {
|
||||
if (!T[(c = v->p[i] & 0xFF)]) {
|
||||
*p++ = c;
|
||||
} else {
|
||||
p[0] = '%';
|
||||
p[1] = "0123456789ABCDEF"[(c & 0xF0) >> 4];
|
||||
p[2] = "0123456789ABCDEF"[(c & 0x0F) >> 0];
|
||||
p += 3;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
28
net/http/escapeuser.c
Normal file
28
net/http/escapeuser.c
Normal 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/escape.h"
|
||||
|
||||
/**
|
||||
* Escapes URL user name.
|
||||
*
|
||||
* @param size if -1 implies strlen
|
||||
*/
|
||||
struct EscapeResult EscapeUser(const char *data, size_t size) {
|
||||
return EscapeUrl(data, size, kEscapeAuthority);
|
||||
}
|
|
@ -20,14 +20,14 @@ Allow, kHttpAllow
|
|||
Authorization, kHttpAuthorization
|
||||
Cache-Control, kHttpCacheControl
|
||||
Chunked, kHttpChunked
|
||||
Close, kHttpClose
|
||||
Link, kHttpLink
|
||||
Connection, kHttpConnection
|
||||
Content-Base, kHttpContentBase
|
||||
Content-Encoding, kHttpContentEncoding
|
||||
Content-Language, kHttpContentLanguage
|
||||
Content-Length, kHttpContentLength
|
||||
Content-Location, kHttpContentLocation
|
||||
Content-Md5, kHttpContentMd5
|
||||
Content-MD5, kHttpContentMd5
|
||||
Content-Range, kHttpContentRange
|
||||
Content-Type, kHttpContentType
|
||||
Date, kHttpDate
|
||||
|
@ -60,7 +60,6 @@ Vary, kHttpVary
|
|||
Warning, kHttpWarning
|
||||
WWW-Authenticate, kHttpWwwAuthenticate
|
||||
Last-Modified, kHttpLastModified
|
||||
Cookie, kHttpCookie
|
||||
Trailer, kHttpTrailer
|
||||
TE, kHttpTe
|
||||
DNT, kHttpDnt
|
||||
|
@ -69,3 +68,4 @@ Content-Disposition, kHttpContentDisposition
|
|||
Content-Description, kHttpContentDescription
|
||||
Origin, kHttpOrigin
|
||||
Upgrade-Insecure-Requests, kHttpUpgradeInsecureRequests
|
||||
URI, kHttpUri
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* ANSI-C code produced by gperf version 3.1 */
|
||||
/* Command-line: gperf gethttpheader.gperf */
|
||||
/* Computed positions: -k'3-4,10' */
|
||||
/* clang-format off */
|
||||
|
||||
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
||||
|
@ -108,13 +107,13 @@ hash (register const char *str, register size_t len)
|
|||
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, 5, 30, 55, 0,
|
||||
35, 30, 0, 35, 98, 40, 0, 30, 0, 20,
|
||||
55, 98, 0, 5, 10, 5, 0, 5, 20, 30,
|
||||
98, 98, 98, 98, 98, 98, 98, 5, 5, 30,
|
||||
55, 0, 35, 30, 0, 35, 98, 40, 0, 30,
|
||||
0, 20, 55, 98, 0, 5, 10, 5, 0, 5,
|
||||
20, 30, 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,
|
||||
|
@ -153,144 +152,146 @@ hash (register const char *str, register size_t len)
|
|||
return hval;
|
||||
}
|
||||
|
||||
static const struct HttpHeaderSlot *
|
||||
const struct HttpHeaderSlot *
|
||||
LookupHttpHeader (register const char *str, register size_t len)
|
||||
{
|
||||
static const struct HttpHeaderSlot wordlist[] =
|
||||
{
|
||||
{""}, {""},
|
||||
#line 65 "gethttpheader.gperf"
|
||||
#line 64 "gethttpheader.gperf"
|
||||
{"TE", kHttpTe},
|
||||
#line 18 "gethttpheader.gperf"
|
||||
{"Age", kHttpAge},
|
||||
{""}, {""},
|
||||
#line 58 "gethttpheader.gperf"
|
||||
{"Server", kHttpServer},
|
||||
#line 60 "gethttpheader.gperf"
|
||||
{"Warning", kHttpWarning},
|
||||
#line 23 "gethttpheader.gperf"
|
||||
{"Link", kHttpLink},
|
||||
{""},
|
||||
#line 56 "gethttpheader.gperf"
|
||||
{"Public", kHttpPublic},
|
||||
#line 50 "gethttpheader.gperf"
|
||||
{"Referer", kHttpReferer},
|
||||
#line 54 "gethttpheader.gperf"
|
||||
{"Via", kHttpVia},
|
||||
{""},
|
||||
#line 24 "gethttpheader.gperf"
|
||||
{"Connection", kHttpConnection},
|
||||
#line 56 "gethttpheader.gperf"
|
||||
{"Public", kHttpPublic},
|
||||
{""},
|
||||
#line 22 "gethttpheader.gperf"
|
||||
{"Chunked", kHttpChunked},
|
||||
#line 66 "gethttpheader.gperf"
|
||||
#line 65 "gethttpheader.gperf"
|
||||
{"DNT", kHttpDnt},
|
||||
#line 33 "gethttpheader.gperf"
|
||||
{"Date", kHttpDate},
|
||||
{""}, {""}, {""}, {""},
|
||||
#line 37 "gethttpheader.gperf"
|
||||
{"Host", kHttpHost},
|
||||
#line 53 "gethttpheader.gperf"
|
||||
{"User-Agent", kHttpUserAgent},
|
||||
#line 57 "gethttpheader.gperf"
|
||||
{"Retry-After", kHttpRetryAfter},
|
||||
#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},
|
||||
#line 19 "gethttpheader.gperf"
|
||||
{"Allow", kHttpAllow},
|
||||
{""},
|
||||
#line 26 "gethttpheader.gperf"
|
||||
{"Content-Encoding", kHttpContentEncoding},
|
||||
#line 25 "gethttpheader.gperf"
|
||||
{"Content-Base", kHttpContentBase},
|
||||
#line 31 "gethttpheader.gperf"
|
||||
{"Content-Range", kHttpContentRange},
|
||||
#line 69 "gethttpheader.gperf"
|
||||
#line 68 "gethttpheader.gperf"
|
||||
{"Content-Description", kHttpContentDescription},
|
||||
#line 23 "gethttpheader.gperf"
|
||||
{"Close", kHttpClose},
|
||||
{""},
|
||||
#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 20 "gethttpheader.gperf"
|
||||
{"Authorization", kHttpAuthorization},
|
||||
#line 59 "gethttpheader.gperf"
|
||||
{"Vary", kHttpVary},
|
||||
#line 49 "gethttpheader.gperf"
|
||||
{"Range", kHttpRange},
|
||||
#line 14 "gethttpheader.gperf"
|
||||
{"Accept", kHttpAccept},
|
||||
#line 52 "gethttpheader.gperf"
|
||||
{"Upgrade", kHttpUpgrade},
|
||||
#line 41 "gethttpheader.gperf"
|
||||
{"If-Range", kHttpIfRange},
|
||||
#line 34 "gethttpheader.gperf"
|
||||
{"ETag", kHttpEtag},
|
||||
{""},
|
||||
#line 45 "gethttpheader.gperf"
|
||||
{"Pragma", kHttpPragma},
|
||||
#line 50 "gethttpheader.gperf"
|
||||
{"Referer", kHttpReferer},
|
||||
#line 55 "gethttpheader.gperf"
|
||||
{"Location", kHttpLocation},
|
||||
{""},
|
||||
#line 17 "gethttpheader.gperf"
|
||||
{"Accept-Language", kHttpAcceptLanguage},
|
||||
#line 60 "gethttpheader.gperf"
|
||||
{"Warning", kHttpWarning},
|
||||
#line 20 "gethttpheader.gperf"
|
||||
{"Authorization", kHttpAuthorization},
|
||||
{""}, {""},
|
||||
#line 29 "gethttpheader.gperf"
|
||||
{"Content-Location", kHttpContentLocation},
|
||||
#line 64 "gethttpheader.gperf"
|
||||
#line 63 "gethttpheader.gperf"
|
||||
{"Trailer", kHttpTrailer},
|
||||
#line 55 "gethttpheader.gperf"
|
||||
{"Location", kHttpLocation},
|
||||
#line 59 "gethttpheader.gperf"
|
||||
{"Vary", kHttpVary},
|
||||
#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},
|
||||
#line 53 "gethttpheader.gperf"
|
||||
{"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 61 "gethttpheader.gperf"
|
||||
{"WWW-Authenticate", kHttpWwwAuthenticate},
|
||||
#line 32 "gethttpheader.gperf"
|
||||
{"Content-Type", kHttpContentType},
|
||||
#line 21 "gethttpheader.gperf"
|
||||
{"Cache-Control", kHttpCacheControl},
|
||||
#line 36 "gethttpheader.gperf"
|
||||
{"From", kHttpFrom},
|
||||
#line 71 "gethttpheader.gperf"
|
||||
{"Upgrade-Insecure-Requests", kHttpUpgradeInsecureRequests},
|
||||
#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 67 "gethttpheader.gperf"
|
||||
{"Expect", kHttpExpect},
|
||||
#line 44 "gethttpheader.gperf"
|
||||
{"Max-Forwards", kHttpMaxForwards},
|
||||
#line 62 "gethttpheader.gperf"
|
||||
{"Last-Modified", kHttpLastModified},
|
||||
#line 68 "gethttpheader.gperf"
|
||||
{"Content-Disposition", kHttpContentDisposition},
|
||||
#line 43 "gethttpheader.gperf"
|
||||
{"Keep-Alive", kHttpKeepAlive},
|
||||
#line 63 "gethttpheader.gperf"
|
||||
{"Cookie", kHttpCookie},
|
||||
{""},
|
||||
#line 38 "gethttpheader.gperf"
|
||||
{"If-Match", kHttpIfMatch},
|
||||
{""}, {""},
|
||||
#line 70 "gethttpheader.gperf"
|
||||
{"Origin", kHttpOrigin},
|
||||
{"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},
|
||||
{""}, {""}, {""},
|
||||
#line 16 "gethttpheader.gperf"
|
||||
{"Accept-Encoding", kHttpAcceptEncoding},
|
||||
#line 30 "gethttpheader.gperf"
|
||||
{"Content-Md5", kHttpContentMd5},
|
||||
#line 39 "gethttpheader.gperf"
|
||||
{"If-Modified-Since", kHttpIfModifiedSince},
|
||||
{"Content-MD5", kHttpContentMd5},
|
||||
{""},
|
||||
#line 62 "gethttpheader.gperf"
|
||||
{"Last-Modified", kHttpLastModified},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{""}, {""},
|
||||
#line 42 "gethttpheader.gperf"
|
||||
{"If-Unmodified-Since", kHttpIfUnmodifiedSince},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
#line 35 "gethttpheader.gperf"
|
||||
{"Expires", kHttpExpires}
|
||||
{"Expires", kHttpExpires},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
#line 44 "gethttpheader.gperf"
|
||||
{"Max-Forwards", kHttpMaxForwards}
|
||||
};
|
||||
|
||||
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
||||
|
|
|
@ -38,8 +38,8 @@ const char *GetHttpHeaderName(int h) {
|
|||
return "Cache-Control";
|
||||
case kHttpChunked:
|
||||
return "Chunked";
|
||||
case kHttpClose:
|
||||
return "Close";
|
||||
case kHttpLink:
|
||||
return "Link";
|
||||
case kHttpConnection:
|
||||
return "Connection";
|
||||
case kHttpContentBase:
|
||||
|
@ -53,7 +53,7 @@ const char *GetHttpHeaderName(int h) {
|
|||
case kHttpContentLocation:
|
||||
return "Content-Location";
|
||||
case kHttpContentMd5:
|
||||
return "Content-Md5";
|
||||
return "Content-MD5";
|
||||
case kHttpContentRange:
|
||||
return "Content-Range";
|
||||
case kHttpContentType:
|
||||
|
@ -118,8 +118,6 @@ const char *GetHttpHeaderName(int h) {
|
|||
return "WWW-Authenticate";
|
||||
case kHttpLastModified:
|
||||
return "Last-Modified";
|
||||
case kHttpCookie:
|
||||
return "Cookie";
|
||||
case kHttpTrailer:
|
||||
return "Trailer";
|
||||
case kHttpTe:
|
||||
|
@ -136,6 +134,8 @@ const char *GetHttpHeaderName(int h) {
|
|||
return "Origin";
|
||||
case kHttpUpgradeInsecureRequests:
|
||||
return "Upgrade-Insecure-Requests";
|
||||
case kHttpUri:
|
||||
return "URI";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
#include "net/http/http.h"
|
||||
|
||||
/**
|
||||
* Returns small number for HTTP method, or -1 if not found.
|
||||
* Returns small number for HTTP method, or 0 if not found.
|
||||
*/
|
||||
int GetHttpMethod(const char *str, size_t len) {
|
||||
const struct HttpMethodSlot *slot;
|
||||
if ((slot = LookupHttpMethod(str, len))) {
|
||||
return slot->code;
|
||||
} else {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 │
|
||||
│ 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 │
|
||||
|
@ -17,54 +17,38 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "net/http/uri.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
/* TODO(jart): Rewrite in C */
|
||||
|
||||
#define static
|
||||
|
||||
/* clang-format off */
|
||||
%% machine uricspn;
|
||||
%% write data;
|
||||
/* clang-format on */
|
||||
|
||||
int uricspn(const char *data, size_t size) {
|
||||
int uricspn$avx(const char *, size_t) hidden;
|
||||
const char *p, *pe;
|
||||
int cs;
|
||||
|
||||
assert(data || !size);
|
||||
assert(size <= 0x7ffff000);
|
||||
assert(size <= 0x7ffff000);
|
||||
|
||||
if (X86_HAVE(AVX)) {
|
||||
return uricspn$avx(data, size);
|
||||
}
|
||||
|
||||
p = data;
|
||||
pe = data + size;
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
%%{
|
||||
mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")";
|
||||
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",";
|
||||
unreserved = alnum | mark;
|
||||
uric = reserved | unreserved | "%";
|
||||
machina := uric*;
|
||||
}%%
|
||||
|
||||
%% write init;
|
||||
cs = uricspn_en_machina;
|
||||
%% write exec;
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
if (cs >= uricspn_first_final) {
|
||||
return p - data;
|
||||
} else {
|
||||
return einval();
|
||||
/**
|
||||
* Returns true if standard header has substring.
|
||||
*
|
||||
* @param m is message parsed by ParseHttpRequest
|
||||
* @param b is buffer that ParseHttpRequest 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
|
||||
* @return true if substring present
|
||||
*/
|
||||
bool HeaderHasSubstring(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;
|
||||
if (m->headers[h].a) {
|
||||
if (memmem(b + m->headers[h].a, m->headers[h].b - m->headers[h].a, s, n)) {
|
||||
return true;
|
||||
}
|
||||
if (kHttpRepeatable[h]) {
|
||||
for (i = 0; i < m->xheaders.n; ++i) {
|
||||
if (GetHttpHeader(b + m->xheaders.p[i].k.a,
|
||||
m->xheaders.p[i].k.b - m->xheaders.p[i].k.a) == h &&
|
||||
memmem(b + m->xheaders.p[i].v.a,
|
||||
m->xheaders.p[i].v.b - m->xheaders.p[i].v.a, s, n)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -3,23 +3,23 @@
|
|||
#include "libc/alg/alg.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
|
||||
#define kHttpGet 0
|
||||
#define kHttpHead 1
|
||||
#define kHttpPost 2
|
||||
#define kHttpPut 3
|
||||
#define kHttpDelete 4
|
||||
#define kHttpOptions 5
|
||||
#define kHttpConnect 6
|
||||
#define kHttpTrace 7
|
||||
#define kHttpCopy 8
|
||||
#define kHttpLock 9
|
||||
#define kHttpMerge 10
|
||||
#define kHttpMkcol 11
|
||||
#define kHttpMove 12
|
||||
#define kHttpNotify 13
|
||||
#define kHttpPatch 14
|
||||
#define kHttpReport 15
|
||||
#define kHttpUnlock 16
|
||||
#define kHttpGet 1
|
||||
#define kHttpHead 2
|
||||
#define kHttpPost 3
|
||||
#define kHttpPut 4
|
||||
#define kHttpDelete 5
|
||||
#define kHttpOptions 6
|
||||
#define kHttpConnect 7
|
||||
#define kHttpTrace 8
|
||||
#define kHttpCopy 9
|
||||
#define kHttpLock 10
|
||||
#define kHttpMerge 11
|
||||
#define kHttpMkcol 12
|
||||
#define kHttpMove 13
|
||||
#define kHttpNotify 14
|
||||
#define kHttpPatch 15
|
||||
#define kHttpReport 16
|
||||
#define kHttpUnlock 17
|
||||
|
||||
#define kHttpAccept 0
|
||||
#define kHttpAcceptCharset 1
|
||||
|
@ -30,7 +30,7 @@
|
|||
#define kHttpAuthorization 6
|
||||
#define kHttpCacheControl 7
|
||||
#define kHttpChunked 8
|
||||
#define kHttpClose 9
|
||||
#define kHttpLink 9
|
||||
#define kHttpConnection 10
|
||||
#define kHttpContentBase 11
|
||||
#define kHttpContentEncoding 12
|
||||
|
@ -70,15 +70,15 @@
|
|||
#define kHttpWarning 46
|
||||
#define kHttpWwwAuthenticate 47
|
||||
#define kHttpLastModified 48
|
||||
#define kHttpCookie 49
|
||||
#define kHttpTrailer 50
|
||||
#define kHttpTe 51
|
||||
#define kHttpDnt 52
|
||||
#define kHttpExpect 53
|
||||
#define kHttpContentDisposition 54
|
||||
#define kHttpContentDescription 55
|
||||
#define kHttpOrigin 56
|
||||
#define kHttpUpgradeInsecureRequests 57
|
||||
#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
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
@ -89,14 +89,17 @@ struct HttpRequestSlice {
|
|||
};
|
||||
|
||||
struct HttpRequest {
|
||||
int i, t, a, method;
|
||||
int i, a;
|
||||
unsigned char t;
|
||||
unsigned char method;
|
||||
unsigned char version;
|
||||
struct HttpRequestSlice k;
|
||||
struct HttpRequestSlice uri;
|
||||
struct HttpRequestSlice version;
|
||||
struct HttpRequestSlice scratch;
|
||||
struct HttpRequestSlice headers[kHttpHeadersMax];
|
||||
struct HttpRequestSlice xmethod;
|
||||
struct HttpRequestHeaders {
|
||||
size_t n;
|
||||
unsigned n;
|
||||
struct HttpRequestHeader {
|
||||
struct HttpRequestSlice k;
|
||||
struct HttpRequestSlice v;
|
||||
|
@ -104,19 +107,22 @@ struct HttpRequest {
|
|||
} xheaders;
|
||||
};
|
||||
|
||||
extern const char kHttpMethod[17][8];
|
||||
extern const char kHttpToken[256];
|
||||
extern const char kHttpMethod[18][8];
|
||||
extern const bool kHttpRepeatable[kHttpHeadersMax];
|
||||
|
||||
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);
|
||||
ssize_t ParseContentLength(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 *);
|
||||
unsigned ParseHttpVersion(const char *, size_t);
|
||||
int64_t ParseHttpDateTime(const char *, size_t);
|
||||
const char *GetHttpReason(int);
|
||||
const char *GetHttpHeaderName(int);
|
||||
|
@ -126,7 +132,10 @@ 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 IsAcceptableHostPort(const char *, size_t);
|
||||
bool IsAcceptableHost(const char *, size_t);
|
||||
bool IsAcceptablePort(const char *, size_t);
|
||||
int64_t ParseIp(const char *, size_t);
|
||||
bool IsMimeType(const char *, size_t, const char *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -20,87 +20,62 @@
|
|||
#include "net/http/http.h"
|
||||
|
||||
/**
|
||||
* Returns true if HOST[:PORT] seems legit.
|
||||
* Returns true if host seems legit.
|
||||
*
|
||||
* This parser is permissive and imposes the subset of restrictions
|
||||
* that'll make things easier for the caller. For example, only one
|
||||
* colon is allowed to appear, which makes memchr() so much easier.
|
||||
* This function may be called after ParseUrl() or ParseHost() has
|
||||
* already handled things like percent encoding. There's currently
|
||||
* no support for IPv6 and IPv7.
|
||||
*
|
||||
* Here's examples of permitted inputs:
|
||||
*
|
||||
* - ""
|
||||
* - 1.2.3.4
|
||||
* - 1.2.3.4.arpa
|
||||
* - 1.2.3.4:8080
|
||||
* - localservice
|
||||
* - hello.example
|
||||
* - _hello.example
|
||||
* - -hello.example
|
||||
* - hi-there.example
|
||||
* - hello.example:443
|
||||
*
|
||||
* Here's some examples of forbidden inputs:
|
||||
*
|
||||
* - :443
|
||||
* - ::1
|
||||
* - 1.2.3
|
||||
* - 1.2.3.4.5
|
||||
* - [::1]:8080
|
||||
* - .hi.example
|
||||
* - hi..example
|
||||
* - hi.example::80
|
||||
* - hi.example:-80
|
||||
* - hi.example:65536
|
||||
*
|
||||
* @param n if -1 implies strlen
|
||||
*/
|
||||
bool IsAcceptableHostPort(const char *s, size_t n) {
|
||||
bool IsAcceptableHost(const char *s, size_t n) {
|
||||
size_t i;
|
||||
bool isip;
|
||||
int c, t, p, b, j;
|
||||
int c, b, j;
|
||||
if (n == -1) n = s ? strlen(s) : 0;
|
||||
if (!n) return false;
|
||||
for (isip = true, b = j = p = t = i = 0; i < n; ++i) {
|
||||
if (!n) return true;
|
||||
for (isip = true, b = j = i = 0; i < n; ++i) {
|
||||
c = s[i] & 255;
|
||||
if (!t) {
|
||||
if (c == ':') {
|
||||
if (!i || s[i - 1] == '.') {
|
||||
return false;
|
||||
} else {
|
||||
t = 1;
|
||||
}
|
||||
} else if (c == '.' && (!i || s[i - 1] == '.')) {
|
||||
return false;
|
||||
} else if (!(isalnum(c) || c == '-' || c == '_' || c == '.')) {
|
||||
return false;
|
||||
}
|
||||
if (isip) {
|
||||
if (isdigit(c)) {
|
||||
b *= 10;
|
||||
b += c - '0';
|
||||
if (b > 255) {
|
||||
return false;
|
||||
}
|
||||
} else if (c == '.') {
|
||||
b = 0;
|
||||
++j;
|
||||
} else {
|
||||
isip = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (c == ':') {
|
||||
return false;
|
||||
} else if ('0' <= c && c <= '9') {
|
||||
p *= 10;
|
||||
p += c - '0';
|
||||
if (p > 65535) {
|
||||
if (c == '.' && (!i || s[i - 1] == '.')) {
|
||||
return false;
|
||||
} else if (!(isalnum(c) || c == '-' || c == '_' || c == '.')) {
|
||||
return false;
|
||||
}
|
||||
if (isip) {
|
||||
if (isdigit(c)) {
|
||||
b *= 10;
|
||||
b += c - '0';
|
||||
if (b > 255) {
|
||||
return false;
|
||||
}
|
||||
} else if (c == '.') {
|
||||
b = 0;
|
||||
++j;
|
||||
} else {
|
||||
return false;
|
||||
isip = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isip && j != 3) return false;
|
||||
if (!t && s[i - 1] == '.') return false;
|
||||
if (i && s[i - 1] == '.') return false;
|
||||
return true;
|
||||
}
|
|
@ -21,7 +21,7 @@
|
|||
#include "net/http/http.h"
|
||||
|
||||
/**
|
||||
* Returns true if request path seems legit.
|
||||
* Returns true if path seems legit.
|
||||
*
|
||||
* 1. The substring "//" is disallowed.
|
||||
* 2. We won't serve hidden files (segment starts with '.').
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 │
|
||||
│ 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 │
|
||||
|
@ -16,30 +16,41 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "net/http/uri.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
/* TODO(jart): Unescape */
|
||||
|
||||
char *urislice2cstr(char *buf, size_t size, struct UriSlice slice,
|
||||
const char *uristr, const char *defaultval) {
|
||||
size_t n;
|
||||
const char *p;
|
||||
if (size) {
|
||||
if (slice.n) {
|
||||
p = uristr + slice.i;
|
||||
n = slice.n;
|
||||
} else if (defaultval) {
|
||||
p = defaultval;
|
||||
n = strlen(defaultval);
|
||||
/**
|
||||
* Returns true if port seems legit.
|
||||
*
|
||||
* Here's examples of permitted inputs:
|
||||
*
|
||||
* - ""
|
||||
* - 0
|
||||
* - 65535
|
||||
*
|
||||
* Here's some examples of forbidden inputs:
|
||||
*
|
||||
* - -1
|
||||
* - 65536
|
||||
* - https
|
||||
*
|
||||
* @param n if -1 implies strlen
|
||||
*/
|
||||
bool IsAcceptablePort(const char *s, size_t n) {
|
||||
int p, c;
|
||||
size_t i;
|
||||
if (n == -1) n = s ? strlen(s) : 0;
|
||||
for (p = i = 0; i < n; ++i) {
|
||||
c = s[i] & 255;
|
||||
if ('0' <= c && c <= '9') {
|
||||
p *= 10;
|
||||
p += c - '0';
|
||||
if (p > 65535) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
p = NULL;
|
||||
n = 0;
|
||||
return false;
|
||||
}
|
||||
n = MIN(n, size - 1);
|
||||
memcpy(buf, p, n);
|
||||
buf[n] = '\0';
|
||||
}
|
||||
return buf;
|
||||
return true;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 │
|
||||
│ 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 │
|
||||
|
@ -16,18 +16,18 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
unsigned ParseHttpVersion(const char *p, size_t n) {
|
||||
unsigned x;
|
||||
if (!n) return 9;
|
||||
if (n >= 8 && READ32LE(p) == ('H' | 'T' << 8 | 'T' << 16 | 'P' << 24)) {
|
||||
if (READ32LE(p + 4) == ('/' | '1' << 8 | '.' << 16 | '1' << 24)) {
|
||||
return 101;
|
||||
} else if (READ32LE(p + 4) == ('/' | '1' << 8 | '.' << 16 | '0' << 24)) {
|
||||
return 100;
|
||||
}
|
||||
/**
|
||||
* Returns true if content-type 𝑡 has mime-type 𝑠.
|
||||
*/
|
||||
bool IsMimeType(const char *t, size_t n, const char *s) {
|
||||
size_t i;
|
||||
if (n == -1) n = t ? strlen(t) : 0;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (!s[i]) return !kHttpToken[t[i] & 0xFF];
|
||||
if (kToLower[s[i] & 0xFF] != kToLower[t[i] & 0xFF]) return false;
|
||||
}
|
||||
return -1;
|
||||
return !s[i];
|
||||
}
|
|
@ -19,28 +19,6 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
// http/1.1 token dispatch
|
||||
// 0 is CTLs, SP, ()<>@,;:\"/[]?={}
|
||||
// 1 is what remains of ascii
|
||||
static const char kHttpToken[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 0x20
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, // 0x30
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 0x50
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 0x70
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xc0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xd0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xe0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xf0
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if string is ASCII without delimiters.
|
||||
*
|
||||
|
|
46
net/http/kescapeauthority.c
Normal file
46
net/http/kescapeauthority.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*-*- 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/escape.h"
|
||||
|
||||
// [user[:pass]@]host[:port]|reg_name dispatch
|
||||
// - 0 is -_.!~*'();&=+$,0-9A-Za-z
|
||||
// - 1 is everything else which needs uppercase hex %XX
|
||||
// note that '& can break html
|
||||
// note that '() can break css urls
|
||||
// note that unicode can still be wild
|
||||
// note that IPv6+ can't be encoded this way
|
||||
// note that user can look deceptively like host
|
||||
const char kEscapeAuthority[256] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10
|
||||
1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // 0x20
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, // 0x30
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x40
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, // 0x50
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, // 0x70
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xc0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xd0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xe0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xf0
|
||||
};
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
|
||||
// url fragment dispatch
|
||||
|
@ -25,7 +24,7 @@
|
|||
// note that '& can break html
|
||||
// note that '() can break css urls
|
||||
// note that unicode can still be wild
|
||||
static const char kEscapeUrlFragment[256] = {
|
||||
const char kEscapeFragment[256] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10
|
||||
1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20
|
||||
|
@ -43,12 +42,3 @@ static const char kEscapeUrlFragment[256] = {
|
|||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xe0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xf0
|
||||
};
|
||||
|
||||
/**
|
||||
* Escapes URL fragment.
|
||||
*
|
||||
* @param size if -1 implies strlen
|
||||
*/
|
||||
struct EscapeResult EscapeUrlFragment(const char *data, size_t size) {
|
||||
return EscapeUrl(data, size, kEscapeUrlFragment);
|
||||
}
|
44
net/http/kescapeip.c
Normal file
44
net/http/kescapeip.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*-*- 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/escape.h"
|
||||
|
||||
// Square Bracket IP-literal dispatch
|
||||
// - 0 is -_.!~*'();&=+$,0-9A-Za-z:
|
||||
// - 1 shouldn't be there; exceptions exist; escape it
|
||||
// same as kEscapeAuthority but with colon
|
||||
// note that '& can break html
|
||||
// note that '() can break css urls
|
||||
const char kEscapeIp[256] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10
|
||||
1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // 0x20
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, // 0x30
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x40
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, // 0x50
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, // 0x70
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xc0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xd0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xe0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xf0
|
||||
};
|
|
@ -16,14 +16,13 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
|
||||
// url query/form name/parameter dispatch
|
||||
// - 0 is -.*_0-9A-Za-z
|
||||
// - 1 is everything else which needs uppercase hex %XX
|
||||
// note that unicode can still be wild
|
||||
static const char kEscapeUrlParam[256] = {
|
||||
const char kEscapeParam[256] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, // 0x20
|
||||
|
@ -41,12 +40,3 @@ static const char kEscapeUrlParam[256] = {
|
|||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xe0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xf0
|
||||
};
|
||||
|
||||
/**
|
||||
* Escapes query/form name/parameter.
|
||||
*
|
||||
* @param size if -1 implies strlen
|
||||
*/
|
||||
struct EscapeResult EscapeUrlParam(const char *data, size_t size) {
|
||||
return EscapeUrl(data, size, kEscapeUrlParam);
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
|
||||
// url path dispatch
|
||||
|
@ -25,7 +24,7 @@
|
|||
// note that '& can break html
|
||||
// note that '() can break css urls
|
||||
// note that unicode can still be wild
|
||||
static const char kEscapeUrlPath[256] = {
|
||||
const char kEscapePath[256] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10
|
||||
1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20
|
||||
|
@ -43,14 +42,3 @@ static const char kEscapeUrlPath[256] = {
|
|||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xe0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xf0
|
||||
};
|
||||
|
||||
/**
|
||||
* Escapes URL path.
|
||||
*
|
||||
* This is the same as EscapeUrlPathSegment() except slash is allowed.
|
||||
*
|
||||
* @param size if -1 implies strlen
|
||||
*/
|
||||
struct EscapeResult EscapeUrlPath(const char *data, size_t size) {
|
||||
return EscapeUrl(data, size, kEscapeUrlPath);
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
|
||||
// url path segment dispatch
|
||||
|
@ -25,7 +24,7 @@
|
|||
// note that '& can break html
|
||||
// note that '() can break css urls
|
||||
// note that unicode can still be wild
|
||||
static const char kEscapeUrlPathSegment[256] = {
|
||||
const char kEscapeSegment[256] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10
|
||||
1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // 0x20
|
||||
|
@ -43,15 +42,3 @@ static const char kEscapeUrlPathSegment[256] = {
|
|||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xe0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xf0
|
||||
};
|
||||
|
||||
/**
|
||||
* Escapes URL path segment.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
struct EscapeResult EscapeUrlPathSegment(const char *data, size_t size) {
|
||||
return EscapeUrl(data, size, kEscapeUrlPathSegment);
|
||||
}
|
38
net/http/khextoint.c
Normal file
38
net/http/khextoint.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*- 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/escape.h"
|
||||
|
||||
const signed char kHexToInt[256] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x20
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 0x30
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x40
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x50
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x60
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x70
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x80
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x90
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xa0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xb0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xc0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xd0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xe0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xf0
|
||||
};
|
|
@ -18,7 +18,8 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "net/http/http.h"
|
||||
|
||||
const char kHttpMethod[17][8] = {
|
||||
const char kHttpMethod[18][8] = {
|
||||
"WUT", //
|
||||
"GET", //
|
||||
"HEAD", //
|
||||
"POST", //
|
||||
|
|
81
net/http/khttprepeatable.c
Normal file
81
net/http/khttprepeatable.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*-*- 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/http.h"
|
||||
|
||||
/**
|
||||
* Set of standard comma-separate HTTP headers that may span lines.
|
||||
*
|
||||
* These headers may specified on multiple lines, e.g.
|
||||
*
|
||||
* Allow: GET
|
||||
* Allow: POST
|
||||
*
|
||||
* Is the same as:
|
||||
*
|
||||
* Allow: GET, POST
|
||||
*
|
||||
* Standard headers that aren't part of this set will be overwritten in
|
||||
* the event that they're specified multiple times. For example,
|
||||
*
|
||||
* Content-Type: application/octet-stream
|
||||
* Content-Type: text/plain; charset=utf-8
|
||||
*
|
||||
* Is the same as:
|
||||
*
|
||||
* Content-Type: text/plain; charset=utf-8
|
||||
*
|
||||
* This set exists to optimize header lookups and parsing. The existence
|
||||
* of standard headers that aren't in this set is an O(1) operation. The
|
||||
* repeatable headers in this list require an O(1) operation if they are
|
||||
* not present, otherwise the extended headers list needs to be crawled.
|
||||
*
|
||||
* Please note non-standard headers exist, e.g. Cookie, that may span
|
||||
* multiple lines, even though they're not comma-delimited. For those
|
||||
* headers we simply don't add them to the perfect hash table.
|
||||
*
|
||||
* @note we choose to not recognize this grammar for kHttpConnection
|
||||
* @note `grep '[A-Z][a-z]*".*":"' rfc2616`
|
||||
* @note `grep ':.*#' rfc2616`
|
||||
* @see RFC7230 § 4.2
|
||||
*/
|
||||
const bool kHttpRepeatable[kHttpHeadersMax] = {
|
||||
[kHttpAcceptCharset] = true,
|
||||
[kHttpAcceptEncoding] = true,
|
||||
[kHttpAcceptLanguage] = true,
|
||||
[kHttpAccept] = true,
|
||||
[kHttpAllow] = true,
|
||||
[kHttpCacheControl] = true,
|
||||
[kHttpContentEncoding] = true,
|
||||
[kHttpContentLanguage] = true,
|
||||
[kHttpExpect] = true,
|
||||
[kHttpIfMatch] = true,
|
||||
[kHttpIfNoneMatch] = true,
|
||||
[kHttpPragma] = true,
|
||||
[kHttpProxyAuthenticate] = true,
|
||||
[kHttpPublic] = true,
|
||||
[kHttpTe] = true,
|
||||
[kHttpTrailer] = true,
|
||||
[kHttpTransferEncoding] = true,
|
||||
[kHttpUpgrade] = true,
|
||||
[kHttpUri] = true,
|
||||
[kHttpVary] = true,
|
||||
[kHttpVia] = true,
|
||||
[kHttpWarning] = true,
|
||||
[kHttpWwwAuthenticate] = true,
|
||||
};
|
42
net/http/khttptoken.c
Normal file
42
net/http/khttptoken.c
Normal 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/http.h"
|
||||
|
||||
// http/1.1 token dispatch
|
||||
// 0 is CTLs, SP, ()<>@,;:\"/[]?={} which are illegal
|
||||
// 1 is everything else in ASCII which is legal
|
||||
// note that &" can break html
|
||||
const char kHttpToken[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 0x20
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, // 0x30
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 0x50
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 0x70
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xc0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xd0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xe0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xf0
|
||||
};
|
|
@ -19,18 +19,25 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
#define MAXIMUM (1024L * 1024L * 1024L * 1024L)
|
||||
|
||||
/**
|
||||
* Parses Content-Length header.
|
||||
*
|
||||
* @param size is byte length and -1 implies strlen
|
||||
* @return -1 on invalid or overflow, otherwise >=0 value
|
||||
*/
|
||||
ssize_t ParseContentLength(const char *s, size_t n) {
|
||||
int i, r = 0;
|
||||
if (!n) return 0;
|
||||
for (i = 0; i < n; ++i) {
|
||||
int64_t ParseContentLength(const char *s, size_t n) {
|
||||
size_t i;
|
||||
int64_t r;
|
||||
if (n == -1) n = s ? strlen(s) : 0;
|
||||
if (!n) return -1;
|
||||
for (r = i = 0; i < n; ++i) {
|
||||
if (s[i] == ',' && i > 0) break;
|
||||
if (!isdigit(s[i])) return -1;
|
||||
if (__builtin_mul_overflow(r, 10, &r)) return -1;
|
||||
if (__builtin_add_overflow(r, s[i] - '0', &r)) return -1;
|
||||
r *= 10;
|
||||
r += s[i] - '0';
|
||||
if (r >= MAXIMUM) return -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,15 @@
|
|||
|
||||
/**
|
||||
* Parses HTTP Range request header.
|
||||
*
|
||||
* Here are some example values:
|
||||
*
|
||||
* Range: bytes=0- (everything)
|
||||
* Range: bytes=0-499 (first 500 bytes)
|
||||
* Range: bytes=500-999 (second 500 bytes)
|
||||
* Range: bytes=-500 (final 500 bytes)
|
||||
* Range: bytes=0-0,-1 (first and last and always)
|
||||
* Range: bytes=500-600,601-999 (overlong but legal)
|
||||
*/
|
||||
bool ParseHttpRange(const char *p, size_t n, long resourcelength,
|
||||
long *out_start, long *out_length) {
|
||||
|
@ -67,10 +76,10 @@ bool ParseHttpRange(const char *p, size_t n, long resourcelength,
|
|||
}
|
||||
if (n) return false;
|
||||
if (start < 0) return false;
|
||||
if (length < 0) return false;
|
||||
*out_start = start;
|
||||
*out_length = length;
|
||||
if (length < 1) return false;
|
||||
if (__builtin_add_overflow(start, length, &ending)) return false;
|
||||
if (ending > resourcelength) return false;
|
||||
*out_start = start;
|
||||
*out_length = length;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/arraylist.internal.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
@ -58,11 +59,19 @@ void DestroyHttpRequest(struct HttpRequest *r) {
|
|||
* messages. Line folding is forbidden. State persists across calls so
|
||||
* that fragmented messages can be handled efficiently. A limitation on
|
||||
* message size is imposed to make the header data structures smaller.
|
||||
* All other things are permissive to the greatest extent possible.
|
||||
* Further functions are provided for the interpretation, validation,
|
||||
* and sanitization of various fields.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @note we assume p points to a buffer that has >=SHRT_MAX bytes
|
||||
* @see HTTP/1.1 RFC2616 RFC2068
|
||||
* @see HTTP/1.0 RFC1945
|
||||
*/
|
||||
int ParseHttpRequest(struct HttpRequest *r, const char *p, size_t n) {
|
||||
int c, h, i;
|
||||
|
@ -71,23 +80,21 @@ int ParseHttpRequest(struct HttpRequest *r, const char *p, size_t n) {
|
|||
c = p[r->i] & 0xff;
|
||||
switch (r->t) {
|
||||
case START:
|
||||
if (c == '\r' || c == '\n') {
|
||||
++r->a; /* RFC7230 § 3.5 */
|
||||
break;
|
||||
}
|
||||
if (c == '\r' || c == '\n') break; /* RFC7230 § 3.5 */
|
||||
if (!kHttpToken[c]) return ebadmsg();
|
||||
r->t = METHOD;
|
||||
/* fallthrough */
|
||||
r->a = r->i;
|
||||
break;
|
||||
case METHOD:
|
||||
for (;;) {
|
||||
if (c == ' ') {
|
||||
if ((r->method = GetHttpMethod(p + r->a, r->i - r->a)) != -1) {
|
||||
r->uri.a = r->i + 1;
|
||||
r->t = URI;
|
||||
} else {
|
||||
return ebadmsg();
|
||||
}
|
||||
r->method = GetHttpMethod(p + r->a, r->i - r->a);
|
||||
r->xmethod.a = r->a;
|
||||
r->xmethod.b = r->i;
|
||||
r->a = r->i + 1;
|
||||
r->t = URI;
|
||||
break;
|
||||
} else if (!('A' <= c && c <= 'Z')) {
|
||||
} else if (!kHttpToken[c]) {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
|
@ -97,17 +104,19 @@ int ParseHttpRequest(struct HttpRequest *r, const char *p, size_t n) {
|
|||
case URI:
|
||||
for (;;) {
|
||||
if (c == ' ' || c == '\r' || c == '\n') {
|
||||
if (r->i == r->uri.a) return ebadmsg();
|
||||
if (r->i == r->a) return ebadmsg();
|
||||
r->uri.a = r->a;
|
||||
r->uri.b = r->i;
|
||||
if (c == ' ') {
|
||||
r->version.a = r->i + 1;
|
||||
r->a = r->i + 1;
|
||||
r->t = VERSION;
|
||||
} else if (c == '\r') {
|
||||
r->t = CR1;
|
||||
} else {
|
||||
r->t = LF1;
|
||||
r->version = 9;
|
||||
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;
|
||||
|
@ -115,8 +124,14 @@ int ParseHttpRequest(struct HttpRequest *r, const char *p, size_t n) {
|
|||
break;
|
||||
case VERSION:
|
||||
if (c == '\r' || c == '\n') {
|
||||
r->version.b = r->i;
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
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;
|
||||
} else {
|
||||
return ebadmsg();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CR1:
|
||||
|
@ -129,9 +144,7 @@ int ParseHttpRequest(struct HttpRequest *r, const char *p, size_t n) {
|
|||
break;
|
||||
} else if (c == '\n') {
|
||||
return ++r->i;
|
||||
} else if (c == ':') {
|
||||
return ebadmsg();
|
||||
} else if (c == ' ' || c == '\t') {
|
||||
} else if (!kHttpToken[c]) {
|
||||
return ebadmsg(); /* RFC7230 § 3.2.4 */
|
||||
}
|
||||
r->k.a = r->i;
|
||||
|
@ -143,6 +156,8 @@ int ParseHttpRequest(struct HttpRequest *r, const char *p, size_t n) {
|
|||
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;
|
||||
|
@ -158,7 +173,8 @@ int ParseHttpRequest(struct HttpRequest *r, const char *p, size_t n) {
|
|||
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) {
|
||||
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(
|
||||
|
@ -172,6 +188,8 @@ int ParseHttpRequest(struct HttpRequest *r, const char *p, size_t 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;
|
||||
|
|
52
net/http/parseip.c
Normal file
52
net/http/parseip.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*-*- 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"
|
||||
|
||||
/**
|
||||
* Parse IPv4 address.
|
||||
*
|
||||
* @param n if -1 implies strlen
|
||||
* @return -1 on failure, otherwise 32-bit host-order unsigned integer
|
||||
*/
|
||||
int64_t ParseIp(const char *s, size_t n) {
|
||||
size_t i;
|
||||
uint32_t x;
|
||||
int b, c, j;
|
||||
if (n == -1) n = s ? strlen(s) : 0;
|
||||
for (b = x = j = i = 0; i < n; ++i) {
|
||||
c = s[i] & 255;
|
||||
if (isdigit(c)) {
|
||||
b *= 10;
|
||||
b += c - '0';
|
||||
if (b > 255) return -1;
|
||||
} else if (c == '.') {
|
||||
x <<= 8;
|
||||
x |= b;
|
||||
b = 0;
|
||||
++j;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
x <<= 8;
|
||||
x |= b;
|
||||
if (j != 3) return -1;
|
||||
return x;
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/limits.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "net/http/escape.h"
|
||||
#include "net/http/url.h"
|
||||
|
||||
struct UrlParser {
|
||||
|
@ -29,29 +30,11 @@ struct UrlParser {
|
|||
int size;
|
||||
bool isform;
|
||||
bool islatin1;
|
||||
bool isopaque;
|
||||
char *p;
|
||||
char *q;
|
||||
};
|
||||
|
||||
static const signed char kHexToInt[256] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x20
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 0x30
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x40
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x50
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x60
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x70
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x80
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x90
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xa0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xb0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xc0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xd0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xe0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xf0
|
||||
};
|
||||
|
||||
static void EmitLatin1(struct UrlParser *u, int c) {
|
||||
u->p[0] = 0300 | c >> 6;
|
||||
u->p[1] = 0200 | c & 077;
|
||||
|
@ -67,10 +50,10 @@ static void EmitKey(struct UrlParser *u, struct UrlParams *h) {
|
|||
|
||||
static void EmitVal(struct UrlParser *u, struct UrlParams *h, bool t) {
|
||||
if (!t) {
|
||||
if (u->p > u->q) {
|
||||
if (u->p > u->q || u->c != '?') {
|
||||
EmitKey(u, h);
|
||||
h->p[h->n - 1].val.p = NULL;
|
||||
h->p[h->n - 1].val.n = SIZE_MAX;
|
||||
h->p[h->n - 1].val.n = 0;
|
||||
}
|
||||
} else {
|
||||
h->p[h->n - 1].val.p = u->q;
|
||||
|
@ -80,14 +63,14 @@ static void EmitVal(struct UrlParser *u, struct UrlParams *h, bool t) {
|
|||
}
|
||||
|
||||
static void ParseEscape(struct UrlParser *u) {
|
||||
int a, b;
|
||||
int a, b, c = '%';
|
||||
if (u->i + 2 <= u->size &&
|
||||
((a = kHexToInt[u->data[u->i + 0] & 0xff]) != -1 &&
|
||||
(b = kHexToInt[u->data[u->i + 1] & 0xff]) != -1)) {
|
||||
u->c = a << 4 | b;
|
||||
c = a << 4 | b;
|
||||
u->i += 2;
|
||||
}
|
||||
*u->p++ = u->c;
|
||||
*u->p++ = c;
|
||||
}
|
||||
|
||||
static bool ParseScheme(struct UrlParser *u, struct Url *h) {
|
||||
|
@ -98,18 +81,22 @@ static bool ParseScheme(struct UrlParser *u, struct Url *h) {
|
|||
++u->i;
|
||||
return true;
|
||||
} else {
|
||||
*u->p++ = u->c;
|
||||
*u->p++ = '/';
|
||||
return false;
|
||||
}
|
||||
} else if (u->c == ':') {
|
||||
} else if (u->c == ':' && u->i > 1) {
|
||||
h->scheme.p = u->q;
|
||||
h->scheme.n = u->p - u->q;
|
||||
u->q = u->p;
|
||||
if (u->i + 2 <= u->size &&
|
||||
(u->data[u->i + 1] == '/' && u->data[u->i + 1] == '/')) {
|
||||
u->i += 2;
|
||||
return true;
|
||||
if (u->i < u->size && u->data[u->i] == '/') {
|
||||
if (u->i + 1 < u->size && u->data[u->i + 1] == '/') {
|
||||
u->i += 2;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
u->isopaque = true;
|
||||
return false;
|
||||
}
|
||||
} else if (u->c == '#' || u->c == '?') {
|
||||
|
@ -119,10 +106,21 @@ static bool ParseScheme(struct UrlParser *u, struct Url *h) {
|
|||
return false;
|
||||
} else if (u->c == '%') {
|
||||
ParseEscape(u);
|
||||
return false;
|
||||
} else if (u->c >= 0200 && u->islatin1) {
|
||||
EmitLatin1(u, u->c);
|
||||
return false;
|
||||
} else {
|
||||
*u->p++ = u->c;
|
||||
if (u->i == 1) {
|
||||
if (!isalpha(u->c)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!isalnum(u->c) && u->c != '+' && u->c != '-' && u->c != '.') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -180,7 +178,9 @@ static void ParseAuthority(struct UrlParser *u, struct Url *h) {
|
|||
static void ParsePath(struct UrlParser *u, struct UrlView *h) {
|
||||
while (u->i < u->size) {
|
||||
u->c = u->data[u->i++] & 0xff;
|
||||
if (u->c == '#' || u->c == '?') {
|
||||
if (u->c == '#') {
|
||||
break;
|
||||
} else if (u->c == '?' && !u->isopaque) {
|
||||
break;
|
||||
} else if (u->c == '%') {
|
||||
ParseEscape(u);
|
||||
|
@ -195,8 +195,9 @@ static void ParsePath(struct UrlParser *u, struct UrlView *h) {
|
|||
u->q = u->p;
|
||||
}
|
||||
|
||||
static void ParseKeyValues(struct UrlParser *u, struct UrlParams *h) {
|
||||
static void ParseQuery(struct UrlParser *u, struct UrlParams *h) {
|
||||
bool t = false;
|
||||
if (!h->p) h->p = xmalloc(0);
|
||||
while (u->i < u->size) {
|
||||
u->c = u->data[u->i++] & 0xff;
|
||||
if (u->c == '#') {
|
||||
|
@ -210,10 +211,8 @@ static void ParseKeyValues(struct UrlParser *u, struct UrlParams *h) {
|
|||
t = false;
|
||||
} else if (u->c == '=') {
|
||||
if (!t) {
|
||||
if (u->p > u->q) {
|
||||
EmitKey(u, h);
|
||||
t = true;
|
||||
}
|
||||
EmitKey(u, h);
|
||||
t = true;
|
||||
} else {
|
||||
*u->p++ = '=';
|
||||
}
|
||||
|
@ -251,13 +250,14 @@ static char *ParseUrlImpl(const char *data, size_t size, struct Url *h,
|
|||
u.c = 0;
|
||||
u.isform = false;
|
||||
u.islatin1 = latin1;
|
||||
u.isopaque = false;
|
||||
u.data = data;
|
||||
u.size = size;
|
||||
memset(h, 0, sizeof(*h));
|
||||
u.q = u.p = m = xmalloc(u.size * 2);
|
||||
u.q = u.p = m = xmalloc(latin1 ? u.size * 2 : u.size);
|
||||
if (ParseScheme(&u, h)) ParseAuthority(&u, h);
|
||||
if (u.c != '#' && u.c != '?') ParsePath(&u, &h->path);
|
||||
if (u.c == '?') ParseKeyValues(&u, &h->params);
|
||||
if (u.c == '?') ParseQuery(&u, &h->params);
|
||||
if (u.c == '#') ParseFragment(&u, &h->fragment);
|
||||
return xrealloc(m, u.p - m);
|
||||
}
|
||||
|
@ -265,22 +265,33 @@ static char *ParseUrlImpl(const char *data, size_t size, struct Url *h,
|
|||
/**
|
||||
* Parses URL.
|
||||
*
|
||||
* This parser is charset agnostic. Percent encoded bytes are decoded
|
||||
* for all fields. Returned values might contain things like NUL
|
||||
* characters, spaces, control codes, and non-canonical encodings.
|
||||
* Absent can be discerned from empty by checking if the pointer is set.
|
||||
*
|
||||
* There's no failure condition for this routine. This is a permissive
|
||||
* parser that doesn't impose character restrictions beyond what is
|
||||
* necessary for parsing. This doesn't normalize path segments like `.`
|
||||
* or `..`. Use IsAcceptablePath() to check for those.
|
||||
* parser. This doesn't normalize path segments like `.` or `..` so use
|
||||
* IsAcceptablePath() to check for those. No restrictions are imposed
|
||||
* beyond that which is strictly necessary for parsing. All the data
|
||||
* that is provided will be consumed to the one of the fields. Strict
|
||||
* conformance is enforced on some fields more than others, like scheme,
|
||||
* since it's the most non-deterministically defined field of them all.
|
||||
*
|
||||
* This parser is charset agnostic. Returned values might contain things
|
||||
* like NUL characters, control codes, and non-canonical encodings.
|
||||
*
|
||||
* This parser doesn't support the ability to accurately parse path
|
||||
* segments which contain percent-encoded slash. There's also no support
|
||||
* for semicolon parameters at the moment.
|
||||
* Please note this is a URL parser, not a URI parser. Which means we
|
||||
* support everything everything the URI spec says we should do except
|
||||
* for the things we won't do, like tokenizing path segments into an
|
||||
* array and then nesting another array beneath each of those for
|
||||
* storing semicolon parameters. So this parser won't make SIP easy.
|
||||
* What it can do is parse HTTP URLs and most URIs like data:opaque,
|
||||
* better in fact than most things which claim to be URI parsers.
|
||||
*
|
||||
* @param data is value like `/hi?x=y&z` or `http://a.example/hi#x`
|
||||
* @param size is byte length and -1 implies strlen
|
||||
* @param h is assumed to be uninitialized
|
||||
* @return memory backing UrlView needing free (and h.params.p too)
|
||||
* @see URI Generic Syntax RFC3986 RFC2396
|
||||
* @see EncodeUrl()
|
||||
*/
|
||||
char *ParseUrl(const char *data, size_t size, struct Url *h) {
|
||||
return ParseUrlImpl(data, size, h, false);
|
||||
|
@ -293,15 +304,13 @@ char *ParseUrl(const char *data, size_t size, struct Url *h) {
|
|||
* assume percent-encoded bytes are expressed as UTF-8. Returned values
|
||||
* might contain things like NUL characters, C0, and C1 control codes.
|
||||
* UTF-8 isn't checked for validity and may contain overlong values.
|
||||
* Absent can be discerned from empty by checking if the pointer is set.
|
||||
*
|
||||
* There's no failure condition for this routine. This is a permissive
|
||||
* parser that doesn't impose character restrictions beyond what is
|
||||
* necessary for parsing. This doesn't normalize path segments like `.`
|
||||
* or `..`. Use IsAcceptablePath() to check for those.
|
||||
*
|
||||
* This parser doesn't support the ability to accurately parse path
|
||||
* segments which contain percent-encoded slash.
|
||||
*
|
||||
* @param data is value like `/hi?x=y&z` or `http://a.example/hi#x`
|
||||
* @param size is byte length and -1 implies strlen
|
||||
* @param h is assumed to be uninitialized
|
||||
|
@ -319,7 +328,8 @@ char *ParseRequestUri(const char *data, size_t size, struct Url *h) {
|
|||
* for this is application/x-www-form-urlencoded.
|
||||
*
|
||||
* This parser is charset agnostic. Returned values might contain things
|
||||
* like NUL characters, control codes, and non-canonical encodings.
|
||||
* like NUL characters, NUL, control codes, and non-canonical encodings.
|
||||
* Absent can be discerned from empty by checking if the pointer is set.
|
||||
*
|
||||
* There's no failure condition for this routine. This is a permissive
|
||||
* parser that doesn't impose character restrictions beyond what is
|
||||
|
@ -335,12 +345,53 @@ char *ParseParams(const char *data, size_t size, struct UrlParams *h) {
|
|||
struct UrlParser u;
|
||||
if (size == -1) size = data ? strlen(data) : 0;
|
||||
u.i = 0;
|
||||
u.c = 0;
|
||||
u.c = '?';
|
||||
u.isform = true;
|
||||
u.islatin1 = false;
|
||||
u.isopaque = false;
|
||||
u.data = data;
|
||||
u.size = size;
|
||||
u.q = u.p = m = xmalloc(u.size);
|
||||
ParseKeyValues(&u, h);
|
||||
ParseQuery(&u, h);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses HTTP Host header.
|
||||
*
|
||||
* The input is ISO-8859-1 which is transcoded to UTF-8. Therefore we
|
||||
* assume percent-encoded bytes are expressed as UTF-8. Returned values
|
||||
* might contain things like NUL characters, C0, and C1 control codes.
|
||||
* UTF-8 isn't checked for validity and may contain overlong values.
|
||||
* Absent can be discerned from empty by checking if the pointer is set.
|
||||
*
|
||||
* This function turns an HTTP header HOST[:PORT] into two strings, one
|
||||
* for host and the other for port. You may then call IsAcceptableHost()
|
||||
* and IsAcceptablePort() to see if they are valid values. After that a
|
||||
* function like sscanf() can be used to do the thing you likely thought
|
||||
* this function would do.
|
||||
*
|
||||
* This function doesn't initialize h since it's assumed this will be
|
||||
* called conditionally after ParseRequestUri() if the host is absent.
|
||||
* Fields unrelated to authority won't be impacted by this function.
|
||||
*
|
||||
* @param data is value like `127.0.0.1` or `foo.example:80`
|
||||
* @param size is byte length and -1 implies strlen
|
||||
* @param h is needs to be initialized by caller
|
||||
* @return memory backing UrlView needing free
|
||||
*/
|
||||
char *ParseHost(const char *data, size_t size, struct Url *h) {
|
||||
char *m;
|
||||
struct UrlParser u;
|
||||
if (size == -1) size = data ? strlen(data) : 0;
|
||||
u.i = 0;
|
||||
u.c = 0;
|
||||
u.isform = false;
|
||||
u.islatin1 = true;
|
||||
u.isopaque = false;
|
||||
u.data = data;
|
||||
u.size = size;
|
||||
u.q = u.p = m = xmalloc(u.size * 2);
|
||||
ParseAuthority(&u, h);
|
||||
return xrealloc(m, u.p - m);
|
||||
}
|
||||
|
|
9075
net/http/rfc2068
9075
net/http/rfc2068
File diff suppressed because it is too large
Load diff
2243
net/http/rfc2396
2243
net/http/rfc2396
File diff suppressed because it is too large
Load diff
118
net/http/uri.h
118
net/http/uri.h
|
@ -1,118 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_NET_HTTP_URI_H_
|
||||
#define COSMOPOLITAN_NET_HTTP_URI_H_
|
||||
#include "libc/dns/dns.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
enum UriScheme {
|
||||
kUriSchemeHttp = 1,
|
||||
kUriSchemeHttps,
|
||||
kUriSchemeFile,
|
||||
kUriSchemeData,
|
||||
kUriSchemeZip,
|
||||
kUriSchemeSip,
|
||||
kUriSchemeSips,
|
||||
kUriSchemeTel,
|
||||
kUriSchemeSsh,
|
||||
kUriSchemeGs,
|
||||
kUriSchemeS3
|
||||
};
|
||||
|
||||
struct UriSlice {
|
||||
/*
|
||||
* !i && !n means absent
|
||||
* i && !n means empty
|
||||
*/
|
||||
unsigned i, n;
|
||||
};
|
||||
|
||||
struct UriSlices {
|
||||
unsigned i, n;
|
||||
struct UriSlice *p;
|
||||
};
|
||||
|
||||
struct UriKeyval {
|
||||
struct UriSlice k, v;
|
||||
};
|
||||
|
||||
struct UriKeyvals {
|
||||
unsigned i, n;
|
||||
struct UriKeyval * p;
|
||||
};
|
||||
|
||||
struct UriRef {
|
||||
unsigned r;
|
||||
};
|
||||
|
||||
struct UriRefs {
|
||||
unsigned i, n;
|
||||
struct UriRef * p;
|
||||
};
|
||||
|
||||
struct Uri {
|
||||
/*
|
||||
* e.g. "", "http", "sip", "http", "dns+http", etc.
|
||||
*/
|
||||
struct UriSlice scheme;
|
||||
|
||||
/*
|
||||
* Holds remainder for exotic URI schemes, e.g. data.
|
||||
*/
|
||||
struct UriSlice opaque;
|
||||
|
||||
/*
|
||||
* e.g. sip:user@host, //user:pass@host
|
||||
*/
|
||||
struct UriSlice userinfo;
|
||||
|
||||
/*
|
||||
* e.g. "", "example.com", "1.2.3.4", "::1", etc.
|
||||
*/
|
||||
struct UriSlice host;
|
||||
|
||||
/*
|
||||
* e.g. "", "5060", "80", etc.
|
||||
*/
|
||||
struct UriSlice port;
|
||||
|
||||
/*
|
||||
* e.g. /dir/index.html means
|
||||
* - memcmp("/dir/index.html",
|
||||
* p + segs.p[0].i,
|
||||
* (segs.p[segs.i - 1].n +
|
||||
* (segs.p[segs.i - 1].i -
|
||||
* segs.p[0].i))) == 0
|
||||
* - memcmp("/dir", p + segs.p[0].i, segs.p[0].n) == 0
|
||||
* - memcmp("/index.html", p + segs.p[1].i, segs.p[1].n) == 0
|
||||
*/
|
||||
struct UriSlices segs;
|
||||
|
||||
/* e.g. ;lr;isup-oli=00;day=tuesday */
|
||||
struct UriKeyvals params;
|
||||
|
||||
/*
|
||||
* e.g. /dir;super=rare/index.html
|
||||
*
|
||||
* let 𝑖 ∈ [0,params.i)
|
||||
* paramsegs.p[𝑖].r ∈ [0,segs.i]
|
||||
*/
|
||||
struct UriRefs paramsegs;
|
||||
|
||||
/* e.g. ?boop&subject=project%20x&lol=cat */
|
||||
struct UriKeyvals queries;
|
||||
|
||||
/* e.g. #anchor */
|
||||
struct UriSlice fragment;
|
||||
};
|
||||
|
||||
int uricspn(const char *data, size_t size);
|
||||
int uriparse(struct Uri *, const char *, size_t) paramsnonnull((1));
|
||||
enum UriScheme urischeme(struct UriSlice, const char *)
|
||||
paramsnonnull() nosideeffect;
|
||||
struct UriSlice uripath(const struct Uri *) paramsnonnull() nosideeffect;
|
||||
char *urislice2cstr(char *, size_t, struct UriSlice, const char *, const char *)
|
||||
paramsnonnull((1, 4));
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_NET_HTTP_URI_H_ */
|
|
@ -1,61 +0,0 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 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/macros.internal.h"
|
||||
|
||||
// Verifies buffer contains only URI characters.
|
||||
//
|
||||
// @param %rdi is data which should be 32-byte aligned
|
||||
// @param %rsi is byte length of data
|
||||
// @return number of kosher bytes
|
||||
// @cost 10x faster than fastest Ragel code
|
||||
uricspn$avx:
|
||||
.leafprologue
|
||||
.profilable
|
||||
vmovaps .Luric(%rip),%xmm0
|
||||
mov $14,%eax
|
||||
mov %rsi,%rdx
|
||||
xor %esi,%esi
|
||||
0: vmovdqu (%rdi,%rsi),%xmm1
|
||||
vmovdqu 16(%rdi,%rsi),%xmm2
|
||||
vpcmpestri $0b00010100,%xmm1,%xmm0
|
||||
jc 1f
|
||||
jo 1f
|
||||
add $16,%rsi
|
||||
sub $16,%rdx
|
||||
vpcmpestri $0b00010100,%xmm2,%xmm0
|
||||
jc 1f
|
||||
jo 1f
|
||||
add $16,%rsi
|
||||
sub $16,%rdx
|
||||
jmp 0b
|
||||
1: lea (%rsi,%rcx),%rax
|
||||
.leafepilogue
|
||||
.endfn uricspn$avx,globl,hidden
|
||||
|
||||
.rodata.cst16
|
||||
.Luric: .byte '!','!'
|
||||
.byte '$',';'
|
||||
.byte '=','='
|
||||
.byte '?','Z'
|
||||
.byte '_','_'
|
||||
.byte 'a','z'
|
||||
.byte '~','~'
|
||||
.byte 0,0
|
||||
.endobj .Luric
|
||||
.previous
|
|
@ -1,185 +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/assert.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "net/http/uri.h"
|
||||
|
||||
/*
|
||||
* GENERATED BY
|
||||
*
|
||||
* ragel -o net/http/uricspn.c net/http/uricspn.rl
|
||||
*
|
||||
* TODO(jart): Rewrite in normal C.
|
||||
*/
|
||||
|
||||
#define static
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#line 29 "net/http/uricspn.rl"
|
||||
|
||||
#line 34 "build/bootstrap/net/http/uricspn.c"
|
||||
static const char _uricspn_key_offsets[] = {
|
||||
0, 0
|
||||
};
|
||||
|
||||
static const char _uricspn_trans_keys[] = {
|
||||
33, 61, 95, 126, 36, 59, 63, 90,
|
||||
97, 122, 0
|
||||
};
|
||||
|
||||
static const char _uricspn_single_lengths[] = {
|
||||
0, 4
|
||||
};
|
||||
|
||||
static const char _uricspn_range_lengths[] = {
|
||||
0, 3
|
||||
};
|
||||
|
||||
static const char _uricspn_index_offsets[] = {
|
||||
0, 0
|
||||
};
|
||||
|
||||
static const char _uricspn_trans_targs[] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 0,
|
||||
0
|
||||
};
|
||||
|
||||
static const int uricspn_start = 1;
|
||||
static const int uricspn_first_final = 1;
|
||||
static const int uricspn_error = 0;
|
||||
|
||||
static const int uricspn_en_machina = 1;
|
||||
|
||||
|
||||
#line 30 "net/http/uricspn.rl"
|
||||
/* clang-format on */
|
||||
|
||||
int uricspn(const char *data, size_t size) {
|
||||
int uricspn$avx(const char *, size_t) hidden;
|
||||
const char *p, *pe;
|
||||
int cs;
|
||||
|
||||
assert(data || !size);
|
||||
assert(size <= 0x7ffff000);
|
||||
assert(size <= 0x7ffff000);
|
||||
|
||||
if (X86_HAVE(AVX)) {
|
||||
return uricspn$avx(data, size);
|
||||
}
|
||||
|
||||
p = data;
|
||||
pe = data + size;
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
|
||||
#line 56 "net/http/uricspn.rl"
|
||||
|
||||
|
||||
|
||||
#line 94 "build/bootstrap/net/http/uricspn.c"
|
||||
{
|
||||
cs = uricspn_start;
|
||||
}
|
||||
|
||||
#line 59 "net/http/uricspn.rl"
|
||||
cs = uricspn_en_machina;
|
||||
|
||||
#line 102 "build/bootstrap/net/http/uricspn.c"
|
||||
{
|
||||
int _klen;
|
||||
unsigned int _trans;
|
||||
const char *_keys;
|
||||
|
||||
if ( p == pe )
|
||||
goto _test_eof;
|
||||
if ( cs == 0 )
|
||||
goto _out;
|
||||
_resume:
|
||||
_keys = _uricspn_trans_keys + _uricspn_key_offsets[cs];
|
||||
_trans = _uricspn_index_offsets[cs];
|
||||
|
||||
_klen = _uricspn_single_lengths[cs];
|
||||
if ( _klen > 0 ) {
|
||||
const char *_lower = _keys;
|
||||
const char *_mid;
|
||||
const char *_upper = _keys + _klen - 1;
|
||||
while (1) {
|
||||
if ( _upper < _lower )
|
||||
break;
|
||||
|
||||
_mid = _lower + ((_upper-_lower) >> 1);
|
||||
if ( (*p) < *_mid )
|
||||
_upper = _mid - 1;
|
||||
else if ( (*p) > *_mid )
|
||||
_lower = _mid + 1;
|
||||
else {
|
||||
_trans += (unsigned int)(_mid - _keys);
|
||||
goto _match;
|
||||
}
|
||||
}
|
||||
_keys += _klen;
|
||||
_trans += _klen;
|
||||
}
|
||||
|
||||
_klen = _uricspn_range_lengths[cs];
|
||||
if ( _klen > 0 ) {
|
||||
const char *_lower = _keys;
|
||||
const char *_mid;
|
||||
const char *_upper = _keys + (_klen<<1) - 2;
|
||||
while (1) {
|
||||
if ( _upper < _lower )
|
||||
break;
|
||||
|
||||
_mid = _lower + (((_upper-_lower) >> 1) & ~1);
|
||||
if ( (*p) < _mid[0] )
|
||||
_upper = _mid - 2;
|
||||
else if ( (*p) > _mid[1] )
|
||||
_lower = _mid + 2;
|
||||
else {
|
||||
_trans += (unsigned int)((_mid - _keys)>>1);
|
||||
goto _match;
|
||||
}
|
||||
}
|
||||
_trans += _klen;
|
||||
}
|
||||
|
||||
_match:
|
||||
cs = _uricspn_trans_targs[_trans];
|
||||
|
||||
if ( cs == 0 )
|
||||
goto _out;
|
||||
if ( ++p != pe )
|
||||
goto _resume;
|
||||
_test_eof: {}
|
||||
_out: {}
|
||||
}
|
||||
|
||||
#line 61 "net/http/uricspn.rl"
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
if (cs >= uricspn_first_final) {
|
||||
return p - data;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,724 +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/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "net/http/uri.h"
|
||||
|
||||
/*
|
||||
* GENERATED BY
|
||||
*
|
||||
* ragel -o net/http/uriparse.c net/http/uriparse.rl
|
||||
*
|
||||
* TODO(jart): Rewrite in normal C.
|
||||
*/
|
||||
|
||||
#define static
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#line 32 "net/http/uriparse.rl"
|
||||
|
||||
#line 37 "build/bootstrap/net/http/uriparse.c"
|
||||
static const char _uriparse_actions[] = {
|
||||
0, 1, 0, 1, 1, 1, 2, 1,
|
||||
3, 1, 4, 1, 5, 1, 6, 1,
|
||||
8, 1, 11, 1, 12, 2, 0, 2,
|
||||
2, 4, 8, 2, 5, 8, 2, 6,
|
||||
9, 2, 6, 10, 2, 7, 9, 2,
|
||||
7, 10, 2, 8, 0, 2, 11, 0,
|
||||
3, 4, 8, 0, 3, 5, 8, 0,
|
||||
3, 6, 9, 0, 3, 7, 9, 0
|
||||
|
||||
};
|
||||
|
||||
static const short _uriparse_key_offsets[] = {
|
||||
0, 0, 6, 12, 18, 24, 37, 43,
|
||||
49, 64, 70, 76, 91, 97, 103, 118,
|
||||
124, 130, 145, 151, 157, 169, 188, 202,
|
||||
208, 214, 224, 226, 233, 241, 256, 273,
|
||||
279, 285, 302, 308, 314, 326, 332, 338,
|
||||
357, 371, 377, 383, 393, 395, 410, 416,
|
||||
422, 437, 443, 449, 456, 464, 479, 494,
|
||||
509, 520, 531, 546, 564, 581, 598, 614,
|
||||
625, 630, 634, 653, 671, 689, 707, 727,
|
||||
728, 739, 742, 759, 775, 777, 797
|
||||
};
|
||||
|
||||
static const char _uriparse_trans_keys[] = {
|
||||
48, 57, 65, 70, 97, 102, 48, 57,
|
||||
65, 70, 97, 102, 48, 57, 65, 70,
|
||||
97, 102, 48, 57, 65, 70, 97, 102,
|
||||
33, 37, 61, 95, 126, 36, 46, 48,
|
||||
58, 64, 90, 97, 122, 48, 57, 65,
|
||||
70, 97, 102, 48, 57, 65, 70, 97,
|
||||
102, 33, 37, 93, 95, 126, 36, 43,
|
||||
45, 46, 48, 58, 65, 91, 97, 122,
|
||||
48, 57, 65, 70, 97, 102, 48, 57,
|
||||
65, 70, 97, 102, 33, 37, 93, 95,
|
||||
126, 36, 43, 45, 46, 48, 58, 65,
|
||||
91, 97, 122, 48, 57, 65, 70, 97,
|
||||
102, 48, 57, 65, 70, 97, 102, 33,
|
||||
36, 37, 63, 93, 95, 126, 39, 43,
|
||||
45, 58, 65, 91, 97, 122, 48, 57,
|
||||
65, 70, 97, 102, 48, 57, 65, 70,
|
||||
97, 102, 33, 36, 37, 63, 93, 95,
|
||||
126, 39, 43, 45, 58, 65, 91, 97,
|
||||
122, 48, 57, 65, 70, 97, 102, 48,
|
||||
57, 65, 70, 97, 102, 33, 37, 47,
|
||||
61, 95, 126, 36, 58, 64, 90, 97,
|
||||
122, 33, 37, 43, 58, 61, 63, 91,
|
||||
95, 126, 36, 44, 45, 46, 48, 57,
|
||||
65, 90, 97, 122, 33, 37, 61, 64,
|
||||
95, 126, 36, 46, 48, 58, 63, 90,
|
||||
97, 122, 48, 57, 65, 70, 97, 102,
|
||||
48, 57, 65, 70, 97, 102, 43, 91,
|
||||
45, 46, 48, 57, 65, 90, 97, 122,
|
||||
48, 57, 46, 48, 58, 65, 70, 97,
|
||||
102, 46, 93, 48, 58, 65, 70, 97,
|
||||
102, 33, 37, 58, 61, 64, 95, 126,
|
||||
36, 46, 48, 57, 63, 90, 97, 122,
|
||||
33, 37, 38, 44, 47, 61, 64, 91,
|
||||
93, 95, 126, 36, 58, 63, 90, 97,
|
||||
122, 48, 57, 65, 70, 97, 102, 48,
|
||||
57, 65, 70, 97, 102, 33, 37, 38,
|
||||
44, 47, 61, 64, 91, 93, 95, 126,
|
||||
36, 58, 63, 90, 97, 122, 48, 57,
|
||||
65, 70, 97, 102, 48, 57, 65, 70,
|
||||
97, 102, 33, 37, 47, 61, 95, 126,
|
||||
36, 59, 63, 90, 97, 122, 48, 57,
|
||||
65, 70, 97, 102, 48, 57, 65, 70,
|
||||
97, 102, 33, 37, 43, 58, 61, 63,
|
||||
91, 95, 126, 36, 44, 45, 46, 48,
|
||||
57, 65, 90, 97, 122, 33, 37, 61,
|
||||
64, 95, 126, 36, 46, 48, 58, 63,
|
||||
90, 97, 122, 48, 57, 65, 70, 97,
|
||||
102, 48, 57, 65, 70, 97, 102, 43,
|
||||
91, 45, 46, 48, 57, 65, 90, 97,
|
||||
122, 48, 57, 33, 37, 93, 95, 126,
|
||||
36, 43, 45, 46, 48, 58, 65, 91,
|
||||
97, 122, 48, 57, 65, 70, 97, 102,
|
||||
48, 57, 65, 70, 97, 102, 33, 37,
|
||||
93, 95, 126, 36, 43, 45, 46, 48,
|
||||
58, 65, 91, 97, 122, 48, 57, 65,
|
||||
70, 97, 102, 48, 57, 65, 70, 97,
|
||||
102, 46, 48, 58, 65, 70, 97, 102,
|
||||
46, 93, 48, 58, 65, 70, 97, 102,
|
||||
33, 37, 58, 61, 64, 95, 126, 36,
|
||||
46, 48, 57, 63, 90, 97, 122, 33,
|
||||
35, 37, 47, 59, 61, 64, 95, 126,
|
||||
36, 57, 65, 90, 97, 122, 33, 35,
|
||||
37, 47, 59, 61, 63, 95, 126, 36,
|
||||
57, 64, 90, 97, 122, 33, 37, 61,
|
||||
95, 126, 36, 59, 63, 90, 97, 122,
|
||||
33, 37, 61, 95, 126, 36, 59, 63,
|
||||
90, 97, 122, 33, 35, 37, 47, 59,
|
||||
61, 63, 95, 126, 36, 58, 64, 90,
|
||||
97, 122, 33, 35, 37, 47, 59, 61,
|
||||
63, 93, 95, 126, 36, 43, 45, 58,
|
||||
65, 91, 97, 122, 33, 35, 37, 47,
|
||||
59, 63, 93, 95, 126, 36, 43, 45,
|
||||
58, 65, 91, 97, 122, 33, 35, 37,
|
||||
38, 61, 63, 93, 95, 126, 36, 43,
|
||||
45, 58, 65, 91, 97, 122, 33, 35,
|
||||
37, 38, 63, 93, 95, 126, 36, 43,
|
||||
45, 58, 65, 91, 97, 122, 35, 43,
|
||||
47, 58, 63, 45, 57, 65, 90, 97,
|
||||
122, 35, 47, 63, 48, 57, 35, 47,
|
||||
58, 63, 33, 35, 37, 43, 47, 58,
|
||||
61, 63, 64, 95, 126, 36, 44, 45,
|
||||
57, 65, 90, 97, 122, 33, 35, 37,
|
||||
47, 58, 61, 63, 64, 95, 126, 36,
|
||||
46, 48, 57, 65, 90, 97, 122, 33,
|
||||
35, 37, 38, 44, 47, 61, 64, 91,
|
||||
93, 95, 126, 36, 58, 63, 90, 97,
|
||||
122, 33, 35, 37, 38, 44, 47, 61,
|
||||
64, 91, 93, 95, 126, 36, 58, 63,
|
||||
90, 97, 122, 33, 35, 37, 43, 47,
|
||||
58, 59, 61, 63, 64, 95, 126, 36,
|
||||
44, 45, 57, 65, 90, 97, 122, 35,
|
||||
43, 58, 59, 45, 46, 48, 57, 65,
|
||||
90, 97, 122, 59, 48, 57, 33, 37,
|
||||
59, 61, 93, 95, 126, 36, 43, 45,
|
||||
46, 48, 58, 65, 91, 97, 122, 33,
|
||||
37, 59, 93, 95, 126, 36, 43, 45,
|
||||
46, 48, 58, 65, 91, 97, 122, 58,
|
||||
59, 33, 37, 43, 58, 59, 61, 63,
|
||||
64, 95, 126, 36, 44, 45, 46, 48,
|
||||
57, 65, 90, 97, 122, 33, 37, 58,
|
||||
59, 61, 64, 95, 126, 36, 46, 48,
|
||||
57, 63, 90, 97, 122, 0
|
||||
};
|
||||
|
||||
static const char _uriparse_single_lengths[] = {
|
||||
0, 0, 0, 0, 0, 5, 0, 0,
|
||||
5, 0, 0, 5, 0, 0, 7, 0,
|
||||
0, 7, 0, 0, 6, 9, 6, 0,
|
||||
0, 2, 0, 1, 2, 7, 11, 0,
|
||||
0, 11, 0, 0, 6, 0, 0, 9,
|
||||
6, 0, 0, 2, 0, 5, 0, 0,
|
||||
5, 0, 0, 1, 2, 7, 9, 9,
|
||||
5, 5, 9, 10, 9, 9, 8, 5,
|
||||
3, 4, 11, 10, 12, 12, 12, 1,
|
||||
3, 1, 7, 6, 2, 10, 8
|
||||
};
|
||||
|
||||
static const char _uriparse_range_lengths[] = {
|
||||
0, 3, 3, 3, 3, 4, 3, 3,
|
||||
5, 3, 3, 5, 3, 3, 4, 3,
|
||||
3, 4, 3, 3, 3, 5, 4, 3,
|
||||
3, 4, 1, 3, 3, 4, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 5,
|
||||
4, 3, 3, 4, 1, 5, 3, 3,
|
||||
5, 3, 3, 3, 3, 4, 3, 3,
|
||||
3, 3, 3, 4, 4, 4, 4, 3,
|
||||
1, 0, 4, 4, 3, 3, 4, 0,
|
||||
4, 1, 5, 5, 0, 5, 4
|
||||
};
|
||||
|
||||
static const short _uriparse_index_offsets[] = {
|
||||
0, 0, 4, 8, 12, 16, 26, 30,
|
||||
34, 45, 49, 53, 64, 68, 72, 84,
|
||||
88, 92, 104, 108, 112, 122, 137, 148,
|
||||
152, 156, 163, 165, 170, 176, 188, 203,
|
||||
207, 211, 226, 230, 234, 244, 248, 252,
|
||||
267, 278, 282, 286, 293, 295, 306, 310,
|
||||
314, 325, 329, 333, 338, 344, 356, 369,
|
||||
382, 391, 400, 413, 428, 442, 456, 469,
|
||||
478, 483, 488, 504, 519, 535, 551, 568,
|
||||
570, 578, 581, 594, 606, 609, 625
|
||||
};
|
||||
|
||||
static const unsigned char _uriparse_indicies[] = {
|
||||
0, 0, 0, 1, 2, 2, 2, 1,
|
||||
3, 3, 3, 1, 4, 4, 4, 1,
|
||||
5, 6, 5, 5, 5, 5, 5, 5,
|
||||
5, 1, 7, 7, 7, 1, 5, 5,
|
||||
5, 1, 8, 9, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 1, 10, 10, 10,
|
||||
1, 11, 11, 11, 1, 12, 13, 12,
|
||||
12, 12, 12, 12, 12, 12, 12, 1,
|
||||
14, 14, 14, 1, 15, 15, 15, 1,
|
||||
16, 16, 17, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 1, 18, 18, 18, 1,
|
||||
19, 19, 19, 1, 20, 20, 21, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 1,
|
||||
22, 22, 22, 1, 23, 23, 23, 1,
|
||||
5, 6, 24, 5, 5, 5, 5, 5,
|
||||
5, 1, 25, 26, 27, 25, 25, 25,
|
||||
28, 25, 25, 25, 27, 27, 27, 27,
|
||||
1, 29, 30, 29, 31, 29, 29, 29,
|
||||
29, 29, 29, 1, 32, 32, 32, 1,
|
||||
29, 29, 29, 1, 33, 28, 33, 33,
|
||||
33, 33, 1, 34, 1, 35, 35, 35,
|
||||
35, 1, 36, 37, 36, 36, 36, 1,
|
||||
29, 30, 29, 29, 31, 29, 29, 29,
|
||||
38, 29, 29, 1, 39, 40, 29, 29,
|
||||
16, 29, 31, 16, 16, 39, 39, 39,
|
||||
39, 39, 1, 41, 41, 41, 1, 42,
|
||||
42, 42, 1, 43, 44, 29, 29, 20,
|
||||
29, 31, 20, 20, 43, 43, 43, 43,
|
||||
43, 1, 45, 45, 45, 1, 46, 46,
|
||||
46, 1, 47, 48, 49, 47, 47, 47,
|
||||
47, 47, 47, 1, 50, 50, 50, 1,
|
||||
47, 47, 47, 1, 51, 52, 53, 51,
|
||||
51, 51, 54, 51, 51, 51, 53, 53,
|
||||
53, 53, 1, 55, 56, 55, 57, 55,
|
||||
55, 55, 55, 55, 55, 1, 58, 58,
|
||||
58, 1, 55, 55, 55, 1, 59, 60,
|
||||
59, 59, 59, 59, 1, 61, 1, 62,
|
||||
63, 62, 62, 62, 62, 62, 62, 62,
|
||||
62, 1, 64, 64, 64, 1, 65, 65,
|
||||
65, 1, 66, 67, 66, 66, 66, 66,
|
||||
66, 66, 66, 66, 1, 68, 68, 68,
|
||||
1, 69, 69, 69, 1, 70, 70, 70,
|
||||
70, 1, 71, 72, 71, 71, 71, 1,
|
||||
55, 56, 55, 55, 57, 55, 55, 55,
|
||||
73, 55, 55, 1, 74, 75, 76, 49,
|
||||
74, 74, 74, 74, 74, 74, 77, 77,
|
||||
1, 4, 78, 79, 80, 4, 4, 81,
|
||||
4, 4, 4, 4, 4, 1, 82, 83,
|
||||
82, 82, 82, 82, 82, 82, 1, 2,
|
||||
84, 2, 2, 2, 2, 2, 2, 1,
|
||||
5, 78, 6, 80, 85, 5, 81, 5,
|
||||
5, 5, 5, 5, 1, 11, 86, 87,
|
||||
88, 89, 90, 91, 11, 11, 11, 11,
|
||||
11, 11, 11, 1, 15, 92, 93, 94,
|
||||
95, 96, 15, 15, 15, 15, 15, 15,
|
||||
15, 1, 19, 97, 98, 99, 100, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 1,
|
||||
23, 101, 102, 103, 23, 23, 23, 23,
|
||||
23, 23, 23, 23, 1, 104, 105, 106,
|
||||
107, 108, 105, 105, 105, 1, 109, 110,
|
||||
112, 111, 1, 113, 114, 115, 116, 1,
|
||||
29, 104, 30, 117, 106, 118, 29, 119,
|
||||
31, 29, 29, 29, 117, 117, 117, 1,
|
||||
29, 109, 30, 110, 29, 29, 121, 31,
|
||||
29, 29, 29, 120, 29, 29, 1, 42,
|
||||
97, 122, 123, 29, 19, 124, 31, 19,
|
||||
19, 42, 42, 42, 42, 42, 1, 46,
|
||||
101, 125, 126, 29, 23, 29, 31, 23,
|
||||
23, 46, 46, 46, 46, 46, 1, 4,
|
||||
78, 79, 127, 80, 128, 4, 4, 81,
|
||||
4, 4, 4, 4, 127, 127, 127, 1,
|
||||
75, 1, 129, 130, 131, 129, 129, 129,
|
||||
129, 1, 133, 132, 1, 65, 134, 135,
|
||||
136, 65, 65, 65, 65, 65, 65, 65,
|
||||
65, 1, 69, 137, 138, 69, 69, 69,
|
||||
69, 69, 69, 69, 69, 1, 139, 140,
|
||||
1, 55, 56, 141, 142, 131, 55, 55,
|
||||
57, 55, 55, 55, 141, 141, 141, 141,
|
||||
1, 55, 56, 55, 133, 55, 57, 55,
|
||||
55, 55, 143, 55, 55, 1, 0
|
||||
};
|
||||
|
||||
static const char _uriparse_trans_targs[] = {
|
||||
2, 0, 57, 4, 55, 58, 6, 7,
|
||||
59, 9, 10, 59, 60, 12, 13, 60,
|
||||
61, 15, 16, 61, 62, 18, 19, 62,
|
||||
21, 22, 23, 66, 27, 22, 23, 25,
|
||||
24, 63, 64, 28, 28, 65, 67, 68,
|
||||
31, 32, 68, 69, 34, 35, 69, 71,
|
||||
37, 20, 38, 40, 41, 77, 51, 40,
|
||||
41, 43, 42, 72, 51, 73, 74, 46,
|
||||
47, 74, 75, 49, 50, 75, 52, 52,
|
||||
76, 78, 55, 56, 3, 70, 56, 3,
|
||||
5, 14, 57, 1, 1, 8, 56, 9,
|
||||
5, 8, 11, 14, 56, 12, 5, 8,
|
||||
14, 56, 15, 14, 17, 56, 18, 14,
|
||||
56, 63, 5, 26, 14, 56, 5, 64,
|
||||
14, 56, 5, 26, 14, 66, 29, 30,
|
||||
67, 30, 31, 30, 33, 34, 30, 70,
|
||||
36, 72, 44, 45, 73, 45, 46, 45,
|
||||
48, 49, 45, 44, 45, 77, 53, 78
|
||||
};
|
||||
|
||||
static const char _uriparse_trans_actions[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 0, 0, 1, 1, 0, 0,
|
||||
1, 1, 0, 0, 1, 1, 0, 0,
|
||||
0, 1, 1, 1, 0, 0, 0, 7,
|
||||
0, 1, 1, 1, 0, 9, 1, 1,
|
||||
1, 0, 0, 1, 1, 0, 0, 19,
|
||||
0, 1, 0, 1, 1, 1, 1, 0,
|
||||
0, 7, 0, 1, 0, 1, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 1, 0,
|
||||
9, 1, 1, 0, 1, 1, 17, 0,
|
||||
45, 17, 1, 1, 0, 17, 30, 0,
|
||||
56, 30, 13, 30, 36, 0, 60, 36,
|
||||
36, 33, 0, 33, 13, 39, 0, 39,
|
||||
24, 0, 48, 9, 24, 27, 52, 0,
|
||||
27, 15, 42, 0, 15, 0, 9, 24,
|
||||
0, 27, 0, 33, 13, 0, 39, 0,
|
||||
3, 0, 9, 9, 0, 11, 0, 30,
|
||||
13, 0, 36, 0, 0, 0, 9, 0
|
||||
};
|
||||
|
||||
static const char _uriparse_eof_actions[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 17,
|
||||
21, 5, 17, 30, 36, 33, 39, 24,
|
||||
27, 15, 24, 27, 33, 39, 17, 0,
|
||||
9, 11, 30, 36, 0, 9, 11
|
||||
};
|
||||
|
||||
static const int uriparse_start = 54;
|
||||
static const int uriparse_first_final = 54;
|
||||
static const int uriparse_error = 0;
|
||||
|
||||
static const int uriparse_en_sip = 39;
|
||||
static const int uriparse_en_uri = 54;
|
||||
|
||||
|
||||
#line 33 "net/http/uriparse.rl"
|
||||
/* clang-format on */
|
||||
|
||||
/**
|
||||
* Parses URI.
|
||||
*
|
||||
* This is a general URL parser. It's typically used for HTTP. Support
|
||||
* for the bonus syntax needed by SIP is provided. The whirlwhind tour
|
||||
* of the URI rabbit hole is as follows:
|
||||
*
|
||||
* /foo.html
|
||||
* //justine.local/foo.html
|
||||
* http://justine.local/foo.html
|
||||
* http://bettersearchengine.local/search.cgi?q=my%20query
|
||||
* file:///etc/passwd
|
||||
* gs://bucket/object.txt
|
||||
* zip:///usr/share/zoneinfo/GMT
|
||||
* sip:127.0.0.1:5060;lr
|
||||
* sip:+12125650666@gateway.example
|
||||
* sip:bob%20barker:priceisright@[dead:beef::666]:5060;isup-oli=00
|
||||
* data:video/mpeg;base64,gigabytesofhex
|
||||
*
|
||||
* This parser operates on slices rather than C strings. It performs
|
||||
* slicing and validation only. Operations like turning "%20"→" " or
|
||||
* "80"→80 and perfect hashing can be done later, if needed.
|
||||
*
|
||||
* The Uri object is owned by the caller; it has a lifecycle like the
|
||||
* following:
|
||||
*
|
||||
* struct Uri uri;
|
||||
* memset(&uri, 0, sizeof(uri));
|
||||
*
|
||||
* uriparse(&uri, s1, strlen(s1));
|
||||
* CHECK_EQ(kUriSchemeHttp, urischeme(uri->scheme, s1));
|
||||
*
|
||||
* uriparse(&uri, s2, strlen(s2));
|
||||
* printf("host = %`.*s\n", uri->host.n, s2 + uri->host.i);
|
||||
*
|
||||
* Inner arrays may be granted memory by the caller. The uri->𝐴.i field
|
||||
* is cleared at the mark of this function. No more than uri->𝐴.n items
|
||||
* can be inserted. If we need more than that, then ENOMEM is returned
|
||||
* rather than dynamically extending uri->𝐴.p. However, if uri->𝐴.n==0,
|
||||
* we assume caller doesn't care about uri->𝐴 and its data is discarded.
|
||||
*
|
||||
* @param uri is owned by caller
|
||||
* @param p is caller-owned uri string; won't copy/alias/mutate
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see RFC2396: Uniform Resource Identifiers (URI): Generic Syntax
|
||||
* @see RFC3261: SIP: Session Initiation Protocol
|
||||
*/
|
||||
int uriparse(struct Uri *uri, const char *p, size_t size) {
|
||||
unsigned zero, cs;
|
||||
struct UriKeyval kv;
|
||||
const char *pe, *eof, *buf, *mark;
|
||||
|
||||
assert(p || !size);
|
||||
assert(size <= 0x7ffff000);
|
||||
|
||||
#define ABSENT ((struct UriSlice){zero, zero})
|
||||
#define SLICE ((struct UriSlice){mark - buf, p - mark})
|
||||
|
||||
cs = zero = VEIL("r", 0u);
|
||||
eof = pe = (mark = buf = p) + size;
|
||||
|
||||
uri->scheme = ABSENT;
|
||||
uri->opaque = ABSENT;
|
||||
uri->userinfo = ABSENT;
|
||||
uri->host = ABSENT;
|
||||
uri->port = ABSENT;
|
||||
uri->fragment = ABSENT;
|
||||
uri->segs.i = zero;
|
||||
uri->paramsegs.i = zero;
|
||||
uri->params.i = zero;
|
||||
uri->queries.i = zero;
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
|
||||
#line 229 "net/http/uriparse.rl"
|
||||
|
||||
|
||||
|
||||
#line 435 "build/bootstrap/net/http/uriparse.c"
|
||||
{
|
||||
cs = uriparse_start;
|
||||
}
|
||||
|
||||
#line 232 "net/http/uriparse.rl"
|
||||
cs = uriparse_en_uri;
|
||||
|
||||
#line 443 "build/bootstrap/net/http/uriparse.c"
|
||||
{
|
||||
int _klen;
|
||||
unsigned int _trans;
|
||||
const char *_acts;
|
||||
unsigned int _nacts;
|
||||
const char *_keys;
|
||||
|
||||
if ( p == pe )
|
||||
goto _test_eof;
|
||||
if ( cs == 0 )
|
||||
goto _out;
|
||||
_resume:
|
||||
_keys = _uriparse_trans_keys + _uriparse_key_offsets[cs];
|
||||
_trans = _uriparse_index_offsets[cs];
|
||||
|
||||
_klen = _uriparse_single_lengths[cs];
|
||||
if ( _klen > 0 ) {
|
||||
const char *_lower = _keys;
|
||||
const char *_mid;
|
||||
const char *_upper = _keys + _klen - 1;
|
||||
while (1) {
|
||||
if ( _upper < _lower )
|
||||
break;
|
||||
|
||||
_mid = _lower + ((_upper-_lower) >> 1);
|
||||
if ( (*p) < *_mid )
|
||||
_upper = _mid - 1;
|
||||
else if ( (*p) > *_mid )
|
||||
_lower = _mid + 1;
|
||||
else {
|
||||
_trans += (unsigned int)(_mid - _keys);
|
||||
goto _match;
|
||||
}
|
||||
}
|
||||
_keys += _klen;
|
||||
_trans += _klen;
|
||||
}
|
||||
|
||||
_klen = _uriparse_range_lengths[cs];
|
||||
if ( _klen > 0 ) {
|
||||
const char *_lower = _keys;
|
||||
const char *_mid;
|
||||
const char *_upper = _keys + (_klen<<1) - 2;
|
||||
while (1) {
|
||||
if ( _upper < _lower )
|
||||
break;
|
||||
|
||||
_mid = _lower + (((_upper-_lower) >> 1) & ~1);
|
||||
if ( (*p) < _mid[0] )
|
||||
_upper = _mid - 2;
|
||||
else if ( (*p) > _mid[1] )
|
||||
_lower = _mid + 2;
|
||||
else {
|
||||
_trans += (unsigned int)((_mid - _keys)>>1);
|
||||
goto _match;
|
||||
}
|
||||
}
|
||||
_trans += _klen;
|
||||
}
|
||||
|
||||
_match:
|
||||
_trans = _uriparse_indicies[_trans];
|
||||
cs = _uriparse_trans_targs[_trans];
|
||||
|
||||
if ( _uriparse_trans_actions[_trans] == 0 )
|
||||
goto _again;
|
||||
|
||||
_acts = _uriparse_actions + _uriparse_trans_actions[_trans];
|
||||
_nacts = (unsigned int) *_acts++;
|
||||
while ( _nacts-- > 0 )
|
||||
{
|
||||
switch ( *_acts++ )
|
||||
{
|
||||
case 0:
|
||||
#line 110 "net/http/uriparse.rl"
|
||||
{ mark = p; }
|
||||
break;
|
||||
case 1:
|
||||
#line 111 "net/http/uriparse.rl"
|
||||
{ uri->scheme = SLICE; }
|
||||
break;
|
||||
case 3:
|
||||
#line 113 "net/http/uriparse.rl"
|
||||
{ uri->userinfo = SLICE; }
|
||||
break;
|
||||
case 4:
|
||||
#line 114 "net/http/uriparse.rl"
|
||||
{ uri->host = SLICE; }
|
||||
break;
|
||||
case 5:
|
||||
#line 115 "net/http/uriparse.rl"
|
||||
{ uri->port = SLICE; }
|
||||
break;
|
||||
case 6:
|
||||
#line 117 "net/http/uriparse.rl"
|
||||
{
|
||||
kv.k = SLICE;
|
||||
kv.v = (struct UriSlice){zero, zero};
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
#line 122 "net/http/uriparse.rl"
|
||||
{
|
||||
kv.v = SLICE;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
#line 126 "net/http/uriparse.rl"
|
||||
{
|
||||
uri->segs.i = zero;
|
||||
uri->paramsegs.i = zero;
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
#line 131 "net/http/uriparse.rl"
|
||||
{
|
||||
if (uri->params.n) {
|
||||
if (uri->params.i < uri->params.n) {
|
||||
uri->params.p[uri->params.i++] = kv;
|
||||
} else {
|
||||
return enomem();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
#line 141 "net/http/uriparse.rl"
|
||||
{
|
||||
if (uri->queries.n) {
|
||||
if (uri->queries.i < uri->queries.n) {
|
||||
uri->queries.p[uri->queries.i++] = kv;
|
||||
} else {
|
||||
return enomem();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
#line 151 "net/http/uriparse.rl"
|
||||
{
|
||||
if (p > mark && uri->segs.n) {
|
||||
if (uri->segs.i < uri->segs.n) {
|
||||
uri->segs.p[uri->segs.i++] = SLICE;
|
||||
} else {
|
||||
return enomem();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
#line 161 "net/http/uriparse.rl"
|
||||
{
|
||||
switch (urischeme(uri->scheme, buf)) {
|
||||
case kUriSchemeSip:
|
||||
case kUriSchemeSips:
|
||||
--p;
|
||||
{cs = 39;goto _again;}
|
||||
default:
|
||||
if (uricspn(p, pe - p) == pe - p) {
|
||||
uri->opaque = (struct UriSlice){p - buf, pe - p};
|
||||
return zero;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#line 611 "build/bootstrap/net/http/uriparse.c"
|
||||
}
|
||||
}
|
||||
|
||||
_again:
|
||||
if ( cs == 0 )
|
||||
goto _out;
|
||||
if ( ++p != pe )
|
||||
goto _resume;
|
||||
_test_eof: {}
|
||||
if ( p == eof )
|
||||
{
|
||||
const char *__acts = _uriparse_actions + _uriparse_eof_actions[cs];
|
||||
unsigned int __nacts = (unsigned int) *__acts++;
|
||||
while ( __nacts-- > 0 ) {
|
||||
switch ( *__acts++ ) {
|
||||
case 0:
|
||||
#line 110 "net/http/uriparse.rl"
|
||||
{ mark = p; }
|
||||
break;
|
||||
case 2:
|
||||
#line 112 "net/http/uriparse.rl"
|
||||
{ uri->fragment = SLICE; }
|
||||
break;
|
||||
case 4:
|
||||
#line 114 "net/http/uriparse.rl"
|
||||
{ uri->host = SLICE; }
|
||||
break;
|
||||
case 5:
|
||||
#line 115 "net/http/uriparse.rl"
|
||||
{ uri->port = SLICE; }
|
||||
break;
|
||||
case 6:
|
||||
#line 117 "net/http/uriparse.rl"
|
||||
{
|
||||
kv.k = SLICE;
|
||||
kv.v = (struct UriSlice){zero, zero};
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
#line 122 "net/http/uriparse.rl"
|
||||
{
|
||||
kv.v = SLICE;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
#line 126 "net/http/uriparse.rl"
|
||||
{
|
||||
uri->segs.i = zero;
|
||||
uri->paramsegs.i = zero;
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
#line 131 "net/http/uriparse.rl"
|
||||
{
|
||||
if (uri->params.n) {
|
||||
if (uri->params.i < uri->params.n) {
|
||||
uri->params.p[uri->params.i++] = kv;
|
||||
} else {
|
||||
return enomem();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
#line 141 "net/http/uriparse.rl"
|
||||
{
|
||||
if (uri->queries.n) {
|
||||
if (uri->queries.i < uri->queries.n) {
|
||||
uri->queries.p[uri->queries.i++] = kv;
|
||||
} else {
|
||||
return enomem();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
#line 151 "net/http/uriparse.rl"
|
||||
{
|
||||
if (p > mark && uri->segs.n) {
|
||||
if (uri->segs.i < uri->segs.n) {
|
||||
uri->segs.p[uri->segs.i++] = SLICE;
|
||||
} else {
|
||||
return enomem();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#line 699 "build/bootstrap/net/http/uriparse.c"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_out: {}
|
||||
}
|
||||
|
||||
#line 234 "net/http/uriparse.rl"
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
if (cs >= uriparse_first_final) {
|
||||
if (uri->host.n <= DNS_NAME_MAX && uri->port.n <= 6) {
|
||||
return zero;
|
||||
} else {
|
||||
return eoverflow();
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
|
@ -1,247 +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/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/dns/dns.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "net/http/uri.h"
|
||||
|
||||
/* TODO(jart): Rewrite in C */
|
||||
|
||||
#define static
|
||||
|
||||
/* clang-format off */
|
||||
%% machine uriparse;
|
||||
%% write data;
|
||||
/* clang-format on */
|
||||
|
||||
/**
|
||||
* Parses URI.
|
||||
*
|
||||
* This is a general URL parser. It's typically used for HTTP. Support
|
||||
* for the bonus syntax needed by SIP is provided. The whirlwhind tour
|
||||
* of the URI rabbit hole is as follows:
|
||||
*
|
||||
* /foo.html
|
||||
* //justine.local/foo.html
|
||||
* http://justine.local/foo.html
|
||||
* http://bettersearchengine.local/search.cgi?q=my%20query
|
||||
* file:///etc/passwd
|
||||
* gs://bucket/object.txt
|
||||
* zip:///usr/share/zoneinfo/GMT
|
||||
* sip:127.0.0.1:5060;lr
|
||||
* sip:+12125650666@gateway.example
|
||||
* sip:bob%20barker:priceisright@[dead:beef::666]:5060;isup-oli=00
|
||||
* data:video/mpeg;base64,gigabytesofhex
|
||||
*
|
||||
* This parser operates on slices rather than C strings. It performs
|
||||
* slicing and validation only. Operations like turning "%20"→" " or
|
||||
* "80"→80 and perfect hashing can be done later, if needed.
|
||||
*
|
||||
* The Uri object is owned by the caller; it has a lifecycle like the
|
||||
* following:
|
||||
*
|
||||
* struct Uri uri;
|
||||
* memset(&uri, 0, sizeof(uri));
|
||||
*
|
||||
* uriparse(&uri, s1, strlen(s1));
|
||||
* CHECK_EQ(kUriSchemeHttp, urischeme(uri->scheme, s1));
|
||||
*
|
||||
* uriparse(&uri, s2, strlen(s2));
|
||||
* printf("host = %`.*s\n", uri->host.n, s2 + uri->host.i);
|
||||
*
|
||||
* Inner arrays may be granted memory by the caller. The uri->𝐴.i field
|
||||
* is cleared at the mark of this function. No more than uri->𝐴.n items
|
||||
* can be inserted. If we need more than that, then ENOMEM is returned
|
||||
* rather than dynamically extending uri->𝐴.p. However, if uri->𝐴.n==0,
|
||||
* we assume caller doesn't care about uri->𝐴 and its data is discarded.
|
||||
*
|
||||
* @param uri is owned by caller
|
||||
* @param p is caller-owned uri string; won't copy/alias/mutate
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see RFC2396: Uniform Resource Identifiers (URI): Generic Syntax
|
||||
* @see RFC3261: SIP: Session Initiation Protocol
|
||||
*/
|
||||
int uriparse(struct Uri *uri, const char *p, size_t size) {
|
||||
unsigned zero, cs;
|
||||
struct UriKeyval kv;
|
||||
const char *pe, *eof, *buf, *mark;
|
||||
|
||||
assert(p || !size);
|
||||
assert(size <= 0x7ffff000);
|
||||
|
||||
#define ABSENT ((struct UriSlice){zero, zero})
|
||||
#define SLICE ((struct UriSlice){mark - buf, p - mark})
|
||||
|
||||
cs = zero = VEIL("r", 0u);
|
||||
eof = pe = (mark = buf = p) + size;
|
||||
|
||||
uri->scheme = ABSENT;
|
||||
uri->opaque = ABSENT;
|
||||
uri->userinfo = ABSENT;
|
||||
uri->host = ABSENT;
|
||||
uri->port = ABSENT;
|
||||
uri->fragment = ABSENT;
|
||||
uri->segs.i = zero;
|
||||
uri->paramsegs.i = zero;
|
||||
uri->params.i = zero;
|
||||
uri->queries.i = zero;
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
%%{
|
||||
action Mark { mark = p; }
|
||||
action SetScheme { uri->scheme = SLICE; }
|
||||
action SetFragment { uri->fragment = SLICE; }
|
||||
action SetUserinfo { uri->userinfo = SLICE; }
|
||||
action SetHost { uri->host = SLICE; }
|
||||
action SetPort { uri->port = SLICE; }
|
||||
|
||||
action SetKey {
|
||||
kv.k = SLICE;
|
||||
kv.v = (struct UriSlice){zero, zero};
|
||||
}
|
||||
|
||||
action SetVal {
|
||||
kv.v = SLICE;
|
||||
}
|
||||
|
||||
action RestartSegs {
|
||||
uri->segs.i = zero;
|
||||
uri->paramsegs.i = zero;
|
||||
}
|
||||
|
||||
action AppendParam {
|
||||
if (uri->params.n) {
|
||||
if (uri->params.i < uri->params.n) {
|
||||
uri->params.p[uri->params.i++] = kv;
|
||||
} else {
|
||||
return enomem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action AppendQuery {
|
||||
if (uri->queries.n) {
|
||||
if (uri->queries.i < uri->queries.n) {
|
||||
uri->queries.p[uri->queries.i++] = kv;
|
||||
} else {
|
||||
return enomem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action AppendSegment {
|
||||
if (p > mark && uri->segs.n) {
|
||||
if (uri->segs.i < uri->segs.n) {
|
||||
uri->segs.p[uri->segs.i++] = SLICE;
|
||||
} else {
|
||||
return enomem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action HandleOpaquePart {
|
||||
switch (urischeme(uri->scheme, buf)) {
|
||||
case kUriSchemeSip:
|
||||
case kUriSchemeSips:
|
||||
--p;
|
||||
fgoto sip;
|
||||
default:
|
||||
if (uricspn(p, pe - p) == pe - p) {
|
||||
uri->opaque = (struct UriSlice){p - buf, pe - p};
|
||||
return zero;
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")";
|
||||
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",";
|
||||
unreserved = alnum | mark;
|
||||
ipv4c = digit | ".";
|
||||
ipv6c = xdigit | "." | ":";
|
||||
hostc = alnum | "-" | ".";
|
||||
telc = digit | "+" | "-";
|
||||
schemec = alnum | "+" | "-" | ".";
|
||||
userinfoc = unreserved | "&" | "=" | "+" | "$" | "," | "?" | ":";
|
||||
paramc = unreserved | "[" | "]" | ":" | "&" | "+" | "$";
|
||||
queryc = unreserved | "[" | "]" | "/" | "?" | ":" | "+" | "$";
|
||||
pathc = unreserved | ":" | "@" | "&" | "=" | "+" | "$" | ",";
|
||||
relc = unreserved | ";" | "@" | "&" | "=" | "+" | "$" | ",";
|
||||
uric = reserved | unreserved;
|
||||
|
||||
escaped = "%" xdigit xdigit;
|
||||
pathchar = escaped | pathc;
|
||||
urichar = escaped | uric;
|
||||
relchar = escaped | relc;
|
||||
userinfochar = escaped | userinfoc;
|
||||
paramchar = escaped | paramc;
|
||||
querychar = escaped | queryc;
|
||||
|
||||
paramkey = paramchar+ >Mark %SetKey;
|
||||
paramval = paramchar+ >Mark %SetVal;
|
||||
param = ";" paramkey ( "=" paramval )? %AppendParam;
|
||||
|
||||
querykey = querychar+ >Mark %SetKey;
|
||||
queryval = querychar+ >Mark %SetVal;
|
||||
query = querykey ( "=" queryval )? %AppendQuery;
|
||||
queries = "?" query ( "&" query )*;
|
||||
|
||||
scheme = ( alpha @Mark schemec* ) ":" @SetScheme;
|
||||
userinfo = userinfochar+ >Mark "@" @SetUserinfo;
|
||||
host6 = "[" ( ipv6c+ >Mark %SetHost ) "]";
|
||||
host = host6 | ( ( ipv4c | hostc | telc )+ >Mark %SetHost );
|
||||
port = digit+ >Mark %SetPort;
|
||||
hostport = host ( ":" port )?;
|
||||
authority = userinfo? hostport;
|
||||
segment = pathchar+ %AppendSegment param*;
|
||||
rel_segment = relchar+ >Mark %AppendSegment;
|
||||
path_segments = segment ( "/" @Mark segment )*;
|
||||
abs_path = "/" @Mark path_segments;
|
||||
net_path = "//" authority abs_path? >RestartSegs;
|
||||
hier_part = ( net_path | abs_path ) queries?;
|
||||
rel_path = rel_segment abs_path?;
|
||||
opaque_part = ( urichar -- "/" ) @HandleOpaquePart;
|
||||
fragment = "#" urichar* >Mark %SetFragment;
|
||||
relativeURI = ( net_path | abs_path | rel_path ) queries?;
|
||||
absoluteURI = scheme ( hier_part | opaque_part );
|
||||
sip := authority >Mark param*;
|
||||
uri := ( relativeURI | absoluteURI )? fragment?;
|
||||
}%%
|
||||
|
||||
%% write init;
|
||||
cs = uriparse_en_uri;
|
||||
%% write exec;
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
if (cs >= uriparse_first_final) {
|
||||
if (uri->host.n <= DNS_NAME_MAX && uri->port.n <= 6) {
|
||||
return zero;
|
||||
} else {
|
||||
return eoverflow();
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -5,31 +5,34 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
struct UrlView {
|
||||
size_t n;
|
||||
char *p; /* not allocated; not nul terminated */
|
||||
char *p;
|
||||
};
|
||||
|
||||
struct UrlParams {
|
||||
size_t n;
|
||||
struct Param {
|
||||
struct UrlParam {
|
||||
struct UrlView key;
|
||||
struct UrlView val; /* val.n may be SIZE_MAX */
|
||||
struct UrlView val;
|
||||
} * p;
|
||||
};
|
||||
|
||||
struct Url {
|
||||
struct UrlView scheme;
|
||||
struct UrlView user;
|
||||
struct UrlView pass;
|
||||
struct UrlView host;
|
||||
struct UrlView port;
|
||||
struct UrlView path;
|
||||
struct UrlView scheme; /* must be [A-Za-z][-+.0-9A-Za-z]* or empty */
|
||||
struct UrlView user; /* depends on host non-absence */
|
||||
struct UrlView pass; /* depends on user non-absence */
|
||||
struct UrlView host; /* or reg_name */
|
||||
struct UrlView port; /* depends on host non-absence */
|
||||
struct UrlView path; /* or opaque_part */
|
||||
struct UrlParams params;
|
||||
struct UrlView fragment;
|
||||
};
|
||||
|
||||
char *EncodeUrl(struct Url *, size_t *);
|
||||
char *ParseUrl(const char *, size_t, struct Url *);
|
||||
char *ParseParams(const char *, size_t, struct UrlParams *);
|
||||
char *ParseRequestUri(const char *, size_t, struct Url *);
|
||||
char *ParseHost(const char *, size_t, struct Url *);
|
||||
char *EscapeUrlView(char *, struct UrlView *, const char[256]);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue