2008-06-30 14:24:29 +00:00
|
|
|
|
2008-08-05 15:08:32 +00:00
|
|
|
#include "base.h"
|
2008-06-30 14:24:29 +00:00
|
|
|
#include "http_request_parser.h"
|
|
|
|
|
|
|
|
/** Machine **/
|
|
|
|
|
2008-09-08 00:20:55 +00:00
|
|
|
#define _getString(M, FPC) (chunk_extract(con, ctx->M, GETMARK(FPC)))
|
2008-07-01 18:56:59 +00:00
|
|
|
#define getString(FPC) _getString(mark, FPC)
|
|
|
|
|
2008-09-08 00:20:55 +00:00
|
|
|
#define _getStringTo(M, FPC, s) (chunk_extract_to(con, ctx->M, GETMARK(FPC), s))
|
2008-08-04 22:25:42 +00:00
|
|
|
#define getStringTo(FPC, s) _getStringTo(mark, FPC, s)
|
|
|
|
|
|
|
|
|
2008-06-30 14:24:29 +00:00
|
|
|
%%{
|
|
|
|
|
|
|
|
machine http_request_parser;
|
2008-07-01 18:56:59 +00:00
|
|
|
variable cs ctx->chunk_ctx.cs;
|
|
|
|
|
|
|
|
action mark { ctx->mark = GETMARK(fpc); }
|
|
|
|
action done { fbreak; }
|
|
|
|
|
2008-08-04 22:25:42 +00:00
|
|
|
action method { getStringTo(fpc, ctx->request->http_method_str); }
|
2008-08-09 15:20:12 +00:00
|
|
|
action uri { getStringTo(fpc, ctx->request->uri.raw); }
|
2008-08-04 22:25:42 +00:00
|
|
|
|
|
|
|
action header_key {
|
|
|
|
getStringTo(fpc, ctx->h_key);
|
|
|
|
g_string_truncate(ctx->h_value, 0);
|
|
|
|
}
|
|
|
|
action header_value {
|
|
|
|
getStringTo(fpc, ctx->h_value);
|
|
|
|
}
|
|
|
|
action header {
|
2008-08-06 18:46:42 +00:00
|
|
|
http_header_insert(ctx->request->headers, GSTR_LEN(ctx->h_key), GSTR_LEN(ctx->h_value));
|
2008-08-04 22:25:42 +00:00
|
|
|
}
|
2008-07-01 18:56:59 +00:00
|
|
|
|
|
|
|
# RFC 2616
|
|
|
|
OCTET = any;
|
|
|
|
CHAR = ascii;
|
|
|
|
UPALPHA = upper;
|
|
|
|
LOALPHA = lower;
|
|
|
|
ALPHA = alpha;
|
|
|
|
DIGIT = digit;
|
|
|
|
CTL = ( 0 .. 31 | 127 );
|
|
|
|
CR = '\r';
|
|
|
|
LF = '\n';
|
|
|
|
SP = ' ';
|
|
|
|
HT = '\t';
|
|
|
|
DQUOTE = '"';
|
|
|
|
|
|
|
|
CRLF = CR LF;
|
|
|
|
LWS = CRLF? (SP | HT)+; # linear white space
|
|
|
|
TEXT = (OCTET - CTL) | LWS;
|
|
|
|
HEX = [a-fA-F0-9];
|
|
|
|
|
|
|
|
Separators = [()<>@,;:\\\"/\[\]?={}] | SP | HT;
|
2008-07-01 20:07:54 +00:00
|
|
|
Token = (OCTET - Separators - CTL)+;
|
2008-07-01 18:56:59 +00:00
|
|
|
|
|
|
|
# original definition
|
|
|
|
# Comment = "(" ( CText | Quoted_Pair | Comment )* ")";
|
|
|
|
# CText = TEXT - [()];
|
|
|
|
|
|
|
|
Quoted_Pair = "\\" CHAR;
|
|
|
|
Comment = ( TEXT | Quoted_Pair )*;
|
|
|
|
QDText = TEXT - DQUOTE;
|
|
|
|
Quoted_String = DQUOTE ( QDText | Quoted_Pair )* DQUOTE;
|
|
|
|
|
2008-08-04 22:25:42 +00:00
|
|
|
HTTP_Version = (
|
2008-08-06 22:26:17 +00:00
|
|
|
"HTTP/1.0" %{ ctx->request->http_version = HTTP_VERSION_1_0; }
|
|
|
|
| "HTTP/1.1" %{ ctx->request->http_version = HTTP_VERSION_1_1; }
|
|
|
|
| "HTTP" "/" DIGIT+ "." DIGIT+ ) >{ ctx->request->http_version = HTTP_VERSION_UNSET; };
|
2008-07-01 18:56:59 +00:00
|
|
|
#HTTP_URL = "http:" "//" Host ( ":" Port )? ( abs_path ( "?" query )? )?;
|
|
|
|
|
|
|
|
# RFC 2396
|
2008-06-30 14:24:29 +00:00
|
|
|
|
2008-07-01 18:56:59 +00:00
|
|
|
Mark = [\-_!~*\'()];
|
|
|
|
Unreserved = alnum | Mark;
|
|
|
|
Escaped = "%" HEX HEX;
|
2008-06-30 14:24:29 +00:00
|
|
|
|
2008-07-01 18:56:59 +00:00
|
|
|
PChar = Unreserved | Escaped | [:@&=+$,];
|
|
|
|
Segment = PChar* ( ";" PChar* )*;
|
|
|
|
Path_Segments = Segment ("/" Segment)*;
|
|
|
|
Abs_Path = "/" Path_Segments;
|
2008-06-30 14:24:29 +00:00
|
|
|
|
2008-08-04 22:25:42 +00:00
|
|
|
Method = (
|
|
|
|
"GET" %{ ctx->request->http_method = HTTP_METHOD_GET; }
|
|
|
|
| "POST" %{ ctx->request->http_method = HTTP_METHOD_POST; }
|
|
|
|
| "HEAD" %{ ctx->request->http_method = HTTP_METHOD_HEAD; }
|
|
|
|
| "OPTIONS" %{ ctx->request->http_method = HTTP_METHOD_OPTIONS; }
|
|
|
|
| "PROPFIND" %{ ctx->request->http_method = HTTP_METHOD_PROPFIND; }
|
|
|
|
| "MKCOL" %{ ctx->request->http_method = HTTP_METHOD_MKCOL; }
|
|
|
|
| "PUT" %{ ctx->request->http_method = HTTP_METHOD_PUT; }
|
|
|
|
| "DELETE" %{ ctx->request->http_method = HTTP_METHOD_DELETE; }
|
|
|
|
| "COPY" %{ ctx->request->http_method = HTTP_METHOD_COPY; }
|
|
|
|
| "MOVE" %{ ctx->request->http_method = HTTP_METHOD_MOVE; }
|
|
|
|
| "PROPPATCH" %{ ctx->request->http_method = HTTP_METHOD_PROPPATCH; }
|
|
|
|
| "REPORT" %{ ctx->request->http_method = HTTP_METHOD_REPORT; }
|
|
|
|
| "CHKECOUT" %{ ctx->request->http_method = HTTP_METHOD_CHECKOUT; }
|
|
|
|
| "CHECKIN" %{ ctx->request->http_method = HTTP_METHOD_CHECKIN; }
|
|
|
|
| "VERSION-CONTROL" %{ ctx->request->http_method = HTTP_METHOD_VERSION_CONTROL; }
|
|
|
|
| "UNCHECKOUT" %{ ctx->request->http_method = HTTP_METHOD_UNCHECKOUT; }
|
|
|
|
| "MKACTIVITY" %{ ctx->request->http_method = HTTP_METHOD_MKACTIVITY; }
|
|
|
|
| "MERGE" %{ ctx->request->http_method = HTTP_METHOD_MERGE; }
|
|
|
|
| "LOCK" %{ ctx->request->http_method = HTTP_METHOD_LOCK; }
|
|
|
|
| "UNLOCK" %{ ctx->request->http_method = HTTP_METHOD_UNLOCK; }
|
|
|
|
| "LABEL" %{ ctx->request->http_method = HTTP_METHOD_LABEL; }
|
|
|
|
| "CONNECT" %{ ctx->request->http_method = HTTP_METHOD_CONNECT; }
|
|
|
|
| Token ) >mark >{ ctx->request->http_method = HTTP_METHOD_UNSET; } %method;
|
|
|
|
|
|
|
|
Request_URI = ("*" | ( any - CTL - SP )+) >mark %uri;
|
2008-07-01 18:56:59 +00:00
|
|
|
Request_Line = Method " " Request_URI " " HTTP_Version CRLF;
|
|
|
|
|
|
|
|
Field_Content = ( TEXT+ | ( Token | Separators | Quoted_String )+ );
|
2008-08-04 22:25:42 +00:00
|
|
|
Field_Value = " "* (Field_Content+ ( Field_Content | LWS )*)? >mark %header_value;
|
|
|
|
Message_Header = Token >mark %header_key ":" Field_Value? % header;
|
2008-07-01 18:56:59 +00:00
|
|
|
|
|
|
|
main := (CRLF)* Request_Line (Message_Header CRLF)* CRLF @ done;
|
2008-06-30 14:24:29 +00:00
|
|
|
}%%
|
|
|
|
|
|
|
|
%% write data;
|
|
|
|
|
2008-07-01 18:56:59 +00:00
|
|
|
static int http_request_parser_has_error(http_request_ctx *ctx) {
|
|
|
|
return ctx->chunk_ctx.cs == http_request_parser_error;
|
|
|
|
}
|
2008-06-30 14:24:29 +00:00
|
|
|
|
2008-07-01 18:56:59 +00:00
|
|
|
static int http_request_parser_is_finished(http_request_ctx *ctx) {
|
|
|
|
return ctx->chunk_ctx.cs >= http_request_parser_first_final;
|
|
|
|
}
|
2008-06-30 14:24:29 +00:00
|
|
|
|
2008-08-05 15:08:32 +00:00
|
|
|
void http_request_parser_init(http_request_ctx* ctx, request *req, chunkqueue *cq) {
|
2008-07-01 18:56:59 +00:00
|
|
|
chunk_parser_init(&ctx->chunk_ctx, cq);
|
2008-07-01 20:07:54 +00:00
|
|
|
ctx->request = req;
|
2008-08-04 22:25:42 +00:00
|
|
|
ctx->h_key = g_string_sized_new(0);
|
|
|
|
ctx->h_value = g_string_sized_new(0);
|
|
|
|
|
2008-08-05 15:08:32 +00:00
|
|
|
%% write init;
|
2008-08-04 22:25:42 +00:00
|
|
|
}
|
|
|
|
|
2008-08-05 15:08:32 +00:00
|
|
|
void http_request_parser_reset(http_request_ctx* ctx) {
|
|
|
|
chunk_parser_reset(&ctx->chunk_ctx);
|
|
|
|
g_string_truncate(ctx->h_key, 0);
|
|
|
|
g_string_truncate(ctx->h_value, 0);
|
2008-08-04 22:25:42 +00:00
|
|
|
|
2008-08-05 15:08:32 +00:00
|
|
|
%% write init;
|
|
|
|
}
|
|
|
|
|
|
|
|
void http_request_parser_clear(http_request_ctx *ctx) {
|
2008-08-04 22:25:42 +00:00
|
|
|
g_string_free(ctx->h_key, TRUE);
|
|
|
|
g_string_free(ctx->h_value, TRUE);
|
2008-07-01 18:56:59 +00:00
|
|
|
}
|
2008-06-30 14:24:29 +00:00
|
|
|
|
2008-09-08 00:20:55 +00:00
|
|
|
handler_t http_request_parse(connection *con, http_request_ctx *ctx) {
|
2008-07-01 18:56:59 +00:00
|
|
|
handler_t res;
|
|
|
|
|
2008-08-04 22:25:42 +00:00
|
|
|
if (http_request_parser_is_finished(ctx)) return HANDLER_GO_ON;
|
|
|
|
|
2008-07-01 18:56:59 +00:00
|
|
|
if (HANDLER_GO_ON != (res = chunk_parser_prepare(&ctx->chunk_ctx))) return res;
|
|
|
|
|
|
|
|
while (!http_request_parser_has_error(ctx) && !http_request_parser_is_finished(ctx)) {
|
|
|
|
char *p, *pe;
|
|
|
|
|
2008-09-08 00:20:55 +00:00
|
|
|
if (HANDLER_GO_ON != (res = chunk_parser_next(con, &ctx->chunk_ctx, &p, &pe))) return res;
|
2008-06-30 14:24:29 +00:00
|
|
|
|
|
|
|
%% write exec;
|
|
|
|
|
2008-08-04 22:25:42 +00:00
|
|
|
chunk_parser_done(&ctx->chunk_ctx, p - ctx->chunk_ctx.buf);
|
2008-06-30 14:24:29 +00:00
|
|
|
}
|
2008-07-01 18:56:59 +00:00
|
|
|
|
|
|
|
if (http_request_parser_has_error(ctx)) return HANDLER_ERROR;
|
2008-08-04 22:25:42 +00:00
|
|
|
if (http_request_parser_is_finished(ctx)) {
|
|
|
|
chunkqueue_skip(ctx->chunk_ctx.cq, ctx->chunk_ctx.bytes_in);
|
|
|
|
return HANDLER_GO_ON;
|
|
|
|
}
|
2008-07-01 18:56:59 +00:00
|
|
|
return HANDLER_ERROR;
|
2008-06-30 14:24:29 +00:00
|
|
|
}
|