added more header handling code for http

This commit is contained in:
hyung-hwan 2010-11-11 08:28:38 +00:00
parent 19af03709a
commit b7c4acf78e
2 changed files with 149 additions and 37 deletions

View File

@ -25,7 +25,8 @@ enum qse_http_errnum_t
QSE_HTTP_ENOERR, QSE_HTTP_ENOERR,
QSE_HTTP_ENOMEM, QSE_HTTP_ENOMEM,
QSE_HTTP_EBADREQ, QSE_HTTP_EBADREQ,
QSE_HTTP_EBADHDR QSE_HTTP_EBADHDR,
QSE_HTTP_ETRAENC /* bad transfer-encoding */
}; };
typedef enum qse_http_errnum_t qse_http_errnum_t; typedef enum qse_http_errnum_t qse_http_errnum_t;
@ -56,6 +57,12 @@ struct qse_http_t
QSE_HTTP_REQ_POST QSE_HTTP_REQ_POST
} method; } method;
struct
{
qse_byte_t* ptr;
qse_size_t len;
} host;
struct struct
{ {
qse_byte_t* ptr; qse_byte_t* ptr;
@ -79,6 +86,14 @@ struct qse_http_t
qse_htb_t tab; qse_htb_t tab;
void* combined; void* combined;
} hdr; } hdr;
/* special attributes derived from the header */
struct
{
int chunked;
int content_length;
int connection_close;
} attr;
} req; } req;
}; };

View File

@ -347,6 +347,16 @@ static QSE_INLINE void clear_combined_headers (qse_http_t* http)
http->req.hdr.combined = QSE_NULL; http->req.hdr.combined = QSE_NULL;
} }
static QSE_INLINE void clear_request (qse_http_t* http)
{
/* clear necessary part of the request before
* reading the next request */
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.raw);
}
#define QSE_HTTP_STATE_REQ 1 #define QSE_HTTP_STATE_REQ 1
#define QSE_HTTP_STATE_HDR 2 #define QSE_HTTP_STATE_HDR 2
#define QSE_HTTP_STATE_POST 3 #define QSE_HTTP_STATE_POST 3
@ -413,7 +423,7 @@ void qse_http_fini (qse_http_t* http)
fini_buffer (http, &http->req.raw); fini_buffer (http, &http->req.raw);
} }
static qse_byte_t* parse_http_req (qse_http_t* http, qse_byte_t* line) static qse_byte_t* parse_http_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;
@ -534,7 +544,14 @@ static qse_byte_t* parse_http_req (qse_http_t* http, qse_byte_t* line)
/* if the line does not end with a new line, it is a bad request */ /* if the line does not end with a new line, it is a bad request */
if (*p != QSE_T('\n')) goto badreq; if (*p != QSE_T('\n')) goto badreq;
qse_printf (QSE_T("parse_http_req ....\n")); /* adjust Connection: close for HTTP 1.0 or eariler */
if (http->req.version.major < 1 ||
(http->req.version.major == 1 && http->req.version.minor == 0))
{
http->req.attr.connection_close = 1;
}
qse_printf (QSE_T("parse_http_reqline ....\n"));
return ++p; return ++p;
badreq: badreq:
@ -570,38 +587,99 @@ static QSE_INLINE int compare_octets (
return (s2 < end2)? -1: 0; return (s2 < end2)? -1: 0;
} }
static QSE_INLINE int capture_connection (
static QSE_INLINE void capture_content_length (
qse_http_t* http, qse_htb_pair_t* pair) qse_http_t* http, qse_htb_pair_t* pair)
{ {
qse_printf (QSE_T("content length %.*S\n"), (int)pair->vlen, pair->vptr); int n;
n = compare_octets (pair->vptr, pair->vlen, "close", 5);
if (n == 0)
{
http->req.attr.connection_close = 1;
return 0;
}
/* don't care about other values */
return 0;
} }
static QSE_INLINE void capture_content_type ( static QSE_INLINE int capture_content_length (
qse_http_t* http, qse_htb_pair_t* pair) qse_http_t* http, qse_htb_pair_t* pair)
{ {
qse_printf (QSE_T("content type %.*S\n"), (int)pair->vlen, pair->vptr); qse_size_t len = 0, off = 0, tmp;
const qse_byte_t* ptr = pair->vptr;
while (off < pair->vlen)
{
int num = digit_to_num (ptr[off]);
if (num <= -1)
{
/* the length contains a non-digit */
http->errnum = QSE_HTTP_EBADREQ;
return -1;
}
tmp = len * 10 + num;
if (tmp < len)
{
/* the length has overflown */
http->errnum = QSE_HTTP_EBADREQ;
return -1;
}
len = tmp;
off++;
}
if (off == 0)
{
/* no length was provided */
http->errnum = QSE_HTTP_EBADREQ;
return -1;
}
http->req.attr.content_length = len;
return 0;
} }
static QSE_INLINE void capture_host ( static QSE_INLINE int capture_host (
qse_http_t* http, qse_htb_pair_t* pair) qse_http_t* http, qse_htb_pair_t* pair)
{ {
qse_printf (QSE_T("host capture => %.*S\n"), (int)pair->vlen, pair->vptr); qse_printf (QSE_T("host capture => %.*S\n"), (int)pair->vlen, pair->vptr);
return 0;
} }
static QSE_INLINE void capture_key_header ( static QSE_INLINE int capture_transfer_encoding (
qse_http_t* http, qse_htb_pair_t* pair)
{
int n;
n = compare_octets (pair->vptr, pair->vlen, "chunked", 7);
if (n == 0)
{
http->req.attr.chunked = 1;
return 0;
}
/* other encoding type not supported yet */
http->errnum = QSE_HTTP_EBADREQ;
return -1;
}
static QSE_INLINE int capture_key_header (
qse_http_t* http, qse_htb_pair_t* pair) qse_http_t* http, qse_htb_pair_t* pair)
{ {
static struct static struct
{ {
const qse_byte_t* ptr; const qse_byte_t* ptr;
qse_size_t len; qse_size_t len;
void (*handler) (qse_http_t*, qse_htb_pair_t*); int (*handler) (qse_http_t*, qse_htb_pair_t*);
} hdrtab[] = } hdrtab[] =
{ {
{ "Content-Length", 14, capture_content_length }, { "Connection", 10, capture_connection },
{ "Content-Type", 12, capture_content_type }, { "Content-Length", 14, capture_content_length },
{ "Host", 4, capture_host } { "Host", 4, capture_host },
{ "Transfer-Encoding", 17, capture_transfer_encoding }
}; };
int n; int n;
@ -620,11 +698,14 @@ static QSE_INLINE void capture_key_header (
if (n == 0) if (n == 0)
{ {
/* bingo! */ /* bingo! */
hdrtab[mid].handler (http, pair); return hdrtab[mid].handler (http, pair);
break;
} }
if (n > 0) { base = mid + 1; count--; } if (n > 0) { base = mid + 1; count--; }
} }
/* No callback functions were interested in this header field. */
return 0;
} }
struct hdr_cbserter_ctx_t struct hdr_cbserter_ctx_t
@ -648,7 +729,16 @@ static qse_htb_pair_t* hdr_cbserter (
p = qse_htb_allocpair (htb, kptr, klen, tx->vptr, tx->vlen); p = qse_htb_allocpair (htb, kptr, klen, tx->vptr, tx->vlen);
if (p == QSE_NULL) tx->http->errnum = QSE_HTTP_ENOMEM; if (p == QSE_NULL) tx->http->errnum = QSE_HTTP_ENOMEM;
else capture_key_header (tx->http, p); else
{
if (capture_key_header (tx->http, p) <= -1)
{
/* Destroy the pair created here
* as it is not added to the hash table yet */
qse_htb_freepair (htb, p);
p = QSE_NULL;
}
}
return p; return p;
} }
@ -722,7 +812,7 @@ Change it to doubly linked for this?
cmb->next = tx->http->req.hdr.combined; cmb->next = tx->http->req.hdr.combined;
tx->http->req.hdr.combined = cmb; tx->http->req.hdr.combined = cmb;
capture_key_header (tx->http, pair); if (capture_key_header (tx->http, pair) <= -1) return QSE_NULL;
return pair; return pair;
} }
@ -794,22 +884,24 @@ qse_byte_t* parse_http_header (qse_http_t* http, qse_byte_t* line)
} }
*last = '\0'; *last = '\0';
{ /* insert the new field to the header table */
struct hdr_cbserter_ctx_t ctx;
ctx.http = http;
ctx.vptr = value.ptr;
ctx.vlen = value.len;
http->errnum = QSE_HTTP_ENOERR;
if (qse_htb_cbsert (
&http->req.hdr.tab, name.ptr, name.len,
hdr_cbserter, &ctx) == QSE_NULL)
{ {
if (http->errnum == QSE_HTTP_ENOERR) http->errnum = QSE_HTTP_ENOMEM; struct hdr_cbserter_ctx_t ctx;
return QSE_NULL;
ctx.http = http;
ctx.vptr = value.ptr;
ctx.vlen = value.len;
http->errnum = QSE_HTTP_ENOERR;
if (qse_htb_cbsert (
&http->req.hdr.tab, name.ptr, name.len,
hdr_cbserter, &ctx) == QSE_NULL)
{
if (http->errnum == QSE_HTTP_ENOERR)
http->errnum = QSE_HTTP_ENOMEM;
return QSE_NULL;
}
} }
}
return p; return p;
@ -868,7 +960,7 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* ptr, qse_size_t len)
while (is_whspace_octet(*p)) p++; while (is_whspace_octet(*p)) p++;
QSE_ASSERT (*p != '\0'); QSE_ASSERT (*p != '\0');
p = parse_http_req (http, p); p = parse_http_reqline (http, p);
if (p == QSE_NULL) return -1; if (p == QSE_NULL) return -1;
do do
@ -876,17 +968,22 @@ int qse_http_feed (qse_http_t* http, const qse_byte_t* ptr, qse_size_t len)
while (is_whspace_octet(*p)) p++; while (is_whspace_octet(*p)) p++;
if (*p == '\0') break; 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); p = parse_http_header (http, p);
if (p == QSE_NULL) return -1; if (p == QSE_NULL) return -1;
} }
while (1); while (1);
if (http->req.attr.content_length > 0)
{
qse_printf (QSE_T("content->length.. %d\n"), (int)http->req.attr.content_length);
}
qse_htb_walk (&http->req.hdr.tab, walk, QSE_NULL); qse_htb_walk (&http->req.hdr.tab, walk, QSE_NULL);
/* 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... */
qse_htb_clear (&http->req.hdr.tab); clear_request (http);
clear_combined_headers (http);
clear_buffer (http, &http->req.raw);
req = ptr; /* let ptr point to the next character to '\n' */ req = ptr; /* let ptr point to the next character to '\n' */
} }
} }