in erts/emulator/beam/packet_parser.c [643:843]
int packet_parse_http(const char* buf, int len, int* statep,
PacketCallbacks* pcb, void* arg)
{
const char* ptr = buf;
const char* p0;
int n = len;
/* remove trailing CRNL (accept NL as well) */
if ((n >= 2) && (buf[n-2] == '\r'))
n -= 2;
else if ((n >= 1) && (buf[n-1] == '\n'))
n -= 1;
if (*statep == 0) {
/* start-line = Request-Line | Status-Line */
if (n >= 5 && (sys_strncmp(buf, "HTTP/", 5) == 0)) {
int major = 0;
int minor = 0;
int status = 0;
/* Status-Line = HTTP-Version SP
* Status-Code SP Reason-Phrase
* CRNL
* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
*/
ptr += 5;
n -= 5;
p0 = ptr;
while (n && isdigit((int) *ptr)) {
major = 10*major + (*ptr - '0');
ptr++;
n--;
}
if (ptr==p0 || !n || (*ptr != '.'))
return -1;
ptr++;
n--;
p0 = ptr;
while (n && isdigit((int) *ptr)) {
minor = 10*minor + (*ptr - '0');
ptr++;
n--;
}
if (ptr==p0) return -1;
p0 = ptr;
while (n && SP(ptr)) {
ptr++; n--;
}
if (ptr==p0) return -1;
while (n && isdigit((int) *ptr)) {
status = 10*status + (*ptr - '0');
ptr++;
n--;
}
p0 = ptr;
while (n && SP(ptr)) {
ptr++; n--;
}
if (ptr==p0 && n>0) return -1;
/* NOTE: the syntax allows empty reason phrases */
(*statep) = !0;
return pcb->http_response(arg, major, minor, status,
ptr, n);
}
else {
/* Request-Line = Method SP Request-URI SP HTTP-Version CRLF */
http_atom_t* meth;
const char* meth_ptr = buf;
int meth_len;
PacketHttpURI uri;
const char* uri_ptr;
int uri_len;
int major = 0;
int minor = 0;
unsigned long h = 0;
while (n && !is_tspecial((unsigned char)*ptr)) {
hash_update(h, (int)*ptr);
ptr++;
n--;
}
meth_len = ptr - meth_ptr;
if (n == 0 || meth_len == 0 || !SP(ptr)) return -1;
meth = http_hash_lookup(meth_ptr, meth_len, h,
http_meth_hash, HTTP_METH_HASH_SIZE);
while (n && SP(ptr)) {
ptr++; n--;
}
uri_ptr = ptr;
while (n && !SP(ptr)) {
ptr++; n--;
}
if ((uri_len = (ptr - uri_ptr)) == 0)
return -1;
while (n && SP(ptr)) {
ptr++; n--;
}
if (n == 0) {
(*statep) = !0;
http_parse_uri(&uri, uri_ptr, uri_len);
return pcb->http_request(arg, meth, meth_ptr, meth_len,
&uri, 0, 9);
}
if (n < 8)
return -1;
if (sys_strncmp(ptr, "HTTP/", 5) != 0)
return -1;
ptr += 5;
n -= 5;
p0 = ptr;
while (n && isdigit((int) *ptr)) {
major = 10*major + (*ptr - '0');
ptr++;
n--;
}
if (ptr==p0 || !n || (*ptr != '.'))
return -1;
ptr++;
n--;
p0 = ptr;
while (n && isdigit((int) *ptr)) {
minor = 10*minor + (*ptr - '0');
ptr++;
n--;
}
if (ptr==p0) return -1;
(*statep) = !0;
http_parse_uri(&uri, uri_ptr, uri_len);
return pcb->http_request(arg, meth, meth_ptr, meth_len,
&uri, major, minor);
}
}
else {
int up = 1; /* make next char uppercase */
http_atom_t* name;
char name_buf[HTTP_MAX_NAME_LEN];
const char* name_ptr = name_buf;
int name_len;
unsigned long h;
if (n == 0) {
/* end of headers */
*statep = 0; /* reset state (for next request) */
return pcb->http_eoh(arg);
}
h = 0;
name_len = 0;
while (!is_tspecial((unsigned char)*ptr)) {
if (name_len < HTTP_MAX_NAME_LEN) {
int c = *ptr;
if (up) {
if (islower(c)) {
c = toupper(c);
}
up = 0;
}
else {
if (isupper(c))
c = tolower(c);
else if (c == '-')
up = 1;
}
name_buf[name_len] = c;
hash_update(h, c);
}
name_len++;
ptr++;
if (--n == 0) return -1;
}
if (*ptr != ':') {
return -1;
}
if (name_len <= HTTP_MAX_NAME_LEN) {
name = http_hash_lookup(name_buf, name_len, h,
http_hdr_hash, HTTP_HDR_HASH_SIZE);
}
else {
/* Is it ok to return original name without case adjustments? */
name_ptr = buf;
name = NULL;
}
ptr++;
n--;
/* Skip white space after ':' */
while (n && SP(ptr)) {
ptr++; n--;
}
return pcb->http_header(arg, name,
name_ptr, name_len,
buf, name_len,
ptr, n);
}
return -1;
}