Continue request parser

personal/stbuehler/wip
Stefan Bühler 14 years ago
parent d45b540603
commit d1c1a1b06f
  1. 20
      src/chunk_parser.c
  2. 1
      src/chunk_parser.h
  3. 8
      src/http_request_parser.h
  4. 82
      src/http_request_parser.rl
  5. 16
      src/request.c
  6. 15
      src/settings.h
  7. 12
      src/sys-socket.h
  8. 22
      src/tests.c

@ -29,7 +29,7 @@ handler_t chunk_parser_next(server *srv, connection *con, chunk_parser_ctx *ctx,
/* Wait at the end of the last chunk if it gets extended */
if (!chunkiter_next(&i)) return HANDLER_WAIT_FOR_EVENT;
ctx->curi = i;
ctx->start = 0;
ctx->start -= l;
}
if (NULL == ctx->curi.element) return HANDLER_WAIT_FOR_EVENT;
@ -48,8 +48,9 @@ void chunk_parser_done(chunk_parser_ctx *ctx, goffset len) {
ctx->start += len;
}
GString* chunk_extract(server *srv, connection *con, chunk_parser_mark from, chunk_parser_mark to) {
GString *str = g_string_sized_new(0);
gboolean chunk_extract_to(server *srv, connection *con, chunk_parser_mark from, chunk_parser_mark to, GString *dest) {
g_string_set_size(dest, 0);
chunk_parser_mark i;
for ( i = from; i.ci.element != to.ci.element; chunkiter_next(&i.ci) ) {
goffset len = chunkiter_length(i.ci);
@ -57,7 +58,7 @@ GString* chunk_extract(server *srv, connection *con, chunk_parser_mark from, chu
char *buf;
off_t we_have;
if (HANDLER_GO_ON != chunkiter_read(srv, con, i.ci, i.pos, len - i.pos, &buf, &we_have)) goto error;
g_string_append_len(str, buf, we_have);
g_string_append_len(dest, buf, we_have);
i.pos += we_have;
}
i.pos = 0;
@ -66,13 +67,20 @@ GString* chunk_extract(server *srv, connection *con, chunk_parser_mark from, chu
char *buf;
off_t we_have;
if (HANDLER_GO_ON != chunkiter_read(srv, con, i.ci, i.pos, to.pos - i.pos, &buf, &we_have)) goto error;
g_string_append_len(str, buf, we_have);
g_string_append_len(dest, buf, we_have);
i.pos += we_have;
}
return str;
return TRUE;
error:
g_string_assign(dest, "");
return FALSE;
}
GString* chunk_extract(server *srv, connection *con, chunk_parser_mark from, chunk_parser_mark to) {
GString *str = g_string_sized_new(0);
if (chunk_extract_to(srv, con, from, to, str)) return str;
g_string_free(str, TRUE);
return NULL;
}

@ -34,6 +34,7 @@ LI_API handler_t chunk_parser_prepare(chunk_parser_ctx *ctx);
LI_API handler_t chunk_parser_next(server *srv, connection *con, chunk_parser_ctx *ctx, char **p, char **pe);
LI_API void chunk_parser_done(chunk_parser_ctx *ctx, goffset len);
LI_API gboolean chunk_extract_to(server *srv, connection *con, chunk_parser_mark from, chunk_parser_mark to, GString *dest);
LI_API GString* chunk_extract(server *srv, connection *con, chunk_parser_mark from, chunk_parser_mark to);
INLINE chunk_parser_mark chunk_parser_getmark(chunk_parser_ctx *ctx, const char *fpc);

@ -9,13 +9,15 @@ typedef struct http_request_ctx http_request_ctx;
struct http_request_ctx {
chunk_parser_ctx chunk_ctx;
request *request;
chunk_parser_mark mark;
request *request;
GString *h_key, *h_value;
};
LI_API void http_request_parser_init(http_request_ctx *ctx, request *req, chunkqueue *cq);
LI_API http_request_ctx* http_request_parser_new(request *req, chunkqueue *cq);
LI_API void http_request_parser_free(http_request_ctx *ctx);
LI_API handler_t http_request_parse(server *srv, connection *con, http_request_ctx *ctx);

@ -6,6 +6,10 @@
#define _getString(M, FPC) (chunk_extract(srv, con, ctx->M, GETMARK(FPC)))
#define getString(FPC) _getString(mark, FPC)
#define _getStringTo(M, FPC, s) (chunk_extract_to(srv, con, ctx->M, GETMARK(FPC), s))
#define getStringTo(FPC, s) _getStringTo(mark, FPC, s)
%%{
machine http_request_parser;
@ -14,8 +18,19 @@
action mark { ctx->mark = GETMARK(fpc); }
action done { fbreak; }
action method { ctx->request->http_method_str = getString(fpc); }
action uri { ctx->request->uri.uri = getString(fpc); }
action method { getStringTo(fpc, ctx->request->http_method_str); }
action uri { getStringTo(fpc, ctx->request->uri.uri); }
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 {
http_header_insert(ctx->request->headers, ctx->h_key, ctx->h_value);
}
# RFC 2616
OCTET = any;
@ -48,7 +63,10 @@
QDText = TEXT - DQUOTE;
Quoted_String = DQUOTE ( QDText | Quoted_Pair )* DQUOTE;
HTTP_Version = "HTTP" "/" DIGIT+ "." DIGIT+;
HTTP_Version = (
"HTTP/1.0"
| "HTTP/1.1"
| "HTTP" "/" DIGIT+ "." DIGIT+ );
#HTTP_URL = "http:" "//" Host ( ":" Port )? ( abs_path ( "?" query )? )?;
# RFC 2396
@ -62,13 +80,37 @@
Path_Segments = Segment ("/" Segment)*;
Abs_Path = "/" Path_Segments;
Method = Token >mark %method;
Request_URI = ("*" | ( any - CTL - SP )) >mark %uri;
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;
Request_Line = Method " " Request_URI " " HTTP_Version CRLF;
Field_Content = ( TEXT+ | ( Token | Separators | Quoted_String )+ );
Field_Value = " "* (Field_Content+ ( Field_Content | LWS )*)? >mark;
Message_Header = Token ":" Field_Value?;
Field_Value = " "* (Field_Content+ ( Field_Content | LWS )*)? >mark %header_value;
Message_Header = Token >mark %header_key ":" Field_Value? % header;
main := (CRLF)* Request_Line (Message_Header CRLF)* CRLF @ done;
}%%
@ -83,15 +125,32 @@ static int http_request_parser_is_finished(http_request_ctx *ctx) {
return ctx->chunk_ctx.cs >= http_request_parser_first_final;
}
void http_request_parser_init(http_request_ctx *ctx, request *req, chunkqueue *cq) {
http_request_ctx* http_request_parser_new(request *req, chunkqueue *cq) {
http_request_ctx *ctx = g_slice_new0(http_request_ctx);
%% write init;
chunk_parser_init(&ctx->chunk_ctx, cq);
ctx->request = req;
ctx->h_key = g_string_sized_new(0);
ctx->h_value = g_string_sized_new(0);
return ctx;
}
void http_request_parser_free(http_request_ctx *ctx) {
if (!ctx) return;
g_string_free(ctx->h_key, TRUE);
g_string_free(ctx->h_value, TRUE);
g_slice_free(http_request_ctx, ctx);
}
handler_t http_request_parse(server *srv, connection *con, http_request_ctx *ctx) {
handler_t res;
if (http_request_parser_is_finished(ctx)) return HANDLER_GO_ON;
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)) {
@ -101,10 +160,13 @@ handler_t http_request_parse(server *srv, connection *con, http_request_ctx *ctx
%% write exec;
chunk_parser_done(&ctx->chunk_ctx, pe - p);
chunk_parser_done(&ctx->chunk_ctx, p - ctx->chunk_ctx.buf);
}
if (http_request_parser_has_error(ctx)) return HANDLER_ERROR;
if (http_request_parser_is_finished(ctx)) return HANDLER_GO_ON;
if (http_request_parser_is_finished(ctx)) {
chunkqueue_skip(ctx->chunk_ctx.cq, ctx->chunk_ctx.bytes_in);
return HANDLER_GO_ON;
}
return HANDLER_ERROR;
}

@ -3,6 +3,22 @@
request* request_new() {
request *req = g_slice_new0(request);
req->http_method = HTTP_METHOD_UNSET;
req->http_method_str = g_string_sized_new(0);
req->http_version = HTTP_VERSION_UNSET;
req->uri.uri = g_string_sized_new(0);
req->uri.orig_uri = g_string_sized_new(0);
req->uri.scheme = g_string_sized_new(0);
req->uri.path = g_string_sized_new(0);
req->uri.query = g_string_sized_new(0);
req->headers = http_headers_new();
req->host = g_string_sized_new(0);
req->content_length = -1;
return req;
}

@ -134,13 +134,14 @@
#endif
typedef enum { HANDLER_UNSET,
HANDLER_GO_ON,
HANDLER_FINISHED,
HANDLER_COMEBACK,
HANDLER_WAIT_FOR_EVENT,
HANDLER_ERROR,
HANDLER_WAIT_FOR_FD
typedef enum {
HANDLER_UNSET,
HANDLER_GO_ON,
HANDLER_FINISHED,
HANDLER_COMEBACK,
HANDLER_WAIT_FOR_EVENT,
HANDLER_ERROR,
HANDLER_WAIT_FOR_FD
} handler_t;
/* Shared library support */

@ -9,7 +9,7 @@
#ifndef FD_SETSIZE
/* By default this is 64 */
#define FD_SETSIZE 4096
#endif
#endif /* FD_SETSIZE */
#include <winsock2.h>
#include <ws2tcpip.h>
//#include <wspiapi.h>
@ -30,7 +30,7 @@
#define STDERR_FILENO 2
#ifndef __MINGW32__
#define ssize_t int
#endif
#endif /* __MINGW32__ */
#define sockread( fd, buf, bytes ) recv( fd, buf, bytes, 0 )
@ -39,7 +39,7 @@ int inet_aton(const char *cp, struct in_addr *inp);
#define HAVE_INET_ADDR
#undef HAVE_INET_ATON
#else
#else /* _WIN32 */
#include <sys/types.h> /* required by netinet/tcp.h on FreeBSD */
#include <sys/socket.h>
#include <sys/ioctl.h>
@ -51,7 +51,7 @@ int inet_aton(const char *cp, struct in_addr *inp);
#ifndef SUN_LEN
#define SUN_LEN(su) \
(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
#endif
#endif /* SUN_LEN */
#define sockread( fd, buf, bytes ) read( fd, buf, bytes )
#define closesocket(x) close(x)
@ -63,8 +63,8 @@ int inet_aton(const char *cp, struct in_addr *inp);
/* only define it if it isn't defined yet */
#ifndef HAVE_IPV6
#define HAVE_IPV6
#endif
#endif
#endif /* HAVE_IPV6 */
#endif /* HAVE_INET_NTOP */
typedef union {
#ifdef HAVE_IPV6

@ -10,26 +10,32 @@
int request_test() {
chunkqueue *cq;
request *req;
http_request_ctx ctx;
http_request_ctx *ctx;
handler_t res;
cq = chunkqueue_new();
req = request_new();
http_request_parser_init(&ctx, req, cq);
ctx = http_request_parser_new(req, cq);
chunkqueue_append_mem(cq, CONST_STR_LEN(
"GET / HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"\r\n"
"abc"
));
res = http_request_parse(NULL, NULL, &ctx);
res = http_request_parse(NULL, NULL, ctx);
if (res != HANDLER_GO_ON) {
fprintf(stderr, "Parser return %i", res);
return -1;
}
return 0;
assert(req->http_method == HTTP_METHOD_GET);
assert(cq->length == 3);
http_request_parser_free(ctx);
return res == HANDLER_GO_ON ? 0 : 1;
}
int main() {
@ -47,10 +53,10 @@ int main() {
s = ipv6_tostring(ipv6);
printf("parsed ipv6: %s/%u\n", s->str, network);
request_test();
return 0;
srv = server_new();
return request_test();
return 0;
}

Loading…
Cancel
Save