From d4f7ac1ca908ed727e21b4a306d41916675cff37 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 15 Nov 2010 07:54:03 +0000 Subject: [PATCH] added code to handle content-length > 0 --- qse/include/qse/utl/http.h | 4 +- qse/lib/utl/http.c | 186 +++++++++++++++++++++---------------- 2 files changed, 106 insertions(+), 84 deletions(-) diff --git a/qse/include/qse/utl/http.h b/qse/include/qse/utl/http.h index be8b210a..45e0ef50 100644 --- a/qse/include/qse/utl/http.h +++ b/qse/include/qse/utl/http.h @@ -40,15 +40,15 @@ struct qse_http_t struct { - /*qse_size_t pending;*/ - int crlf; /* crlf status */ qse_size_t plen; /* raw request length excluding crlf */ + qse_size_t need; /* number of octets needed for contents */ } state; struct { qse_http_octb_t raw; + qse_http_octb_t con; enum { diff --git a/qse/lib/utl/http.c b/qse/lib/utl/http.c index b812dcb2..eee6f6b2 100644 --- a/qse/lib/utl/http.c +++ b/qse/lib/utl/http.c @@ -297,6 +297,7 @@ static QSE_INLINE int push_to_buffer ( if (nsize > (octb)->capa) { + /* TODO: enhance the resizing scheme */ qse_size_t ncapa = (nsize > (octb)->capa * 2)? nsize: ((octb)->capa * 2); do @@ -354,6 +355,7 @@ static QSE_INLINE void clear_request (qse_http_t* http) QSE_MEMSET (&http->req.attr, 0, QSE_SIZEOF(http->req.attr)); qse_htb_clear (&http->req.hdr.tab); clear_combined_headers (http); + clear_buffer (http, &http->req.con); clear_buffer (http, &http->req.raw); } @@ -406,6 +408,7 @@ qse_http_t* qse_http_init (qse_http_t* http, qse_mmgr_t* mmgr) http->state.crlf = 0; http->state.plen = 0; init_buffer (http, &http->req.raw); + init_buffer (http, &http->req.con); if (qse_htb_init (&http->req.hdr.tab, mmgr, 60, 70, 1, 1) == QSE_NULL) { @@ -420,10 +423,11 @@ void qse_http_fini (qse_http_t* http) { qse_htb_fini (&http->req.hdr.tab); clear_combined_headers (http); + fini_buffer (http, &http->req.con); fini_buffer (http, &http->req.raw); } -static qse_byte_t* parse_http_reqline (qse_http_t* http, qse_byte_t* line) +static qse_byte_t* parse_reqline (qse_http_t* http, qse_byte_t* line) { qse_byte_t* p = line; qse_byte_t* tmp; @@ -551,7 +555,7 @@ static qse_byte_t* parse_http_reqline (qse_http_t* http, qse_byte_t* line) http->req.attr.connection_close = 1; } -qse_printf (QSE_T("parse_http_reqline ....\n")); +qse_printf (QSE_T("parse_reqline ....\n")); return ++p; badreq: @@ -818,7 +822,7 @@ Change it to doubly linked for this? } } -qse_byte_t* parse_http_header (qse_http_t* http, qse_byte_t* line) +qse_byte_t* parse_header_fields (qse_http_t* http, qse_byte_t* line) { qse_byte_t* p = line, * last; struct @@ -917,13 +921,55 @@ qse_printf (QSE_T("HEADER OK %d[%S] %d[%S]\n"), (int)pair->klen, pair->kptr, (i return QSE_HTB_WALK_FORWARD; } +static QSE_INLINE int parse_request ( + qse_http_t* http, const qse_byte_t* req, qse_size_t rlen) +{ + static const qse_byte_t nul = '\0'; + qse_byte_t* p; + + /* add the actual request */ + if (push_to_buffer (http, &http->req.raw, req, rlen) <= -1) return -1; + + /* add the terminating null for easier parsing */ + if (push_to_buffer (http, &http->req.raw, &nul, 1) <= -1) return -1; + + p = http->req.raw.data; + + while (is_whspace_octet(*p)) p++; + QSE_ASSERT (*p != '\0'); + + /* parse the request line */ + p = parse_reqline (http, p); + if (p == QSE_NULL) return -1; + + /* parse header fields */ + do + { + while (is_whspace_octet(*p)) p++; + if (*p == '\0') break; + + /* TODO: return error if protocol is 0.9. + * HTTP/0.9 must not get headers... */ + + p = parse_header_fields (http, p); + if (p == QSE_NULL) return -1; + } + while (1); + + return 0; +} + /* feed the percent encoded string */ int qse_http_feed (qse_http_t* http, const qse_byte_t* ptr, qse_size_t len) { const qse_byte_t* end = ptr + len; const qse_byte_t* req = ptr; - static const qse_byte_t nul = '\0'; + if (http->state.need > 0) + { + /* does this goto drop code maintainability? */ + goto get_content; + } while (ptr < end) { @@ -939,52 +985,69 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* ptr, qse_size_t len) if (b == '\n') { - if (http->state.crlf <= 1) http->state.crlf = 2; + if (http->state.crlf <= 1) + { + /* http->state.crlf == 0, CR was not seen + * http->state.crlf == 1, CR was seen + * whatever the current case is, mark the + * first LF is seen here. + */ + http->state.crlf = 2; + } else { - qse_byte_t* p; + /* http->state.crlf == 2, no 2nd CR before LF + * http->state.crlf == 3, 2nd CR before LF + */ + /* we got a complete request. */ QSE_ASSERT (http->state.crlf <= 3); - /* got a complete request */ + /* reset the crlf state */ http->state.crlf = 0; + /* reset the raw request length */ http->state.plen = 0; - /* add the actual request */ - if (push_to_buffer (http, &http->req.raw, req, ptr-req) <= -1) return -1; + if (parse_request (http, req, ptr - req) <= -1) + return -1; - /* add the terminating null for easier parsing */ - if (push_to_buffer (http, &http->req.raw, &nul, 1) <= -1) return -1; - - p = http->req.raw.data; - - while (is_whspace_octet(*p)) p++; - QSE_ASSERT (*p != '\0'); - p = parse_http_reqline (http, p); - if (p == QSE_NULL) return -1; - - do - { - while (is_whspace_octet(*p)) p++; - if (*p == '\0') break; - - /* TODO: return error if protocol is 0.9. - * HTTP/0.9 must not get headers... */ - - p = parse_http_header (http, p); - if (p == QSE_NULL) return -1; - } - while (1); - if (http->req.attr.content_length > 0) { -qse_printf (QSE_T("content->length.. %d\n"), (int)http->req.attr.content_length); + /* let's get content */ + qse_size_t avail; + + http->state.need = http->req.attr.content_length; + + get_content: + avail = end - ptr; + + if (avail < http->state.need) + { + if (push_to_buffer (http, &http->req.con, ptr, avail) <= -1) return -1; + http->state.need -= avail; + goto done; + } + else + { + /* we are given all needed or more than needed */ + if (push_to_buffer (http, &http->req.con, ptr, http->state.need) <= -1) return -1; + ptr += http->state.need; + http->state.need = 0; + } } + + qse_htb_walk (&http->req.hdr.tab, walk, QSE_NULL); +if (http->req.attr.content_length > 0) +{ + qse_printf (QSE_T("content = [%.*S]\n"), (int)http->req.attr.content_length, http->req.con.data); +} /* TODO: do the main job here... before the raw buffer is cleared out... */ clear_request (http); - req = ptr; /* let ptr point to the next character to '\n' */ + + /* let ptr point to the next character to LF or the optional contents */ + req = ptr; } } else if (b == '\r') @@ -995,13 +1058,17 @@ qse_htb_walk (&http->req.hdr.tab, walk, QSE_NULL); } else if (b == '\0') { - /* guarantee that the request does not contain a null character */ + /* guarantee that the request does not contain a null + * character */ http->errnum = QSE_HTTP_EBADREQ; return -1; } else { - http->state.plen++; + /* increment length of a request in raw + * excluding crlf */ + http->state.plen++; + /* mark that neither CR nor LF was seen */ http->state.crlf = 0; } } @@ -1012,51 +1079,6 @@ qse_htb_walk (&http->req.hdr.tab, walk, QSE_NULL); if (push_to_buffer (http, &http->req.raw, req, ptr - req) <= -1) return -1; } -#if 0 - while (ptr < end) - { - if (*ptr++ == '\n') - { - qse_size_t reqlen = ptr - req; - int blank; - - if (http->state.pending > 0) - { - QSE_ASSERT (http->req.raw.size > 0); - blank = (reqlen + http->state.pending == 2 && - http->req.raw.data[http->req.raw.size-1] == '\r'); - http->state.pending = 0; - } - else - { - blank = (reqlen == 1 || (reqlen == 2 && req[0] == '\r')); - } - - if (push_to_buffer ( - http, &http->req.raw, req, reqlen) <= -1) return -1; - - if (blank) - { - /* blank line - we got a complete request. - * we didn't process the optinal message body yet, though */ - - /* DO SOMETHIGN ... */ -qse_printf (QSE_T("[[[%.*S]]]]\n"), (int)http->req.raw.size, http->req.raw.data), - - clear_buffer (http, &http->req.raw); - } - - req = ptr; /* let ptr point to the next character to '\n' */ - } - } - - if (ptr > req) - { - /* enbuffer the unfinished data */ - if (push_to_buffer (http, &http->req.raw, req, ptr - req) <= -1) return -1; - http->state.pending = ptr - req; - } -#endif - +done: return 0; }