save more space by removing buffer and shortening method

This also fixes test failures from the previous commit.

It also adds support for the LOCK method, which was previously
missing.

This brings the size of http_parser from 44 bytes to 32 bytes.  It
also makes the code substantially shorter, at a slight cost in
craziness.
event_stream
Cliff Frey 15 years ago committed by Ryan Dahl
parent 7a1103ae53
commit 9eac636531

@ -248,35 +248,6 @@ enum flags
#endif #endif
#define ngx_str3_cmp(m, c0, c1, c2) \
m[0] == c0 && m[1] == c1 && m[2] == c2
#define ngx_str3Ocmp(m, c0, c1, c2, c3) \
m[0] == c0 && m[2] == c2 && m[3] == c3
#define ngx_str4cmp(m, c0, c1, c2, c3) \
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3
#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4
#define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5) \
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
&& m[4] == c4 && m[5] == c5
#define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
&& m[4] == c4 && m[5] == c5 && m[6] == c6
#define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
&& m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7
#define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
&& m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8
size_t http_parser_execute (http_parser *parser, size_t http_parser_execute (http_parser *parser,
const http_parser_settings *settings, const http_parser_settings *settings,
const char *data, const char *data,
@ -354,10 +325,7 @@ size_t http_parser_execute (http_parser *parser,
state = s_res_or_resp_H; state = s_res_or_resp_H;
else { else {
parser->type = HTTP_REQUEST; parser->type = HTTP_REQUEST;
if (ch < 'A' || 'Z' < ch) goto error; goto start_req_method_assign;
parser->buffer[0] = ch;
index = 0;
state = s_req_method;
} }
break; break;
} }
@ -367,12 +335,10 @@ size_t http_parser_execute (http_parser *parser,
parser->type = HTTP_RESPONSE; parser->type = HTTP_RESPONSE;
state = s_res_HT; state = s_res_HT;
} else { } else {
if (ch < 'A' || 'Z' < ch) goto error; if (ch != 'E') goto error;
parser->type = HTTP_REQUEST; parser->type = HTTP_REQUEST;
parser->method = (enum http_method) 0; parser->method = HTTP_HEAD;
parser->buffer[0] = 'H'; index = 2;
parser->buffer[1] = ch;
index = 1;
state = s_req_method; state = s_req_method;
} }
break; break;
@ -535,128 +501,69 @@ size_t http_parser_execute (http_parser *parser,
if (ch < 'A' || 'Z' < ch) goto error; if (ch < 'A' || 'Z' < ch) goto error;
start_req_method_assign:
parser->method = (enum http_method) 0; parser->method = (enum http_method) 0;
index = 0; index = 1;
parser->buffer[0] = ch; switch (ch) {
case 'C': parser->method = HTTP_CONNECT; /* or COPY */ break;
case 'D': parser->method = HTTP_DELETE; break;
case 'G': parser->method = HTTP_GET; break;
case 'H': parser->method = HTTP_HEAD; break;
case 'L': parser->method = HTTP_LOCK; break;
case 'M': parser->method = HTTP_MKCOL; /* or MOVE */ break;
case 'O': parser->method = HTTP_OPTIONS; break;
case 'P': parser->method = HTTP_POST; /* or PROPFIND or PROPPATCH or PUT */ break;
case 'T': parser->method = HTTP_TRACE; break;
case 'U': parser->method = HTTP_UNLOCK; break;
default: goto error;
}
state = s_req_method; state = s_req_method;
break; break;
} }
case s_req_method: case s_req_method:
if (ch == ' ') { {
assert(index+1 < HTTP_PARSER_MAX_METHOD_LEN); if (ch == '\0')
parser->buffer[index+1] = '\0'; goto error;
switch (index+1) {
case 3:
if (ngx_str3_cmp(parser->buffer, 'G', 'E', 'T')) {
parser->method = HTTP_GET;
break;
}
if (ngx_str3_cmp(parser->buffer, 'P', 'U', 'T')) {
parser->method = HTTP_PUT;
break;
}
break;
case 4:
if (ngx_str4cmp(parser->buffer, 'P', 'O', 'S', 'T')) {
parser->method = HTTP_POST;
break;
}
if (ngx_str4cmp(parser->buffer, 'H', 'E', 'A', 'D')) {
parser->method = HTTP_HEAD;
break;
}
if (ngx_str4cmp(parser->buffer, 'C', 'O', 'P', 'Y')) { static const char *match_strs[] = {
"DELETE",
"GET",
"HEAD",
"POST",
"PUT",
"CONNECT",
"OPTIONS",
"TRACE",
"COPY",
"LOCK",
"MKCOL",
"MOVE",
"PROPFIND",
"PROPPATCH",
"UNLOCK" };
const char *matcher = match_strs[parser->method];
if (ch == ' ' && matcher[index] == '\0')
state = s_req_spaces_before_url;
else if (ch == matcher[index])
; // nada
else if (index == 2 && parser->method == HTTP_CONNECT && ch == 'P')
parser->method = HTTP_COPY; parser->method = HTTP_COPY;
break; else if (index == 1 && parser->method == HTTP_MKCOL && ch == 'O')
}
if (ngx_str4cmp(parser->buffer, 'M', 'O', 'V', 'E')) {
parser->method = HTTP_MOVE; parser->method = HTTP_MOVE;
break; else if (index == 1 && parser->method == HTTP_POST && ch == 'R')
} parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
else if (index == 1 && parser->method == HTTP_POST && ch == 'U')
break; parser->method = HTTP_PUT;
else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P')
case 5:
if (ngx_str5cmp(parser->buffer, 'M', 'K', 'C', 'O', 'L')) {
parser->method = HTTP_MKCOL;
break;
}
if (ngx_str5cmp(parser->buffer, 'T', 'R', 'A', 'C', 'E')) {
parser->method = HTTP_TRACE;
break;
}
break;
case 6:
if (ngx_str6cmp(parser->buffer, 'D', 'E', 'L', 'E', 'T', 'E')) {
parser->method = HTTP_DELETE;
break;
}
if (ngx_str6cmp(parser->buffer, 'U', 'N', 'L', 'O', 'C', 'K')) {
parser->method = HTTP_UNLOCK;
break;
}
break;
case 7:
if (ngx_str7_cmp(parser->buffer,
'O', 'P', 'T', 'I', 'O', 'N', 'S', '\0')) {
parser->method = HTTP_OPTIONS;
break;
}
if (ngx_str7_cmp(parser->buffer,
'C', 'O', 'N', 'N', 'E', 'C', 'T', '\0')) {
parser->method = HTTP_CONNECT;
break;
}
break;
case 8:
if (ngx_str8cmp(parser->buffer,
'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D')) {
parser->method = HTTP_PROPFIND;
break;
}
break;
case 9:
if (ngx_str9cmp(parser->buffer,
'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H')) {
parser->method = HTTP_PROPPATCH; parser->method = HTTP_PROPPATCH;
break; else
}
break;
}
state = s_req_spaces_before_url;
break;
}
if (ch < 'A' || 'Z' < ch) goto error;
if (++index >= HTTP_PARSER_MAX_METHOD_LEN - 1) {
goto error; goto error;
}
parser->buffer[index] = ch;
++index;
break; break;
}
case s_req_spaces_before_url: case s_req_spaces_before_url:
{ {
if (ch == ' ') break; if (ch == ' ') break;

@ -63,29 +63,25 @@ typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
typedef int (*http_cb) (http_parser*); typedef int (*http_cb) (http_parser*);
/* Should be at least one longer than the longest request method */
#define HTTP_PARSER_MAX_METHOD_LEN 10
/* Request Methods */ /* Request Methods */
enum http_method enum http_method
{ HTTP_DELETE = 0x0001 { HTTP_DELETE = 0
, HTTP_GET = 0x0002 , HTTP_GET
, HTTP_HEAD = 0x0004 , HTTP_HEAD
, HTTP_POST = 0x0008 , HTTP_POST
, HTTP_PUT = 0x0010 , HTTP_PUT
/* pathological */ /* pathological */
, HTTP_CONNECT = 0x0020 , HTTP_CONNECT
, HTTP_OPTIONS = 0x0040 , HTTP_OPTIONS
, HTTP_TRACE = 0x0080 , HTTP_TRACE
/* webdav */ /* webdav */
, HTTP_COPY = 0x0100 , HTTP_COPY
, HTTP_LOCK = 0x0200 , HTTP_LOCK
, HTTP_MKCOL = 0x0400 , HTTP_MKCOL
, HTTP_MOVE = 0x0800 , HTTP_MOVE
, HTTP_PROPFIND = 0x1000 , HTTP_PROPFIND
, HTTP_PROPPATCH = 0x2000 , HTTP_PROPPATCH
, HTTP_UNLOCK = 0x4000 , HTTP_UNLOCK
}; };
@ -105,11 +101,10 @@ struct http_parser {
ssize_t content_length; ssize_t content_length;
/** READ-ONLY **/ /** READ-ONLY **/
unsigned short status_code; /* responses only */
unsigned short method; /* requests only */
unsigned short http_major; unsigned short http_major;
unsigned short http_minor; unsigned short http_minor;
char buffer[HTTP_PARSER_MAX_METHOD_LEN]; unsigned short status_code; /* responses only */
unsigned char method; /* requests only */
/* 1 = Upgrade header was present and the parser has exited because of that. /* 1 = Upgrade header was present and the parser has exited because of that.
* 0 = No upgrade header present. * 0 = No upgrade header present.

Loading…
Cancel
Save