added code to handle content-length > 0
This commit is contained in:
parent
b7c4acf78e
commit
d4f7ac1ca9
@ -40,15 +40,15 @@ struct qse_http_t
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
/*qse_size_t pending;*/
|
|
||||||
|
|
||||||
int crlf; /* crlf status */
|
int crlf; /* crlf status */
|
||||||
qse_size_t plen; /* raw request length excluding crlf */
|
qse_size_t plen; /* raw request length excluding crlf */
|
||||||
|
qse_size_t need; /* number of octets needed for contents */
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
qse_http_octb_t raw;
|
qse_http_octb_t raw;
|
||||||
|
qse_http_octb_t con;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -297,6 +297,7 @@ static QSE_INLINE int push_to_buffer (
|
|||||||
|
|
||||||
if (nsize > (octb)->capa)
|
if (nsize > (octb)->capa)
|
||||||
{
|
{
|
||||||
|
/* TODO: enhance the resizing scheme */
|
||||||
qse_size_t ncapa = (nsize > (octb)->capa * 2)? nsize: ((octb)->capa * 2);
|
qse_size_t ncapa = (nsize > (octb)->capa * 2)? nsize: ((octb)->capa * 2);
|
||||||
|
|
||||||
do
|
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_MEMSET (&http->req.attr, 0, QSE_SIZEOF(http->req.attr));
|
||||||
qse_htb_clear (&http->req.hdr.tab);
|
qse_htb_clear (&http->req.hdr.tab);
|
||||||
clear_combined_headers (http);
|
clear_combined_headers (http);
|
||||||
|
clear_buffer (http, &http->req.con);
|
||||||
clear_buffer (http, &http->req.raw);
|
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.crlf = 0;
|
||||||
http->state.plen = 0;
|
http->state.plen = 0;
|
||||||
init_buffer (http, &http->req.raw);
|
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)
|
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);
|
qse_htb_fini (&http->req.hdr.tab);
|
||||||
clear_combined_headers (http);
|
clear_combined_headers (http);
|
||||||
|
fini_buffer (http, &http->req.con);
|
||||||
fini_buffer (http, &http->req.raw);
|
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* p = line;
|
||||||
qse_byte_t* tmp;
|
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;
|
http->req.attr.connection_close = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
qse_printf (QSE_T("parse_http_reqline ....\n"));
|
qse_printf (QSE_T("parse_reqline ....\n"));
|
||||||
return ++p;
|
return ++p;
|
||||||
|
|
||||||
badreq:
|
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;
|
qse_byte_t* p = line, * last;
|
||||||
struct
|
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;
|
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 */
|
/* feed the percent encoded string */
|
||||||
int qse_http_feed (qse_http_t* http, const qse_byte_t* ptr, qse_size_t len)
|
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* end = ptr + len;
|
||||||
const qse_byte_t* req = ptr;
|
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)
|
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 (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
|
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);
|
QSE_ASSERT (http->state.crlf <= 3);
|
||||||
|
|
||||||
/* got a complete request */
|
/* reset the crlf state */
|
||||||
http->state.crlf = 0;
|
http->state.crlf = 0;
|
||||||
|
/* reset the raw request length */
|
||||||
http->state.plen = 0;
|
http->state.plen = 0;
|
||||||
|
|
||||||
/* add the actual request */
|
if (parse_request (http, req, ptr - req) <= -1)
|
||||||
if (push_to_buffer (http, &http->req.raw, req, ptr-req) <= -1) return -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)
|
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);
|
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... */
|
/* TODO: do the main job here... before the raw buffer is cleared out... */
|
||||||
|
|
||||||
clear_request (http);
|
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')
|
else if (b == '\r')
|
||||||
@ -995,13 +1058,17 @@ qse_htb_walk (&http->req.hdr.tab, walk, QSE_NULL);
|
|||||||
}
|
}
|
||||||
else if (b == '\0')
|
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;
|
http->errnum = QSE_HTTP_EBADREQ;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* increment length of a request in raw
|
||||||
|
* excluding crlf */
|
||||||
http->state.plen++;
|
http->state.plen++;
|
||||||
|
/* mark that neither CR nor LF was seen */
|
||||||
http->state.crlf = 0;
|
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 (push_to_buffer (http, &http->req.raw, req, ptr - req) <= -1) return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
done:
|
||||||
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
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user