added some code to support raw proxying
This commit is contained in:
		| @ -356,9 +356,10 @@ 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; | ||||
| 	 | ||||
|  | ||||
| 			if (rsrc->u.proxy.src.type == QSE_NWAD_IN4) | ||||
| 				rsrc->u.proxy.src.u.in4.port = 0; /* reset the port to 0. */ | ||||
| 			else if (rsrc->u.proxy.src.type == QSE_NWAD_IN6) | ||||
| @ -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; | ||||
|  | ||||
| @ -62,7 +62,7 @@ struct qse_htre_t | ||||
| 	enum | ||||
| 	{ | ||||
| 		QSE_HTRE_Q, | ||||
| 		QSE_HTRE_S	 | ||||
| 		QSE_HTRE_S | ||||
| 	} type; | ||||
|  | ||||
| 	/* version */ | ||||
|  | ||||
| @ -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,21 +519,17 @@ 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 | ||||
| 		{ | ||||
| 			const qse_mchar_t* dst; | ||||
| 		} reloc;	 | ||||
| 		} reloc; | ||||
|  | ||||
| 		struct | ||||
| 		{ | ||||
| 			const qse_mchar_t* dst; | ||||
| 		} redir;	 | ||||
| 		} redir; | ||||
|  | ||||
| 		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 | ||||
| ); | ||||
|  | ||||
| /* -------------------------------------------- */ | ||||
|  | ||||
| @ -169,9 +169,9 @@ QSE_EXPORT qse_httpd_server_t* qse_httpd_attachserverstd ( | ||||
| QSE_EXPORT qse_httpd_server_t* qse_httpd_attachserverstdwithuri ( | ||||
| 	qse_httpd_t*                 httpd, | ||||
| 	const qse_char_t*            uri, | ||||
| 	qse_httpd_server_detach_t    detach,	 | ||||
| 	qse_httpd_server_impede_t    impede,	 | ||||
| 	qse_httpd_serverstd_query_t  query,	 | ||||
| 	qse_httpd_server_detach_t    detach, | ||||
| 	qse_httpd_server_impede_t    impede, | ||||
| 	qse_httpd_serverstd_query_t  query, | ||||
| 	qse_size_t                   xtnsize | ||||
| ); | ||||
| #endif | ||||
|  | ||||
| @ -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) | ||||
| 	{ | ||||
| @ -1196,7 +1207,7 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len) | ||||
| 						 */ | ||||
| 						if (ptr < end && push_content (htrd, ptr, end - ptr) <= -1) return -1; | ||||
|  | ||||
| 						/* i don't really know if it is really completed 	 | ||||
| 						/* i don't really know if it is really completed  | ||||
| 						 * with content. QSE_HTRD_PEEKONLY is not compatible | ||||
| 						 * with the completed state. anyway, let me complete | ||||
| 						 * it. */ | ||||
| @ -1213,12 +1224,12 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len) | ||||
| 					{ | ||||
| 						/* transfer-encoding: chunked */ | ||||
| 						QSE_ASSERT (!(htrd->re.attr.flags & QSE_HTRE_ATTR_LENGTH)); | ||||
| 	 | ||||
|  | ||||
| 					dechunk_start: | ||||
| 						htrd->fed.s.chunk.phase = GET_CHUNK_LEN; | ||||
| 						htrd->fed.s.chunk.len = 0; | ||||
| 						htrd->fed.s.chunk.count = 0; | ||||
| 	 | ||||
|  | ||||
| 					dechunk_resume: | ||||
| 						ptr = getchunklen (htrd, ptr, end - ptr); | ||||
| 						if (ptr == QSE_NULL) return -1; | ||||
| @ -1242,7 +1253,7 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len) | ||||
| 						dechunk_get_trailers: | ||||
| 							ptr = get_trailing_headers (htrd, ptr, end); | ||||
| 							if (ptr == QSE_NULL) return -1; | ||||
| 	 | ||||
|  | ||||
| 							if (htrd->fed.s.chunk.phase == GET_CHUNK_TRAILERS) | ||||
| 							{ | ||||
| 								/* still in the same state. | ||||
| @ -1330,7 +1341,7 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len) | ||||
| 					{ | ||||
| 						QSE_ASSERT (htrd->fed.s.need == 0); | ||||
| 						htrd->fed.s.chunk.phase = GET_CHUNK_CRLF; | ||||
| 	 | ||||
|  | ||||
| 					dechunk_crlf: | ||||
| 						while (ptr < end && is_space_octet(*ptr)) ptr++; | ||||
| 						if (ptr < end) | ||||
| @ -1339,12 +1350,12 @@ int qse_htrd_feed (qse_htrd_t* htrd, const qse_mchar_t* req, qse_size_t len) | ||||
| 							{ | ||||
| 								/* end of chunk data. */ | ||||
| 								ptr++; | ||||
| 	 | ||||
|  | ||||
| 								/* more octets still available.  | ||||
| 								 * let it decode the next chunk  | ||||
| 								 */ | ||||
| 								if (ptr < end) goto dechunk_start;  | ||||
| 							 | ||||
|  | ||||
| 								/* no more octets available after  | ||||
| 								 * chunk data. the chunk state variables | ||||
| 								 * need to be reset when a jump is made | ||||
| @ -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;  | ||||
|  | ||||
| @ -262,7 +262,7 @@ static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req) | ||||
| 		location = qse_htre_getheaderval (req, QSE_MT("Location")); | ||||
| 		if (location) | ||||
| 		{ | ||||
| 			snprintf (buf, QSE_COUNTOF(buf), 	 | ||||
| 			snprintf (buf, QSE_COUNTOF(buf), | ||||
| 				QSE_MT("HTTP/%d.%d 301 Moved Permanently\r\n"), | ||||
| 				cgi->version.major, cgi->version.minor | ||||
| 			); | ||||
| @ -277,7 +277,7 @@ static int cgi_htrd_peek_script_output (qse_htrd_t* htrd, qse_htre_t* req) | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			snprintf (buf, QSE_COUNTOF(buf), 	 | ||||
| 			snprintf (buf, QSE_COUNTOF(buf), | ||||
| 				QSE_MT("HTTP/%d.%d 200 OK\r\n"), | ||||
| 				cgi->version.major, cgi->version.minor | ||||
| 			); | ||||
| @ -755,7 +755,7 @@ static int task_init_cgi ( | ||||
| 	cgi->version = *qse_htre_getversion(arg->req); | ||||
| 	cgi->keepalive = (arg->req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE); | ||||
| 	cgi->nph = arg->nph; | ||||
| 	cgi->req = QSE_NULL;	 | ||||
| 	cgi->req = QSE_NULL; | ||||
|  | ||||
| 	content_length = 0; | ||||
| 	if (arg->req->state & QSE_HTRE_DISCARDED) goto done; | ||||
| @ -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  | ||||
| @ -1025,7 +1075,7 @@ qse_printf (QSE_T("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigg | ||||
| 							log_proxy_error (proxy, "proxy premature eof - "); | ||||
| 						return -1; | ||||
| 					} | ||||
| 				}	 | ||||
| 				} | ||||
| 				 | ||||
| 				task->main = task_main_proxy_5; | ||||
| 				task->trigger[0].mask = 0; | ||||
| @ -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; | ||||
| 			} | ||||
| @ -1287,7 +1330,7 @@ qse_printf (QSE_T("]\n")); | ||||
| 				goto oops; | ||||
| 			} | ||||
| 		} | ||||
| 			 | ||||
|  | ||||
| 		proxy->buflen += n; | ||||
|  | ||||
| #if 0 | ||||
| @ -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 */ | ||||
| @ -2087,11 +2126,11 @@ if (qse_htre_getcontentlen(req) > 0) | ||||
| 		else | ||||
| 		{ | ||||
| 			/* when the request is handled locally,  | ||||
| 			 * there's nothing special to do here */		 | ||||
| 			 * there's nothing special to do here */ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE)) | ||||
| 	if (!(req->attr.flags & QSE_HTRE_ATTR_KEEPALIVE) || mth == QSE_HTTP_CONNECT) | ||||
| 	{ | ||||
| 		if (!peek) | ||||
| 		{ | ||||
| @ -2286,7 +2325,7 @@ static qse_mchar_t* merge_paths ( | ||||
| 	ta[idx++] = base; | ||||
| 	if (path[0] != QSE_MT('\0')) | ||||
| 	{ | ||||
| 		ta[idx++] = QSE_MT("/");	 | ||||
| 		ta[idx++] = QSE_MT("/"); | ||||
| 		ta[idx++] = path; | ||||
| 	} | ||||
| 	ta[idx++] = QSE_NULL; | ||||
| @ -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; | ||||
| @ -2630,7 +2691,7 @@ auth_ok: | ||||
| 		tmp.final_match = 1; | ||||
|  | ||||
| 		if (st.isdir) | ||||
| 		{	 | ||||
| 		{ | ||||
| 			/* it is a directory */ | ||||
| 			if (tmp.index.count > 0) | ||||
| 			{ | ||||
| @ -2869,7 +2930,7 @@ static int query_server ( | ||||
| 					*(const qse_mchar_t**)result = mimetab[i].type; | ||||
| 					return 0; | ||||
| 				} | ||||
| 			}			 | ||||
| 			} | ||||
|  | ||||
| 			*(const qse_mchar_t**)result = QSE_NULL; | ||||
| 			return 0; | ||||
|  | ||||
| @ -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