mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-22 21:32:31 +00:00
Merge HTTP request / response parsing code
This change also fixes a bug so that DNS lookups work correctly when the first answer is a CNAME record.
This commit is contained in:
parent
5a6c0f27c3
commit
a68cc690ff
20 changed files with 561 additions and 616 deletions
|
@ -85,3 +85,11 @@ Uri, kHttpUri
|
|||
Warning, kHttpWarning
|
||||
WWW-Authenticate, kHttpWwwAuthenticate
|
||||
Via, kHttpVia
|
||||
Strict-Transport-Security, kHttpStrictTransportSecurity
|
||||
X-Frame-Options, kHttpXFrameOptions
|
||||
X-Content-Type-Options, kHttpXContentTypeOptions
|
||||
Alt-Svc, kHttpAltSvc
|
||||
Referrer-Policy, kHttpReferrerPolicy
|
||||
X-XSS-Protection, kHttpXXssProtection
|
||||
Accept-Ranges, kHttpAcceptRanges
|
||||
Set-Cookie, kHttpSetCookie
|
||||
|
|
|
@ -38,12 +38,12 @@
|
|||
#line 12 "gethttpheader.gperf"
|
||||
struct thatispacked HttpHeaderSlot { char *name; char code; };
|
||||
|
||||
#define TOTAL_KEYWORDS 73
|
||||
#define TOTAL_KEYWORDS 82
|
||||
#define MIN_WORD_LENGTH 2
|
||||
#define MAX_WORD_LENGTH 32
|
||||
#define MIN_HASH_VALUE 6
|
||||
#define MAX_HASH_VALUE 142
|
||||
/* maximum key range = 137, duplicates = 0 */
|
||||
#define MAX_HASH_VALUE 133
|
||||
/* maximum key range = 128, duplicates = 0 */
|
||||
|
||||
#ifndef GPERF_DOWNCASE
|
||||
#define GPERF_DOWNCASE 1
|
||||
|
@ -72,7 +72,7 @@ static unsigned char gperf_downcase[256] =
|
|||
|
||||
#ifndef GPERF_CASE_STRNCMP
|
||||
#define GPERF_CASE_STRNCMP 1
|
||||
static inline int
|
||||
static int
|
||||
gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
|
||||
{
|
||||
for (; n > 0;)
|
||||
|
@ -102,32 +102,32 @@ hash (register const char *str, register size_t len)
|
|||
{
|
||||
static const unsigned char asso_values[] =
|
||||
{
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 0, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 0, 143, 20, 75, 5,
|
||||
35, 30, 15, 30, 143, 55, 15, 40, 0, 65,
|
||||
30, 143, 35, 20, 0, 50, 10, 30, 55, 45,
|
||||
143, 143, 143, 143, 143, 143, 143, 0, 143, 20,
|
||||
75, 5, 35, 30, 15, 30, 143, 55, 15, 40,
|
||||
0, 65, 30, 143, 35, 20, 0, 50, 10, 30,
|
||||
55, 45, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
|
||||
143, 143, 143, 143, 143, 143
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 20, 134, 134, 134, 134,
|
||||
134, 134, 134, 0, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 0, 134, 20, 95, 5,
|
||||
10, 70, 15, 30, 134, 5, 15, 20, 0, 75,
|
||||
40, 134, 35, 20, 0, 50, 25, 30, 0, 30,
|
||||
134, 134, 134, 134, 134, 134, 134, 0, 134, 20,
|
||||
95, 5, 10, 70, 15, 30, 134, 5, 15, 20,
|
||||
0, 75, 40, 134, 35, 20, 0, 50, 25, 30,
|
||||
0, 30, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
|
||||
134, 134, 134, 134, 134, 134
|
||||
};
|
||||
register unsigned int hval = len;
|
||||
|
||||
|
@ -165,7 +165,7 @@ hash (register const char *str, register size_t len)
|
|||
return hval + asso_values[(unsigned char)str[len - 1]];
|
||||
}
|
||||
|
||||
static inline const struct thatispacked HttpHeaderSlot *
|
||||
static const struct thatispacked HttpHeaderSlot *
|
||||
LookupHttpHeader (register const char *str, register size_t len)
|
||||
{
|
||||
static const struct thatispacked HttpHeaderSlot wordlist[] =
|
||||
|
@ -185,18 +185,31 @@ LookupHttpHeader (register const char *str, register size_t len)
|
|||
{"Authorization", kHttpAuthorization},
|
||||
#line 48 "gethttpheader.gperf"
|
||||
{"Accept-Charset", kHttpAcceptCharset},
|
||||
{""}, {""}, {""}, {""},
|
||||
{""},
|
||||
#line 93 "gethttpheader.gperf"
|
||||
{"X-XSS-Protection", kHttpXXssProtection},
|
||||
#line 34 "gethttpheader.gperf"
|
||||
{"X-CSRF-Token", kHttpXCsrfToken},
|
||||
{""},
|
||||
#line 14 "gethttpheader.gperf"
|
||||
{"Host", kHttpHost},
|
||||
#line 18 "gethttpheader.gperf"
|
||||
{"Accept-Language", kHttpAcceptLanguage},
|
||||
{""}, {""},
|
||||
#line 32 "gethttpheader.gperf"
|
||||
{"X-Forwarded-Host", kHttpXForwardedHost},
|
||||
{""},
|
||||
#line 73 "gethttpheader.gperf"
|
||||
{"Location", kHttpLocation},
|
||||
{""}, {""},
|
||||
#line 72 "gethttpheader.gperf"
|
||||
{"Link", kHttpLink},
|
||||
#line 71 "gethttpheader.gperf"
|
||||
{"Keep-Alive", kHttpKeepAlive},
|
||||
#line 53 "gethttpheader.gperf"
|
||||
{"Access-Control-MaxAge", kHttpAccessControlMaxAge},
|
||||
{""}, {""},
|
||||
#line 91 "gethttpheader.gperf"
|
||||
{"Alt-Svc", kHttpAltSvc},
|
||||
#line 87 "gethttpheader.gperf"
|
||||
{"Via", kHttpVia},
|
||||
#line 35 "gethttpheader.gperf"
|
||||
{"Save-Data", kHttpSaveData},
|
||||
#line 16 "gethttpheader.gperf"
|
||||
|
@ -205,18 +218,21 @@ LookupHttpHeader (register const char *str, register size_t len)
|
|||
{"Cookie", kHttpCookie},
|
||||
#line 42 "gethttpheader.gperf"
|
||||
{"Expires", kHttpExpires},
|
||||
{""}, {""},
|
||||
#line 94 "gethttpheader.gperf"
|
||||
{"Accept-Ranges", kHttpAcceptRanges},
|
||||
#line 29 "gethttpheader.gperf"
|
||||
{"From", kHttpFrom},
|
||||
#line 46 "gethttpheader.gperf"
|
||||
{"Allow", kHttpAllow},
|
||||
#line 25 "gethttpheader.gperf"
|
||||
{"Pragma", kHttpPragma},
|
||||
#line 31 "gethttpheader.gperf"
|
||||
{"X-Requested-With", kHttpXRequestedWith},
|
||||
#line 60 "gethttpheader.gperf"
|
||||
{"Content-Base", kHttpContentBase},
|
||||
#line 47 "gethttpheader.gperf"
|
||||
{"Content-Range", kHttpContentRange},
|
||||
#line 45 "gethttpheader.gperf"
|
||||
{"ETag", kHttpEtag},
|
||||
{""},
|
||||
#line 95 "gethttpheader.gperf"
|
||||
{"Set-Cookie", kHttpSetCookie},
|
||||
#line 63 "gethttpheader.gperf"
|
||||
{"Content-Language", kHttpContentLanguage},
|
||||
#line 81 "gethttpheader.gperf"
|
||||
|
@ -227,8 +243,8 @@ LookupHttpHeader (register const char *str, register size_t len)
|
|||
{"Content-Description", kHttpContentDescription},
|
||||
#line 36 "gethttpheader.gperf"
|
||||
{"Range", kHttpRange},
|
||||
#line 77 "gethttpheader.gperf"
|
||||
{"Proxy-Connection", kHttpProxyConnection},
|
||||
#line 25 "gethttpheader.gperf"
|
||||
{"Pragma", kHttpPragma},
|
||||
#line 28 "gethttpheader.gperf"
|
||||
{"Sec-GPC", kHttpSecGpc},
|
||||
#line 15 "gethttpheader.gperf"
|
||||
|
@ -239,15 +255,15 @@ LookupHttpHeader (register const char *str, register size_t len)
|
|||
{"Access-Control-Request-Methods", kHttpAccessControlRequestMethods},
|
||||
#line 86 "gethttpheader.gperf"
|
||||
{"WWW-Authenticate", kHttpWwwAuthenticate},
|
||||
#line 82 "gethttpheader.gperf"
|
||||
{"Transfer-Encoding", kHttpTransferEncoding},
|
||||
{""},
|
||||
#line 67 "gethttpheader.gperf"
|
||||
{"If-Match", kHttpIfMatch},
|
||||
#line 37 "gethttpheader.gperf"
|
||||
{"Content-Length", kHttpContentLength},
|
||||
{""},
|
||||
#line 78 "gethttpheader.gperf"
|
||||
{"Public", kHttpPublic},
|
||||
#line 22 "gethttpheader.gperf"
|
||||
{"X-Forwarded-For", kHttpXForwardedFor},
|
||||
#line 77 "gethttpheader.gperf"
|
||||
{"Proxy-Connection", kHttpProxyConnection},
|
||||
#line 30 "gethttpheader.gperf"
|
||||
{"If-Modified-Since", kHttpIfModifiedSince},
|
||||
#line 68 "gethttpheader.gperf"
|
||||
|
@ -262,86 +278,87 @@ LookupHttpHeader (register const char *str, register size_t len)
|
|||
{"Upgrade", kHttpUpgrade},
|
||||
#line 50 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Headers", kHttpAccessControlAllowHeaders},
|
||||
#line 70 "gethttpheader.gperf"
|
||||
{"If-Unmodified-Since", kHttpIfUnmodifiedSince},
|
||||
{""},
|
||||
#line 78 "gethttpheader.gperf"
|
||||
{"Public", kHttpPublic},
|
||||
#line 38 "gethttpheader.gperf"
|
||||
{"Content-Type", kHttpContentType},
|
||||
#line 51 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Methods", kHttpAccessControlAllowMethods},
|
||||
#line 62 "gethttpheader.gperf"
|
||||
{"Content-Disposition", kHttpContentDisposition},
|
||||
{""}, {""},
|
||||
#line 49 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Credentials", kHttpAccessControlAllowCredentials},
|
||||
{""},
|
||||
#line 76 "gethttpheader.gperf"
|
||||
{"Proxy-Authorization", kHttpProxyAuthorization},
|
||||
#line 89 "gethttpheader.gperf"
|
||||
{"X-Frame-Options", kHttpXFrameOptions},
|
||||
{""},
|
||||
#line 21 "gethttpheader.gperf"
|
||||
{"Referer", kHttpReferer},
|
||||
#line 75 "gethttpheader.gperf"
|
||||
{"Proxy-Authenticate", kHttpProxyAuthenticate},
|
||||
#line 45 "gethttpheader.gperf"
|
||||
{"ETag", kHttpEtag},
|
||||
{""},
|
||||
#line 23 "gethttpheader.gperf"
|
||||
{"Origin", kHttpOrigin},
|
||||
#line 90 "gethttpheader.gperf"
|
||||
{"X-Content-Type-Options", kHttpXContentTypeOptions},
|
||||
#line 84 "gethttpheader.gperf"
|
||||
{"Uri", kHttpUri},
|
||||
{""}, {""},
|
||||
#line 79 "gethttpheader.gperf"
|
||||
{"Retry-After", kHttpRetryAfter},
|
||||
#line 74 "gethttpheader.gperf"
|
||||
{"Max-Forwards", kHttpMaxForwards},
|
||||
{""}, {""}, {""}, {""},
|
||||
#line 82 "gethttpheader.gperf"
|
||||
{"Transfer-Encoding", kHttpTransferEncoding},
|
||||
{""}, {""}, {""}, {""},
|
||||
#line 33 "gethttpheader.gperf"
|
||||
{"X-Forwarded-Proto", kHttpXForwardedProto},
|
||||
#line 27 "gethttpheader.gperf"
|
||||
{"DNT", kHttpDnt},
|
||||
{""},
|
||||
#line 24 "gethttpheader.gperf"
|
||||
{"Upgrade-Insecure-Requests", kHttpUpgradeInsecureRequests},
|
||||
{""},
|
||||
#line 52 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Origin", kHttpAccessControlAllowOrigin},
|
||||
{""},
|
||||
#line 40 "gethttpheader.gperf"
|
||||
{"Date", kHttpDate},
|
||||
#line 19 "gethttpheader.gperf"
|
||||
{"Accept-Encoding", kHttpAcceptEncoding},
|
||||
#line 43 "gethttpheader.gperf"
|
||||
{"Content-Encoding", kHttpContentEncoding},
|
||||
#line 85 "gethttpheader.gperf"
|
||||
{"Warning", kHttpWarning},
|
||||
#line 75 "gethttpheader.gperf"
|
||||
{"Proxy-Authenticate", kHttpProxyAuthenticate},
|
||||
#line 62 "gethttpheader.gperf"
|
||||
{"Content-Disposition", kHttpContentDisposition},
|
||||
{""},
|
||||
#line 23 "gethttpheader.gperf"
|
||||
{"Origin", kHttpOrigin},
|
||||
#line 49 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Credentials", kHttpAccessControlAllowCredentials},
|
||||
{""},
|
||||
#line 72 "gethttpheader.gperf"
|
||||
{"Link", kHttpLink},
|
||||
#line 71 "gethttpheader.gperf"
|
||||
{"Keep-Alive", kHttpKeepAlive},
|
||||
#line 32 "gethttpheader.gperf"
|
||||
{"X-Forwarded-Host", kHttpXForwardedHost},
|
||||
#line 21 "gethttpheader.gperf"
|
||||
{"Referer", kHttpReferer},
|
||||
#line 27 "gethttpheader.gperf"
|
||||
{"DNT", kHttpDnt},
|
||||
#line 29 "gethttpheader.gperf"
|
||||
{"From", kHttpFrom},
|
||||
{""}, {""},
|
||||
#line 38 "gethttpheader.gperf"
|
||||
{"Content-Type", kHttpContentType},
|
||||
#line 84 "gethttpheader.gperf"
|
||||
{"Uri", kHttpUri},
|
||||
#line 40 "gethttpheader.gperf"
|
||||
{"Date", kHttpDate},
|
||||
{""},
|
||||
#line 79 "gethttpheader.gperf"
|
||||
{"Retry-After", kHttpRetryAfter},
|
||||
{""},
|
||||
#line 51 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Methods", kHttpAccessControlAllowMethods},
|
||||
#line 70 "gethttpheader.gperf"
|
||||
{"If-Unmodified-Since", kHttpIfUnmodifiedSince},
|
||||
{""},
|
||||
#line 31 "gethttpheader.gperf"
|
||||
{"X-Requested-With", kHttpXRequestedWith},
|
||||
#line 52 "gethttpheader.gperf"
|
||||
{"Access-Control-Allow-Origin", kHttpAccessControlAllowOrigin},
|
||||
{""}, {""}, {""},
|
||||
#line 88 "gethttpheader.gperf"
|
||||
{"Strict-Transport-Security", kHttpStrictTransportSecurity},
|
||||
#line 64 "gethttpheader.gperf"
|
||||
{"Content-Location", kHttpContentLocation},
|
||||
{""}, {""}, {""}, {""},
|
||||
#line 54 "gethttpheader.gperf"
|
||||
{"Access-Control-Method", kHttpAccessControlMethod},
|
||||
{""}, {""}, {""},
|
||||
#line 24 "gethttpheader.gperf"
|
||||
{"Upgrade-Insecure-Requests", kHttpUpgradeInsecureRequests},
|
||||
#line 64 "gethttpheader.gperf"
|
||||
{"Content-Location", kHttpContentLocation},
|
||||
{""}, {""},
|
||||
#line 92 "gethttpheader.gperf"
|
||||
{"Referrer-Policy", kHttpReferrerPolicy},
|
||||
{""}, {""}, {""},
|
||||
#line 56 "gethttpheader.gperf"
|
||||
{"Access-Control-Request-Method", kHttpAccessControlRequestMethod},
|
||||
{""},
|
||||
#line 65 "gethttpheader.gperf"
|
||||
{"Content-MD5", kHttpContentMd5},
|
||||
#line 74 "gethttpheader.gperf"
|
||||
{"Max-Forwards", kHttpMaxForwards},
|
||||
{""}, {""},
|
||||
#line 22 "gethttpheader.gperf"
|
||||
{"X-Forwarded-For", kHttpXForwardedFor},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{""}, {""},
|
||||
#line 34 "gethttpheader.gperf"
|
||||
{"X-CSRF-Token", kHttpXCsrfToken},
|
||||
{""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
|
||||
{""}, {""}, {""}, {""}, {""}, {""},
|
||||
#line 44 "gethttpheader.gperf"
|
||||
{"Last-Modified", kHttpLastModified},
|
||||
{""}, {""}, {""},
|
||||
#line 33 "gethttpheader.gperf"
|
||||
{"X-Forwarded-Proto", kHttpXForwardedProto}
|
||||
{"Last-Modified", kHttpLastModified}
|
||||
};
|
||||
|
||||
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
||||
|
|
|
@ -168,6 +168,22 @@ const char *GetHttpHeaderName(int h) {
|
|||
return "WWW-Authenticate";
|
||||
case kHttpVia:
|
||||
return "Via";
|
||||
case kHttpStrictTransportSecurity:
|
||||
return "Strict-Transport-Security";
|
||||
case kHttpXFrameOptions:
|
||||
return "X-Frame-Options";
|
||||
case kHttpXContentTypeOptions:
|
||||
return "X-Content-Type-Options";
|
||||
case kHttpAltSvc:
|
||||
return "Alt-Svc";
|
||||
case kHttpReferrerPolicy:
|
||||
return "Referrer-Policy";
|
||||
case kHttpXXssProtection:
|
||||
return "X-XSS-Protection";
|
||||
case kHttpAcceptRanges:
|
||||
return "Accept-Ranges";
|
||||
case kHttpSetCookie:
|
||||
return "Set-Cookie";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
/**
|
||||
* Returns true if standard header has substring.
|
||||
*
|
||||
* @param m is message parsed by ParseHttpRequest
|
||||
* @param b is buffer that ParseHttpRequest parsed
|
||||
* @param m is message parsed by ParseHttpMessage
|
||||
* @param b is buffer that ParseHttpMessage parsed
|
||||
* @param h is known header, e.g. kHttpAcceptEncoding
|
||||
* @param s should not contain comma
|
||||
* @param n is byte length of s where -1 implies strlen
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
#define COSMOPOLITAN_LIBC_HTTP_HTTP_H_
|
||||
#include "libc/time/struct/tm.h"
|
||||
|
||||
#define kHttpRequest 0
|
||||
#define kHttpResponse 1
|
||||
|
||||
#define kHttpGet 1
|
||||
#define kHttpHead 2
|
||||
#define kHttpPost 3
|
||||
|
@ -94,7 +97,15 @@
|
|||
#define kHttpWarning 71
|
||||
#define kHttpWwwAuthenticate 72
|
||||
#define kHttpVia 73
|
||||
#define kHttpHeadersMax 74
|
||||
#define kHttpStrictTransportSecurity 74
|
||||
#define kHttpXFrameOptions 75
|
||||
#define kHttpXContentTypeOptions 76
|
||||
#define kHttpAltSvc 77
|
||||
#define kHttpReferrerPolicy 78
|
||||
#define kHttpXXssProtection 79
|
||||
#define kHttpAcceptRanges 80
|
||||
#define kHttpSetCookie 81
|
||||
#define kHttpHeadersMax 82
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
@ -116,6 +127,7 @@ struct HttpHeaders {
|
|||
struct HttpMessage {
|
||||
int i, a, status;
|
||||
unsigned char t;
|
||||
unsigned char type;
|
||||
unsigned char method;
|
||||
unsigned char version;
|
||||
struct HttpSlice k;
|
||||
|
@ -135,12 +147,9 @@ const char *GetHttpReason(int);
|
|||
const char *GetHttpHeaderName(int);
|
||||
int GetHttpHeader(const char *, size_t);
|
||||
int GetHttpMethod(const char *, size_t);
|
||||
void InitHttpRequest(struct HttpMessage *);
|
||||
void DestroyHttpRequest(struct HttpMessage *);
|
||||
int ParseHttpRequest(struct HttpMessage *, const char *, size_t);
|
||||
void InitHttpResponse(struct HttpMessage *);
|
||||
void DestroyHttpResponse(struct HttpMessage *);
|
||||
int ParseHttpResponse(struct HttpMessage *, const char *, size_t);
|
||||
void InitHttpMessage(struct HttpMessage *, int);
|
||||
void DestroyHttpMessage(struct HttpMessage *);
|
||||
int ParseHttpMessage(struct HttpMessage *, const char *, size_t);
|
||||
bool HeaderHas(struct HttpMessage *, const char *, int, const char *, size_t);
|
||||
int64_t ParseContentLength(const char *, size_t);
|
||||
char *FormatHttpDateTime(char[hasatleast 30], struct tm *);
|
||||
|
|
|
@ -19,11 +19,25 @@
|
|||
#include "net/http/ip.h"
|
||||
|
||||
/**
|
||||
* Returns true if IPv4 address can come from the Internet.
|
||||
* Returns true if IPv4 address is Globally Reachable.
|
||||
*
|
||||
* We intentionally omit TEST-NET here which can be used to simulate
|
||||
* public Internet traffic using non-Internet IPs.
|
||||
*
|
||||
* @return true 92.4499% of the time
|
||||
* @see IANA IPv4 Special-Purpose Address Registry
|
||||
*/
|
||||
bool IsPublicIp(uint32_t x) {
|
||||
return !IsLoopbackIp(x) && !IsPrivateIp(x);
|
||||
return !((x & 0xffffffff) == 0x00000000 /* 0.0.0.0/32 */ ||
|
||||
(x & 0xff000000) == 0x00000000 /* 0.0.0.0/8 */ ||
|
||||
(x & 0xff000000) == 0x0a000000 /* 10.0.0.0/8 */ ||
|
||||
(x & 0xff000000) == 0x7f000000 /* 127.0.0.0/8 */ ||
|
||||
(x & 0xfff00000) == 0xac100000 /* 172.16.0.0/12 */ ||
|
||||
(x & 0xffffff00) == 0xc0000000 /* 192.0.0.0/24 */ ||
|
||||
(x & 0xffff0000) == 0xc0a80000 /* 192.168.0.0/16 */ ||
|
||||
(x & 0xffff0000) == 0xa9fe0000 /* 169.254.0.0/16 */ ||
|
||||
(x & 0xffc00000) == 0x64400000 /* 100.64.0.0/10 */ ||
|
||||
(x & 0xfffe0000) == 0xc6120000 /* 198.18.0.0/15 */ ||
|
||||
(x & 0xf0000000) == 0xf0000000 /* 240.0.0.0/4 */ ||
|
||||
(x & 0xffffffff) == 0xffffffff /* 255.255.255.255/32 */);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/arraylist.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -30,19 +31,34 @@
|
|||
|
||||
#define LIMIT (SHRT_MAX - 2)
|
||||
|
||||
enum { START, METHOD, URI, VERSION, HKEY, HSEP, HVAL, CR1, LF1, LF2 };
|
||||
enum HttpMessageState {
|
||||
START,
|
||||
METHOD,
|
||||
URI,
|
||||
VERSION,
|
||||
STATUS,
|
||||
MESSAGE,
|
||||
HKEY,
|
||||
HSEP,
|
||||
HVAL,
|
||||
CR1,
|
||||
LF1,
|
||||
LF2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes HTTP request parser.
|
||||
* Initializes HTTP message parser.
|
||||
*/
|
||||
void InitHttpRequest(struct HttpMessage *r) {
|
||||
void InitHttpMessage(struct HttpMessage *r, int type) {
|
||||
assert(type == kHttpRequest || type == kHttpResponse);
|
||||
memset(r, 0, sizeof(*r));
|
||||
r->type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys HTTP request parser.
|
||||
* Destroys HTTP message parser.
|
||||
*/
|
||||
void DestroyHttpRequest(struct HttpMessage *r) {
|
||||
void DestroyHttpMessage(struct HttpMessage *r) {
|
||||
if (r->xheaders.p) {
|
||||
free(r->xheaders.p);
|
||||
r->xheaders.p = NULL;
|
||||
|
@ -51,7 +67,7 @@ void DestroyHttpRequest(struct HttpMessage *r) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Parses HTTP request.
|
||||
* Parses HTTP request or response.
|
||||
*
|
||||
* This parser is responsible for determining the length of a message
|
||||
* and slicing the strings inside it. Performance is attained using
|
||||
|
@ -83,7 +99,7 @@ void DestroyHttpRequest(struct HttpMessage *r) {
|
|||
* @see HTTP/1.1 RFC2616 RFC2068
|
||||
* @see HTTP/1.0 RFC1945
|
||||
*/
|
||||
int ParseHttpRequest(struct HttpMessage *r, const char *p, size_t n) {
|
||||
int ParseHttpMessage(struct HttpMessage *r, const char *p, size_t n) {
|
||||
int c, h, i;
|
||||
struct HttpHeader *x;
|
||||
for (n = MIN(n, LIMIT); r->i < n; ++r->i) {
|
||||
|
@ -92,7 +108,7 @@ int ParseHttpRequest(struct HttpMessage *r, const char *p, size_t n) {
|
|||
case START:
|
||||
if (c == '\r' || c == '\n') break; /* RFC7230 § 3.5 */
|
||||
if (!kHttpToken[c]) return ebadmsg();
|
||||
r->t = METHOD;
|
||||
r->t = r->type == kHttpRequest ? METHOD : VERSION;
|
||||
r->a = r->i;
|
||||
break;
|
||||
case METHOD:
|
||||
|
@ -133,17 +149,57 @@ int ParseHttpRequest(struct HttpMessage *r, const char *p, size_t n) {
|
|||
}
|
||||
break;
|
||||
case VERSION:
|
||||
if (c == '\r' || c == '\n') {
|
||||
if (c == ' ' || c == '\r' || c == '\n') {
|
||||
if (r->i - r->a == 8 &&
|
||||
(READ64BE(p + r->a) & 0xFFFFFFFFFF00FF00) == 0x485454502F002E00 &&
|
||||
isdigit(p[r->a + 5]) && isdigit(p[r->a + 7])) {
|
||||
r->version = (p[r->a + 5] - '0') * 10 + (p[r->a + 7] - '0');
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
if (r->type == kHttpRequest) {
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
} else {
|
||||
r->t = STATUS;
|
||||
}
|
||||
} else {
|
||||
return ebadmsg();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATUS:
|
||||
for (;;) {
|
||||
if (c == ' ' || c == '\r' || c == '\n') {
|
||||
if (r->status < 100) return ebadmsg();
|
||||
if (c == ' ') {
|
||||
r->a = r->i + 1;
|
||||
r->t = MESSAGE;
|
||||
} else {
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
}
|
||||
break;
|
||||
} else if ('0' <= c && c <= '9') {
|
||||
r->status *= 10;
|
||||
r->status += c - '0';
|
||||
if (r->status > 999) return ebadmsg();
|
||||
} else {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
}
|
||||
break;
|
||||
case MESSAGE:
|
||||
for (;;) {
|
||||
if (c == '\r' || c == '\n') {
|
||||
r->message.a = r->a;
|
||||
r->message.b = r->i;
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
break;
|
||||
} else if (c < 0x20 || (0x7F <= c && c < 0xA0)) {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
}
|
||||
break;
|
||||
case CR1:
|
||||
if (c != '\n') return ebadmsg();
|
||||
r->t = LF1;
|
|
@ -1,187 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "net/http/http.h"
|
||||
|
||||
#define LIMIT (SHRT_MAX - 2)
|
||||
|
||||
enum { START, VERSION, STATUS, MESSAGE, HKEY, HSEP, HVAL, CR1, LF1, LF2 };
|
||||
|
||||
/**
|
||||
* Initializes HTTP response parser.
|
||||
*/
|
||||
void InitHttpResponse(struct HttpMessage *r) {
|
||||
memset(r, 0, sizeof(*r));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys HTTP response parser.
|
||||
*/
|
||||
void DestroyHttpResponse(struct HttpMessage *r) {
|
||||
if (r->xheaders.p) {
|
||||
free(r->xheaders.p);
|
||||
r->xheaders.p = NULL;
|
||||
r->xheaders.n = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses HTTP response.
|
||||
*/
|
||||
int ParseHttpResponse(struct HttpMessage *r, const char *p, size_t n) {
|
||||
int c, h, i;
|
||||
struct HttpHeader *x;
|
||||
for (n = MIN(n, LIMIT); r->i < n; ++r->i) {
|
||||
c = p[r->i] & 0xff;
|
||||
switch (r->t) {
|
||||
case START:
|
||||
if (c == '\r' || c == '\n') break; /* RFC7230 § 3.5 */
|
||||
if (c != 'H') return ebadmsg();
|
||||
r->t = VERSION;
|
||||
r->a = r->i;
|
||||
break;
|
||||
case VERSION:
|
||||
if (c == ' ') {
|
||||
if (r->i - r->a == 8 &&
|
||||
(READ64BE(p + r->a) & 0xFFFFFFFFFF00FF00) == 0x485454502F002E00 &&
|
||||
isdigit(p[r->a + 5]) && isdigit(p[r->a + 7])) {
|
||||
r->version = (p[r->a + 5] - '0') * 10 + (p[r->a + 7] - '0');
|
||||
r->t = STATUS;
|
||||
} else {
|
||||
return ebadmsg();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATUS:
|
||||
for (;;) {
|
||||
if (c == ' ' || c == '\r' || c == '\n') {
|
||||
if (r->status < 100) return ebadmsg();
|
||||
if (c == ' ') {
|
||||
r->a = r->i + 1;
|
||||
r->t = MESSAGE;
|
||||
} else {
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
}
|
||||
break;
|
||||
} else if ('0' <= c && c <= '9') {
|
||||
r->status *= 10;
|
||||
r->status += c - '0';
|
||||
if (r->status > 999) return ebadmsg();
|
||||
} else {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
}
|
||||
break;
|
||||
case MESSAGE:
|
||||
for (;;) {
|
||||
if (c == '\r' || c == '\n') {
|
||||
r->message.a = r->a;
|
||||
r->message.b = r->i;
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
break;
|
||||
} else if (c < 0x20 || (0x7F <= c && c < 0xA0)) {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
}
|
||||
break;
|
||||
case CR1:
|
||||
if (c != '\n') return ebadmsg();
|
||||
r->t = LF1;
|
||||
break;
|
||||
case LF1:
|
||||
if (c == '\r') {
|
||||
r->t = LF2;
|
||||
break;
|
||||
} else if (c == '\n') {
|
||||
return ++r->i;
|
||||
} else if (!kHttpToken[c]) {
|
||||
return ebadmsg(); /* RFC7230 § 3.2.4 */
|
||||
}
|
||||
r->k.a = r->i;
|
||||
r->t = HKEY;
|
||||
break;
|
||||
case HKEY:
|
||||
for (;;) {
|
||||
if (c == ':') {
|
||||
r->k.b = r->i;
|
||||
r->t = HSEP;
|
||||
break;
|
||||
} else if (!kHttpToken[c]) {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
}
|
||||
break;
|
||||
case HSEP:
|
||||
if (c == ' ' || c == '\t') break;
|
||||
r->a = r->i;
|
||||
r->t = HVAL;
|
||||
/* fallthrough */
|
||||
case HVAL:
|
||||
for (;;) {
|
||||
if (c == '\r' || c == '\n') {
|
||||
i = r->i;
|
||||
while (i > r->a && (p[i - 1] == ' ' || p[i - 1] == '\t')) --i;
|
||||
if ((h = GetHttpHeader(p + r->k.a, r->k.b - r->k.a)) != -1 &&
|
||||
(!r->headers[h].a || !kHttpRepeatable[h])) {
|
||||
r->headers[h].a = r->a;
|
||||
r->headers[h].b = i;
|
||||
} else if ((x = realloc(
|
||||
r->xheaders.p,
|
||||
(r->xheaders.n + 1) * sizeof(*r->xheaders.p)))) {
|
||||
x[r->xheaders.n].k = r->k;
|
||||
x[r->xheaders.n].v.a = r->a;
|
||||
x[r->xheaders.n].v.b = i;
|
||||
r->xheaders.p = x;
|
||||
++r->xheaders.n;
|
||||
}
|
||||
r->t = c == '\r' ? CR1 : LF1;
|
||||
break;
|
||||
} else if ((c < 0x20 && c != '\t') || (0x7F <= c && c < 0xA0)) {
|
||||
return ebadmsg();
|
||||
}
|
||||
if (++r->i == n) break;
|
||||
c = p[r->i] & 0xff;
|
||||
}
|
||||
break;
|
||||
case LF2:
|
||||
if (c == '\n') {
|
||||
return ++r->i;
|
||||
}
|
||||
return ebadmsg();
|
||||
default:
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
if (r->i < LIMIT) {
|
||||
return 0;
|
||||
} else {
|
||||
return ebadmsg();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue