added more header handling code for http
This commit is contained in:
parent
19af03709a
commit
b7c4acf78e
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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' */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user