changed how to handle http header fields.

fixed a few http proxying bugs.
This commit is contained in:
hyung-hwan 2012-04-11 15:18:51 +00:00
parent 654003e06d
commit 130bbe9e21
10 changed files with 717 additions and 336 deletions

View File

@ -39,6 +39,8 @@
#define QSE_MBS_LEN(s) ((s)->val.len) #define QSE_MBS_LEN(s) ((s)->val.len)
/** string pointer */ /** string pointer */
#define QSE_MBS_PTR(s) ((s)->val.ptr) #define QSE_MBS_PTR(s) ((s)->val.ptr)
/** pointer to a particular position */
#define QSE_MBS_CPTR(s,idx) (&(s)->val.ptr[idx])
/** string capacity */ /** string capacity */
#define QSE_MBS_CAPA(s) ((s)->capa) #define QSE_MBS_CAPA(s) ((s)->capa)
/** character at the given position */ /** character at the given position */
@ -54,6 +56,8 @@
#define QSE_WCS_LEN(s) ((s)->val.len) #define QSE_WCS_LEN(s) ((s)->val.len)
/** string pointer */ /** string pointer */
#define QSE_WCS_PTR(s) ((s)->val.ptr) #define QSE_WCS_PTR(s) ((s)->val.ptr)
/** pointer to a particular position */
#define QSE_WCS_CPTR(s,idx) (&(s)->val.ptr[idx])
/** string capacity */ /** string capacity */
#define QSE_WCS_CAPA(s) ((s)->capa) #define QSE_WCS_CAPA(s) ((s)->capa)
/** character at the given position */ /** character at the given position */
@ -79,6 +83,7 @@ typedef qse_size_t (*qse_wcs_sizer_t) (
# define QSE_STR_CSTR(s) ((qse_cstr_t*)QSE_MBS_XSTR(s)) # define QSE_STR_CSTR(s) ((qse_cstr_t*)QSE_MBS_XSTR(s))
# define QSE_STR_LEN(s) QSE_MBS_LEN(s) # define QSE_STR_LEN(s) QSE_MBS_LEN(s)
# define QSE_STR_PTR(s) QSE_MBS_PTR(s) # define QSE_STR_PTR(s) QSE_MBS_PTR(s)
# define QSE_STR_CPTR(s,idx) QSE_MBS_CPTR(s,idx)
# define QSE_STR_CAPA(s) QSE_MBS_CAPA(s) # define QSE_STR_CAPA(s) QSE_MBS_CAPA(s)
# define QSE_STR_CHAR(s,idx) QSE_MBS_CHAR(s,idx) # define QSE_STR_CHAR(s,idx) QSE_MBS_CHAR(s,idx)
# define QSE_STR_LASTCHAR(s) QSE_MBS_LASTCHAR(s) # define QSE_STR_LASTCHAR(s) QSE_MBS_LASTCHAR(s)
@ -89,6 +94,7 @@ typedef qse_size_t (*qse_wcs_sizer_t) (
# define QSE_STR_CSTR(s) ((qse_cstr_t*)QSE_WCS_XSTR(s)) # define QSE_STR_CSTR(s) ((qse_cstr_t*)QSE_WCS_XSTR(s))
# define QSE_STR_LEN(s) QSE_WCS_LEN(s) # define QSE_STR_LEN(s) QSE_WCS_LEN(s)
# define QSE_STR_PTR(s) QSE_WCS_PTR(s) # define QSE_STR_PTR(s) QSE_WCS_PTR(s)
# define QSE_STR_CPTR(s,idx) QSE_WCS_CPTR(s,idx)
# define QSE_STR_CAPA(s) QSE_WCS_CAPA(s) # define QSE_STR_CAPA(s) QSE_WCS_CAPA(s)
# define QSE_STR_CHAR(s,idx) QSE_WCS_CHAR(s,idx) # define QSE_STR_CHAR(s,idx) QSE_WCS_CHAR(s,idx)
# define QSE_STR_LASTCHAR(s) QSE_WCS_LASTCHAR(s) # define QSE_STR_LASTCHAR(s) QSE_WCS_LASTCHAR(s)

View File

@ -94,9 +94,6 @@ struct qse_htrd_t
qse_htob_t raw; /* buffer to hold raw octets */ qse_htob_t raw; /* buffer to hold raw octets */
qse_htob_t tra; /* buffer for handling trailers */ qse_htob_t tra; /* buffer for handling trailers */
} b; } b;
/* points to the head of the combined header list */
void* chl;
} fed; } fed;
qse_htre_t re; qse_htre_t re;

View File

@ -25,8 +25,15 @@
#include <qse/cmn/htb.h> #include <qse/cmn/htb.h>
#include <qse/cmn/str.h> #include <qse/cmn/str.h>
/*
* You should not manipulate an object of the #qse_htre_t
* type directly since it's complex. Use #qse_htrd_t to
* create an object of the qse_htre_t type.
*/
/* header and contents of request/response */ /* header and contents of request/response */
typedef struct qse_htre_t qse_htre_t; typedef struct qse_htre_t qse_htre_t;
typedef struct qse_htre_hdrval_t qse_htre_hdrval_t;
enum qse_htre_state_t enum qse_htre_state_t
{ {
@ -41,6 +48,13 @@ typedef int (*qse_htre_concb_t) (
void* ctx void* ctx
); );
struct qse_htre_hdrval_t
{
const qse_mchar_t* ptr;
qse_size_t len;
qse_htre_hdrval_t* next;
};
struct qse_htre_t struct qse_htre_t
{ {
qse_mmgr_t* mmgr; qse_mmgr_t* mmgr;
@ -84,10 +98,10 @@ struct qse_htre_t
#define QSE_HTRE_ATTR_CHUNKED (1 << 0) #define QSE_HTRE_ATTR_CHUNKED (1 << 0)
#define QSE_HTRE_ATTR_LENGTH (1 << 1) #define QSE_HTRE_ATTR_LENGTH (1 << 1)
#define QSE_HTRE_ATTR_KEEPALIVE (1 << 2) #define QSE_HTRE_ATTR_KEEPALIVE (1 << 2)
#define QSE_HTRE_ATTR_EXPECT100 (1 << 3)
int flags; int flags;
qse_size_t content_length; qse_size_t content_length;
const qse_mchar_t* expect; const qse_mchar_t* status; /* for cgi */
const qse_mchar_t* status;
} attr; } attr;
/* header table */ /* header table */
@ -129,7 +143,7 @@ struct qse_htre_t
typedef int (*qse_htre_header_walker_t) ( typedef int (*qse_htre_header_walker_t) (
qse_htre_t* re, qse_htre_t* re,
const qse_mchar_t* key, const qse_mchar_t* key,
const qse_mchar_t* val, const qse_htre_hdrval_t* val,
void* ctx void* ctx
); );
@ -162,12 +176,12 @@ int qse_htre_setstrfromxstr (
const qse_mxstr_t* xstr const qse_mxstr_t* xstr
); );
const qse_mchar_t* qse_htre_getheaderval ( const qse_htre_hdrval_t* qse_htre_getheaderval (
const qse_htre_t* re, const qse_htre_t* re,
const qse_mchar_t* key const qse_mchar_t* key
); );
const qse_mchar_t* qse_htre_gettrailerval ( const qse_htre_hdrval_t* qse_htre_gettrailerval (
const qse_htre_t* re, const qse_htre_t* re,
const qse_mchar_t* key const qse_mchar_t* key
); );

View File

@ -189,6 +189,7 @@ static QSE_INLINE pair_t* change_pair_val (
static mancbs_t mancbs[] = static mancbs_t mancbs[] =
{ {
/* == QSE_HTB_MANCBS_DEFAULT == */
{ {
{ {
QSE_HTB_COPIER_DEFAULT, QSE_HTB_COPIER_DEFAULT,
@ -204,6 +205,7 @@ static mancbs_t mancbs[] =
QSE_HTB_HASHER_DEFAULT QSE_HTB_HASHER_DEFAULT
}, },
/* == QSE_HTB_MANCBS_INLINE_COPIERS == */
{ {
{ {
QSE_HTB_COPIER_INLINE, QSE_HTB_COPIER_INLINE,
@ -219,6 +221,7 @@ static mancbs_t mancbs[] =
QSE_HTB_HASHER_DEFAULT QSE_HTB_HASHER_DEFAULT
}, },
/* == QSE_HTB_MANCBS_INLINE_KEY_COPIER == */
{ {
{ {
QSE_HTB_COPIER_INLINE, QSE_HTB_COPIER_INLINE,
@ -234,6 +237,7 @@ static mancbs_t mancbs[] =
QSE_HTB_HASHER_DEFAULT QSE_HTB_HASHER_DEFAULT
}, },
/* == QSE_HTB_MANCBS_INLINE_VALUE_COPIER == */
{ {
{ {
QSE_HTB_COPIER_DEFAULT, QSE_HTB_COPIER_DEFAULT,
@ -288,7 +292,6 @@ int qse_htb_init (
QSE_ASSERTX (factor >= 0 && factor <= 100, QSE_ASSERTX (factor >= 0 && factor <= 100,
"The load factor should be between 0 and 100 inclusive. In the release mode, a value out of the range is adjusted to 100"); "The load factor should be between 0 and 100 inclusive. In the release mode, a value out of the range is adjusted to 100");
/* some initial adjustment */ /* some initial adjustment */
if (capa <= 0) capa = 1; if (capa <= 0) capa = 1;
if (factor > 100) factor = 100; if (factor > 100) factor = 100;

View File

@ -114,20 +114,6 @@ struct hdr_cmb_t
struct hdr_cmb_t* next; struct hdr_cmb_t* next;
}; };
static QSE_INLINE void clear_combined_headers (qse_htrd_t* htrd)
{
struct hdr_cmb_t* cmb = (struct hdr_cmb_t*)htrd->fed.chl;
while (cmb)
{
struct hdr_cmb_t* next = cmb->next;
QSE_MMGR_FREE (htrd->mmgr, cmb);
cmb = next;
}
htrd->fed.chl = QSE_NULL;
}
static QSE_INLINE void clear_feed (qse_htrd_t* htrd) static QSE_INLINE void clear_feed (qse_htrd_t* htrd)
{ {
/* clear necessary part of the request/response before /* clear necessary part of the request/response before
@ -136,7 +122,6 @@ static QSE_INLINE void clear_feed (qse_htrd_t* htrd)
qse_mbs_clear (&htrd->fed.b.tra); qse_mbs_clear (&htrd->fed.b.tra);
qse_mbs_clear (&htrd->fed.b.raw); qse_mbs_clear (&htrd->fed.b.raw);
clear_combined_headers (htrd);
QSE_MEMSET (&htrd->fed.s, 0, QSE_SIZEOF(htrd->fed.s)); QSE_MEMSET (&htrd->fed.s, 0, QSE_SIZEOF(htrd->fed.s));
} }
@ -198,7 +183,6 @@ void qse_htrd_fini (qse_htrd_t* htrd)
{ {
qse_htre_fini (&htrd->re); qse_htre_fini (&htrd->re);
clear_combined_headers (htrd);
qse_mbs_fini (&htrd->fed.b.tra); qse_mbs_fini (&htrd->fed.b.tra);
qse_mbs_fini (&htrd->fed.b.raw); qse_mbs_fini (&htrd->fed.b.raw);
#if 0 #if 0
@ -465,19 +449,19 @@ void qse_htrd_setrecbs (qse_htrd_t* htrd, const qse_htrd_recbs_t* recbs)
static int capture_connection (qse_htrd_t* htrd, qse_htb_pair_t* pair) static int capture_connection (qse_htrd_t* htrd, qse_htb_pair_t* pair)
{ {
int n; int n;
qse_htre_hdrval_t* val;
n = qse_mbsxncasecmp ( val = QSE_HTB_VPTR(pair);
QSE_HTB_VPTR(pair), QSE_HTB_VLEN(pair), while (val->next) val = val->next;
"close", 5);
n = qse_mbscmp (val->ptr, QSE_MT("close"));
if (n == 0) if (n == 0)
{ {
htrd->re.attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE; htrd->re.attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE;
return 0; return 0;
} }
n = qse_mbsxncasecmp ( n = qse_mbscmp (val->ptr, QSE_MT("keep-alive"));
QSE_HTB_VPTR(pair), QSE_HTB_VLEN(pair),
"keep-alive", 10);
if (n == 0) if (n == 0)
{ {
htrd->re.attr.flags |= QSE_HTRE_ATTR_KEEPALIVE; htrd->re.attr.flags |= QSE_HTRE_ATTR_KEEPALIVE;
@ -504,9 +488,15 @@ static int capture_connection (qse_htrd_t* htrd, qse_htb_pair_t* pair)
static int capture_content_length (qse_htrd_t* htrd, qse_htb_pair_t* pair) static int capture_content_length (qse_htrd_t* htrd, qse_htb_pair_t* pair)
{ {
qse_size_t len = 0, off = 0, tmp; qse_size_t len = 0, off = 0, tmp;
const qse_mchar_t* ptr = QSE_HTB_VPTR(pair); const qse_mchar_t* ptr;
qse_htre_hdrval_t* val;
while (off < QSE_HTB_VLEN(pair)) /* get the last content_length */
val = QSE_HTB_VPTR(pair);
while (val->next) val = val->next;
ptr = val->ptr;
while (off < val->len)
{ {
int num = digit_to_num (ptr[off]); int num = digit_to_num (ptr[off]);
if (num <= -1) if (num <= -1)
@ -550,22 +540,37 @@ static int capture_content_length (qse_htrd_t* htrd, qse_htb_pair_t* pair)
static int capture_expect (qse_htrd_t* htrd, qse_htb_pair_t* pair) static int capture_expect (qse_htrd_t* htrd, qse_htb_pair_t* pair)
{ {
htrd->re.attr.expect = QSE_HTB_VPTR(pair); qse_htre_hdrval_t* val;
val = QSE_HTB_VPTR(pair);
while (val->next) val = val->next;
if (qse_mbscmp (val->ptr, QSE_MT("100-continue")) == 0)
htrd->re.attr.flags |= QSE_HTRE_ATTR_EXPECT100;
return 0; return 0;
} }
static int capture_status (qse_htrd_t* htrd, qse_htb_pair_t* pair) static int capture_status (qse_htrd_t* htrd, qse_htb_pair_t* pair)
{ {
htrd->re.attr.status = QSE_HTB_VPTR(pair); qse_htre_hdrval_t* val;
val = QSE_HTB_VPTR(pair);
while (val->next) val = val->next;
htrd->re.attr.status = val->ptr;
return 0; return 0;
} }
static int capture_transfer_encoding (qse_htrd_t* htrd, qse_htb_pair_t* pair) static int capture_transfer_encoding (qse_htrd_t* htrd, qse_htb_pair_t* pair)
{ {
int n; int n;
qse_htre_hdrval_t* val;
n = qse_mbsxncasecmp ( val = QSE_HTB_VPTR(pair);
QSE_HTB_VPTR(pair), QSE_HTB_VLEN(pair), "chunked", 7); while (val->next) val = val->next;
n = qse_mbscasecmp (val->ptr, QSE_MT("chunked"));
if (n == 0) if (n == 0)
{ {
/* if (htrd->re.attr.content_length > 0) */ /* if (htrd->re.attr.content_length > 0) */
@ -645,10 +650,26 @@ static qse_htb_pair_t* hdr_cbserter (
{ {
/* the key is new. let's create a new pair. */ /* the key is new. let's create a new pair. */
qse_htb_pair_t* p; qse_htb_pair_t* p;
qse_htre_hdrval_t *val;
p = qse_htb_allocpair (htb, kptr, klen, tx->vptr, tx->vlen); val = QSE_MMGR_ALLOC (htb->mmgr, QSE_SIZEOF(*val));
if (val == QSE_NULL)
{
tx->htrd->errnum = QSE_HTRD_ENOMEM;
return QSE_NULL;
}
if (p == QSE_NULL) tx->htrd->errnum = QSE_HTRD_ENOMEM; QSE_MEMSET (val, 0, QSE_SIZEOF(*val));
val->ptr = tx->vptr;
val->len = tx->vlen;
val->next = QSE_NULL;
p = qse_htb_allocpair (htb, kptr, klen, val, 0);
if (p == QSE_NULL)
{
QSE_MMGR_FREE (htb->mmgr, val);
tx->htrd->errnum = QSE_HTRD_ENOMEM;
}
else else
{ {
if (capture_key_header (tx->htrd, p) <= -1) if (capture_key_header (tx->htrd, p) <= -1)
@ -664,81 +685,65 @@ static qse_htb_pair_t* hdr_cbserter (
} }
else else
{ {
/* the key exists. let's combine values, each separated /* RFC2616
* by a comma */ * Multiple message-header fields with the same field-name
struct hdr_cmb_t* cmb; * MAY be present in a message if and only if the entire
qse_mchar_t* ptr; * field-value for that header field is defined as a
qse_size_t len; * comma-separated list [i.e., #(values)]. It MUST be possible
* to combine the multiple header fields into one
* "field-name: field-value" pair, without changing the semantics
* of the message, by appending each subsequent field-value
* to the first, each separated by a comma. The order in which
* header fields with the same field-name are received is therefore
* significant to the interpretation of the combined field value,
* and thus a proxy MUST NOT change the order of these field values
* when a message is forwarded.
/* TODO: reduce waste in case the same key appears again. * RFC6265 defines the syntax for Set-Cookie and Cookie.
* this seems to be conflicting with RFC2616.
* *
* the current implementation is not space nor performance * Origin servers SHOULD NOT fold multiple Set-Cookie header fields
* efficient. it allocates a new buffer again whenever it * into a single header field. The usual mechanism for folding HTTP
* encounters the same key. memory is wasted and performance * headers fields (i.e., as defined in [RFC2616]) might change the
* is sacrificed. * semantics of the Set-Cookie header field because the %x2C (",")
* character is used by Set-Cookie in a way that conflicts with
* hopefully, a htrd header does not include a lot of * such folding.
* duplicate fields and this implmentation can afford wastage. *
* So i just maintain the list of valuea for a key instead of
* folding them.
*/ */
/* allocate a block to combine the existing value and the new value */ qse_htre_hdrval_t* val;
cmb = (struct hdr_cmb_t*) QSE_MMGR_ALLOC ( qse_htre_hdrval_t* tmp;
tx->htrd->mmgr,
QSE_SIZEOF(*cmb) + val = (qse_htre_hdrval_t*) QSE_MMGR_ALLOC (
QSE_SIZEOF(qse_mchar_t) * (QSE_HTB_VLEN(pair) + 1 + tx->vlen + 1) tx->htrd->mmgr, QSE_SIZEOF(*val));
); if (val == QSE_NULL)
if (cmb == QSE_NULL)
{ {
tx->htrd->errnum = QSE_HTRD_ENOMEM; tx->htrd->errnum = QSE_HTRD_ENOMEM;
return QSE_NULL; return QSE_NULL;
} }
/* let 'ptr' point to the actual space for the combined value */ QSE_MEMSET (val, 0, QSE_SIZEOF(*val));
ptr = (qse_mchar_t*)(cmb + 1); val->ptr = tx->vptr;
len = 0; val->len = tx->vlen;
val->next = QSE_NULL;
/* fill the space with the value */ /* TODO: doubly linked list for speed-up??? */
QSE_MEMCPY (&ptr[len], QSE_HTB_VPTR(pair), QSE_HTB_VLEN(pair)); tmp = QSE_HTB_VPTR(pair);
len += QSE_HTB_VLEN(pair); QSE_ASSERT (tmp != QSE_NULL);
ptr[len++] = ',';
QSE_MEMCPY (&ptr[len], tx->vptr, tx->vlen);
len += tx->vlen;
ptr[len] = '\0';
#if 0 /* find the tail */
TODO: while (tmp->next) tmp = tmp->next;
Not easy to unlink when using a singly linked list... /* append it to the list*/
Change it to doubly linked for this? tmp->next = val;
/* let's destroy the old buffer at least */
if (!(ptr >= tx->htrd->fed.b.raw.data && ptr <
&tx->htrd->fed.b.raw.data[tx->htrd->fed.b.raw.size]))
{
/* NOTE the range check in 'if' assumes that raw.data is never
* relocated for resizing */
QSE_MMGR_FREE (
tx->htrd->mmgr,
((struct hdr_cmb_t*)QSE_HTB_VPTR(pair)) - 1
);
}
#endif
/* update the value pointer and length */
QSE_HTB_VPTR(pair) = ptr;
QSE_HTB_VLEN(pair) = len;
/* link the new combined value block */
cmb->next = tx->htrd->fed.chl;
tx->htrd->fed.chl = cmb;
if (capture_key_header (tx->htrd, pair) <= -1) return QSE_NULL; if (capture_key_header (tx->htrd, pair) <= -1) return QSE_NULL;
return pair; return pair;
} }
} }
qse_mchar_t* parse_header_fields ( qse_mchar_t* parse_header_field (
qse_htrd_t* htrd, qse_mchar_t* line, qse_htb_t* tab) qse_htrd_t* htrd, qse_mchar_t* line, qse_htb_t* tab)
{ {
qse_mchar_t* p = line, * last; qse_mchar_t* p = line, * last;
@ -757,26 +762,26 @@ qse_mchar_t* parse_header_fields (
/* check the field name */ /* check the field name */
name.ptr = last = p; name.ptr = last = p;
while (*p != '\0' && *p != '\n' && *p != ':') while (*p != QSE_MT('\0') && *p != QSE_MT('\n') && *p != QSE_MT(':'))
{ {
if (!is_space_octet(*p++)) last = p; if (!is_space_octet(*p++)) last = p;
} }
name.len = last - name.ptr; name.len = last - name.ptr;
if (*p != ':') goto badhdr; if (*p != QSE_MT(':')) goto badhdr;
*last = '\0'; *last = '\0';
/* skip the colon and spaces after it */ /* skip the colon and spaces after it */
do { p++; } while (is_space_octet(*p)); do { p++; } while (is_space_octet(*p));
value.ptr = last = p; value.ptr = last = p;
while (*p != '\0' && *p != '\n') while (*p != QSE_MT('\0') && *p != QSE_MT('\n'))
{ {
if (!is_space_octet(*p++)) last = p; if (!is_space_octet(*p++)) last = p;
} }
value.len = last - value.ptr; value.len = last - value.ptr;
if (*p != '\n') goto badhdr; /* not ending with a new line */ if (*p != QSE_MT('\n')) goto badhdr; /* not ending with a new line */
/* peep at the beginning of the next line to check if it is /* peep at the beginning of the next line to check if it is
* the continuation */ * the continuation */
@ -785,25 +790,25 @@ qse_mchar_t* parse_header_fields (
qse_mchar_t* cpydst; qse_mchar_t* cpydst;
cpydst = p - 1; cpydst = p - 1;
if (*(cpydst-1) == '\r') cpydst--; if (*(cpydst-1) == QSE_MT('\r')) cpydst--;
/* process all continued lines */ /* process all continued lines */
do do
{ {
while (*p != '\0' && *p != '\n') while (*p != QSE_MT('\0') && *p != QSE_MT('\n'))
{ {
*cpydst = *p++; *cpydst = *p++;
if (!is_space_octet(*cpydst++)) last = cpydst; if (!is_space_octet(*cpydst++)) last = cpydst;
} }
value.len = last - value.ptr; value.len = last - value.ptr;
if (*p != '\n') goto badhdr; if (*p != QSE_MT('\n')) goto badhdr;
if (*(cpydst-1) == '\r') cpydst--; if (*(cpydst-1) == QSE_MT('\r')) cpydst--;
} }
while (is_purespace_octet(*++p)); while (is_purespace_octet(*++p));
} }
*last = '\0'; *last = QSE_MT('\0');
/* insert the new field to the header table */ /* insert the new field to the header table */
{ {
@ -867,11 +872,12 @@ static QSE_INLINE int parse_initial_line_and_headers (
/* TODO: return error if protocol is 0.9. /* TODO: return error if protocol is 0.9.
* HTTP/0.9 must not get headers... */ * HTTP/0.9 must not get headers... */
p = parse_header_fields (htrd, p, &htrd->re.hdrtab); p = parse_header_field (htrd, p, &htrd->re.hdrtab);
if (p == QSE_NULL) return -1; if (p == QSE_NULL) return -1;
} }
while (1); while (1);
return 0; return 0;
} }
@ -997,7 +1003,7 @@ static const qse_mchar_t* get_trailing_headers (
/* TODO: return error if protocol is 0.9. /* TODO: return error if protocol is 0.9.
* HTTP/0.9 must not get headers... */ * HTTP/0.9 must not get headers... */
p = parse_header_fields ( p = parse_header_field (
htrd, p, htrd, p,
((htrd->option & QSE_HTRD_TRAILERS)? &htrd->re.trailers: &htrd->re.hdrtab) ((htrd->option & QSE_HTRD_TRAILERS)? &htrd->re.trailers: &htrd->re.hdrtab)
); );

View File

@ -21,14 +21,47 @@
#include <qse/net/htre.h> #include <qse/net/htre.h>
#include "../cmn/mem.h" #include "../cmn/mem.h"
static void free_hdrval (qse_htb_t* htb, void* vptr, qse_size_t vlen)
{
qse_htre_hdrval_t* val;
qse_htre_hdrval_t* tmp;
val = vptr;
while (val)
{
tmp = val;
val = val->next;
QSE_MMGR_FREE (htb->mmgr, tmp);
}
}
int qse_htre_init (qse_htre_t* re, qse_mmgr_t* mmgr) int qse_htre_init (qse_htre_t* re, qse_mmgr_t* mmgr)
{ {
static qse_htb_mancbs_t mancbs =
{
{
QSE_HTB_COPIER_DEFAULT,
QSE_HTB_COPIER_DEFAULT
},
{
QSE_HTB_FREEER_DEFAULT,
free_hdrval
},
QSE_HTB_COMPER_DEFAULT,
QSE_HTB_KEEPER_DEFAULT,
QSE_HTB_SIZER_DEFAULT,
QSE_HTB_HASHER_DEFAULT
};
QSE_MEMSET (re, 0, QSE_SIZEOF(*re)); QSE_MEMSET (re, 0, QSE_SIZEOF(*re));
re->mmgr = mmgr; re->mmgr = mmgr;
if (qse_htb_init (&re->hdrtab, mmgr, 60, 70, 1, 1) <= -1) return -1; if (qse_htb_init (&re->hdrtab, mmgr, 60, 70, 1, 1) <= -1) return -1;
if (qse_htb_init (&re->trailers, mmgr, 20, 70, 1, 1) <= -1) return -1; if (qse_htb_init (&re->trailers, mmgr, 20, 70, 1, 1) <= -1) return -1;
qse_htb_setmancbs (&re->hdrtab, &mancbs);
qse_htb_setmancbs (&re->trailers, &mancbs);
qse_mbs_init (&re->content, mmgr, 0); qse_mbs_init (&re->content, mmgr, 0);
#if 0 #if 0
qse_mbs_init (&re->iniline, mmgr, 0); qse_mbs_init (&re->iniline, mmgr, 0);
@ -86,7 +119,7 @@ int qse_htre_setstrfromxstr (
return (qse_mbs_ncpy (str, xstr->ptr, xstr->len) == (qse_size_t)-1)? -1: 0; return (qse_mbs_ncpy (str, xstr->ptr, xstr->len) == (qse_size_t)-1)? -1: 0;
} }
const qse_mchar_t* qse_htre_getheaderval ( const qse_htre_hdrval_t* qse_htre_getheaderval (
const qse_htre_t* re, const qse_mchar_t* name) const qse_htre_t* re, const qse_mchar_t* name)
{ {
qse_htb_pair_t* pair; qse_htb_pair_t* pair;
@ -95,7 +128,7 @@ const qse_mchar_t* qse_htre_getheaderval (
return QSE_HTB_VPTR(pair); return QSE_HTB_VPTR(pair);
} }
const qse_mchar_t* qse_htre_gettrailerval ( const qse_htre_hdrval_t* qse_htre_gettrailerval (
const qse_htre_t* re, const qse_mchar_t* name) const qse_htre_t* re, const qse_mchar_t* name)
{ {
qse_htb_pair_t* pair; qse_htb_pair_t* pair;
@ -148,7 +181,6 @@ int qse_htre_walktrailers (
return hwctx.ret; return hwctx.ret;
} }
int qse_htre_addcontent ( int qse_htre_addcontent (
qse_htre_t* re, const qse_mchar_t* ptr, qse_size_t len) qse_htre_t* re, const qse_mchar_t* ptr, qse_size_t len)
{ {

View File

@ -636,6 +636,7 @@ static int task_main_dir (
set_chunklen: set_chunklen:
/* right alignment with space padding on the left */ /* right alignment with space padding on the left */
/* TODO: change snprintf to qse_fmtuintmaxtombs() */
x = snprintf ( x = snprintf (
ctx->buf, (SIZE_CHLEN + SIZE_CHLENCRLF) - 1, ctx->buf, (SIZE_CHLEN + SIZE_CHLENCRLF) - 1,
QSE_MT("%*lX"), (int)(SIZE_CHLEN + SIZE_CHLENCRLF - 2), QSE_MT("%*lX"), (int)(SIZE_CHLEN + SIZE_CHLENCRLF - 2),
@ -906,7 +907,7 @@ qse_httpd_task_t* qse_httpd_entaskpath (
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
task_path_t data; task_path_t data;
const qse_mchar_t* tmp; const qse_htre_hdrval_t* tmp;
QSE_MEMSET (&data, 0, QSE_SIZEOF(data)); QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
data.name = name; data.name = name;
@ -916,7 +917,8 @@ qse_httpd_task_t* qse_httpd_entaskpath (
tmp = qse_htre_getheaderval(req, QSE_MT("Range")); tmp = qse_htre_getheaderval(req, QSE_MT("Range"));
if (tmp) if (tmp)
{ {
if (qse_parsehttprange (tmp, &data.range) <= -1) while (tmp->next) tmp = tmp->next; /* get the last value */
if (qse_parsehttprange (tmp->ptr, &data.range) <= -1)
{ {
return entask_error (httpd, client, pred, 416, &data.version, data.keepalive); return entask_error (httpd, client, pred, 416, &data.version, data.keepalive);
} }
@ -1197,7 +1199,7 @@ qse_httpd_task_t* qse_httpd_entaskfile (
{ {
qse_httpd_task_t task; qse_httpd_task_t task;
task_file_t data; task_file_t data;
const qse_mchar_t* tmp; const qse_htre_hdrval_t* tmp;
QSE_MEMSET (&data, 0, QSE_SIZEOF(data)); QSE_MEMSET (&data, 0, QSE_SIZEOF(data));
data.path = path; data.path = path;
@ -1207,7 +1209,8 @@ qse_httpd_task_t* qse_httpd_entaskfile (
tmp = qse_htre_getheaderval(req, QSE_MT("Range")); tmp = qse_htre_getheaderval(req, QSE_MT("Range"));
if (tmp) if (tmp)
{ {
if (qse_parsehttprange (tmp, &data.range) <= -1) while (tmp->next) tmp = tmp->next; /* get the last value */
if (qse_parsehttprange (tmp->ptr, &data.range) <= -1)
{ {
return qse_httpd_entaskerror (httpd, client, pred, 416, req); return qse_httpd_entaskerror (httpd, client, pred, 416, req);
} }
@ -1284,8 +1287,8 @@ struct task_cgi_t
qse_size_t buflen; qse_size_t buflen;
}; };
typedef struct cgi_script_output_htrd_xtn_t cgi_script_output_htrd_xtn_t; typedef struct cgi_script_htrd_xtn_t cgi_script_htrd_xtn_t;
struct cgi_script_output_htrd_xtn_t struct cgi_script_htrd_xtn_t
{ {
task_cgi_t* cgi; task_cgi_t* cgi;
qse_httpd_client_t* client; qse_httpd_client_t* client;
@ -1299,8 +1302,8 @@ struct cgi_client_req_hdr_ctx_t
qse_env_t* env; qse_env_t* env;
}; };
static int cgi_walk_client_req_header ( static int cgi_capture_client_header (
qse_htre_t* req, const qse_mchar_t* key, const qse_mchar_t* val, void* ctx) qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx)
{ {
cgi_client_req_hdr_ctx_t* hdrctx; cgi_client_req_hdr_ctx_t* hdrctx;
qse_mchar_t* http_key; qse_mchar_t* http_key;
@ -1316,12 +1319,21 @@ static int cgi_walk_client_req_header (
return -1; return -1;
} }
ret = qse_env_insertmbs (hdrctx->env, http_key, val); /* TODO EXCLUDE VARIOUS FIELDS like transfer-encoding or should i let cgi handle transfer-encoding: chunked??? */
/* TODO: special handling for Cookie??? */
do
{
ret = qse_env_insertmbs (hdrctx->env, http_key, val->ptr);
if (ret <= -1) break;
val = val->next;
}
while (val);
QSE_MMGR_FREE (req->mmgr, http_key); QSE_MMGR_FREE (req->mmgr, http_key);
return ret; return ret;
} }
static int cgi_capture_script_header (qse_htre_t* req, const qse_mchar_t* key, const qse_mchar_t* val, void* ctx) static int cgi_capture_script_header (qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx)
{ {
task_cgi_t* cgi = (task_cgi_t*)ctx; task_cgi_t* cgi = (task_cgi_t*)ctx;
@ -1329,15 +1341,23 @@ static int cgi_capture_script_header (qse_htre_t* req, const qse_mchar_t* key, c
if (qse_mbscmp (key, QSE_MT("Status")) != 0 && if (qse_mbscmp (key, QSE_MT("Status")) != 0 &&
qse_mbscmp (key, QSE_MT("Connection")) != 0 && qse_mbscmp (key, QSE_MT("Connection")) != 0 &&
qse_mbscmp (key, QSE_MT("Transfer-Encoding")) != 0) qse_mbscmp (key, QSE_MT("Transfer-Encoding")) != 0)
{
/* multiple items with the same keys are also
* copied back to the response buffer */
do
{ {
if (qse_mbs_cat (cgi->res, key) == (qse_size_t)-1 || if (qse_mbs_cat (cgi->res, key) == (qse_size_t)-1 ||
qse_mbs_cat (cgi->res, QSE_MT(": ")) == (qse_size_t)-1 || qse_mbs_cat (cgi->res, QSE_MT(": ")) == (qse_size_t)-1 ||
qse_mbs_cat (cgi->res, val) == (qse_size_t)-1 || qse_mbs_cat (cgi->res, val->ptr) == (qse_size_t)-1 ||
qse_mbs_cat (cgi->res, QSE_MT("\r\n")) == (qse_size_t)-1) qse_mbs_cat (cgi->res, QSE_MT("\r\n")) == (qse_size_t)-1)
{ {
cgi->httpd->errnum = QSE_HTTPD_ENOMEM; cgi->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1; return -1;
} }
val = val->next;
}
while (val);
} }
return 0; return 0;
@ -1345,11 +1365,11 @@ static int cgi_capture_script_header (qse_htre_t* req, const qse_mchar_t* key, c
static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req) static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req)
{ {
cgi_script_output_htrd_xtn_t* xtn; cgi_script_htrd_xtn_t* xtn;
task_cgi_t* cgi; task_cgi_t* cgi;
int keepalive; int keepalive;
xtn = (cgi_script_output_htrd_xtn_t*) qse_htrd_getxtn (htrd); xtn = (cgi_script_htrd_xtn_t*) qse_htrd_getxtn (htrd);
cgi = xtn->cgi; cgi = xtn->cgi;
QSE_ASSERT (!cgi->nph); QSE_ASSERT (!cgi->nph);
@ -1386,7 +1406,7 @@ static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req)
} }
else else
{ {
const qse_mchar_t* location; const qse_htre_hdrval_t* location;
qse_mchar_t buf[128]; qse_mchar_t buf[128];
location = qse_htre_getheaderval (req, QSE_MT("Location")); location = qse_htre_getheaderval (req, QSE_MT("Location"));
@ -1430,6 +1450,7 @@ static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req)
/* no Content-Length returned by CGI. */ /* no Content-Length returned by CGI. */
if (qse_comparehttpversions (&cgi->version, &http_v11) >= 0) if (qse_comparehttpversions (&cgi->version, &http_v11) >= 0)
{ {
/* the client side supports chunking */
cgi->resflags |= CGI_RES_CLIENT_CHUNK; cgi->resflags |= CGI_RES_CLIENT_CHUNK;
if (qse_mbs_cat (cgi->res, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1) if (qse_mbs_cat (cgi->res, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1)
{ {
@ -1493,8 +1514,14 @@ qse_printf (QSE_T("CGI SCRIPT FUCKED - RETURNING TOO MUCH...\n"));
if (cgi->resflags & CGI_RES_CLIENT_CHUNK) if (cgi->resflags & CGI_RES_CLIENT_CHUNK)
{ {
qse_mchar_t buf[64]; qse_mchar_t buf[64];
snprintf (buf, QSE_COUNTOF(buf), QSE_MT("%lX\r\n"), (unsigned long)cgi->script_output_received);
if (qse_mbs_cat (cgi->res, buf) == (qse_size_t)-1) qse_fmtuintmaxtombs (
buf, QSE_COUNTOF(buf),
cgi->script_output_received,
16 | QSE_FMTUINTMAXTOMBS_UPPERCASE,
-1, QSE_MT('\0'), QSE_NULL);
if (qse_mbs_cat (cgi->res, buf) == (qse_size_t)-1 ||
qse_mbs_cat (cgi->res, QSE_MT("\r\n")) == (qse_size_t)-1)
{ {
cgi->httpd->errnum = QSE_HTTPD_ENOMEM; cgi->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1; return -1;
@ -1520,7 +1547,7 @@ qse_printf (QSE_T("CGI SCRIPT FUCKED - RETURNING TOO MUCH...\n"));
return 0; return 0;
} }
static qse_htrd_recbs_t cgi_script_output_htrd_cbs = static qse_htrd_recbs_t cgi_script_htrd_cbs =
{ {
cgi_htrd_peek_script_output, cgi_htrd_peek_script_output,
QSE_NULL /* not needed for CGI */ QSE_NULL /* not needed for CGI */
@ -1568,8 +1595,8 @@ static qse_env_t* makecgienv (
{ {
qse_mchar_t tmp[64]; qse_mchar_t tmp[64];
qse_fmtuintmaxtombs ( qse_fmtuintmaxtombs (
tmp, QSE_COUNTOF(tmp), content_length, 10, tmp, QSE_COUNTOF(tmp), content_length,
-1, QSE_MT('\0'), QSE_NULL); 10, -1, QSE_MT('\0'), QSE_NULL);
qse_env_insertmbs (env, QSE_MT("CONTENT_LENGTH"), tmp); qse_env_insertmbs (env, QSE_MT("CONTENT_LENGTH"), tmp);
} }
@ -1610,26 +1637,48 @@ static qse_env_t* makecgienv (
#if 0 #if 0
ctx.httpd = httpd; ctx.httpd = httpd;
ctx.env = env; ctx.env = env;
if (qse_htre_walkheaders (req, cgi_walk_client_req_header, &ctx) <= -1) return -1; if (qse_htre_walkheaders (req, cgi_capture_client_header, &ctx) <= -1) return -1;
#endif #endif
/* TODO: memory error check */
{ {
const qse_mchar_t* tmp; const qse_htre_hdrval_t* tmp;
tmp = qse_htre_getheaderval(req, QSE_MT("Content-Type")); tmp = qse_htre_getheaderval(req, QSE_MT("Content-Type"));
if (tmp) qse_env_insertmbs (env, QSE_MT("CONTENT_TYPE"), tmp); if (tmp)
{
while (tmp->next) tmp = tmp->next;
qse_env_insertmbs (env, QSE_MT("CONTENT_TYPE"), tmp->ptr);
}
tmp = qse_htre_getheaderval(req, QSE_MT("Cookie")); tmp = qse_htre_getheaderval(req, QSE_MT("Cookie"));
if (tmp) qse_env_insertmbs (env, QSE_MT("HTTP_COOKIE"), tmp); if (tmp)
{
/* TODO: should cookie be combined into 1??? */
while (tmp->next) tmp = tmp->next;
qse_env_insertmbs (env, QSE_MT("HTTP_COOKIE"), tmp->ptr);
}
tmp = qse_htre_getheaderval(req, QSE_MT("Host")); tmp = qse_htre_getheaderval(req, QSE_MT("Host"));
if (tmp) qse_env_insertmbs (env, QSE_MT("HTTP_HOST"), tmp); if (tmp)
{
while (tmp->next) tmp = tmp->next;
qse_env_insertmbs (env, QSE_MT("HTTP_HOST"), tmp->ptr);
}
tmp = qse_htre_getheaderval(req, QSE_MT("Referer")); tmp = qse_htre_getheaderval(req, QSE_MT("Referer"));
if (tmp) qse_env_insertmbs (env, QSE_MT("HTTP_REFERER"), tmp); if (tmp)
{
while (tmp->next) tmp = tmp->next;
qse_env_insertmbs (env, QSE_MT("HTTP_REFERER"), tmp->ptr);
}
tmp = qse_htre_getheaderval(req, QSE_MT("User-Agent")); tmp = qse_htre_getheaderval(req, QSE_MT("User-Agent"));
if (tmp) qse_env_insertmbs (env, QSE_MT("HTTP_USER_AGENT"), tmp); if (tmp)
{
while (tmp->next) tmp = tmp->next;
qse_env_insertmbs (env, QSE_MT("HTTP_USER_AGENT"), tmp->ptr);
}
} }
return env; return env;
@ -2120,6 +2169,7 @@ qse_printf (QSE_T("TASK_MAIN_CGI_4\n"));
} }
/* set the chunk length */ /* set the chunk length */
/* TODO: chagne snprintf to qse_fmtuintmaxtombs() */
snprintf (chunklen, QSE_COUNTOF(chunklen), snprintf (chunklen, QSE_COUNTOF(chunklen),
QSE_MT("%-4lX\r\n"), (unsigned long)n); QSE_MT("%-4lX\r\n"), (unsigned long)n);
QSE_MEMCPY (&cgi->buf[cgi->buflen], QSE_MEMCPY (&cgi->buf[cgi->buflen],
@ -2373,14 +2423,14 @@ static int task_main_cgi (
} }
else else
{ {
cgi_script_output_htrd_xtn_t* xtn; cgi_script_htrd_xtn_t* xtn;
cgi->script_htrd = qse_htrd_open (httpd->mmgr, QSE_SIZEOF(cgi_script_output_htrd_xtn_t)); cgi->script_htrd = qse_htrd_open (httpd->mmgr, QSE_SIZEOF(cgi_script_htrd_xtn_t));
if (cgi->script_htrd == QSE_NULL) goto oops; if (cgi->script_htrd == QSE_NULL) goto oops;
xtn = (cgi_script_output_htrd_xtn_t*) qse_htrd_getxtn (cgi->script_htrd); xtn = (cgi_script_htrd_xtn_t*) qse_htrd_getxtn (cgi->script_htrd);
xtn->cgi = cgi; xtn->cgi = cgi;
xtn->task = task; xtn->task = task;
xtn->client = client; xtn->client = client;
qse_htrd_setrecbs (cgi->script_htrd, &cgi_script_output_htrd_cbs); qse_htrd_setrecbs (cgi->script_htrd, &cgi_script_htrd_cbs);
qse_htrd_setoption ( qse_htrd_setoption (
cgi->script_htrd, cgi->script_htrd,
QSE_HTRD_SKIPINITIALLINE | QSE_HTRD_SKIPINITIALLINE |
@ -2554,6 +2604,8 @@ struct task_proxy_t
#define PROXY_PEER_CONNECTED (1 << 1) #define PROXY_PEER_CONNECTED (1 << 1)
int peer_status; int peer_status;
#define PROXY_REQ_CHUNKED (1 << 0)
int reqflags;
qse_htre_t* req; /* original client request associated with this */ qse_htre_t* req; /* original client request associated with this */
qse_mbs_t* reqfwdbuf; /* content from the request */ qse_mbs_t* reqfwdbuf; /* content from the request */
int reqfwderr; int reqfwderr;
@ -2568,6 +2620,7 @@ struct task_proxy_t
#define PROXY_RES_PEER_CHUNK (1 << 4) /* peer's output is chunked */ #define PROXY_RES_PEER_CHUNK (1 << 4) /* peer's output is chunked */
#define PROXY_RES_PEER_LENGTH (1 << 5) /* peer's output is set with #define PROXY_RES_PEER_LENGTH (1 << 5) /* peer's output is set with
* the content-length */ * the content-length */
#define PROXY_RES_PEER_LENGTH_FAKE (1 << 6) /* peer_output_length is fake */
#define PROXY_RES_AWAIT_100 (1 << 10) /* waiting for 100 continue */ #define PROXY_RES_AWAIT_100 (1 << 10) /* waiting for 100 continue */
#define PROXY_RES_AWAIT_RESHDR (1 << 11) /* waiting for response header */ #define PROXY_RES_AWAIT_RESHDR (1 << 11) /* waiting for response header */
#define PROXY_RES_AWAIT_RESCON (1 << 12) /* waiting for response content. #define PROXY_RES_AWAIT_RESCON (1 << 12) /* waiting for response content.
@ -2595,6 +2648,83 @@ struct proxy_peer_htrd_xtn_t
qse_httpd_task_t* task; qse_httpd_task_t* task;
}; };
static int proxy_add_header_to_buffer (
task_proxy_t* proxy, qse_mbs_t* buf, const qse_mchar_t* key, const qse_htre_hdrval_t* val)
{
QSE_ASSERT (val != QSE_NULL);
do
{
if (qse_mbs_cat (buf, key) == (qse_size_t)-1 ||
qse_mbs_cat (buf, QSE_MT(": ")) == (qse_size_t)-1 ||
qse_mbs_cat (buf, val->ptr) == (qse_size_t)-1 ||
qse_mbs_cat (buf, QSE_MT("\r\n")) == (qse_size_t)-1)
{
proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
val = val->next;
}
while (val);
return 0;
}
static int proxy_capture_peer_header (qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx)
{
task_proxy_t* proxy = (task_proxy_t*)ctx;
if (qse_mbscmp (key, QSE_MT("Connection")) != 0 &&
qse_mbscmp (key, QSE_MT("Transfer-Encoding")) != 0)
{
return proxy_add_header_to_buffer (proxy, proxy->res, key, val);
}
return 0;
}
static int proxy_capture_peer_trailer (qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx)
{
task_proxy_t* proxy = (task_proxy_t*)ctx;
if (qse_mbscasecmp (key, QSE_MT("Transfer-Encoding")) != 0 &&
qse_mbscasecmp (key, QSE_MT("Content-Length")) != 0 &&
qse_mbscasecmp (key, QSE_MT("Connection")) != 0)
{
return proxy_add_header_to_buffer (proxy, proxy->res, key, val);
}
return 0;
}
static int proxy_capture_client_header (qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx)
{
task_proxy_t* proxy = (task_proxy_t*)ctx;
if (qse_mbscasecmp (key, QSE_MT("Transfer-Encoding")) != 0 &&
qse_mbscasecmp (key, QSE_MT("Content-Length")) != 0)
{
return proxy_add_header_to_buffer (proxy, proxy->reqfwdbuf, key, val);
}
return 0;
}
static int proxy_capture_client_trailer (qse_htre_t* req, const qse_mchar_t* key, const qse_htre_hdrval_t* val, void* ctx)
{
task_proxy_t* proxy = (task_proxy_t*)ctx;
if (qse_mbscasecmp (key, QSE_MT("Transfer-Encoding")) != 0 &&
qse_mbscasecmp (key, QSE_MT("Content-Length")) != 0 &&
qse_mbscasecmp (key, QSE_MT("Connection")) != 0)
{
return proxy_add_header_to_buffer (proxy, proxy->reqfwdbuf, key, val);
}
return 0;
}
static int proxy_snatch_client_input ( static int proxy_snatch_client_input (
qse_htre_t* req, const qse_mchar_t* ptr, qse_size_t len, void* ctx) qse_htre_t* req, const qse_mchar_t* ptr, qse_size_t len, void* ctx)
{ {
@ -2618,6 +2748,18 @@ else qse_printf (QSE_T("!!!PROXY SNATCHING DONE\n"));
*/ */
QSE_ASSERT (len == 0); QSE_ASSERT (len == 0);
if (proxy->reqflags & PROXY_REQ_CHUNKED)
{
/* add the 0-sized chunk and trailers */
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("0\r\n")) == (qse_size_t)-1 ||
qse_htre_walktrailers (req, proxy_capture_client_trailer, proxy) <= -1 ||
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1)
{
proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
}
/* mark the there's nothing to read form the client side */ /* mark the there's nothing to read form the client side */
qse_htre_unsetconcb (proxy->req); qse_htre_unsetconcb (proxy->req);
proxy->req = QSE_NULL; proxy->req = QSE_NULL;
@ -2636,6 +2778,7 @@ else qse_printf (QSE_T("!!!PROXY SNATCHING DONE\n"));
* for task invocation. */ * for task invocation. */
task->trigger[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
} }
} }
else if (!proxy->reqfwderr) else if (!proxy->reqfwderr)
{ {
@ -2643,11 +2786,31 @@ else qse_printf (QSE_T("!!!PROXY SNATCHING DONE\n"));
* didn't occur previously. we store data from the client side * didn't occur previously. we store data from the client side
* to the forwaring buffer only if there's no such previous * to the forwaring buffer only if there's no such previous
* error. if an error occurred, we simply drop the data. */ * error. if an error occurred, we simply drop the data. */
if (proxy->reqflags & PROXY_REQ_CHUNKED)
{
qse_mchar_t buf[64];
qse_fmtuintmaxtombs (
buf, QSE_COUNTOF(buf), len,
16 | QSE_FMTUINTMAXTOMBS_UPPERCASE,
-1, QSE_MT('\0'), QSE_NULL);
if (qse_mbs_cat (proxy->reqfwdbuf, buf) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 ||
qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1)
{
proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
}
else
{
if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1) if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1)
{ {
proxy->httpd->errnum = QSE_HTTPD_ENOMEM; proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1; return -1;
} }
}
qse_printf (QSE_T("!!!PROXY SNATCHED [%.*hs]\n"), len, ptr); qse_printf (QSE_T("!!!PROXY SNATCHED [%.*hs]\n"), len, ptr);
} }
@ -2680,17 +2843,19 @@ static int proxy_snatch_peer_output (
if (ptr == QSE_NULL) if (ptr == QSE_NULL)
{ {
/* content completed */ /* content completed */
QSE_ASSERT (len == 0); QSE_ASSERT (len == 0);
qse_printf (QSE_T("PROXY GOT ALL RESPONSE>>>>>>>\n")); qse_printf (QSE_T("PROXY GOT ALL RESPONSE>>>>>>>\n"));
if (qse_mbs_cat (proxy->res, QSE_MT("0\r\n\r\n")) == (qse_size_t)-1)
if (qse_mbs_cat (proxy->res, QSE_MT("0\r\n")) == (qse_size_t)-1 ||
qse_htre_walktrailers (req, proxy_capture_peer_trailer, proxy) <= -1 ||
qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1)
{ {
proxy->httpd->errnum = QSE_HTTPD_ENOMEM; proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1; return -1;
} }
/* TODO: include trailers into proxy->res if any. for this htrd and htre need to be enhanced as well */
proxy->resflags &= ~PROXY_RES_AWAIT_RESCON; proxy->resflags &= ~PROXY_RES_AWAIT_RESCON;
proxy->resflags |= PROXY_RES_RECEIVED_RESCON; proxy->resflags |= PROXY_RES_RECEIVED_RESCON;
} }
@ -2698,9 +2863,13 @@ qse_printf (QSE_T("PROXY GOT ALL RESPONSE>>>>>>>\n"));
{ {
/* append the peer response content to the response buffer */ /* append the peer response content to the response buffer */
qse_mchar_t buf[64]; qse_mchar_t buf[64];
snprintf (buf, QSE_COUNTOF(buf), QSE_MT("%lX\r\n"), (unsigned long)len); qse_fmtuintmaxtombs (
buf, QSE_COUNTOF(buf), len,
16 | QSE_FMTUINTMAXTOMBS_UPPERCASE,
-1, QSE_MT('\0'), QSE_NULL);
if (qse_mbs_cat (proxy->res, buf) == (qse_size_t)-1 || if (qse_mbs_cat (proxy->res, buf) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1 ||
qse_mbs_ncat (proxy->res, ptr, len) == (qse_size_t)-1 || qse_mbs_ncat (proxy->res, ptr, len) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1) qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1)
{ {
@ -2713,26 +2882,6 @@ qse_printf (QSE_T("PROXY GOT ALL RESPONSE>>>>>>>\n"));
return 0; return 0;
} }
static int proxy_capture_peer_header (qse_htre_t* req, const qse_mchar_t* key, const qse_mchar_t* val, void* ctx)
{
task_proxy_t* proxy = (task_proxy_t*)ctx;
if (qse_mbscmp (key, QSE_MT("Connection")) != 0 &&
qse_mbscmp (key, QSE_MT("Transfer-Encoding")) != 0)
{
if (qse_mbs_cat (proxy->res, key) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->res, QSE_MT(": ")) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->res, val) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1)
{
proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
}
return 0;
}
static int proxy_htrd_peek_peer_output (qse_htrd_t* htrd, qse_htre_t* res) static int proxy_htrd_peek_peer_output (qse_htrd_t* htrd, qse_htre_t* res)
{ {
proxy_peer_htrd_xtn_t* xtn; proxy_peer_htrd_xtn_t* xtn;
@ -2741,6 +2890,8 @@ static int proxy_htrd_peek_peer_output (qse_htrd_t* htrd, qse_htre_t* res)
xtn = (proxy_peer_htrd_xtn_t*) qse_htrd_getxtn (htrd); xtn = (proxy_peer_htrd_xtn_t*) qse_htrd_getxtn (htrd);
proxy = xtn->proxy; proxy = xtn->proxy;
QSE_ASSERT (!(res->state & QSE_HTRE_DISCARDED));
if (proxy->resflags & PROXY_RES_RECEIVED_RESHDR) if (proxy->resflags & PROXY_RES_RECEIVED_RESHDR)
{ {
/* this peek handler is being called again. /* this peek handler is being called again.
@ -2758,12 +2909,16 @@ qse_printf (QSE_T("10000000000000000000000000000 CONTINUE 1000000000000000000000
proxy->resflags &= ~PROXY_RES_AWAIT_100; proxy->resflags &= ~PROXY_RES_AWAIT_100;
proxy->resflags |= PROXY_RES_RECEIVED_100; proxy->resflags |= PROXY_RES_RECEIVED_100;
if (qse_mbs_cat (proxy->res, qse_htre_getverstr(res)) == (qse_size_t)-1) return -1; if (qse_mbs_cat (proxy->res, qse_htre_getverstr(res)) == (qse_size_t)-1 ||
if (qse_mbs_cat (proxy->res, QSE_MT(" ")) == (qse_size_t)-1) return -1;; qse_mbs_cat (proxy->res, QSE_MT(" ")) == (qse_size_t)-1 ||
if (qse_mbs_cat (proxy->res, qse_htre_getscodestr(res)) == (qse_size_t)-1) return -1; qse_mbs_cat (proxy->res, qse_htre_getscodestr(res)) == (qse_size_t)-1 ||
if (qse_mbs_cat (proxy->res, QSE_MT(" ")) == (qse_size_t)-1) return -1; qse_mbs_cat (proxy->res, QSE_MT(" ")) == (qse_size_t)-1 ||
if (qse_mbs_cat (proxy->res, qse_htre_getsmesg(res)) == (qse_size_t)-1) return -1; qse_mbs_cat (proxy->res, qse_htre_getsmesg(res)) == (qse_size_t)-1 ||
if (qse_mbs_cat (proxy->res, QSE_MT("\r\n\r\n")) == (qse_size_t)-1) return -1; qse_mbs_cat (proxy->res, QSE_MT("\r\n\r\n")) == (qse_size_t)-1)
{
proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
/* i don't relay any headers and contents in '100 continue' /* i don't relay any headers and contents in '100 continue'
* back to the client */ * back to the client */
@ -2787,6 +2942,17 @@ qse_printf (QSE_T("NORMAL REPLY 222222222222222222222 NORMAL REPLY\n"));
proxy->resflags |= PROXY_RES_PEER_LENGTH; proxy->resflags |= PROXY_RES_PEER_LENGTH;
proxy->peer_output_length = res->attr.content_length; proxy->peer_output_length = res->attr.content_length;
} }
else if (res->state & QSE_HTRE_COMPLETED)
{
/* the response from the peer is chunked or
* should be read until disconnection.
* but the whold response has already been
* received. so i dont' have to do complex
* chunking or something when returning the
* response back to the client. */
proxy->resflags |= PROXY_RES_PEER_LENGTH | PROXY_RES_PEER_LENGTH_FAKE;
proxy->peer_output_length = qse_htre_getcontentlen(res);
}
else else
{ {
if (qse_comparehttpversions (&proxy->version, &http_v11) >= 0) if (qse_comparehttpversions (&proxy->version, &http_v11) >= 0)
@ -2812,7 +2978,10 @@ qse_printf (QSE_T("NORMAL REPLY 222222222222222222222 NORMAL REPLY\n"));
{ {
/* client doesn't support chunking */ /* client doesn't support chunking */
keepalive = 0; keepalive = 0;
/* mark that the connection to client should be closed */
proxy->resflags |= PROXY_RES_CLIENT_DISCON; proxy->resflags |= PROXY_RES_CLIENT_DISCON;
/* and push the actual disconnection task */
if (qse_httpd_entaskdisconnect (proxy->httpd, xtn->client, xtn->task) == QSE_NULL) return -1; if (qse_httpd_entaskdisconnect (proxy->httpd, xtn->client, xtn->task) == QSE_NULL) return -1;
if (res->attr.flags & QSE_HTRE_ATTR_CHUNKED) if (res->attr.flags & QSE_HTRE_ATTR_CHUNKED)
@ -2829,20 +2998,53 @@ qse_printf (QSE_T("NORMAL REPLY 222222222222222222222 NORMAL REPLY\n"));
qse_mchar_t vbuf[64]; qse_mchar_t vbuf[64];
snprintf (vbuf, QSE_COUNTOF(vbuf), QSE_MT("HTTP/%d.%d"), snprintf (vbuf, QSE_COUNTOF(vbuf), QSE_MT("HTTP/%d.%d"),
(int)proxy->version.major, (int)proxy->version.minor); (int)proxy->version.major, (int)proxy->version.minor);
if (qse_mbs_cat (proxy->res, vbuf) == (qse_size_t)-1) return -1; if (qse_mbs_cat (proxy->res, vbuf) == (qse_size_t)-1)
{
proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
} }
else else
{ {
if (qse_mbs_cat (proxy->res, qse_htre_getverstr(res)) == (qse_size_t)-1) return -1; if (qse_mbs_cat (proxy->res, qse_htre_getverstr(res)) == (qse_size_t)-1)
{
proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
}
if (qse_mbs_cat (proxy->res, QSE_MT(" ")) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->res, qse_htre_getscodestr(res)) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->res, QSE_MT(" ")) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->res, qse_htre_getsmesg(res)) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1)
{
proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
} }
if (qse_mbs_cat (proxy->res, QSE_MT(" ")) == (qse_size_t)-1) return -1;;
if (qse_mbs_cat (proxy->res, qse_htre_getscodestr(res)) == (qse_size_t)-1) return -1;
if (qse_mbs_cat (proxy->res, QSE_MT(" ")) == (qse_size_t)-1) return -1;
if (qse_mbs_cat (proxy->res, qse_htre_getsmesg(res)) == (qse_size_t)-1) return -1;
if (qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1) return -1;
/* end initial line */ /* end initial line */
if (proxy->resflags & PROXY_RES_CLIENT_CHUNK) if (proxy->resflags & PROXY_RES_PEER_LENGTH_FAKE)
{
qse_mchar_t buf[64];
/* length should be added by force.
* let me add Content-Length event if it's 0
* for less code */
qse_fmtuintmaxtombs (
buf, QSE_COUNTOF(buf),
proxy->peer_output_length,
10, -1, QSE_MT('\0'), QSE_NULL);
if (qse_mbs_cat (proxy->res, QSE_MT("Content-Length: ")) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->res, buf) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1)
{
proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1;
}
}
else if (proxy->resflags & PROXY_RES_CLIENT_CHUNK)
{ {
if (qse_mbs_cat (proxy->res, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1) if (qse_mbs_cat (proxy->res, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1)
{ {
@ -2861,7 +3063,6 @@ qse_printf (QSE_T("NORMAL REPLY 222222222222222222222 NORMAL REPLY\n"));
/* end of headers */ /* end of headers */
if (qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1) return -1; if (qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1) return -1;
/* content body begins here */ /* content body begins here */
proxy->peer_output_received = qse_htre_getcontentlen(res); proxy->peer_output_received = qse_htre_getcontentlen(res);
if ((proxy->resflags & PROXY_RES_PEER_LENGTH) && if ((proxy->resflags & PROXY_RES_PEER_LENGTH) &&
@ -2881,10 +3082,16 @@ qse_printf (QSE_T("PROXY PEER FUCKED - RETURNING TOO MUCH...\n"));
if (proxy->resflags & PROXY_RES_CLIENT_CHUNK) if (proxy->resflags & PROXY_RES_CLIENT_CHUNK)
{ {
qse_mchar_t buf[64]; qse_mchar_t buf[64];
snprintf (buf, QSE_COUNTOF(buf), QSE_MT("%lX\r\n"), (unsigned long)proxy->peer_output_received); qse_fmtuintmaxtombs (
buf, QSE_COUNTOF(buf),
proxy->peer_output_received,
16 | QSE_FMTUINTMAXTOMBS_UPPERCASE,
-1, QSE_MT('\0'), QSE_NULL);
if (qse_mbs_cat (proxy->res, buf) == (qse_size_t)-1 || if (qse_mbs_cat (proxy->res, buf) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1 ||
qse_mbs_ncat (proxy->res, qse_htre_getcontentptr(res), qse_htre_getcontentlen(res)) == (qse_size_t)-1 || qse_mbs_ncat (proxy->res, qse_htre_getcontentptr(res), qse_htre_getcontentlen(res)) == (qse_size_t)-1 ||
qse_mbs_ncat (proxy->res, QSE_MT("\r\n"), 2) == (qse_size_t)-1) qse_mbs_cat (proxy->res, QSE_MT("\r\n")) == (qse_size_t)-1)
{ {
proxy->httpd->errnum = QSE_HTTPD_ENOMEM; proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return -1; return -1;
@ -2918,7 +3125,7 @@ qse_printf (QSE_T("FINISHED READING RESPONSE...\n"));
return 0; return 0;
} }
static qse_htrd_recbs_t proxy_htrd_cbs = static qse_htrd_recbs_t proxy_peer_htrd_cbs =
{ {
proxy_htrd_peek_peer_output, proxy_htrd_peek_peer_output,
proxy_htrd_handle_peer_output proxy_htrd_handle_peer_output
@ -2996,18 +3203,6 @@ qse_printf (QSE_T("FORWARD: @@@@@@@@NOTHING MORE TO WRITE TO PROXY\n"));
} }
} }
static int add_header_to_proxy_fwdbuf (qse_htre_t* req, const qse_mchar_t* key, const qse_mchar_t* val, void* ctx)
{
task_proxy_t* proxy = (task_proxy_t*)ctx;
if (qse_mbs_cat (proxy->reqfwdbuf, key) == (qse_size_t)-1) return -1;
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT(": ")) == (qse_size_t)-1) return -1;
if (qse_mbs_cat (proxy->reqfwdbuf, val) == (qse_size_t)-1) return -1;
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) return -1;
return 0;
}
static int task_init_proxy ( static int task_init_proxy (
qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task)
{ {
@ -3015,6 +3210,7 @@ static int task_init_proxy (
task_proxy_arg_t* arg; task_proxy_arg_t* arg;
qse_size_t len; qse_size_t len;
const qse_mchar_t* ptr; const qse_mchar_t* ptr;
int snatch_needed;
proxy = (task_proxy_t*)qse_httpd_gettaskxtn (httpd, task); proxy = (task_proxy_t*)qse_httpd_gettaskxtn (httpd, task);
arg = (task_proxy_arg_t*)task->ctx; arg = (task_proxy_arg_t*)task->ctx;
@ -3049,84 +3245,122 @@ len = 1024;
if (qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getverstr(arg->req)) == (qse_size_t)-1) goto oops; if (qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getverstr(arg->req)) == (qse_size_t)-1) goto oops;
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops; if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
if (qse_htre_walkheaders (arg->req, add_header_to_proxy_fwdbuf, proxy) <= -1) goto oops; if (qse_htre_walkheaders (arg->req, proxy_capture_client_header, proxy) <= -1) goto oops;
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
proxy->resflags |= PROXY_RES_AWAIT_RESHDR; proxy->resflags |= PROXY_RES_AWAIT_RESHDR;
if (arg->req->attr.expect && if ((arg->req->attr.flags & QSE_HTRE_ATTR_EXPECT100) &&
(arg->req->version.major > 1 || (arg->req->version.major > 1 ||
(arg->req->version.major == 1 && arg->req->version.minor >= 1))) (arg->req->version.major == 1 && arg->req->version.minor >= 1)))
{
if (qse_mbscasecmp(arg->req->attr.expect, QSE_MT("100-continue")) == 0)
{ {
proxy->resflags |= PROXY_RES_AWAIT_100; proxy->resflags |= PROXY_RES_AWAIT_100;
} }
}
if (arg->req->state & QSE_HTRE_DISCARDED) goto done; snatch_needed = 0;
if (arg->req->state & QSE_HTRE_DISCARDED)
{
/* no content to add */
/*if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Content-Length: 0\r\n")) == (qse_size_t)-1) goto oops;*/
/* i don't also add chunk traiers if the
* request content has been discarded */
/* end of header */
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
}
else if (arg->req->state & QSE_HTRE_COMPLETED)
{
qse_mchar_t buf[64];
len = qse_htre_getcontentlen(arg->req); len = qse_htre_getcontentlen(arg->req);
if ((arg->req->state & QSE_HTRE_COMPLETED) && len <= 0)
if (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED)
{ {
/* the content part is completed and no content /* add trailers if any */
* in the content buffer. there is nothing to forward */ if (qse_htre_walktrailers (
goto done; arg->req, proxy_capture_client_trailer, proxy) <= -1) goto oops;
} }
if (!(arg->req->state & QSE_HTRE_COMPLETED) && qse_fmtuintmaxtombs (
!(arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH)) buf, QSE_COUNTOF(buf), len,
10, -1, QSE_MT('\0'), QSE_NULL);
/* force-insert content-length. content-length is added
* even if the original request dones't contain it */
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Content-Length: ")) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->reqfwdbuf, buf) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n\r\n")) == (qse_size_t)-1) goto oops;
if (len > 0)
{ {
/* if the request is not completed and doesn't have /* content */
* content-length set, it's not really possible to
* pass the content. this function, however, allows
* such a request to entask a proxy script dropping the
* content */
qse_htre_discardcontent (arg->req);
}
else
{
/* create a buffer to hold request content from the client
* and copy content received already */
ptr = qse_htre_getcontentptr(arg->req); ptr = qse_htre_getcontentptr(arg->req);
if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1) goto oops; if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1) goto oops;
}
if (arg->req->state & QSE_HTRE_COMPLETED) }
else if (arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH)
{ {
/* no furthur forwarding is needed. qse_mchar_t buf[64];
* even a chunked request entaksed when completed qse_fmtuintmaxtombs (
* should reach here. if content-length is set buf, QSE_COUNTOF(buf),
* the length should match len. */ arg->req->attr.content_length,
QSE_ASSERT (len > 0); 10, -1, QSE_MT('\0'), QSE_NULL);
QSE_ASSERT (!(arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) ||
((arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) && if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Content-Length: ")) == (qse_size_t)-1 ||
arg->req->attr.content_length == len)); qse_mbs_cat (proxy->reqfwdbuf, buf) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n\r\n")) == (qse_size_t)-1) goto oops;
len = qse_htre_getcontentlen(arg->req);
if (len > 0)
{
/* content received so far */
ptr = qse_htre_getcontentptr(arg->req);
if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1) goto oops;
}
snatch_needed = 1;
} }
else else
{ {
/* proxy entasking is invoked probably from the peek handler QSE_ASSERT (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED);
* that was triggered after the request header is received.
* you can know this because the request is not completed.
* In this case, arrange to forward content
* bypassing the buffer in the request object itself. */
/* TODO: callback chain instead of a single pointer??? proxy->reqflags |= PROXY_REQ_CHUNKED;
if the request is already set up with a callback, something will go wrong. if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1 ||
*/ qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 /* end of header */) goto oops;
len = qse_htre_getcontentlen(arg->req);
if (len > 0)
{
qse_mchar_t buf[64];
ptr = qse_htre_getcontentptr(arg->req);
qse_fmtuintmaxtombs (
buf, QSE_COUNTOF(buf), len,
16 | QSE_FMTUINTMAXTOMBS_UPPERCASE,
-1, QSE_MT('\0'), QSE_NULL);
/* chunk length and chunk content */
if (qse_mbs_cat (proxy->reqfwdbuf, buf) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 ||
qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1 ||
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
}
snatch_needed = 1;
}
if (snatch_needed)
{
/* set up a callback to be called when the request content /* set up a callback to be called when the request content
* is fed to the htrd reader. qse_htre_addcontent() that * is fed to the htrd reader. qse_htre_addcontent() that
* htrd calls invokes this callback. */ * htrd calls invokes this callback. */
proxy->req = arg->req; proxy->req = arg->req;
qse_htre_setconcb (proxy->req, proxy_snatch_client_input, task); qse_htre_setconcb (proxy->req, proxy_snatch_client_input, task);
QSE_ASSERT (arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH);
}
} }
done:
/* no triggers yet since the main loop doesn't allow me to set /* no triggers yet since the main loop doesn't allow me to set
* triggers in the task initializer. however the main task handler * triggers in the task initializer. however the main task handler
* will be invoked so long as the client handle is writable by * will be invoked so long as the client handle is writable by
* the main loop. */ * the main loop. */
qse_printf (QSE_T("GOING TO PROXY [%hs]\n"), QSE_MBS_PTR(proxy->reqfwdbuf)); qse_printf (QSE_T("GOING TO PROXY [%hs]\n"), QSE_MBS_PTR(proxy->reqfwdbuf));
task->ctx = proxy; task->ctx = proxy;
return 0; return 0;
@ -3142,6 +3376,8 @@ oops:
} }
proxy->init_failed = 1; proxy->init_failed = 1;
task->ctx = proxy; task->ctx = proxy;
proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
return 0; return 0;
} }
@ -3349,21 +3585,25 @@ qse_printf (QSE_T("[proxy-3 send failure....\n"));
proxy->res_consumed += n; proxy->res_consumed += n;
proxy->res_pending -= n; proxy->res_pending -= n;
/* TODO: compact buffer */
} }
if (proxy->res_pending <= 0) if (proxy->res_pending <= 0)
{ {
qse_mbs_clear (proxy->res); qse_mbs_clear (proxy->res);
proxy->res_consumed = 0;
if ((proxy->resflags & PROXY_RES_CLIENT_CHUNK) || if ((proxy->resflags & PROXY_RES_CLIENT_CHUNK) ||
((proxy->resflags & PROXY_RES_PEER_LENGTH) && proxy->peer_output_received >= proxy->peer_output_length)) ((proxy->resflags & PROXY_RES_PEER_LENGTH) && proxy->peer_output_received >= proxy->peer_output_length))
{ {
qse_printf (QSE_T("SWITINCG TO 55555555555555555555555555 %d %d %d %d\n"),
(proxy->resflags & PROXY_RES_CLIENT_CHUNK), (proxy->resflags & PROXY_RES_PEER_LENGTH),
(int)proxy->peer_output_received, (int)proxy->peer_output_length);
task->main = task_main_proxy_5; task->main = task_main_proxy_5;
task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
} }
else else
{ {
qse_printf (QSE_T("SWITINCG TO 4444444444444444444444444444\n"));
task->main = task_main_proxy_4; task->main = task_main_proxy_4;
task->trigger[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE;
} }
@ -3381,6 +3621,7 @@ static int task_main_proxy_2 (
task_proxy_t* proxy = (task_proxy_t*)task->ctx; task_proxy_t* proxy = (task_proxy_t*)task->ctx;
int http_errnum = 0; int http_errnum = 0;
qse_printf (QSE_T("task_main_proxy_2....\n"));
if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) if (task->trigger[2].mask & QSE_HTTPD_TASK_TRIGGER_READABLE)
{ {
proxy_forward_client_input_to_peer (httpd, task, 0); proxy_forward_client_input_to_peer (httpd, task, 0);
@ -3411,11 +3652,18 @@ static int task_main_proxy_2 (
count = proxy->res_pending; count = proxy->res_pending;
if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE; if (count > MAX_SEND_SIZE) count = MAX_SEND_SIZE;
qse_printf (QSE_T("[proxy_2 sending %d bytes] [%.*hs]\n"), (int)count, (int)count, &QSE_MBS_CHAR(proxy->res,proxy->res_consumed)); qse_printf (QSE_T("[proxy_2 sending %d bytes (index %d)] ["),
(int)count, (int)proxy->res_consumed);
{
int i;
for (i = 0; i < count; i++) qse_printf (QSE_T("%hc"), QSE_MBS_CHAR(proxy->res,proxy->res_consumed+i));
}
qse_printf (QSE_T("]\n"));
httpd->errnum = QSE_HTTPD_ENOERR; httpd->errnum = QSE_HTTPD_ENOERR;
n = httpd->cbs->client.send ( n = httpd->cbs->client.send (
httpd, client, httpd, client,
&QSE_MBS_CHAR(proxy->res,proxy->res_consumed), QSE_MBS_CPTR(proxy->res,proxy->res_consumed),
count count
); );
if (n <= -1) if (n <= -1)
@ -3427,8 +3675,6 @@ qse_printf (QSE_T("[proxy-2 send failure....\n"));
proxy->res_consumed += n; proxy->res_consumed += n;
proxy->res_pending -= n; proxy->res_pending -= n;
/* TODO: compact buffer */
if (proxy->res_pending <= 0) if (proxy->res_pending <= 0)
{ {
/* '100 Continue' and payload received together /* '100 Continue' and payload received together
@ -3493,7 +3739,7 @@ qse_printf (QSE_T("#####PREMATURE EOF FROM PEER CLIENT CHUNK\n"));
proxy->buflen += n; proxy->buflen += n;
qse_printf (QSE_T("#####PROXY FEEDING [%.*hs]\n"), (int)proxy->buflen, proxy->buf); qse_printf (QSE_T("#####PROXY FEEDING %d [%.*hs]\n"), (int)proxy->buflen, (int)proxy->buflen, proxy->buf);
if (qse_htrd_feed (proxy->peer_htrd, proxy->buf, proxy->buflen) <= -1) if (qse_htrd_feed (proxy->peer_htrd, proxy->buf, proxy->buflen) <= -1)
{ {
/* TODO: logging */ /* TODO: logging */
@ -3528,7 +3774,7 @@ qse_printf (QSE_T("#####INVALID HEADER FROM PEER [%.*hs]\n"), (int)proxy->buflen
} }
else else
{ {
qse_printf (QSE_T("TRAILING DATA=[%hs]\n"), &QSE_MBS_CHAR(proxy->res,proxy->res_consumed)); qse_printf (QSE_T("TRAILING DATA=[%hs]\n"), QSE_MBS_CPTR(proxy->res,proxy->res_consumed));
/* switch to the next phase */ /* switch to the next phase */
task->main = task_main_proxy_3; task->main = task_main_proxy_3;
task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE; task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
@ -3561,6 +3807,7 @@ static int task_main_proxy_1 (
int http_errnum = 500; int http_errnum = 500;
/* wait for peer to get connected */ /* wait for peer to get connected */
qse_printf (QSE_T("task_main_proxy_1....\n"));
if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE || if (task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE ||
task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE) task->trigger[0].mask & QSE_HTTPD_TASK_TRIGGER_WRITABLE)
@ -3626,8 +3873,8 @@ qse_printf (QSE_T("task_main_proxy....\n"));
xtn->proxy = proxy; xtn->proxy = proxy;
xtn->client = client; xtn->client = client;
xtn->task = task; xtn->task = task;
qse_htrd_setrecbs (proxy->peer_htrd, &proxy_htrd_cbs); qse_htrd_setrecbs (proxy->peer_htrd, &proxy_peer_htrd_cbs);
qse_htrd_setoption (proxy->peer_htrd, QSE_HTRD_RESPONSE); qse_htrd_setoption (proxy->peer_htrd, QSE_HTRD_RESPONSE | QSE_HTRD_TRAILERS);
proxy->res = qse_mbs_open (httpd->mmgr, 0, 256); proxy->res = qse_mbs_open (httpd->mmgr, 0, 256);
if (proxy->res == QSE_NULL) goto oops; if (proxy->res == QSE_NULL) goto oops;

View File

@ -49,10 +49,12 @@ QSE_IMPLEMENT_COMMON_FUNCTIONS (httpd)
#define CLIENT_BAD (1 << 0) #define CLIENT_BAD (1 << 0)
#define CLIENT_READY (1 << 1) #define CLIENT_READY (1 << 1)
#define CLIENT_SECURE (1 << 2) #define CLIENT_SECURE (1 << 2)
#define CLIENT_HANDLE_READ_IN_MUX (1 << 3) #define CLIENT_MUTE (1 << 3)
#define CLIENT_HANDLE_WRITE_IN_MUX (1 << 4) #define CLIENT_MUTE_DELETED (1 << 4)
#define CLIENT_HANDLE_READ_IN_MUX (1 << 5)
#define CLIENT_HANDLE_WRITE_IN_MUX (1 << 6)
#define CLIENT_HANDLE_IN_MUX (CLIENT_HANDLE_READ_IN_MUX|CLIENT_HANDLE_WRITE_IN_MUX) #define CLIENT_HANDLE_IN_MUX (CLIENT_HANDLE_READ_IN_MUX|CLIENT_HANDLE_WRITE_IN_MUX)
#define CLIENT_TASK_TRIGGER_IN_MUX(i) (1 << ((i) + 5)) #define CLIENT_TASK_TRIGGER_IN_MUX(i) (1 << ((i) + 7))
static void free_server_list ( static void free_server_list (
qse_httpd_t* httpd, qse_httpd_server_t* server); qse_httpd_t* httpd, qse_httpd_server_t* server);
@ -276,7 +278,6 @@ static qse_httpd_client_t* new_client (
{ {
qse_httpd_client_t* client; qse_httpd_client_t* client;
htrd_xtn_t* xtn; htrd_xtn_t* xtn;
int opt;
client = qse_httpd_allocmem (httpd, QSE_SIZEOF(*client)); client = qse_httpd_allocmem (httpd, QSE_SIZEOF(*client));
if (client == QSE_NULL) return QSE_NULL; if (client == QSE_NULL) return QSE_NULL;
@ -291,10 +292,7 @@ static qse_httpd_client_t* new_client (
return QSE_NULL; return QSE_NULL;
} }
opt = qse_htrd_getoption (client->htrd); qse_htrd_setoption (client->htrd, QSE_HTRD_REQUEST | QSE_HTRD_TRAILERS);
opt |= QSE_HTRD_REQUEST;
opt &= ~QSE_HTRD_RESPONSE;
qse_htrd_setoption (client->htrd, opt);
if (httpd->cbs->client.accepted == QSE_NULL) if (httpd->cbs->client.accepted == QSE_NULL)
client->status |= CLIENT_READY; client->status |= CLIENT_READY;
@ -661,7 +659,7 @@ int qse_httpd_addserver (qse_httpd_t* httpd, const qse_char_t* uri)
static int read_from_client (qse_httpd_t* httpd, qse_httpd_client_t* client) static int read_from_client (qse_httpd_t* httpd, qse_httpd_client_t* client)
{ {
qse_mchar_t buf[2048]; /* TODO: adjust this buffer size */ qse_mchar_t buf[4096]; /* TODO: adjust this buffer size */
qse_ssize_t m; qse_ssize_t m;
QSE_ASSERT (httpd->cbs->client.recv != QSE_NULL); QSE_ASSERT (httpd->cbs->client.recv != QSE_NULL);
@ -674,7 +672,7 @@ reread:
if (httpd->errnum == QSE_HTTPD_EAGAIN) if (httpd->errnum == QSE_HTTPD_EAGAIN)
{ {
/* nothing to read yet. */ /* nothing to read yet. */
qse_fprintf (QSE_STDERR, QSE_T("Warning: Nothing to read from a client %d\n"), client->handle.i); qse_printf (QSE_T("Warning: Nothing to read from a client %d\n"), client->handle.i);
return 0; /* return ok */ return 0; /* return ok */
} }
else if (httpd->errnum == QSE_HTTPD_EINTR) else if (httpd->errnum == QSE_HTTPD_EINTR)
@ -684,25 +682,38 @@ qse_fprintf (QSE_STDERR, QSE_T("Warning: Nothing to read from a client %d\n"), c
else else
{ {
/* TOOD: if (httpd->errnum == QSE_HTTPD_ENOERR) httpd->errnum = QSE_HTTPD_ECALLBACK; */ /* TOOD: if (httpd->errnum == QSE_HTTPD_ENOERR) httpd->errnum = QSE_HTTPD_ECALLBACK; */
qse_fprintf (QSE_STDERR, QSE_T("Error: failed to read from a client %d\n"), client->handle.i); qse_printf (QSE_T("Error: failed to read from a client %d\n"), client->handle.i);
/* TODO: find a way to disconnect */ /* TODO: find a way to disconnect */
return -1; return -1;
} }
} }
else if (m == 0) else if (m == 0)
{
qse_printf (QSE_T("Debug: connection closed %d - errno %d\n"), client->handle.i, errno);
if (client->task.head)
{
/* there is still more tasks to finish */
client->status |= CLIENT_MUTE;
return 0;
}
else
{ {
httpd->errnum = QSE_HTTPD_EDISCON; httpd->errnum = QSE_HTTPD_EDISCON;
qse_fprintf (QSE_STDERR, QSE_T("Debug: connection closed %d\n"), client->handle.i);
return -1; return -1;
} }
}
/* feed may have called the request callback multiple times... /* feed may have called the request callback multiple times...
* that's because we don't know how many valid requests * that's because we don't know how many valid requests
* are included in 'buf' */ * are included in 'buf' */
qse_fprintf (QSE_STDERR, QSE_T("Debug: read from a client %d\n"), client->handle.i);
httpd->errnum = QSE_HTTPD_ENOERR; httpd->errnum = QSE_HTTPD_ENOERR;
qse_printf (QSE_T("!!!!!FEEDING [%.*hs]\n"), (int)m, buf); qse_printf (QSE_T("!!!!!FEEDING %d from %d ["), (int)m, (int)client->handle.i);
{
int i;
for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]);
}
qse_printf (QSE_T("]\n"));
if (qse_htrd_feed (client->htrd, buf, m) <= -1) if (qse_htrd_feed (client->htrd, buf, m) <= -1)
{ {
if (httpd->errnum == QSE_HTTPD_ENOERR) if (httpd->errnum == QSE_HTTPD_ENOERR)
@ -713,7 +724,12 @@ qse_printf (QSE_T("!!!!!FEEDING [%.*hs]\n"), (int)m, buf);
else httpd->errnum = QSE_HTTPD_ENOMEM; /* TODO: better translate error code */ else httpd->errnum = QSE_HTTPD_ENOMEM; /* TODO: better translate error code */
} }
qse_fprintf (QSE_STDERR, QSE_T("Error: http error while processing \n")); qse_printf (QSE_T("Error: http error while processing %d ["), (int)client->handle.i);
{
int i;
for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]);
}
qse_printf (QSE_T("]\n"));
return -1; return -1;
} }
@ -731,19 +747,31 @@ static int invoke_client_task (
/* TODO: handle comparison callback ... */ /* TODO: handle comparison callback ... */
if (handle.i == client->handle.i && (mask & QSE_HTTPD_MUX_READ)) /* TODO: no direct comparision */ if (handle.i == client->handle.i && (mask & QSE_HTTPD_MUX_READ)) /* TODO: no direct comparision */
{ {
if (read_from_client (httpd, client) <= -1) if (!(client->status & CLIENT_MUTE) &&
read_from_client (httpd, client) <= -1)
{ {
/* return failure on disconnection also in order to /* return failure on disconnection also in order to
* purge the client in perform_client_task(). * purge the client in perform_client_task().
* thus the following line isn't necessary. * thus the following line isn't necessary.
*if (httpd->errnum == QSE_HTTPD_EDISCON) return 0;*/ *if (httpd->errnum == QSE_HTTPD_EDISCON) return 0;*/
qse_printf (QSE_T("ERROR: read from client [%d] failed...\n"), (int)handle.i);
return -1; return -1;
} }
} }
/* this client doesn't have any task */ /* this client doesn't have any task */
task = client->task.head; task = client->task.head;
if (task == QSE_NULL) return 0; if (task == QSE_NULL)
{
if (client->status & CLIENT_MUTE)
{
/* handle this delayed client disconnection */
qse_printf (QSE_T("ERROR: mute client got no more task [%d] failed...\n"), (int)client->handle.i);
return -1;
}
return 0;
}
trigger_fired = 0; trigger_fired = 0;
client_handle_writable = 0; client_handle_writable = 0;
@ -793,7 +821,6 @@ qse_printf (QSE_T("task returend %d\n"), n);
* from the mux. so i don't clear them explicitly here */ * from the mux. so i don't clear them explicitly here */
dequeue_task (httpd, client); dequeue_task (httpd, client);
mux_mask = QSE_HTTPD_MUX_READ; mux_mask = QSE_HTTPD_MUX_READ;
mux_status = CLIENT_HANDLE_READ_IN_MUX; mux_status = CLIENT_HANDLE_READ_IN_MUX;
if (client->task.head) if (client->task.head)
@ -802,6 +829,23 @@ qse_printf (QSE_T("task returend %d\n"), n);
* trigger it as if it is just entasked */ * trigger it as if it is just entasked */
mux_mask |= QSE_HTTPD_MUX_WRITE; mux_mask |= QSE_HTTPD_MUX_WRITE;
mux_status |= CLIENT_HANDLE_WRITE_IN_MUX; mux_status |= CLIENT_HANDLE_WRITE_IN_MUX;
if (client->status & CLIENT_MUTE)
{
qse_printf (QSE_T("REMOVING XXXXX FROM READING....\n"));
mux_mask &= ~QSE_HTTPD_MUX_READ;
mux_status &= ~CLIENT_HANDLE_READ_IN_MUX;
}
}
else
{
if (client->status & CLIENT_MUTE)
{
/* no more task. but this client
* has closed connection previously */
qse_printf (QSE_T("REMOVING XXXXX FROM READING NO MORE TASK....\n"));
return -1;
}
} }
if ((client->status & CLIENT_HANDLE_IN_MUX) != if ((client->status & CLIENT_HANDLE_IN_MUX) !=
@ -810,11 +854,17 @@ qse_printf (QSE_T("task returend %d\n"), n);
httpd->cbs->mux.delhnd (httpd, httpd->mux, client->handle); httpd->cbs->mux.delhnd (httpd, httpd->mux, client->handle);
client->status &= ~CLIENT_HANDLE_IN_MUX; client->status &= ~CLIENT_HANDLE_IN_MUX;
if (mux_status)
{
if (httpd->cbs->mux.addhnd ( if (httpd->cbs->mux.addhnd (
httpd, httpd->mux, client->handle, httpd, httpd->mux, client->handle,
mux_mask, perform_client_task, client) <= -1) return -1; mux_mask, perform_client_task, client) <= -1)
{
return -1;
}
client->status |= mux_status; client->status |= mux_status;
} }
}
QSE_MEMSET (client->trigger, 0, QSE_SIZEOF(client->trigger)); QSE_MEMSET (client->trigger, 0, QSE_SIZEOF(client->trigger));
return 0; return 0;
@ -832,7 +882,8 @@ qse_printf (QSE_T("task returend %d\n"), n);
QSE_HTTPD_TASK_TRIGGER_WRITABLE); QSE_HTTPD_TASK_TRIGGER_WRITABLE);
} }
if (QSE_MEMCMP (client->trigger, task->trigger, QSE_SIZEOF(client->trigger)) != 0) if (QSE_MEMCMP (client->trigger, task->trigger, QSE_SIZEOF(client->trigger)) != 0 ||
((client->status & CLIENT_MUTE) && !(client->status & CLIENT_MUTE_DELETED)))
{ {
/* manipulate muxtiplexer settings if there are trigger changes */ /* manipulate muxtiplexer settings if there are trigger changes */
@ -852,14 +903,30 @@ qse_printf (QSE_T("task returend %d\n"), n);
} }
has_trigger = 0; has_trigger = 0;
client_handle_mux_mask = QSE_HTTPD_MUX_READ; client_handle_mux_mask = 0;
client_handle_mux_status = 0;
if (client->status & CLIENT_MUTE)
{
client->status |= CLIENT_MUTE_DELETED;
}
else
{
client_handle_mux_mask |= QSE_HTTPD_MUX_READ;
client_handle_mux_status |= CLIENT_HANDLE_READ_IN_MUX;
}
/* add new trigger handles */ /* add new trigger handles */
for (i = 0; i < QSE_COUNTOF(task->trigger); i++) for (i = 0; i < QSE_COUNTOF(task->trigger); i++)
{ {
trigger_mux_mask = 0; trigger_mux_mask = 0;
if (task->trigger[i].mask & QSE_HTTPD_TASK_TRIGGER_READ) if (task->trigger[i].mask & QSE_HTTPD_TASK_TRIGGER_READ)
{
if (task->trigger[i].handle.i != client->handle.i ||
!(client->status & CLIENT_MUTE))
{
trigger_mux_mask |= QSE_HTTPD_MUX_READ; trigger_mux_mask |= QSE_HTTPD_MUX_READ;
}
}
if (task->trigger[i].mask & QSE_HTTPD_TASK_TRIGGER_WRITE) if (task->trigger[i].mask & QSE_HTTPD_TASK_TRIGGER_WRITE)
trigger_mux_mask |= QSE_HTTPD_MUX_WRITE; trigger_mux_mask |= QSE_HTTPD_MUX_WRITE;
@ -878,15 +945,15 @@ qse_printf (QSE_T("task returend %d\n"), n);
{ {
if (httpd->cbs->mux.addhnd ( if (httpd->cbs->mux.addhnd (
httpd, httpd->mux, task->trigger[i].handle, httpd, httpd->mux, task->trigger[i].handle,
trigger_mux_mask, perform_client_task, client) <= -1) return -1; trigger_mux_mask, perform_client_task, client) <= -1)
{
return -1;
}
client->status |= CLIENT_TASK_TRIGGER_IN_MUX(i); client->status |= CLIENT_TASK_TRIGGER_IN_MUX(i);
} }
} }
} }
/* manipulate the client handle. reading is always enabled
* on the cleint handle */
client_handle_mux_status = CLIENT_HANDLE_READ_IN_MUX;
if (client_handle_mux_mask) if (client_handle_mux_mask)
{ {
/* if the client handle is included in the trigger /* if the client handle is included in the trigger
@ -908,11 +975,17 @@ qse_printf (QSE_T("task returend %d\n"), n);
httpd->cbs->mux.delhnd (httpd, httpd->mux, client->handle); httpd->cbs->mux.delhnd (httpd, httpd->mux, client->handle);
client->status &= ~CLIENT_HANDLE_IN_MUX; client->status &= ~CLIENT_HANDLE_IN_MUX;
if (client_handle_mux_mask)
{
if (httpd->cbs->mux.addhnd ( if (httpd->cbs->mux.addhnd (
httpd, httpd->mux, client->handle, httpd, httpd->mux, client->handle,
client_handle_mux_mask, perform_client_task, client) <= -1) return -1; client_handle_mux_mask, perform_client_task, client) <= -1)
{
return -1;
}
client->status |= client_handle_mux_status; client->status |= client_handle_mux_status;
} }
}
QSE_MEMCPY (client->trigger, task->trigger, QSE_SIZEOF(client->trigger)); QSE_MEMCPY (client->trigger, task->trigger, QSE_SIZEOF(client->trigger));
} }
@ -949,13 +1022,17 @@ static int perform_client_task (
qse_gettime (&client->last_active); /* TODO: error check??? */ qse_gettime (&client->last_active); /* TODO: error check??? */
move_client_to_tail (httpd, client); move_client_to_tail (httpd, client);
if (invoke_client_task (httpd, client, handle, mask) <= -1) goto oops; if (invoke_client_task (httpd, client, handle, mask) <= -1)
{
qse_printf (QSE_T("OOPS AFTER CLIENT TASK BAD XXXXXXXXXXXXXX [%d]\n"), (int)handle.i);
goto oops;
}
} }
return 0; return 0;
oops: oops:
qse_printf (QSE_T("MARKING BAD XXXXXXXXXXXXXX\n")); qse_printf (QSE_T("MARKING BAD XXXXXXXXXXXXXX [%d]\n"), (int)handle.i);
/*purge_client (httpd, client);*/ /*purge_client (httpd, client);*/
client->status |= CLIENT_BAD; client->status |= CLIENT_BAD;
client->bad_next = httpd->client.bad; client->bad_next = httpd->client.bad;

View File

@ -892,7 +892,7 @@ static qse_ssize_t client_recv (
} }
else else
{ {
ssize_t ret = read (client->handle.i, buf, bufsize); ssize_t ret = recv (client->handle.i, buf, bufsize, 0);
if (ret <= -1) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno)); if (ret <= -1) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
return ret; return ret;
} }
@ -916,7 +916,7 @@ static qse_ssize_t client_send (
} }
else else
{ {
ssize_t ret = write (client->handle.i, buf, bufsize); ssize_t ret = send (client->handle.i, buf, bufsize, 0);
if (ret <= -1) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno)); if (ret <= -1) qse_httpd_seterrnum (httpd, syserr_to_errnum(errno));
return ret; return ret;
} }
@ -999,7 +999,14 @@ static void client_closed (qse_httpd_t* httpd, qse_httpd_client_t* client)
/* ------------------------------------------------------------------- */ /* ------------------------------------------------------------------- */
static qse_htb_walk_t walk (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx) static qse_htb_walk_t walk (qse_htb_t* htb, qse_htb_pair_t* pair, void* ctx)
{ {
qse_printf (QSE_T("HEADER OK %d[%hs] %d[%hs]\n"), (int)QSE_HTB_KLEN(pair), QSE_HTB_KPTR(pair), (int)QSE_HTB_VLEN(pair), QSE_HTB_VPTR(pair)); qse_htre_hdrval_t* val;
val = QSE_HTB_VPTR(pair);
while (val)
{
qse_printf (QSE_T("HEADER OK %d[%hs] %d[%hs]\n"), (int)QSE_HTB_KLEN(pair), QSE_HTB_KPTR(pair), (int)val->len, val->ptr);
val = val->next;
}
return QSE_HTB_WALK_FORWARD; return QSE_HTB_WALK_FORWARD;
} }
@ -1042,7 +1049,7 @@ if (qse_htre_getcontentlen(req) > 0)
qse_httpd_discardcontent (httpd, req); qse_httpd_discardcontent (httpd, req);
} }
if (req->attr.expect && if ((req->attr.flags & QSE_HTRE_ATTR_EXPECT100) &&
(req->version.major > 1 || (req->version.major > 1 ||
(req->version.major == 1 && req->version.minor >= 1)) && (req->version.major == 1 && req->version.minor >= 1)) &&
!content_received) !content_received)
@ -1051,15 +1058,6 @@ if (qse_htre_getcontentlen(req) > 0)
/* "expect" in the header, version 1.1 or higher, /* "expect" in the header, version 1.1 or higher,
* and no content received yet */ * and no content received yet */
if (qse_mbscasecmp(req->attr.expect, QSE_MT("100-continue")) != 0)
{
if (qse_httpd_entaskerror (
httpd, client, QSE_NULL, 417, req) == QSE_NULL) return -1;
if (qse_httpd_entaskdisconnect (
httpd, client, QSE_NULL) == QSE_NULL) return -1;
}
else
{
/* TODO: determine if to return 100-continue or other errors */ /* TODO: determine if to return 100-continue or other errors */
{ {
qse_ntime_t now; qse_ntime_t now;
@ -1070,7 +1068,6 @@ qse_printf (QSE_T("entasking continue at %lld\n"), (long long)now);
httpd, client, QSE_NULL, req) == QSE_NULL) return -1; httpd, client, QSE_NULL, req) == QSE_NULL) return -1;
} }
} }
}
if (qse_htre_getcontentlen(req) > 0) if (qse_htre_getcontentlen(req) > 0)
{ {
@ -1131,7 +1128,7 @@ qse_printf (QSE_T("Entasking chunked CGI...\n"));
{ {
if (peek) if (peek)
{ {
const qse_mchar_t* auth; const qse_htre_hdrval_t* auth;
int authorized = 0; int authorized = 0;
auth = qse_htre_getheaderval (req, QSE_MT("Authorization")); auth = qse_htre_getheaderval (req, QSE_MT("Authorization"));
@ -1139,6 +1136,7 @@ qse_printf (QSE_T("Entasking chunked CGI...\n"));
{ {
/* TODO: PERFORM authorization... */ /* TODO: PERFORM authorization... */
/* BASE64 decode... */ /* BASE64 decode... */
while (auth->next) auth = auth->next;
authorized = 1; authorized = 1;
} }
@ -1436,6 +1434,7 @@ int qse_main (int argc, qse_achar_t* argv[])
setlocale (LC_ALL, ""); setlocale (LC_ALL, "");
qse_setdflcmgr (qse_slmbcmgr); qse_setdflcmgr (qse_slmbcmgr);
#endif #endif
return qse_runmain (argc, argv, httpd_main); return qse_runmain (argc, argv, httpd_main);
} }