changed how to handle http header fields.
fixed a few http proxying bugs.
This commit is contained in:
parent
654003e06d
commit
130bbe9e21
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
@ -127,10 +141,10 @@ struct qse_htre_t
|
|||||||
#define qse_htre_getcontentlen(re) QSE_MBS_LEN(&(re)->content)
|
#define qse_htre_getcontentlen(re) QSE_MBS_LEN(&(re)->content)
|
||||||
|
|
||||||
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
|
||||||
);
|
);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -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
|
||||||
);
|
);
|
||||||
|
@ -218,21 +218,21 @@ struct qse_httpd_cbs_t
|
|||||||
typedef struct qse_httpd_task_t qse_httpd_task_t;
|
typedef struct qse_httpd_task_t qse_httpd_task_t;
|
||||||
|
|
||||||
typedef int (*qse_httpd_task_init_t) (
|
typedef int (*qse_httpd_task_init_t) (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
qse_httpd_task_t* task
|
qse_httpd_task_t* task
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef void (*qse_httpd_task_fini_t) (
|
typedef void (*qse_httpd_task_fini_t) (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
qse_httpd_task_t* task
|
qse_httpd_task_t* task
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef int (*qse_httpd_task_main_t) (
|
typedef int (*qse_httpd_task_main_t) (
|
||||||
qse_httpd_t* httpd,
|
qse_httpd_t* httpd,
|
||||||
qse_httpd_client_t* client,
|
qse_httpd_client_t* client,
|
||||||
qse_httpd_task_t* task
|
qse_httpd_task_t* task
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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,88 +685,72 @@ 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;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
qse_mchar_t* ptr;
|
qse_mchar_t* ptr;
|
||||||
qse_size_t len;
|
qse_size_t len;
|
||||||
} name, value;
|
} name, value;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -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)
|
||||||
);
|
);
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
|
||||||
@ -1330,14 +1342,22 @@ static int cgi_capture_script_header (qse_htre_t* req, const qse_mchar_t* key, c
|
|||||||
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)
|
||||||
{
|
{
|
||||||
if (qse_mbs_cat (cgi->res, key) == (qse_size_t)-1 ||
|
/* multiple items with the same keys are also
|
||||||
qse_mbs_cat (cgi->res, QSE_MT(": ")) == (qse_size_t)-1 ||
|
* copied back to the response buffer */
|
||||||
qse_mbs_cat (cgi->res, val) == (qse_size_t)-1 ||
|
do
|
||||||
qse_mbs_cat (cgi->res, QSE_MT("\r\n")) == (qse_size_t)-1)
|
|
||||||
{
|
{
|
||||||
cgi->httpd->errnum = QSE_HTTPD_ENOMEM;
|
if (qse_mbs_cat (cgi->res, key) == (qse_size_t)-1 ||
|
||||||
return -1;
|
qse_mbs_cat (cgi->res, QSE_MT(": ")) == (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)
|
||||||
|
{
|
||||||
|
cgi->httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||||
|
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,10 +2786,30 @@ 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 (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1)
|
if (proxy->reqflags & PROXY_REQ_CHUNKED)
|
||||||
{
|
{
|
||||||
proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
|
qse_mchar_t buf[64];
|
||||||
return -1;
|
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)
|
||||||
|
{
|
||||||
|
proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED)
|
||||||
{
|
{
|
||||||
proxy->resflags |= PROXY_RES_AWAIT_100;
|
/* add trailers if any */
|
||||||
|
if (qse_htre_walktrailers (
|
||||||
|
arg->req, proxy_capture_client_trailer, proxy) <= -1) goto oops;
|
||||||
|
}
|
||||||
|
|
||||||
|
qse_fmtuintmaxtombs (
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/* content */
|
||||||
|
ptr = qse_htre_getcontentptr(arg->req);
|
||||||
|
if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1) goto oops;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH)
|
||||||
if (arg->req->state & QSE_HTRE_DISCARDED) goto done;
|
|
||||||
|
|
||||||
len = qse_htre_getcontentlen(arg->req);
|
|
||||||
if ((arg->req->state & QSE_HTRE_COMPLETED) && len <= 0)
|
|
||||||
{
|
{
|
||||||
/* the content part is completed and no content
|
qse_mchar_t buf[64];
|
||||||
* in the content buffer. there is nothing to forward */
|
qse_fmtuintmaxtombs (
|
||||||
goto done;
|
buf, QSE_COUNTOF(buf),
|
||||||
}
|
arg->req->attr.content_length,
|
||||||
|
10, -1, QSE_MT('\0'), QSE_NULL);
|
||||||
|
|
||||||
if (!(arg->req->state & QSE_HTRE_COMPLETED) &&
|
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Content-Length: ")) == (qse_size_t)-1 ||
|
||||||
!(arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH))
|
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 the request is not completed and doesn't have
|
|
||||||
* content-length set, it's not really possible to
|
len = qse_htre_getcontentlen(arg->req);
|
||||||
* pass the content. this function, however, allows
|
if (len > 0)
|
||||||
* such a request to entask a proxy script dropping the
|
{
|
||||||
* content */
|
/* content received so far */
|
||||||
qse_htre_discardcontent (arg->req);
|
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
|
||||||
{
|
{
|
||||||
/* create a buffer to hold request content from the client
|
QSE_ASSERT (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED);
|
||||||
* and copy content received already */
|
|
||||||
ptr = qse_htre_getcontentptr(arg->req);
|
|
||||||
if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1) goto oops;
|
|
||||||
|
|
||||||
if (arg->req->state & QSE_HTRE_COMPLETED)
|
proxy->reqflags |= PROXY_REQ_CHUNKED;
|
||||||
{
|
if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1 ||
|
||||||
/* no furthur forwarding is needed.
|
qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 /* end of header */) goto oops;
|
||||||
* even a chunked request entaksed when completed
|
|
||||||
* should reach here. if content-length is set
|
|
||||||
* the length should match len. */
|
|
||||||
QSE_ASSERT (len > 0);
|
|
||||||
QSE_ASSERT (!(arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) ||
|
|
||||||
((arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
|
|
||||||
arg->req->attr.content_length == len));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* proxy entasking is invoked probably from the peek handler
|
|
||||||
* 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???
|
len = qse_htre_getcontentlen(arg->req);
|
||||||
if the request is already set up with a callback, something will go wrong.
|
if (len > 0)
|
||||||
*/
|
{
|
||||||
/* set up a callback to be called when the request content
|
qse_mchar_t buf[64];
|
||||||
* is fed to the htrd reader. qse_htre_addcontent() that
|
|
||||||
* htrd calls invokes this callback. */
|
ptr = qse_htre_getcontentptr(arg->req);
|
||||||
proxy->req = arg->req;
|
qse_fmtuintmaxtombs (
|
||||||
qse_htre_setconcb (proxy->req, proxy_snatch_client_input, task);
|
buf, QSE_COUNTOF(buf), len,
|
||||||
QSE_ASSERT (arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH);
|
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
|
||||||
|
* is fed to the htrd reader. qse_htre_addcontent() that
|
||||||
|
* htrd calls invokes this callback. */
|
||||||
|
proxy->req = arg->req;
|
||||||
|
qse_htre_setconcb (proxy->req, proxy_snatch_client_input, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
httpd->errnum = QSE_HTTPD_EDISCON;
|
qse_printf (QSE_T("Debug: connection closed %d - errno %d\n"), client->handle.i, errno);
|
||||||
qse_fprintf (QSE_STDERR, QSE_T("Debug: connection closed %d\n"), client->handle.i);
|
if (client->task.head)
|
||||||
return -1;
|
{
|
||||||
|
/* there is still more tasks to finish */
|
||||||
|
client->status |= CLIENT_MUTE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
httpd->errnum = QSE_HTTPD_EDISCON;
|
||||||
|
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,10 +854,16 @@ 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 (httpd->cbs->mux.addhnd (
|
if (mux_status)
|
||||||
httpd, httpd->mux, client->handle,
|
{
|
||||||
mux_mask, perform_client_task, client) <= -1) return -1;
|
if (httpd->cbs->mux.addhnd (
|
||||||
client->status |= mux_status;
|
httpd, httpd->mux, client->handle,
|
||||||
|
mux_mask, perform_client_task, client) <= -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
client->status |= mux_status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QSE_MEMSET (client->trigger, 0, QSE_SIZEOF(client->trigger));
|
QSE_MEMSET (client->trigger, 0, QSE_SIZEOF(client->trigger));
|
||||||
@ -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)
|
||||||
trigger_mux_mask |= QSE_HTTPD_MUX_READ;
|
{
|
||||||
|
if (task->trigger[i].handle.i != client->handle.i ||
|
||||||
|
!(client->status & CLIENT_MUTE))
|
||||||
|
{
|
||||||
|
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,10 +975,16 @@ 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 (httpd->cbs->mux.addhnd (
|
if (client_handle_mux_mask)
|
||||||
httpd, httpd->mux, client->handle,
|
{
|
||||||
client_handle_mux_mask, perform_client_task, client) <= -1) return -1;
|
if (httpd->cbs->mux.addhnd (
|
||||||
client->status |= client_handle_mux_status;
|
httpd, httpd->mux, client->handle,
|
||||||
|
client_handle_mux_mask, perform_client_task, client) <= -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
@ -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,24 +1058,14 @@ 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;
|
||||||
qse_gettime (&now);
|
qse_gettime (&now);
|
||||||
qse_printf (QSE_T("entasking continue at %lld\n"), (long long)now);
|
qse_printf (QSE_T("entasking continue at %lld\n"), (long long)now);
|
||||||
}
|
}
|
||||||
if (qse_httpd_entaskcontinue (
|
if (qse_httpd_entaskcontinue (
|
||||||
httpd, client, QSE_NULL, req) == QSE_NULL) return -1;
|
httpd, client, QSE_NULL, req) == QSE_NULL) return -1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user