const char* parse_request(const char* buf, const char* buf_end, const char** method, size_t* method_len, const char** path, size_t* path_len, int* minor_version, struct phr_header* headers, size_t* num_headers, size_t max_headers, int* ret) { /* skip first empty line (some clients add CRLF after POST content) */ CHECK_EOF(); if (*buf == '\015') { ++buf; EXPECT_CHAR('\012'); } else if (*buf == '\012') { ++buf; } /* parse request line */ ADVANCE_TOKEN(*method, *method_len); ++buf; ADVANCE_TOKEN(*path, *path_len); ++buf; if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) { return NULL; } if (*buf == '\015') { ++buf; EXPECT_CHAR('\012'); } else if (*buf == '\012') { ++buf; } else { *ret = -1; return NULL; } return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); }
static const char* is_complete(const char* buf, const char* buf_end, size_t last_len, int* ret) { int ret_cnt = 0; buf = last_len < 3 ? buf : buf + last_len - 3; while (1) { CHECK_EOF(); if (*buf == '\015') { ++buf; CHECK_EOF(); EXPECT_CHAR('\012'); ++ret_cnt; } else if (*buf == '\012') { ++buf; ++ret_cnt; } else { ++buf; ret_cnt = 0; } if (ret_cnt == 2) { return buf; } } *ret = -2; return NULL; }
static const char* get_token_to_eol(const char* buf, const char* buf_end, const char** token, size_t* token_len, int* ret) { const char* token_start = buf; #ifdef __SSE4_2__ static const char ranges1[] = "\0\010" /* allow HT */ "\012\037" /* allow SP and up to but not including DEL */ "\177\177" /* allow chars w. MSB set */ ; int found; buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found); if (found) goto FOUND_CTL; #else /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */ while (likely(buf_end - buf >= 8)) { #define DOIT() if (unlikely(! IS_PRINTABLE_ASCII(*buf))) goto NonPrintable; ++buf DOIT(); DOIT(); DOIT(); DOIT(); DOIT(); DOIT(); DOIT(); DOIT(); #undef DOIT continue; NonPrintable: if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { goto FOUND_CTL; } ++buf; } #endif for (; ; ++buf) { CHECK_EOF(); if (unlikely(! IS_PRINTABLE_ASCII(*buf))) { if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { goto FOUND_CTL; } } } FOUND_CTL: if (likely(*buf == '\015')) { ++buf; EXPECT_CHAR('\012'); *token_len = buf - 2 - token_start; } else if (*buf == '\012') { *token_len = buf - token_start; ++buf; } else { *ret = -1; return NULL; } *token = token_start; return buf; }
/* returned pointer is always within [buf, buf_end), or null */ static const char* parse_http_version(const char* buf, const char* buf_end, int* minor_version, int* ret) { EXPECT_CHAR('H'); EXPECT_CHAR('T'); EXPECT_CHAR('T'); EXPECT_CHAR('P'); EXPECT_CHAR('/'); EXPECT_CHAR('1'); EXPECT_CHAR('.'); return parse_int(buf, buf_end, minor_version, ret); }
static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret) { for (;; ++*num_headers) { CHECK_EOF(); if (*buf == '\015') { ++buf; EXPECT_CHAR('\012'); break; } else if (*buf == '\012') { ++buf; break; } if (*num_headers == max_headers) { *ret = -1; return NULL; } if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) { if (!token_char_map[(unsigned char)*buf]) { *ret = -1; return NULL; } /* parsing name, but do not discard SP before colon, see * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */ headers[*num_headers].name = buf; static const char ALIGNED(16) ranges1[] = "::\x00\037"; int found; buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found); if (!found) { CHECK_EOF(); } while (1) { if (*buf == ':') { break; } else if (*buf < ' ') { *ret = -1; return NULL; } ++buf; CHECK_EOF(); } headers[*num_headers].name_len = buf - headers[*num_headers].name; ++buf; for (;; ++buf) { CHECK_EOF(); if (!(*buf == ' ' || *buf == '\t')) { break; } } } else { headers[*num_headers].name = NULL; headers[*num_headers].name_len = 0; } if ((buf = get_token_to_eol(buf, buf_end, &headers[*num_headers].value, &headers[*num_headers].value_len, ret)) == NULL) { return NULL; } }
/* * Read key blob from string buffer (null terminated) and convert it to * binary format. Returns xmallocated blob, and if blob_len, version_major, * version_minor, or is_public have non NULL value the length of blob, * major and minor version numbers of format, and whatever the blob was * private or public key are returned. */ unsigned char *ssh_key_blob_read_from_string(const char *str, size_t *blob_len, char **headers, unsigned int *version_major, unsigned int *version_minor, Boolean *is_public) { unsigned char *blob, *blob2; const char *base64blob, *crc64blob; unsigned int number; size_t base64blob_len, crc64blob_len; const char *p, *compare, *again, *headers_beg, *headers_end; unsigned char *p2; Boolean public; SshUInt32 crc32; if (version_major != NULL) *version_major = 0; if (version_minor != NULL) *version_minor = 0; if (blob_len != NULL) *blob_len = 0; p = str; #define SKIP_SPACE(p) \ do { while (isspace(*(p))) (p)++; } while (0) #define EXPECT_CHAR(p,ch) \ do { if (*(p) != (ch)) goto error; } while (0) #define SKIP_CHARS(p,ch) \ do { while (*(p) == (ch) || isspace(*(p))) (p)++; } while (0) #define MATCH_STRING(p,str) \ do { for(; *(p) && *(str) == tolower(*(p));(str)++) { (p)++; SKIP_SPACE(p);}\ } while (0) #define MATCH_STRING_GOTO_ERROR(p,str) \ do { MATCH_STRING((p),(str)); if (*(str)) goto error; } while (0) #define READ_NUMBER(p,n) \ do { (n) = 0; SKIP_SPACE(p); for(; isdigit(*(p)); ) \ { (n) = ((n) * 10) + (*(p) - '0'); (p)++; SKIP_SPACE(p); } } while (0) SKIP_SPACE(p); /* Read begin line */ EXPECT_CHAR(p, '-'); SKIP_CHARS(p, '-'); compare = "beginssh"; MATCH_STRING_GOTO_ERROR(p, compare); again = p; compare = "public"; MATCH_STRING(p, compare); if (*compare) { p = again; compare = "private"; MATCH_STRING_GOTO_ERROR(p, compare); public = FALSE; }
static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret) { for (;; ++*num_headers) { CHECK_EOF(); if (*buf == '\015') { ++buf; EXPECT_CHAR('\012'); break; } else if (*buf == '\012') { ++buf; break; } if (*num_headers == max_headers) { *ret = -1; return NULL; } if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) { /* parsing name, but do not discard SP before colon, see * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */ headers[*num_headers].name = buf; static const char ALIGNED(16) ranges1[] = "\x00 " /* control chars and up to SP */ "\"\"" /* 0x22 */ "()" /* 0x28,0x29 */ ",," /* 0x2c */ "//" /* 0x2f */ ":@" /* 0x3a-0x40 */ "[]" /* 0x5b-0x5d */ "{\377"; /* 0x7b-0xff */ int found; buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found); if (!found) { CHECK_EOF(); } while (1) { if (*buf == ':') { break; } else if (!token_char_map[(unsigned char)*buf]) { *ret = -1; return NULL; } ++buf; CHECK_EOF(); } if ((headers[*num_headers].name_len = buf - headers[*num_headers].name) == 0) { *ret = -1; return NULL; } ++buf; for (;; ++buf) { CHECK_EOF(); if (!(*buf == ' ' || *buf == '\t')) { break; } } } else {
static const char* parse_headers(const char* buf, const char* buf_end, struct phr_header* headers, size_t* num_headers, size_t max_headers, int* ret) { for (; ; ++*num_headers) { CHECK_EOF(); if (*buf == '\015') { ++buf; EXPECT_CHAR('\012'); break; } else if (*buf == '\012') { ++buf; break; } if (*num_headers == max_headers) { *ret = -1; return NULL; } if (*num_headers == 0 || ! (*buf == ' ' || *buf == '\t')) { /* parsing name, but do not discard SP before colon, see * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */ headers[*num_headers].name = buf; for (; ; ++buf) { CHECK_EOF(); if (*buf == ':') { break; } else if (*buf < ' ') { *ret = -1; return NULL; } } headers[*num_headers].name_len = buf - headers[*num_headers].name; ++buf; for (; ; ++buf) { CHECK_EOF(); if (! (*buf == ' ' || *buf == '\t')) { break; } } } else { headers[*num_headers].name = NULL; headers[*num_headers].name_len = 0; } if ((buf = get_token_to_eol(buf, buf_end, &headers[*num_headers].value, &headers[*num_headers].value_len, ret)) == NULL) { return NULL; } } return buf; }
static void test_many_chars() { msg_t *msg; msg = CEX_make_write_msg(0); REQ_WMSG(msg); for (int cycle=0; cycle<6; cycle++) { for (int ci=1<<cycle; ci<256; ci++) { CEX_msg_write_char(msg, (char)ci); } } setup_read(msg); for (int cycle=0; cycle<6; cycle++) { for (int ci=1<<cycle; ci<256; ci++) { EXPECT_CHAR((char)ci, CEX_msg_read_char(msg)); } } REQ_MSG_EOFP(msg); CEX_free_msg(msg); }
static const char* get_token_to_eol(const char* buf, const char* buf_end, const char** token, size_t* token_len, int* ret) { const char* token_start = buf; while (1) { if (likely(buf_end - buf >= 16)) { unsigned i; for (i = 0; i < 16; i++, ++buf) { if (unlikely((unsigned char)*buf <= '\015') && (*buf == '\015' || *buf == '\012')) { goto EOL_FOUND; } } } else { for (; ; ++buf) { CHECK_EOF(); if (unlikely((unsigned char)*buf <= '\015') && (*buf == '\015' || *buf == '\012')) { goto EOL_FOUND; } } } } EOL_FOUND: if (*buf == '\015') { ++buf; EXPECT_CHAR('\012'); *token_len = buf - 2 - token_start; } else { /* should be: *buf == '\012' */ *token_len = buf - token_start; ++buf; } *token = token_start; return buf; }
static ssize_t parse_proxy_line(char *src, size_t len, struct sockaddr *sa, socklen_t *salen) { #define CHECK_EOF() \ if (p == end) \ return -2 #define EXPECT_CHAR(ch) \ do { \ CHECK_EOF(); \ if (*p++ != ch) \ return -1; \ } while (0) #define SKIP_TO_WS() \ do { \ do { \ CHECK_EOF(); \ } while (*p++ != ' '); \ --p; \ } while (0) char *p = src, *end = p + len; void *addr; in_port_t *port; /* "PROXY "*/ EXPECT_CHAR('P'); EXPECT_CHAR('R'); EXPECT_CHAR('O'); EXPECT_CHAR('X'); EXPECT_CHAR('Y'); EXPECT_CHAR(' '); /* "TCP[46] " */ CHECK_EOF(); if (*p++ != 'T') { *salen = 0; /* indicate that no data has been obtained */ goto SkipToEOL; } EXPECT_CHAR('C'); EXPECT_CHAR('P'); CHECK_EOF(); switch (*p++) { case '4': *salen = sizeof(struct sockaddr_in); *((struct sockaddr_in *)sa) = (struct sockaddr_in){}; sa->sa_family = AF_INET; addr = &((struct sockaddr_in *)sa)->sin_addr; port = &((struct sockaddr_in *)sa)->sin_port; break; case '6': *salen = sizeof(struct sockaddr_in6); *((struct sockaddr_in6 *)sa) = (struct sockaddr_in6){}; sa->sa_family = AF_INET6; addr = &((struct sockaddr_in6 *)sa)->sin6_addr; port = &((struct sockaddr_in6 *)sa)->sin6_port; break; default: return -1; } EXPECT_CHAR(' '); /* parse peer address */ char *addr_start = p; SKIP_TO_WS(); *p = '\0'; if (inet_pton(sa->sa_family, addr_start, addr) != 1) return -1; *p++ = ' '; /* skip local address */ SKIP_TO_WS(); ++p; /* parse peer port */ char *port_start = p; SKIP_TO_WS(); *p = '\0'; unsigned short usval; if (sscanf(port_start, "%hu", &usval) != 1) return -1; *port = htons(usval); *p++ = ' '; SkipToEOL: do { CHECK_EOF(); } while (*p++ != '\r'); CHECK_EOF(); if (*p++ != '\n') return -2; return p - src; #undef CHECK_EOF #undef EXPECT_CHAR #undef SKIP_TO_WS }