Skip to content

Commit

Permalink
save more space by removing buffer and shortening method
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Cliff Frey authored and ry committed Jun 11, 2010
1 parent 7a1103a commit 9eac636
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 171 deletions.
205 changes: 56 additions & 149 deletions http_parser.c
Expand Up @@ -248,35 +248,6 @@ enum flags
#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,
const http_parser_settings *settings,
const char *data,
Expand Down Expand Up @@ -354,10 +325,7 @@ size_t http_parser_execute (http_parser *parser,
state = s_res_or_resp_H;
else {
parser->type = HTTP_REQUEST;
if (ch < 'A' || 'Z' < ch) goto error;
parser->buffer[0] = ch;
index = 0;
state = s_req_method;
goto start_req_method_assign;
}
break;
}
Expand All @@ -367,12 +335,10 @@ size_t http_parser_execute (http_parser *parser,
parser->type = HTTP_RESPONSE;
state = s_res_HT;
} else {
if (ch < 'A' || 'Z' < ch) goto error;
if (ch != 'E') goto error;
parser->type = HTTP_REQUEST;
parser->method = (enum http_method) 0;
parser->buffer[0] = 'H';
parser->buffer[1] = ch;
index = 1;
parser->method = HTTP_HEAD;
index = 2;
state = s_req_method;
}
break;
Expand Down Expand Up @@ -535,128 +501,69 @@ size_t http_parser_execute (http_parser *parser,

if (ch < 'A' || 'Z' < ch) goto error;

start_req_method_assign:
parser->method = (enum http_method) 0;
index = 0;
parser->buffer[0] = ch;
index = 1;
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;
break;
}

case s_req_method:
if (ch == ' ') {
assert(index+1 < HTTP_PARSER_MAX_METHOD_LEN);
parser->buffer[index+1] = '\0';

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')) {
parser->method = HTTP_COPY;
break;
}

if (ngx_str4cmp(parser->buffer, 'M', 'O', 'V', 'E')) {
parser->method = HTTP_MOVE;
break;
}

break;

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;
break;
}
{
if (ch == '\0')
goto error;

break;
}
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;
break;
}

if (ch < 'A' || 'Z' < ch) goto error;

if (++index >= HTTP_PARSER_MAX_METHOD_LEN - 1) {
else if (ch == matcher[index])
; // nada
else if (index == 2 && parser->method == HTTP_CONNECT && ch == 'P')
parser->method = HTTP_COPY;
else if (index == 1 && parser->method == HTTP_MKCOL && ch == 'O')
parser->method = HTTP_MOVE;
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')
parser->method = HTTP_PUT;
else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P')
parser->method = HTTP_PROPPATCH;
else
goto error;
}

parser->buffer[index] = ch;

++index;
break;

}
case s_req_spaces_before_url:
{
if (ch == ' ') break;
Expand Down
39 changes: 17 additions & 22 deletions http_parser.h
Expand Up @@ -63,29 +63,25 @@ typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
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 */
enum http_method
{ HTTP_DELETE = 0x0001
, HTTP_GET = 0x0002
, HTTP_HEAD = 0x0004
, HTTP_POST = 0x0008
, HTTP_PUT = 0x0010
{ HTTP_DELETE = 0
, HTTP_GET
, HTTP_HEAD
, HTTP_POST
, HTTP_PUT
/* pathological */
, HTTP_CONNECT = 0x0020
, HTTP_OPTIONS = 0x0040
, HTTP_TRACE = 0x0080
, HTTP_CONNECT
, HTTP_OPTIONS
, HTTP_TRACE
/* webdav */
, HTTP_COPY = 0x0100
, HTTP_LOCK = 0x0200
, HTTP_MKCOL = 0x0400
, HTTP_MOVE = 0x0800
, HTTP_PROPFIND = 0x1000
, HTTP_PROPPATCH = 0x2000
, HTTP_UNLOCK = 0x4000
, HTTP_COPY
, HTTP_LOCK
, HTTP_MKCOL
, HTTP_MOVE
, HTTP_PROPFIND
, HTTP_PROPPATCH
, HTTP_UNLOCK
};


Expand All @@ -105,11 +101,10 @@ struct http_parser {
ssize_t content_length;

/** READ-ONLY **/
unsigned short status_code; /* responses only */
unsigned short method; /* requests only */
unsigned short http_major;
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.
* 0 = No upgrade header present.
Expand Down

0 comments on commit 9eac636

Please sign in to comment.