added some code to support raw proxying
This commit is contained in:
		@ -356,6 +356,7 @@ static int make_resource (
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			rsrc->type = QSE_HTTPD_RSRC_PROXY;
 | 
			
		||||
			rsrc->u.proxy.raw = 0;
 | 
			
		||||
			rsrc->u.proxy.dst = client->orgdst_addr;
 | 
			
		||||
			rsrc->u.proxy.src = client->remote_addr;
 | 
			
		||||
 | 
			
		||||
@ -1658,7 +1659,7 @@ static void reconf_server (qse_httpd_t* httpd, qse_httpd_server_t* server)
 | 
			
		||||
	server_xtn_t* server_xtn;
 | 
			
		||||
	qse_xli_pair_t* pair;
 | 
			
		||||
 | 
			
		||||
	/* reconfigure the server when the server is impeded. */
 | 
			
		||||
	/* reconfigure the server when the server is impeded in sig_reconf(). */
 | 
			
		||||
 | 
			
		||||
	httpd_xtn = qse_httpd_getxtnstd (httpd);
 | 
			
		||||
	server_xtn = qse_httpd_getserverstdxtn (httpd, server);
 | 
			
		||||
@ -1681,6 +1682,8 @@ static void impede_httpd (qse_httpd_t* httpd)
 | 
			
		||||
{
 | 
			
		||||
	httpd_xtn_t* httpd_xtn;
 | 
			
		||||
 | 
			
		||||
	/* reconfigure the server when the server is impeded in sig_reconf(). */
 | 
			
		||||
 | 
			
		||||
	httpd_xtn = qse_httpd_getxtnstd (httpd);
 | 
			
		||||
 | 
			
		||||
	if (open_config_file (httpd) >= 0)
 | 
			
		||||
 | 
			
		||||
@ -56,7 +56,8 @@ enum qse_htrd_option_t
 | 
			
		||||
	QSE_HTRD_REQUEST         = (1 << 4), /**< parse input as a request */
 | 
			
		||||
	QSE_HTRD_RESPONSE        = (1 << 5), /**< parse input as a response */
 | 
			
		||||
	QSE_HTRD_TRAILERS        = (1 << 6), /**< store trailers in a separate table */
 | 
			
		||||
	QSE_HTRD_STRICT          = (1 << 7)  /**< be more picky */
 | 
			
		||||
	QSE_HTRD_STRICT          = (1 << 7), /**< be more picky */
 | 
			
		||||
	QSE_HTRD_DUMMY           = (1 << 8)  /**< be dummy */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum qse_htrd_option_t qse_htrd_option_t;
 | 
			
		||||
 | 
			
		||||
@ -477,6 +477,14 @@ struct qse_httpd_rsrc_cgi_t
 | 
			
		||||
	int nph;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct qse_httpd_rsrc_proxy_t qse_httpd_rsrc_proxy_t;
 | 
			
		||||
struct qse_httpd_rsrc_proxy_t
 | 
			
		||||
{
 | 
			
		||||
	qse_nwad_t dst;
 | 
			
		||||
	qse_nwad_t src;
 | 
			
		||||
	int raw;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct qse_httpd_rsrc_dir_t qse_httpd_rsrc_dir_t;
 | 
			
		||||
struct qse_httpd_rsrc_dir_t
 | 
			
		||||
{
 | 
			
		||||
@ -511,11 +519,7 @@ struct qse_httpd_rsrc_t
 | 
			
		||||
			const qse_mchar_t* mime;
 | 
			
		||||
		} file;
 | 
			
		||||
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			qse_nwad_t dst;
 | 
			
		||||
			qse_nwad_t src;
 | 
			
		||||
		} proxy;
 | 
			
		||||
		qse_httpd_rsrc_proxy_t proxy;
 | 
			
		||||
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
@ -758,15 +762,15 @@ QSE_EXPORT qse_httpd_task_t* qse_httpd_entasktext (
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskerr (
 | 
			
		||||
     qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_client_t*       client,
 | 
			
		||||
	qse_httpd_task_t*         pred,
 | 
			
		||||
     int                       code, 
 | 
			
		||||
	int                       code, 
 | 
			
		||||
	qse_htre_t*               req
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskcontinue (
 | 
			
		||||
     qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_client_t*       client,
 | 
			
		||||
	qse_httpd_task_t*         pred,
 | 
			
		||||
	qse_htre_t*               req
 | 
			
		||||
@ -776,7 +780,7 @@ QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskcontinue (
 | 
			
		||||
 * The qse_httpd_entaskauth() function adds a basic authorization task.
 | 
			
		||||
 */
 | 
			
		||||
QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskauth (
 | 
			
		||||
     qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_client_t*       client,
 | 
			
		||||
	qse_httpd_task_t*         pred,
 | 
			
		||||
	const qse_mchar_t*        realm,
 | 
			
		||||
@ -784,7 +788,7 @@ QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskauth (
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskreloc (
 | 
			
		||||
     qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_client_t*       client,
 | 
			
		||||
	qse_httpd_task_t*         pred,
 | 
			
		||||
	const qse_mchar_t*        dst,
 | 
			
		||||
@ -792,7 +796,7 @@ QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskreloc (
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskredir (
 | 
			
		||||
     qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_client_t*       client,
 | 
			
		||||
	qse_httpd_task_t*         pred,
 | 
			
		||||
	const qse_mchar_t*        dst,
 | 
			
		||||
@ -801,7 +805,7 @@ QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskredir (
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
QSE_EXPORT qse_httpd_task_t* qse_httpd_entasknomod (
 | 
			
		||||
     qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_client_t*       client,
 | 
			
		||||
	qse_httpd_task_t*         pred,
 | 
			
		||||
	qse_htre_t*               req
 | 
			
		||||
@ -833,20 +837,19 @@ QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskfile (
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskcgi (
 | 
			
		||||
	qse_httpd_t*              httpd,
 | 
			
		||||
	qse_httpd_client_t*       client,
 | 
			
		||||
	qse_httpd_task_t*         pred,
 | 
			
		||||
	qse_httpd_rsrc_cgi_t*     cgi,
 | 
			
		||||
	qse_htre_t*               req
 | 
			
		||||
	qse_httpd_t*                    httpd,
 | 
			
		||||
	qse_httpd_client_t*             client,
 | 
			
		||||
	qse_httpd_task_t*               pred,
 | 
			
		||||
	const qse_httpd_rsrc_cgi_t*     cgi,
 | 
			
		||||
	qse_htre_t*                     req
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
QSE_EXPORT qse_httpd_task_t* qse_httpd_entaskproxy (
 | 
			
		||||
	qse_httpd_t*            httpd,
 | 
			
		||||
	qse_httpd_client_t*     client,
 | 
			
		||||
	qse_httpd_task_t*       pred,
 | 
			
		||||
	const qse_nwad_t*       dst,
 | 
			
		||||
	const qse_nwad_t*       src,
 | 
			
		||||
	qse_htre_t*             req
 | 
			
		||||
	qse_httpd_t*                  httpd,
 | 
			
		||||
	qse_httpd_client_t*           client,
 | 
			
		||||
	qse_httpd_task_t*             pred,
 | 
			
		||||
	const qse_httpd_rsrc_proxy_t* proxy,
 | 
			
		||||
	qse_htre_t*                   req
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/* -------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
@ -837,6 +837,10 @@ qse_mchar_t* parse_header_field (
 | 
			
		||||
	 * the continuation */
 | 
			
		||||
	if (is_purespace_octet (*++p))
 | 
			
		||||
	{
 | 
			
		||||
		/* RFC: HTTP/1.0 headers may be folded onto multiple lines if 
 | 
			
		||||
		 * each continuation line begins with a space or horizontal tab. 
 | 
			
		||||
		 * All linear whitespace, including folding, has the same semantics 
 | 
			
		||||
		 * as SP. */
 | 
			
		||||
		qse_mchar_t* cpydst;
 | 
			
		||||
 | 
			
		||||
		cpydst = p - 1;
 | 
			
		||||
@ -1091,6 +1095,13 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len)
 | 
			
		||||
 | 
			
		||||
	QSE_ASSERT (len > 0);
 | 
			
		||||
 | 
			
		||||
	if (htrd->option & QSE_HTRD_DUMMY)
 | 
			
		||||
	{
 | 
			
		||||
		/* treat everything as contents.
 | 
			
		||||
		 * i don't care about headers or whatsoever. */
 | 
			
		||||
		return push_content (htrd, req, len);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* does this goto drop code maintainability? */
 | 
			
		||||
	if (htrd->fed.s.need > 0) 
 | 
			
		||||
	{
 | 
			
		||||
@ -1117,7 +1128,7 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len)
 | 
			
		||||
			goto dechunk_get_trailers;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	htrd->clean = 0; /* mark that the htrd is in need of some data */
 | 
			
		||||
	htrd->clean = 0; /* mark that htrd is in need of some data */
 | 
			
		||||
 | 
			
		||||
	while (ptr < end)
 | 
			
		||||
	{
 | 
			
		||||
@ -1419,6 +1430,17 @@ qse_printf (QSE_T("CONTENT_LENGTH %d, RAW HEADER LENGTH %d\n"),
 | 
			
		||||
					clear_feed (htrd);
 | 
			
		||||
					if (ptr >= end) return 0; /* no more feeds to handle */
 | 
			
		||||
 | 
			
		||||
					if (htrd->option & QSE_HTRD_DUMMY)
 | 
			
		||||
					{
 | 
			
		||||
						/* once the mode changes to RAW in a callback,
 | 
			
		||||
						 * left-over is pused as contents */
 | 
			
		||||
						if (ptr < end)
 | 
			
		||||
							return push_content (htrd, ptr, end - ptr);
 | 
			
		||||
						else
 | 
			
		||||
							return 0;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
					/* let ptr point to the next character to LF or 
 | 
			
		||||
					 * the optional contents */
 | 
			
		||||
					req = ptr; 
 | 
			
		||||
 | 
			
		||||
@ -1519,7 +1519,7 @@ qse_httpd_task_t* qse_httpd_entaskcgi (
 | 
			
		||||
	qse_httpd_t* httpd,
 | 
			
		||||
	qse_httpd_client_t* client,
 | 
			
		||||
	qse_httpd_task_t* pred,
 | 
			
		||||
	qse_httpd_rsrc_cgi_t* cgi,
 | 
			
		||||
	const qse_httpd_rsrc_cgi_t* cgi,
 | 
			
		||||
	qse_htre_t* req)
 | 
			
		||||
{
 | 
			
		||||
	qse_httpd_task_t task;
 | 
			
		||||
 | 
			
		||||
@ -27,8 +27,7 @@
 | 
			
		||||
typedef struct task_proxy_arg_t task_proxy_arg_t;
 | 
			
		||||
struct task_proxy_arg_t 
 | 
			
		||||
{
 | 
			
		||||
	const qse_nwad_t* peer_nwad;
 | 
			
		||||
	const qse_nwad_t* peer_local;
 | 
			
		||||
	const qse_httpd_rsrc_proxy_t* rsrc;
 | 
			
		||||
	qse_htre_t* req;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -43,6 +42,7 @@ struct task_proxy_t
 | 
			
		||||
	int method;
 | 
			
		||||
	qse_http_version_t version;
 | 
			
		||||
	int keepalive; /* taken from the request */
 | 
			
		||||
	int raw;
 | 
			
		||||
 | 
			
		||||
	qse_htrd_t* peer_htrd;
 | 
			
		||||
 | 
			
		||||
@ -184,9 +184,40 @@ static int proxy_capture_client_trailer (qse_htre_t* req, const qse_mchar_t* key
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int proxy_snatch_client_input_raw (
 | 
			
		||||
	qse_htre_t* req, const qse_mchar_t* ptr, qse_size_t len, void* ctx)
 | 
			
		||||
{
 | 
			
		||||
	/* it is a callback function set to the client-side htrd reader
 | 
			
		||||
	 * when the raw proxying is enabled. raw proxying doesn't parse
 | 
			
		||||
	 * requests. */
 | 
			
		||||
 | 
			
		||||
	qse_httpd_task_t* task;
 | 
			
		||||
	task_proxy_t* proxy; 
 | 
			
		||||
 | 
			
		||||
	task = (qse_httpd_task_t*)ctx;
 | 
			
		||||
	proxy = (task_proxy_t*)task->ctx;
 | 
			
		||||
 | 
			
		||||
	if (ptr && !(proxy->reqflags & PROXY_REQ_FWDERR))
 | 
			
		||||
	{
 | 
			
		||||
		if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1)
 | 
			
		||||
		{
 | 
			
		||||
			proxy->httpd->errnum = QSE_HTTPD_ENOMEM;
 | 
			
		||||
		return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		task->trigger[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int proxy_snatch_client_input (
 | 
			
		||||
	qse_htre_t* req, const qse_mchar_t* ptr, qse_size_t len, void* ctx)
 | 
			
		||||
{
 | 
			
		||||
	/* it is a callback function set to the client-side htrd reader
 | 
			
		||||
	 * when the normal proxying is enabled. normal proxying requires
 | 
			
		||||
	 * request parsing. */
 | 
			
		||||
 | 
			
		||||
	qse_httpd_task_t* task;
 | 
			
		||||
	task_proxy_t* proxy; 
 | 
			
		||||
 | 
			
		||||
@ -708,7 +739,7 @@ static int task_init_proxy (
 | 
			
		||||
	task_proxy_arg_t* arg;
 | 
			
		||||
	qse_size_t len;
 | 
			
		||||
	const qse_mchar_t* ptr;
 | 
			
		||||
	int snatch_needed;
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	proxy = (task_proxy_t*)qse_httpd_gettaskxtn (httpd, task);
 | 
			
		||||
	arg = (task_proxy_arg_t*)task->ctx;
 | 
			
		||||
@ -719,9 +750,11 @@ static int task_init_proxy (
 | 
			
		||||
	proxy->method = qse_htre_getqmethodtype(arg->req);
 | 
			
		||||
	proxy->version = *qse_htre_getversion(arg->req);
 | 
			
		||||
	proxy->keepalive = (arg->req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE);
 | 
			
		||||
	proxy->peer.nwad = *arg->peer_nwad;
 | 
			
		||||
	if (arg->peer_local) proxy->peer.local = *arg->peer_local;
 | 
			
		||||
	else proxy->peer.local.type = arg->peer_nwad->type;
 | 
			
		||||
	proxy->peer.nwad = arg->rsrc->dst;
 | 
			
		||||
	proxy->peer.local = arg->rsrc->src;
 | 
			
		||||
	proxy->raw = arg->rsrc->raw;
 | 
			
		||||
	/*if (arg->rsrc->src) proxy->peer.local = arg->rsrc->src;
 | 
			
		||||
	else proxy->peer.local.type = arg->rsrc->dst.type;*/
 | 
			
		||||
 | 
			
		||||
	proxy->req = QSE_NULL;
 | 
			
		||||
 | 
			
		||||
@ -731,158 +764,175 @@ static int task_init_proxy (
 | 
			
		||||
 * -------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
	/* TODO: DETERMINE THIS SIZE */
 | 
			
		||||
	len = 2048;
 | 
			
		||||
	len = 4096;
 | 
			
		||||
 | 
			
		||||
	proxy->reqfwdbuf = qse_mbs_open (httpd->mmgr, 0, (len < 512? 512: len));
 | 
			
		||||
	if (proxy->reqfwdbuf == QSE_NULL) goto oops;
 | 
			
		||||
 | 
			
		||||
	if (qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getqmethodname(arg->req)) == (qse_size_t)-1 ||
 | 
			
		||||
	    qse_mbs_cat (proxy->reqfwdbuf, QSE_MT(" ")) == (qse_size_t)-1 ||
 | 
			
		||||
	    qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getqpath(arg->req)) == (qse_size_t)-1) goto oops;
 | 
			
		||||
 | 
			
		||||
	if (qse_htre_getqparam(arg->req))
 | 
			
		||||
	if (proxy->raw)
 | 
			
		||||
	{
 | 
			
		||||
		if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("?")) == (qse_size_t)-1 ||
 | 
			
		||||
		    qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getqparam(arg->req)) == (qse_size_t)-1) goto oops;
 | 
			
		||||
	}
 | 
			
		||||
	if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT(" ")) == (qse_size_t)-1 ||
 | 
			
		||||
	    qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getverstr(arg->req)) == (qse_size_t)-1 ||
 | 
			
		||||
	    qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 ||
 | 
			
		||||
	    qse_htre_walkheaders (arg->req, proxy_capture_client_header, proxy) <= -1) goto oops;
 | 
			
		||||
/* TODO: when connect is attempted, no keep-alive must be hornored. 
 | 
			
		||||
 *       when connection fails, it returns failure page  followed by close....  */
 | 
			
		||||
 | 
			
		||||
	proxy->resflags |= PROXY_RES_AWAIT_RESHDR;
 | 
			
		||||
	if ((arg->req->attr.flags & QSE_HTRE_ATTR_EXPECT100) &&
 | 
			
		||||
	    (arg->req->version.major > 1 || 
 | 
			
		||||
	     (arg->req->version.major == 1 && arg->req->version.minor >= 1)))
 | 
			
		||||
	{
 | 
			
		||||
		proxy->resflags |= PROXY_RES_AWAIT_100;
 | 
			
		||||
	}
 | 
			
		||||
		/* the caller must make sure that the actual content is discarded or completed
 | 
			
		||||
		 * and the following data is treated as contents */
 | 
			
		||||
printf ("proxy req = %p %d %d\n", arg->req, (arg->req->state & QSE_HTRE_DISCARDED), (arg->req->state&  QSE_HTRE_COMPLETED));
 | 
			
		||||
		QSE_ASSERT (arg->req->state & (QSE_HTRE_DISCARDED | QSE_HTRE_COMPLETED));
 | 
			
		||||
		QSE_ASSERT (qse_htrd_getoption(client->htrd) & QSE_HTRD_DUMMY);
 | 
			
		||||
 | 
			
		||||
	snatch_needed = 0;
 | 
			
		||||
 | 
			
		||||
	if (!(httpd->opt.trait & QSE_HTTPD_PROXYNOVIA))
 | 
			
		||||
	{
 | 
			
		||||
		/* add the Via: header into the request */
 | 
			
		||||
		if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Via: ")) == (qse_size_t)-1 ||
 | 
			
		||||
		    qse_mbs_cat (proxy->reqfwdbuf, qse_httpd_getname (httpd)) == (qse_size_t)-1 ||
 | 
			
		||||
		    qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (arg->req->state & QSE_HTRE_DISCARDED)
 | 
			
		||||
	{
 | 
			
		||||
		/* no content to add */
 | 
			
		||||
		if ((arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) || 
 | 
			
		||||
		    (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
 | 
			
		||||
		{
 | 
			
		||||
			/* i don't add chunk traiers if the 
 | 
			
		||||
			 * request content has been discarded */
 | 
			
		||||
			if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Content-Length: 0\r\n\r\n")) == (qse_size_t)-1) goto oops;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (arg->req->state & QSE_HTRE_COMPLETED)
 | 
			
		||||
	{
 | 
			
		||||
		if (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED)
 | 
			
		||||
		{
 | 
			
		||||
			/* add trailers if any */
 | 
			
		||||
			if (qse_htre_walktrailers (
 | 
			
		||||
				arg->req, proxy_capture_client_trailer, proxy) <= -1) goto oops;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		len = qse_htre_getcontentlen(arg->req);
 | 
			
		||||
		if (len > 0 || (arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) || 
 | 
			
		||||
		               (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
 | 
			
		||||
		{
 | 
			
		||||
			qse_mchar_t buf[64];
 | 
			
		||||
 | 
			
		||||
			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 (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH)
 | 
			
		||||
	{
 | 
			
		||||
		/* the Content-Length header field is contained in the request. */
 | 
			
		||||
		qse_mchar_t buf[64];
 | 
			
		||||
		qse_fmtuintmaxtombs (
 | 
			
		||||
			buf, QSE_COUNTOF(buf),
 | 
			
		||||
			arg->req->attr.content_length, 
 | 
			
		||||
			10, -1, QSE_MT('\0'), QSE_NULL);
 | 
			
		||||
 | 
			
		||||
		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;
 | 
			
		||||
 | 
			
		||||
		len = qse_htre_getcontentlen(arg->req);
 | 
			
		||||
		if (len > 0)
 | 
			
		||||
		{
 | 
			
		||||
			/* content received so far */
 | 
			
		||||
			ptr = qse_htre_getcontentptr(arg->req);
 | 
			
		||||
			if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1) goto oops;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		snatch_needed = 1;
 | 
			
		||||
		proxy->req = arg->req;
 | 
			
		||||
		qse_htre_setconcb (proxy->req, proxy_snatch_client_input_raw, task);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		/* if this request is not chunked nor not length based,
 | 
			
		||||
		 * the state should be QSE_HTRE_COMPLETED. so only a
 | 
			
		||||
		 * chunked request should reach here */
 | 
			
		||||
		QSE_ASSERT (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED);
 | 
			
		||||
		int snatch_needed = 0;
 | 
			
		||||
 | 
			
		||||
		proxy->reqflags |= PROXY_REQ_FWDCHUNKED;
 | 
			
		||||
		if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1 ||
 | 
			
		||||
		    qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 /* end of header */) goto oops; 
 | 
			
		||||
		if (qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getqmethodname(arg->req)) == (qse_size_t)-1 ||
 | 
			
		||||
			qse_mbs_cat (proxy->reqfwdbuf, QSE_MT(" ")) == (qse_size_t)-1 ||
 | 
			
		||||
			qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getqpath(arg->req)) == (qse_size_t)-1) goto oops;
 | 
			
		||||
 | 
			
		||||
		len = qse_htre_getcontentlen(arg->req);
 | 
			
		||||
		if (len > 0)
 | 
			
		||||
		if (qse_htre_getqparam(arg->req))
 | 
			
		||||
		{
 | 
			
		||||
			qse_mchar_t buf[64];
 | 
			
		||||
			if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("?")) == (qse_size_t)-1 ||
 | 
			
		||||
				qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getqparam(arg->req)) == (qse_size_t)-1) goto oops;
 | 
			
		||||
		}
 | 
			
		||||
		if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT(" ")) == (qse_size_t)-1 ||
 | 
			
		||||
			qse_mbs_cat (proxy->reqfwdbuf, qse_htre_getverstr(arg->req)) == (qse_size_t)-1 ||
 | 
			
		||||
			qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 ||
 | 
			
		||||
			qse_htre_walkheaders (arg->req, proxy_capture_client_header, proxy) <= -1) goto oops;
 | 
			
		||||
 | 
			
		||||
			qse_fmtuintmaxtombs (
 | 
			
		||||
				buf, QSE_COUNTOF(buf), len,
 | 
			
		||||
				16 | QSE_FMTUINTMAXTOMBS_UPPERCASE, 
 | 
			
		||||
				-1, QSE_MT('\0'), QSE_NULL);
 | 
			
		||||
 | 
			
		||||
			ptr = qse_htre_getcontentptr(arg->req);
 | 
			
		||||
 | 
			
		||||
			/* 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;
 | 
			
		||||
		proxy->resflags |= PROXY_RES_AWAIT_RESHDR;
 | 
			
		||||
		if ((arg->req->attr.flags & QSE_HTRE_ATTR_EXPECT100) &&
 | 
			
		||||
			(arg->req->version.major > 1 || 
 | 
			
		||||
			 (arg->req->version.major == 1 && arg->req->version.minor >= 1)))
 | 
			
		||||
		{
 | 
			
		||||
			proxy->resflags |= PROXY_RES_AWAIT_100;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		snatch_needed = 1;
 | 
			
		||||
	}
 | 
			
		||||
		if (!(httpd->opt.trait & QSE_HTTPD_PROXYNOVIA))
 | 
			
		||||
		{
 | 
			
		||||
			/* add the Via: header into the request */
 | 
			
		||||
			if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Via: ")) == (qse_size_t)-1 ||
 | 
			
		||||
				qse_mbs_cat (proxy->reqfwdbuf, qse_httpd_getname (httpd)) == (qse_size_t)-1 ||
 | 
			
		||||
				qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
		if (arg->req->state & QSE_HTRE_DISCARDED)
 | 
			
		||||
		{
 | 
			
		||||
			/* no content to add */
 | 
			
		||||
			if ((arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) || 
 | 
			
		||||
				(arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
 | 
			
		||||
			{
 | 
			
		||||
				/* i don't add chunk traiers if the 
 | 
			
		||||
				 * request content has been discarded */
 | 
			
		||||
				if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Content-Length: 0\r\n\r\n")) == (qse_size_t)-1) goto oops;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (arg->req->state & QSE_HTRE_COMPLETED)
 | 
			
		||||
		{
 | 
			
		||||
			if (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED)
 | 
			
		||||
			{
 | 
			
		||||
				/* add trailers if any */
 | 
			
		||||
				if (qse_htre_walktrailers (
 | 
			
		||||
					arg->req, proxy_capture_client_trailer, proxy) <= -1) goto oops;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			len = qse_htre_getcontentlen(arg->req);
 | 
			
		||||
			if (len > 0 || (arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH) || 
 | 
			
		||||
						   (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
 | 
			
		||||
			{
 | 
			
		||||
				qse_mchar_t buf[64];
 | 
			
		||||
 | 
			
		||||
				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 (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1) goto oops;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (arg->req->attr.flags & QSE_HTRE_ATTR_LENGTH)
 | 
			
		||||
		{
 | 
			
		||||
			/* the Content-Length header field is contained in the request. */
 | 
			
		||||
			qse_mchar_t buf[64];
 | 
			
		||||
			qse_fmtuintmaxtombs (
 | 
			
		||||
				buf, QSE_COUNTOF(buf),
 | 
			
		||||
				arg->req->attr.content_length, 
 | 
			
		||||
				10, -1, QSE_MT('\0'), QSE_NULL);
 | 
			
		||||
 | 
			
		||||
			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;
 | 
			
		||||
 | 
			
		||||
			len = qse_htre_getcontentlen(arg->req);
 | 
			
		||||
			if (len > 0)
 | 
			
		||||
			{
 | 
			
		||||
				/* content received so far */
 | 
			
		||||
				ptr = qse_htre_getcontentptr(arg->req);
 | 
			
		||||
				if (qse_mbs_ncat (proxy->reqfwdbuf, ptr, len) == (qse_size_t)-1) goto oops;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			snatch_needed = 1;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			/* if this request is not chunked nor not length based,
 | 
			
		||||
			 * the state should be QSE_HTRE_COMPLETED. so only a
 | 
			
		||||
			 * chunked request should reach here */
 | 
			
		||||
			QSE_ASSERT (arg->req->attr.flags & QSE_HTRE_ATTR_CHUNKED);
 | 
			
		||||
 | 
			
		||||
			proxy->reqflags |= PROXY_REQ_FWDCHUNKED;
 | 
			
		||||
			if (qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("Transfer-Encoding: chunked\r\n")) == (qse_size_t)-1 ||
 | 
			
		||||
				qse_mbs_cat (proxy->reqfwdbuf, QSE_MT("\r\n")) == (qse_size_t)-1 /* end of header */) goto oops; 
 | 
			
		||||
 | 
			
		||||
			len = qse_htre_getcontentlen(arg->req);
 | 
			
		||||
			if (len > 0)
 | 
			
		||||
			{
 | 
			
		||||
				qse_mchar_t buf[64];
 | 
			
		||||
 | 
			
		||||
				qse_fmtuintmaxtombs (
 | 
			
		||||
					buf, QSE_COUNTOF(buf), len,
 | 
			
		||||
					16 | QSE_FMTUINTMAXTOMBS_UPPERCASE, 
 | 
			
		||||
					-1, QSE_MT('\0'), QSE_NULL);
 | 
			
		||||
 | 
			
		||||
				ptr = qse_htre_getcontentptr(arg->req);
 | 
			
		||||
 | 
			
		||||
				/* 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);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* no triggers yet since the main loop doesn't allow me to set 
 | 
			
		||||
@ -1135,19 +1185,12 @@ qse_printf (QSE_T("task_main_proxy_3 trigger[0].mask=%d trigger[1].mask=%d trigg
 | 
			
		||||
			if ((proxy->resflags & PROXY_RES_CLIENT_CHUNK) ||
 | 
			
		||||
			    ((proxy->resflags & PROXY_RES_PEER_LENGTH) && proxy->peer_output_received >= proxy->peer_output_length))
 | 
			
		||||
			{
 | 
			
		||||
#if 0
 | 
			
		||||
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);
 | 
			
		||||
#endif
 | 
			
		||||
				task->main = task_main_proxy_5;
 | 
			
		||||
				task->trigger[2].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
#if 0
 | 
			
		||||
qse_printf (QSE_T("SWITICHING TO 4444444444444444444444444444\n"));
 | 
			
		||||
#endif
 | 
			
		||||
				/* arrange to read the remaining contents from the peer */
 | 
			
		||||
				task->main = task_main_proxy_4;
 | 
			
		||||
				task->trigger[2].mask &= ~QSE_HTTPD_TASK_TRIGGER_WRITE;
 | 
			
		||||
			}
 | 
			
		||||
@ -1299,6 +1342,7 @@ for (i = 0; i < proxy->buflen; i++) qse_printf (QSE_T("%hc"), proxy->buf[i]);
 | 
			
		||||
qse_printf (QSE_T("]\n"));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
		if (qse_htrd_feed (proxy->peer_htrd, proxy->buf, proxy->buflen) <= -1)
 | 
			
		||||
		{
 | 
			
		||||
			if (httpd->opt.trait & QSE_HTTPD_LOGACT) 
 | 
			
		||||
@ -1415,7 +1459,11 @@ static int task_main_proxy_1 (
 | 
			
		||||
					task->trigger[0].mask |= QSE_HTTPD_TASK_TRIGGER_WRITE;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			task->main = task_main_proxy_2;
 | 
			
		||||
 | 
			
		||||
			if (proxy->raw)
 | 
			
		||||
				task->main  = task_main_proxy_4;
 | 
			
		||||
			else
 | 
			
		||||
				task->main = task_main_proxy_2;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -1435,16 +1483,19 @@ static int task_main_proxy (
 | 
			
		||||
 | 
			
		||||
	if (proxy->init_failed) goto oops;
 | 
			
		||||
 | 
			
		||||
	/* set up a http reader to read a response from the peer */
 | 
			
		||||
	proxy->peer_htrd = qse_htrd_open (
 | 
			
		||||
		httpd->mmgr, QSE_SIZEOF(proxy_peer_htrd_xtn_t));
 | 
			
		||||
	if (proxy->peer_htrd == QSE_NULL) goto oops;
 | 
			
		||||
	xtn = (proxy_peer_htrd_xtn_t*) qse_htrd_getxtn (proxy->peer_htrd);
 | 
			
		||||
	xtn->proxy = proxy;
 | 
			
		||||
	xtn->client = client;
 | 
			
		||||
	xtn->task = task;
 | 
			
		||||
	qse_htrd_setrecbs (proxy->peer_htrd, &proxy_peer_htrd_cbs);
 | 
			
		||||
	qse_htrd_setoption (proxy->peer_htrd, QSE_HTRD_RESPONSE | QSE_HTRD_TRAILERS);
 | 
			
		||||
	if (!proxy->raw)
 | 
			
		||||
	{
 | 
			
		||||
		/* set up a http reader to read a response from the peer */
 | 
			
		||||
		proxy->peer_htrd = qse_htrd_open (
 | 
			
		||||
			httpd->mmgr, QSE_SIZEOF(proxy_peer_htrd_xtn_t));
 | 
			
		||||
		if (proxy->peer_htrd == QSE_NULL) goto oops;
 | 
			
		||||
		xtn = (proxy_peer_htrd_xtn_t*) qse_htrd_getxtn (proxy->peer_htrd);
 | 
			
		||||
		xtn->proxy = proxy;
 | 
			
		||||
		xtn->client = client;
 | 
			
		||||
		xtn->task = task;
 | 
			
		||||
		qse_htrd_setrecbs (proxy->peer_htrd, &proxy_peer_htrd_cbs);
 | 
			
		||||
		qse_htrd_setoption (proxy->peer_htrd, QSE_HTRD_RESPONSE | QSE_HTRD_TRAILERS);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	proxy->res = qse_mbs_open (httpd->mmgr, 0, 256);
 | 
			
		||||
	if (proxy->res == QSE_NULL) goto oops;
 | 
			
		||||
@ -1519,15 +1570,13 @@ qse_httpd_task_t* qse_httpd_entaskproxy (
 | 
			
		||||
	qse_httpd_t* httpd,
 | 
			
		||||
	qse_httpd_client_t* client,
 | 
			
		||||
	qse_httpd_task_t* pred, 
 | 
			
		||||
	const qse_nwad_t* dst,
 | 
			
		||||
	const qse_nwad_t* src,
 | 
			
		||||
	const qse_httpd_rsrc_proxy_t* proxy,
 | 
			
		||||
	qse_htre_t* req)
 | 
			
		||||
{
 | 
			
		||||
	qse_httpd_task_t task;
 | 
			
		||||
	task_proxy_arg_t arg;
 | 
			
		||||
 | 
			
		||||
	arg.peer_nwad = dst;
 | 
			
		||||
	arg.peer_local = src;
 | 
			
		||||
	arg.rsrc = proxy;
 | 
			
		||||
	arg.req = req;
 | 
			
		||||
 | 
			
		||||
	QSE_MEMSET (&task, 0, QSE_SIZEOF(task));
 | 
			
		||||
 | 
			
		||||
@ -1977,6 +1977,8 @@ static int process_request (
 | 
			
		||||
{
 | 
			
		||||
	qse_httpd_task_t* task;
 | 
			
		||||
	server_xtn_t* server_xtn;
 | 
			
		||||
	qse_http_method_t mth;
 | 
			
		||||
	qse_httpd_rsrc_t rsrc;
 | 
			
		||||
 | 
			
		||||
	server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, client->server);
 | 
			
		||||
 | 
			
		||||
@ -2008,31 +2010,40 @@ if (qse_htre_getcontentlen(req) > 0)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	mth = qse_htre_getqmethodtype(req);
 | 
			
		||||
 | 
			
		||||
	if (peek)
 | 
			
		||||
	{
 | 
			
		||||
		qse_httpd_rsrc_t rsrc;
 | 
			
		||||
 | 
			
		||||
		/* determine what to do once the header fields are all received.
 | 
			
		||||
		 * i don't want to delay this until the contents are received.
 | 
			
		||||
		 * if you don't like this behavior, you must implement your own
 | 
			
		||||
		 * callback function for request handling. */
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
/* TODO support X-HTTP-Method-Override */
 | 
			
		||||
	if (data.method == QSE_HTTP_POST)
 | 
			
		||||
	{
 | 
			
		||||
		tmp = qse_htre_getheaderval(req, QSE_MT("X-HTTP-Method-Override"));
 | 
			
		||||
		if (tmp)
 | 
			
		||||
		/* TODO support X-HTTP-Method-Override */
 | 
			
		||||
		if (data.method == QSE_HTTP_POST)
 | 
			
		||||
		{
 | 
			
		||||
			/*while (tmp->next) tmp = tmp->next;*/ /* get the last value */
 | 
			
		||||
			data.method = qse_mbstohttpmethod (tmp->ptr);
 | 
			
		||||
			tmp = qse_htre_getheaderval(req, QSE_MT("X-HTTP-Method-Override"));
 | 
			
		||||
			if (tmp)
 | 
			
		||||
			{
 | 
			
		||||
				/*while (tmp->next) tmp = tmp->next;*/ /* get the last value */
 | 
			
		||||
				data.method = qse_mbstohttpmethod (tmp->ptr);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		if (qse_htre_getqmethodtype(req) == QSE_HTTP_POST &&
 | 
			
		||||
		    !(req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
 | 
			
		||||
		    !(req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
 | 
			
		||||
		if (mth == QSE_HTTP_CONNECT)
 | 
			
		||||
		{
 | 
			
		||||
			/* CONNECT method must not have content set. 
 | 
			
		||||
			 * however, arrange to discard it if so. 
 | 
			
		||||
			 *
 | 
			
		||||
			 * NOTE: CONNECT is implemented to ignore many headers like
 | 
			
		||||
			 *       'Expect: 100-continue' and 'Connection: keep-alive'. */
 | 
			
		||||
			qse_httpd_discardcontent (httpd, req);
 | 
			
		||||
		}
 | 
			
		||||
		else if (mth == QSE_HTTP_POST &&
 | 
			
		||||
		         !(req->attr.flags & QSE_HTRE_ATTR_LENGTH) &&
 | 
			
		||||
		         !(req->attr.flags & QSE_HTRE_ATTR_CHUNKED))
 | 
			
		||||
		{
 | 
			
		||||
			/* POST without Content-Length nor not chunked */
 | 
			
		||||
			req->attr.flags &= ~QSE_HTRE_ATTR_KEEPALIVE;
 | 
			
		||||
@ -2058,9 +2069,12 @@ if (qse_htre_getcontentlen(req) > 0)
 | 
			
		||||
		{
 | 
			
		||||
			task = QSE_NULL;
 | 
			
		||||
 | 
			
		||||
			/* inject '100 continue' first if it is needed */
 | 
			
		||||
			if ((rsrc.flags & QSE_HTTPD_RSRC_100_CONTINUE) && 
 | 
			
		||||
			    (task = qse_httpd_entaskcontinue (httpd, client, task, req)) == QSE_NULL) goto oops;
 | 
			
		||||
			    (task = qse_httpd_entaskcontinue (httpd, client, task, req)) == QSE_NULL) 
 | 
			
		||||
			{
 | 
			
		||||
				/* inject '100 continue' first if it is needed */
 | 
			
		||||
				goto oops;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* arrange the actual resource to be returned */
 | 
			
		||||
			task = qse_httpd_entaskrsrc (httpd, client, task, &rsrc, req);
 | 
			
		||||
@ -2079,7 +2093,32 @@ if (qse_htre_getcontentlen(req) > 0)
 | 
			
		||||
	{
 | 
			
		||||
		/* contents are all received */
 | 
			
		||||
 | 
			
		||||
		if (req->attr.flags & QSE_HTRE_ATTR_PROXIED)
 | 
			
		||||
		if (mth == QSE_HTTP_CONNECT)
 | 
			
		||||
		{
 | 
			
		||||
printf ("SWITCHING HTRD TO DUMMY....\n");
 | 
			
		||||
			/* Switch the http read to a dummy mode so that the subsqeuent
 | 
			
		||||
			 * input is just treaet as connects to the request just completed */
 | 
			
		||||
			qse_htrd_setoption (client->htrd, qse_htrd_getoption(client->htrd) | QSE_HTRD_DUMMY);
 | 
			
		||||
 | 
			
		||||
			if (server_xtn->makersrc (httpd, client, req, &rsrc) <= -1)
 | 
			
		||||
			{
 | 
			
		||||
				/* failed to make a resource. just send the internal server error.
 | 
			
		||||
				 * the makersrc handler can return a negative number to return 
 | 
			
		||||
				 * '500 Internal Server Error'. If it wants to return a specific
 | 
			
		||||
				 * error code, it should return 0 with the QSE_HTTPD_RSRC_ERR
 | 
			
		||||
				 * resource. */
 | 
			
		||||
				task = qse_httpd_entaskerr (httpd, client, QSE_NULL, 500, req);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				/* arrange the actual resource to be returned */
 | 
			
		||||
				task = qse_httpd_entaskrsrc (httpd, client, QSE_NULL, &rsrc, req);
 | 
			
		||||
				server_xtn->freersrc (httpd, client, req, &rsrc);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (task == QSE_NULL) goto oops;
 | 
			
		||||
		}
 | 
			
		||||
		else if (req->attr.flags & QSE_HTRE_ATTR_PROXIED)
 | 
			
		||||
		{
 | 
			
		||||
			/* the contents should be proxied. 
 | 
			
		||||
			 * do nothing locally */
 | 
			
		||||
@ -2091,7 +2130,7 @@ if (qse_htre_getcontentlen(req) > 0)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE))
 | 
			
		||||
	if (!(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE) || mth == QSE_HTTP_CONNECT)
 | 
			
		||||
	{
 | 
			
		||||
		if (!peek)
 | 
			
		||||
		{
 | 
			
		||||
@ -2483,6 +2522,7 @@ static int make_resource (
 | 
			
		||||
{
 | 
			
		||||
	server_xtn_t* server_xtn;
 | 
			
		||||
	struct rsrc_tmp_t tmp;
 | 
			
		||||
	qse_http_method_t mth;
 | 
			
		||||
 | 
			
		||||
	qse_httpd_stat_t st;
 | 
			
		||||
	int n, stx, acc;
 | 
			
		||||
@ -2495,15 +2535,36 @@ static int make_resource (
 | 
			
		||||
 | 
			
		||||
	server_xtn = qse_httpd_getserverxtn (httpd, client->server);
 | 
			
		||||
 | 
			
		||||
	mth = qse_htre_getqmethodtype (req);
 | 
			
		||||
	if (mth == QSE_HTTP_CONNECT)
 | 
			
		||||
	{
 | 
			
		||||
		/* TODO: query if CONNECT is allowed */
 | 
			
		||||
		/* TODO: Proxy-Authorization???? */
 | 
			
		||||
		target->type = QSE_HTTPD_RSRC_PROXY;
 | 
			
		||||
		target->u.proxy.raw = 1;
 | 
			
		||||
 | 
			
		||||
		if (qse_mbstonwad (qse_htre_getqpath(req), &target->u.proxy.dst) <= -1) return -1;
 | 
			
		||||
		target->u.proxy.src.type = target->u.proxy.dst.type;
 | 
			
		||||
 | 
			
		||||
		/* mark that this request is going to be proxied. */
 | 
			
		||||
		/*req->attr.flags |= QSE_HTRE_ATTR_PROXIED;*/
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (server_xtn->query (httpd, client->server, req, QSE_NULL, QSE_HTTPD_SERVERSTD_ROOT, &tmp.root) <= -1) return -1;
 | 
			
		||||
	switch (tmp.root.type)
 | 
			
		||||
	{
 | 
			
		||||
		case QSE_HTTPD_SERVERSTD_ROOT_NWAD:
 | 
			
		||||
			/* proxy the request */
 | 
			
		||||
			target->type = QSE_HTTPD_RSRC_PROXY;
 | 
			
		||||
			/*target->u.proxy.dst = client->orgdst_addr;*/
 | 
			
		||||
			target->u.proxy.dst = tmp.root.u.nwad;
 | 
			
		||||
			target->u.proxy.raw = 0;
 | 
			
		||||
 | 
			
		||||
			/* transparent proxy may do the following
 | 
			
		||||
			target->u.proxy.dst = client->orgdst_addr; 
 | 
			
		||||
			target->u.proxy.src = client->remote_addr;
 | 
			
		||||
			*/
 | 
			
		||||
			target->u.proxy.dst = tmp.root.u.nwad;
 | 
			
		||||
			target->u.proxy.src.type = target->u.proxy.dst.type;
 | 
			
		||||
 | 
			
		||||
			/* mark that this request is going to be proxied. */
 | 
			
		||||
			req->attr.flags |= QSE_HTRE_ATTR_PROXIED;
 | 
			
		||||
 | 
			
		||||
@ -398,7 +398,7 @@ qse_httpd_task_t* qse_httpd_entaskrsrc (
 | 
			
		||||
			break;
 | 
			
		||||
	
 | 
			
		||||
		case QSE_HTTPD_RSRC_PROXY:
 | 
			
		||||
			task = qse_httpd_entaskproxy (httpd, client, pred, &rsrc->u.proxy.dst, &rsrc->u.proxy.src, req);
 | 
			
		||||
			task = qse_httpd_entaskproxy (httpd, client, pred, &rsrc->u.proxy, req);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case QSE_HTTPD_RSRC_RELOC:
 | 
			
		||||
 | 
			
		||||
@ -319,7 +319,7 @@ static QSE_INLINE int dequeue_task (
 | 
			
		||||
 | 
			
		||||
	if (client->task.count <= 0) return -1;
 | 
			
		||||
 | 
			
		||||
	task = client->task.head;
 | 
			
		||||
	task = (qse_httpd_real_task_t*)client->task.head;
 | 
			
		||||
 | 
			
		||||
	/* clear task triggers from mux if they are registered */
 | 
			
		||||
	for (i = 0; i < QSE_COUNTOF(task->core.trigger); i++)
 | 
			
		||||
@ -333,7 +333,7 @@ static QSE_INLINE int dequeue_task (
 | 
			
		||||
 | 
			
		||||
	/* --------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
	if (task == client->task.tail)
 | 
			
		||||
	if (task == (qse_httpd_real_task_t*)client->task.tail)
 | 
			
		||||
	{
 | 
			
		||||
		client->task.head = QSE_NULL;
 | 
			
		||||
		client->task.tail = QSE_NULL;
 | 
			
		||||
@ -345,7 +345,7 @@ static QSE_INLINE int dequeue_task (
 | 
			
		||||
	}
 | 
			
		||||
	client->task.count--;
 | 
			
		||||
 | 
			
		||||
	if (task->core.fini) task->core.fini (httpd, client, task);
 | 
			
		||||
	if (task->core.fini) task->core.fini (httpd, client, (qse_httpd_task_t*)task);
 | 
			
		||||
	qse_httpd_freemem (httpd, task);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
@ -816,7 +816,7 @@ qse_printf (QSE_T("]\n"));
 | 
			
		||||
		if (httpd->errnum == QSE_HTTPD_ENOERR)
 | 
			
		||||
		{
 | 
			
		||||
			if (client->htrd->errnum == QSE_HTRD_EBADRE || 
 | 
			
		||||
			    client->htrd->errnum == QSE_HTRD_EBADHDR)
 | 
			
		||||
				client->htrd->errnum == QSE_HTRD_EBADHDR)
 | 
			
		||||
				httpd->errnum = QSE_HTTPD_EBADREQ;
 | 
			
		||||
			else httpd->errnum = QSE_HTTPD_ENOMEM; /* TODO: better translate error code */
 | 
			
		||||
		}
 | 
			
		||||
@ -829,10 +829,10 @@ for (i = 0; i < m; i++) qse_printf (QSE_T("%hc"), buf[i]);
 | 
			
		||||
}
 | 
			
		||||
qse_printf (QSE_T("]\n"));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
qse_printf (QSE_T("!!!!!FEEDING OK OK OK OK %d from %d\n"), (int)m, (int)client->handle.i);
 | 
			
		||||
#endif
 | 
			
		||||
@ -1370,7 +1370,7 @@ qse_mchar_t* qse_httpd_escapehtml (qse_httpd_t* httpd, const qse_mchar_t* str)
 | 
			
		||||
	qse_mchar_t* ptr, * buf;
 | 
			
		||||
	qse_size_t reqlen = 0;
 | 
			
		||||
 | 
			
		||||
	for (ptr = str; *ptr != QSE_MT('\0'); ptr++) 
 | 
			
		||||
	for (ptr = (qse_mchar_t*)str; *ptr != QSE_MT('\0'); ptr++) 
 | 
			
		||||
	{
 | 
			
		||||
		switch (*ptr)
 | 
			
		||||
		{
 | 
			
		||||
@ -1389,7 +1389,7 @@ qse_mchar_t* qse_httpd_escapehtml (qse_httpd_t* httpd, const qse_mchar_t* str)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ptr - str == reqlen) return str; /* no escaping is needed */
 | 
			
		||||
	if (ptr - str == reqlen) return (qse_mchar_t*)str; /* no escaping is needed */
 | 
			
		||||
 | 
			
		||||
	buf = qse_httpd_allocmem (httpd, QSE_SIZEOF(*buf) * (reqlen + 1));
 | 
			
		||||
	if (buf == QSE_NULL) return QSE_NULL;
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user