implemented proxy peer connection caching experimentally
This commit is contained in:
		| @ -167,8 +167,13 @@ enum qse_httpd_peer_flag_t | |||||||
| 	/* internal use only */ | 	/* internal use only */ | ||||||
| 	QSE_HTTPD_PEER_PENDING = (1 << 21), | 	QSE_HTTPD_PEER_PENDING = (1 << 21), | ||||||
|  |  | ||||||
|  | 	/* internal use only */ | ||||||
|  | 	QSE_HTTPD_PEER_CACHED = (1 << 23), | ||||||
|  |  | ||||||
| 	/* all internal enumerators */ | 	/* all internal enumerators */ | ||||||
| 	QSE_HTTPD_PEER_ALL_INTERNALS = (QSE_HTTPD_PEER_CONNECTED | QSE_HTTPD_PEER_PENDING) | 	QSE_HTTPD_PEER_ALL_INTERNALS = (QSE_HTTPD_PEER_CONNECTED | | ||||||
|  | 	                                QSE_HTTPD_PEER_PENDING | | ||||||
|  | 	                                QSE_HTTPD_PEER_CACHED) | ||||||
| }; | }; | ||||||
| typedef enum qse_httpd_peer_flag_t qse_httpd_peer_flag_t; | typedef enum qse_httpd_peer_flag_t qse_httpd_peer_flag_t; | ||||||
|  |  | ||||||
| @ -176,10 +181,20 @@ typedef struct qse_httpd_peer_t qse_httpd_peer_t; | |||||||
| struct qse_httpd_peer_t | struct qse_httpd_peer_t | ||||||
| { | { | ||||||
| 	int flags; /* 0 or bitwised-OR'ed of qse_httpd_peer_flag_t enumerators */ | 	int flags; /* 0 or bitwised-OR'ed of qse_httpd_peer_flag_t enumerators */ | ||||||
|  |  | ||||||
| 	qse_nwad_t nwad; | 	qse_nwad_t nwad; | ||||||
| 	qse_nwad_t local; /* local side address facing the peer */ | 	qse_nwad_t local; /* local side address facing the peer */ | ||||||
|  |  | ||||||
|  | 	/* peer.open can set these handles */ | ||||||
| 	qse_httpd_hnd_t handle; | 	qse_httpd_hnd_t handle; | ||||||
| 	qse_httpd_hnd_t handle2; | 	qse_httpd_hnd_t handle2; | ||||||
|  |  | ||||||
|  | 	/* peer links for the proxy peer cache list in client. | ||||||
|  | 	 * internal use only. don't mess with these */ | ||||||
|  | 	qse_httpd_peer_t* next; | ||||||
|  | 	qse_httpd_peer_t* prev; | ||||||
|  |  | ||||||
|  | 	qse_ntime_t timestamp; /* internal use only */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
| enum qse_httpd_mux_mask_t | enum qse_httpd_mux_mask_t | ||||||
| @ -332,6 +347,42 @@ struct qse_httpd_scb_t | |||||||
| 		int (*accept) (qse_httpd_t* httpd, qse_httpd_server_t* server, qse_httpd_client_t* client); | 		int (*accept) (qse_httpd_t* httpd, qse_httpd_server_t* server, qse_httpd_client_t* client); | ||||||
| 	} server; | 	} server; | ||||||
|  |  | ||||||
|  | 	struct | ||||||
|  | 	{ | ||||||
|  | 		void (*close) ( | ||||||
|  | 			qse_httpd_t* httpd, | ||||||
|  | 			qse_httpd_client_t* client); | ||||||
|  |  | ||||||
|  | 		void (*shutdown) ( | ||||||
|  | 			qse_httpd_t* httpd, | ||||||
|  | 			qse_httpd_client_t* client); | ||||||
|  |  | ||||||
|  | 		/* action */ | ||||||
|  | 		qse_ssize_t (*recv) ( | ||||||
|  | 			qse_httpd_t* httpd,  | ||||||
|  | 			qse_httpd_client_t* client, | ||||||
|  | 			qse_mchar_t* buf, qse_size_t bufsize); | ||||||
|  |  | ||||||
|  | 		qse_ssize_t (*send) ( | ||||||
|  | 			qse_httpd_t* httpd, | ||||||
|  | 			qse_httpd_client_t* client, | ||||||
|  | 			const qse_mchar_t* buf, qse_size_t bufsize); | ||||||
|  |  | ||||||
|  | 		qse_ssize_t (*sendfile) ( | ||||||
|  | 			qse_httpd_t* httpd, | ||||||
|  | 			qse_httpd_client_t* client, | ||||||
|  | 			qse_httpd_hnd_t handle, qse_foff_t* offset, qse_size_t count); | ||||||
|  |  | ||||||
|  | 		/* event notification */ | ||||||
|  | 		int (*accepted) ( | ||||||
|  | 			qse_httpd_t* httpd, | ||||||
|  | 			qse_httpd_client_t* client);  /* optional */ | ||||||
|  | 		void (*closed) ( | ||||||
|  | 			qse_httpd_t* httpd, | ||||||
|  | 			qse_httpd_client_t* client);  /* optional */ | ||||||
|  | 	} client; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	struct | 	struct | ||||||
| 	{ | 	{ | ||||||
| 		int (*open) (qse_httpd_t* httpd, qse_httpd_peer_t* peer); | 		int (*open) (qse_httpd_t* httpd, qse_httpd_peer_t* peer); | ||||||
| @ -399,40 +450,6 @@ struct qse_httpd_scb_t | |||||||
| 			qse_httpd_dirent_t* ent); | 			qse_httpd_dirent_t* ent); | ||||||
| 	} dir; | 	} dir; | ||||||
|  |  | ||||||
| 	struct |  | ||||||
| 	{ |  | ||||||
| 		void (*close) ( |  | ||||||
| 			qse_httpd_t* httpd, |  | ||||||
| 			qse_httpd_client_t* client); |  | ||||||
|  |  | ||||||
| 		void (*shutdown) ( |  | ||||||
| 			qse_httpd_t* httpd, |  | ||||||
| 			qse_httpd_client_t* client); |  | ||||||
|  |  | ||||||
| 		/* action */ |  | ||||||
| 		qse_ssize_t (*recv) ( |  | ||||||
| 			qse_httpd_t* httpd,  |  | ||||||
| 			qse_httpd_client_t* client, |  | ||||||
| 			qse_mchar_t* buf, qse_size_t bufsize); |  | ||||||
|  |  | ||||||
| 		qse_ssize_t (*send) ( |  | ||||||
| 			qse_httpd_t* httpd, |  | ||||||
| 			qse_httpd_client_t* client, |  | ||||||
| 			const qse_mchar_t* buf, qse_size_t bufsize); |  | ||||||
|  |  | ||||||
| 		qse_ssize_t (*sendfile) ( |  | ||||||
| 			qse_httpd_t* httpd, |  | ||||||
| 			qse_httpd_client_t* client, |  | ||||||
| 			qse_httpd_hnd_t handle, qse_foff_t* offset, qse_size_t count); |  | ||||||
|  |  | ||||||
| 		/* event notification */ |  | ||||||
| 		int (*accepted) ( |  | ||||||
| 			qse_httpd_t* httpd, |  | ||||||
| 			qse_httpd_client_t* client);  /* optional */ |  | ||||||
| 		void (*closed) ( |  | ||||||
| 			qse_httpd_t* httpd, |  | ||||||
| 			qse_httpd_client_t* client);  /* optional */ |  | ||||||
| 	} client; |  | ||||||
| 	 | 	 | ||||||
| 	struct | 	struct | ||||||
| 	{ | 	{ | ||||||
| @ -663,6 +680,12 @@ struct qse_httpd_client_t | |||||||
| 	int                      initial_ifindex; | 	int                      initial_ifindex; | ||||||
|  |  | ||||||
| 	/* == PRIVATE == */ | 	/* == PRIVATE == */ | ||||||
|  | 	struct | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_peer_t* first; | ||||||
|  | 		qse_httpd_peer_t* last; | ||||||
|  | 	} peer; /* list of proxy peers for this client */ | ||||||
|  |  | ||||||
| 	qse_htrd_t*              htrd; | 	qse_htrd_t*              htrd; | ||||||
| 	int                      status; | 	int                      status; | ||||||
| 	qse_httpd_task_trigger_t trigger; | 	qse_httpd_task_trigger_t trigger; | ||||||
| @ -1404,9 +1427,9 @@ QSE_EXPORT qse_httpd_mod_t* qse_httpd_findmod ( | |||||||
| /* -------------------------------------------- */ | /* -------------------------------------------- */ | ||||||
|  |  | ||||||
| QSE_EXPORT int qse_httpd_inserttimerevent ( | QSE_EXPORT int qse_httpd_inserttimerevent ( | ||||||
| 	qse_httpd_t*             httpd, | 	qse_httpd_t*                   httpd, | ||||||
| 	const qse_httpd_timer_event_t* event, | 	const qse_httpd_timer_event_t* event, | ||||||
| 	qse_httpd_timer_index_t* index | 	qse_httpd_timer_index_t*       index | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  |  | ||||||
| @ -1415,6 +1438,7 @@ QSE_EXPORT void qse_httpd_removetimerevent ( | |||||||
| 	qse_httpd_timer_index_t  index | 	qse_httpd_timer_index_t  index | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | /* -------------------------------------------- */ | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  | |||||||
| @ -82,7 +82,8 @@ struct task_proxy_t | |||||||
| 	qse_mchar_t* peer_name; | 	qse_mchar_t* peer_name; | ||||||
| 	qse_uint16_t peer_port; | 	qse_uint16_t peer_port; | ||||||
|  |  | ||||||
| 	qse_httpd_peer_t peer; | 	qse_httpd_peer_t* peer; /* it points to static_peer initially. it can get changed to something else */ | ||||||
|  | 	qse_httpd_peer_t static_peer; | ||||||
| #define PROXY_PEER_OPEN      (1 << 0) | #define PROXY_PEER_OPEN      (1 << 0) | ||||||
| #define PROXY_PEER_CONNECTED (1 << 1) | #define PROXY_PEER_CONNECTED (1 << 1) | ||||||
| 	int peer_status; | 	int peer_status; | ||||||
| @ -132,17 +133,19 @@ struct proxy_peer_htrd_xtn_t | |||||||
| 	qse_httpd_task_t* task; | 	qse_httpd_task_t* task; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static void log_proxy_error (task_proxy_t* proxy, const qse_mchar_t* shortmsg) | /* ----------------------------------------------------------------- */ | ||||||
| { |  | ||||||
| /* TODO: change this to HTTPD_DBGOUTXXXX */ |  | ||||||
| 	qse_httpd_act_t msg; |  | ||||||
| 	qse_size_t pos = 0; |  | ||||||
|  |  | ||||||
| 	msg.code = QSE_HTTPD_CATCH_MERRMSG; | #if defined(QSE_HTTPD_DEBUG) | ||||||
| 	pos += qse_mbsxcpy (&msg.u.merrmsg[pos], QSE_COUNTOF(msg.u.merrmsg) - pos, shortmsg); | 	#define DBGOUT_PROXY_ERROR(proxy, msg) \ | ||||||
| 	pos += qse_nwadtombs (&proxy->peer.nwad, &msg.u.merrmsg[pos], QSE_COUNTOF(msg.u.merrmsg) - pos, QSE_NWADTOMBS_ALL); | 	do { \ | ||||||
| 	proxy->httpd->opt.rcb.logact (proxy->httpd, &msg); | 		qse_mchar_t tmp1[128], tmp2[128]; \ | ||||||
| } | 		qse_nwadtombs (&(proxy)->peer->nwad, tmp1, QSE_COUNTOF(tmp1), QSE_NWADTOMBS_ALL); \ | ||||||
|  | 		qse_nwadtombs (&(proxy)->client->remote_addr, tmp2, QSE_COUNTOF(tmp2), QSE_NWADTOMBS_ALL); \ | ||||||
|  | 		HTTPD_DBGOUT3 ("Proxy error with peer [%hs] client [%hs] - %hs\n", tmp1, tmp2, msg); \ | ||||||
|  | 	} while(0) | ||||||
|  | #else | ||||||
|  | 	#define DBGOUT_PROXY_ERROR(proxy, msg) | ||||||
|  | #endif | ||||||
|  |  | ||||||
| static int proxy_add_header_to_buffer ( | 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) | 	task_proxy_t* proxy, qse_mbs_t* buf, const qse_mchar_t* key, const qse_htre_hdrval_t* val) | ||||||
| @ -705,9 +708,7 @@ static int proxy_htrd_peek_peer_output (qse_htrd_t* htrd, qse_htre_t* res) | |||||||
| 		if ((proxy->resflags & PROXY_RES_PEER_LENGTH) &&  | 		if ((proxy->resflags & PROXY_RES_PEER_LENGTH) &&  | ||||||
| 		    proxy->peer_output_received > proxy->peer_output_length) | 		    proxy->peer_output_received > proxy->peer_output_length) | ||||||
| 		{ | 		{ | ||||||
| 			if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 			DBGOUT_PROXY_ERROR (proxy, "Redundant output from peer"); | ||||||
| 				log_proxy_error (proxy, "proxy redundant output - "); |  | ||||||
|  |  | ||||||
| 			httpd->errnum = QSE_HTTPD_EINVAL; /* TODO: change it to a better error code */ | 			httpd->errnum = QSE_HTTPD_EINVAL; /* TODO: change it to a better error code */ | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
| @ -831,7 +832,7 @@ static void proxy_forward_client_input_to_peer (qse_httpd_t* httpd, qse_httpd_ta | |||||||
|  |  | ||||||
| 			httpd->errnum = QSE_HTTPD_ENOERR; | 			httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 			n = httpd->opt.scb.peer.send ( | 			n = httpd->opt.scb.peer.send ( | ||||||
| 				httpd, &proxy->peer, | 				httpd, proxy->peer, | ||||||
| 				QSE_MBS_PTR(proxy->reqfwdbuf), | 				QSE_MBS_PTR(proxy->reqfwdbuf), | ||||||
| 				QSE_MBS_LEN(proxy->reqfwdbuf) | 				QSE_MBS_LEN(proxy->reqfwdbuf) | ||||||
| 			); | 			); | ||||||
| @ -840,8 +841,7 @@ static void proxy_forward_client_input_to_peer (qse_httpd_t* httpd, qse_httpd_ta | |||||||
| 			{ | 			{ | ||||||
| 				if (httpd->errnum != QSE_HTTPD_EAGAIN) | 				if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 				{ | 				{ | ||||||
| 					if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 					DBGOUT_PROXY_ERROR (proxy, "Cannot send to peer"); | ||||||
| 						log_proxy_error (proxy, "proxy send-to-peer error - "); |  | ||||||
|  |  | ||||||
| 					proxy->reqflags |= PROXY_REQ_FWDERR; | 					proxy->reqflags |= PROXY_REQ_FWDERR; | ||||||
| 					qse_mbs_clear (proxy->reqfwdbuf);  | 					qse_mbs_clear (proxy->reqfwdbuf);  | ||||||
| @ -902,7 +902,7 @@ static void adjust_peer_name_and_port (task_proxy_t* proxy) | |||||||
| 		if (proxy->flags & PROXY_RAW) proxy->peer_port = QSE_HTTPD_DEFAULT_SECURE_PORT; | 		if (proxy->flags & PROXY_RAW) proxy->peer_port = QSE_HTTPD_DEFAULT_SECURE_PORT; | ||||||
| 		else  | 		else  | ||||||
| 		{ | 		{ | ||||||
| 			if (proxy->peer.flags & QSE_HTTPD_PEER_SECURE) | 			if (proxy->peer->flags & QSE_HTTPD_PEER_SECURE) | ||||||
| 				proxy->peer_port = QSE_HTTPD_DEFAULT_SECURE_PORT; | 				proxy->peer_port = QSE_HTTPD_DEFAULT_SECURE_PORT; | ||||||
| 			else | 			else | ||||||
| 				proxy->peer_port = QSE_HTTPD_DEFAULT_PORT; | 				proxy->peer_port = QSE_HTTPD_DEFAULT_PORT; | ||||||
| @ -947,9 +947,10 @@ static int task_init_proxy ( | |||||||
| 	if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_X_FORWARDED) proxy->flags |= PROXY_X_FORWARDED; | 	if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_X_FORWARDED) proxy->flags |= PROXY_X_FORWARDED; | ||||||
| 	if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_ALLOW_UPGRADE) proxy->flags |= PROXY_ALLOW_UPGRADE; | 	if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_ALLOW_UPGRADE) proxy->flags |= PROXY_ALLOW_UPGRADE; | ||||||
|  |  | ||||||
| 	if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_DST_SECURE) proxy->peer.flags |= QSE_HTTPD_PEER_SECURE; | 	proxy->peer = &proxy->static_peer; | ||||||
|  | 	if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_DST_SECURE) proxy->peer->flags |= QSE_HTTPD_PEER_SECURE; | ||||||
|  |  | ||||||
| 	proxy->peer.local = arg->rsrc->src.nwad; | 	proxy->peer->local = arg->rsrc->src.nwad; | ||||||
| 	if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_DST_STR) | 	if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_DST_STR) | ||||||
| 	{ | 	{ | ||||||
| 		/* the destination given is a string. | 		/* the destination given is a string. | ||||||
| @ -982,7 +983,7 @@ static int task_init_proxy ( | |||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		proxy->peer.nwad = arg->rsrc->dst.nwad; | 		proxy->peer->nwad = arg->rsrc->dst.nwad; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_ENABLE_URS) | 	if (arg->rsrc->flags & QSE_HTTPD_RSRC_PROXY_ENABLE_URS) | ||||||
| @ -1352,14 +1353,48 @@ static void task_fini_proxy ( | |||||||
|  |  | ||||||
| 	if (proxy->peer_status & PROXY_PEER_OPEN)  | 	if (proxy->peer_status & PROXY_PEER_OPEN)  | ||||||
| 	{ | 	{ | ||||||
| 	#if defined(QSE_HTTPD_DEBUG) | 		int reuse = 0; | ||||||
|  |  | ||||||
|  | 		/* check if the peer connection can be reused */ | ||||||
|  | 		if (!(proxy->flags & (PROXY_RAW | PROXY_UPGRADE_REQUESTED | PROXY_PROTOCOL_SWITCHED)) && | ||||||
|  | 		    !(proxy->resflags & PROXY_RES_PEER_CLOSE)) | ||||||
| 		{ | 		{ | ||||||
| 			qse_mchar_t tmp[128]; | 			qse_mchar_t tmpch; | ||||||
| 			qse_nwadtombs (&proxy->peer.nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); |  | ||||||
| 			HTTPD_DBGOUT2 ("Closing peer [%hs] - %zd\n", tmp, (qse_size_t)proxy->peer.handle); | 			/* check if the peer connection dropped connection or | ||||||
|  | 			 * sending excessive data. don't reuse such a connection */ | ||||||
|  | 			if (httpd->opt.scb.peer.recv (httpd, proxy->peer, &tmpch, 1) <= -1 && | ||||||
|  | 			    httpd->errnum == QSE_HTTPD_EAGAIN) reuse = 1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (reuse && qse_httpd_cacheproxypeer (httpd, client, proxy->peer)) | ||||||
|  | 		{ | ||||||
|  | 			/* cache a reusable peer connection */ | ||||||
|  |  | ||||||
|  | 		#if defined(QSE_HTTPD_DEBUG) | ||||||
|  | 			qse_mchar_t tmp[128]; | ||||||
|  |  | ||||||
|  | 			qse_nwadtombs (&proxy->peer->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); | ||||||
|  | 			HTTPD_DBGOUT2 ("Cached peer [%hs] - %zd\n", tmp, (qse_size_t)proxy->peer->handle); | ||||||
|  | 		#endif | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 		#if defined(QSE_HTTPD_DEBUG) | ||||||
|  | 			qse_mchar_t tmp[128]; | ||||||
|  |  | ||||||
|  | 			qse_nwadtombs (&proxy->peer->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); | ||||||
|  | 			HTTPD_DBGOUT2 ("Closing peer [%hs] - %zd\n", tmp, (qse_size_t)proxy->peer->handle); | ||||||
|  | 		#endif | ||||||
|  |  | ||||||
|  | 			httpd->opt.scb.peer.close (httpd, proxy->peer); | ||||||
|  |  | ||||||
|  | 			if (proxy->peer->flags & QSE_HTTPD_PEER_CACHED) | ||||||
|  | 			{ | ||||||
|  | 				QSE_ASSERT (proxy->peer != &proxy->static_peer); | ||||||
|  | 				qse_httpd_freemem (httpd, proxy->peer); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	#endif |  | ||||||
| 		httpd->opt.scb.peer.close (httpd, &proxy->peer); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if ((proxy->flags & (PROXY_UPGRADE_REQUESTED | PROXY_PROTOCOL_SWITCHED)) == PROXY_UPGRADE_REQUESTED) | 	if ((proxy->flags & (PROXY_UPGRADE_REQUESTED | PROXY_PROTOCOL_SWITCHED)) == PROXY_UPGRADE_REQUESTED) | ||||||
| @ -1409,8 +1444,7 @@ printf ("task_main_proxy_5 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask | |||||||
| 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				/* can't return internal server error any more... */ | 				/* can't return internal server error any more... */ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				DBGOUT_PROXY_ERROR (proxy, "Cannot send to client"); | ||||||
| 					log_proxy_error (proxy, "proxy send-to-client error - "); |  | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -1448,7 +1482,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% | |||||||
| 		/* reading from the peer */ | 		/* reading from the peer */ | ||||||
| 		httpd->errnum = QSE_HTTPD_ENOERR; | 		httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 		n = httpd->opt.scb.peer.recv ( | 		n = httpd->opt.scb.peer.recv ( | ||||||
| 			httpd, &proxy->peer, | 			httpd, proxy->peer, | ||||||
| 			&proxy->buf[proxy->buflen],  | 			&proxy->buf[proxy->buflen],  | ||||||
| 			QSE_SIZEOF(proxy->buf) - proxy->buflen | 			QSE_SIZEOF(proxy->buf) - proxy->buflen | ||||||
| 		); | 		); | ||||||
| @ -1457,8 +1491,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% | |||||||
| 			/* can't return internal server error any more... */ | 			/* can't return internal server error any more... */ | ||||||
| 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				DBGOUT_PROXY_ERROR (proxy, "Cannot receive from peer"); | ||||||
| 					log_proxy_error (proxy, "proxy recv-from-peer error - "); |  | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @ -1473,8 +1506,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% | |||||||
|  |  | ||||||
| 				if (proxy->peer_output_received < proxy->peer_output_length) | 				if (proxy->peer_output_received < proxy->peer_output_length) | ||||||
| 				{ | 				{ | ||||||
| 					if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 					DBGOUT_PROXY_ERROR (proxy, "Premature content end"); | ||||||
| 						log_proxy_error (proxy, "proxy premature eof(content) - "); |  | ||||||
| 					return -1; | 					return -1; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| @ -1517,8 +1549,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% | |||||||
| 				if (proxy->peer_output_received > proxy->peer_output_length) | 				if (proxy->peer_output_received > proxy->peer_output_length) | ||||||
| 				{ | 				{ | ||||||
| 					/* proxy returning too much data... something is wrong in PROXY */ | 					/* proxy returning too much data... something is wrong in PROXY */ | ||||||
| 					if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 					DBGOUT_PROXY_ERROR (proxy, "Redundant output from peer"); | ||||||
| 						log_proxy_error (proxy, "proxy redundant output - "); |  | ||||||
| 					return -1; | 					return -1; | ||||||
| 				} | 				} | ||||||
| 				else if (proxy->peer_output_received == proxy->peer_output_length) | 				else if (proxy->peer_output_received == proxy->peer_output_length) | ||||||
| @ -1547,8 +1578,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% | |||||||
| 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				/* can't return internal server error any more... */ | 				/* can't return internal server error any more... */ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT) | 				DBGOUT_PROXY_ERROR (proxy, "Cannot send to client"); | ||||||
| 					log_proxy_error (proxy, "proxy send-to-client error - "); |  | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -1559,7 +1589,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (proxy->peer.flags & QSE_HTTPD_PEER_PENDING) | 	if (proxy->peer->flags & QSE_HTTPD_PEER_PENDING) | ||||||
| 	{ | 	{ | ||||||
| 		/* this QSE_HTTPD_CLIENT_PENDING thing is a dirty hack for SSL. | 		/* this QSE_HTTPD_CLIENT_PENDING thing is a dirty hack for SSL. | ||||||
| 		 * In SSL, data is transmitted in a record. a record can be | 		 * In SSL, data is transmitted in a record. a record can be | ||||||
| @ -1620,8 +1650,7 @@ printf ("task_main_proxy_3 trigger[0].mask=%d trigger[1].mask=%d trigger[2].mask | |||||||
| 		{ | 		{ | ||||||
| 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				DBGOUT_PROXY_ERROR (proxy, "Cannot send to client"); | ||||||
| 					log_proxy_error (proxy, "proxy send-to-client error - "); |  | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -1709,8 +1738,7 @@ static int task_main_proxy_2 ( | |||||||
| 		{ | 		{ | ||||||
| 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				DBGOUT_PROXY_ERROR (proxy, "Cannot send to client"); | ||||||
| 					log_proxy_error (proxy, "proxy send-to-client error - "); |  | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -1741,7 +1769,7 @@ static int task_main_proxy_2 ( | |||||||
| 		/* there is something to read from peer */ | 		/* there is something to read from peer */ | ||||||
| 		httpd->errnum = QSE_HTTPD_ENOERR; | 		httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 		n = httpd->opt.scb.peer.recv ( | 		n = httpd->opt.scb.peer.recv ( | ||||||
| 			httpd, &proxy->peer, | 			httpd, proxy->peer, | ||||||
| 			&proxy->buf[proxy->buflen],  | 			&proxy->buf[proxy->buflen],  | ||||||
| 			QSE_SIZEOF(proxy->buf) - proxy->buflen | 			QSE_SIZEOF(proxy->buf) - proxy->buflen | ||||||
| 		); | 		); | ||||||
| @ -1749,8 +1777,7 @@ static int task_main_proxy_2 ( | |||||||
| 		{ | 		{ | ||||||
| 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | 			if (httpd->errnum != QSE_HTTPD_EAGAIN) | ||||||
| 			{ | 			{ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				DBGOUT_PROXY_ERROR (proxy, "Cannot receive from peer"); | ||||||
| 					log_proxy_error (proxy, "proxy recv-from-peer error - "); |  | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -1760,9 +1787,7 @@ static int task_main_proxy_2 ( | |||||||
| 			{ | 			{ | ||||||
| 				/* end of output from peer before it has seen a header. | 				/* end of output from peer before it has seen a header. | ||||||
| 				 * the proxy peer must be bad. */ | 				 * the proxy peer must be bad. */ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				DBGOUT_PROXY_ERROR (proxy, "Premature header end from peer"); | ||||||
| 					log_proxy_error (proxy, "proxy premature eof(header) - "); |  | ||||||
|  |  | ||||||
| 				if (!(proxy->resflags & PROXY_RES_RECEIVED_100)) http_errnum = 502; | 				if (!(proxy->resflags & PROXY_RES_RECEIVED_100)) http_errnum = 502; | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| @ -1782,8 +1807,7 @@ static int task_main_proxy_2 ( | |||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				/* premature eof from the peer */ | 				/* premature eof from the peer */ | ||||||
| 				if (httpd->opt.trait & QSE_HTTPD_LOGACT)  | 				DBGOUT_PROXY_ERROR (proxy, "No chunked content from peer"); | ||||||
| 					log_proxy_error (proxy, "proxy no content(chunked) - "); |  | ||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -1886,7 +1910,7 @@ static int task_main_proxy_1 ( | |||||||
| 		int n; | 		int n; | ||||||
|  |  | ||||||
| 		httpd->errnum = QSE_HTTPD_ENOERR; | 		httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 		n = httpd->opt.scb.peer.connected (httpd, &proxy->peer); | 		n = httpd->opt.scb.peer.connected (httpd, proxy->peer); | ||||||
| 		if (n <= -1)  | 		if (n <= -1)  | ||||||
| 		{ | 		{ | ||||||
| 			/* TODO: translate more error codes to http error codes... */ | 			/* TODO: translate more error codes to http error codes... */ | ||||||
| @ -1898,7 +1922,7 @@ static int task_main_proxy_1 ( | |||||||
| 		#if defined(QSE_HTTPD_DEBUG) | 		#if defined(QSE_HTTPD_DEBUG) | ||||||
| 			{ | 			{ | ||||||
| 				qse_mchar_t tmp[128]; | 				qse_mchar_t tmp[128]; | ||||||
| 				qse_nwadtombs (&proxy->peer.nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); | 				qse_nwadtombs (&proxy->peer->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); | ||||||
| 				HTTPD_DBGOUT1 ("Cannnot connect to peer [%hs]\n", tmp); | 				HTTPD_DBGOUT1 ("Cannnot connect to peer [%hs]\n", tmp); | ||||||
| 			} | 			} | ||||||
| 		#endif | 		#endif | ||||||
| @ -1982,11 +2006,11 @@ static void on_peer_name_resolved (qse_httpd_t* httpd, const qse_mchar_t* name, | |||||||
| 	{ | 	{ | ||||||
| 		/* resolved successfully */ | 		/* resolved successfully */ | ||||||
| 		 | 		 | ||||||
| 		proxy->peer.nwad = *nwad; | 		proxy->peer->nwad = *nwad; | ||||||
| 		qse_setnwadport (&proxy->peer.nwad, qse_hton16(proxy->peer_port)); | 		qse_setnwadport (&proxy->peer->nwad, qse_hton16(proxy->peer_port)); | ||||||
|  |  | ||||||
| 		if (proxy->peer.local.type == QSE_NWAD_NX) | 		if (proxy->peer->local.type == QSE_NWAD_NX) | ||||||
| 			proxy->peer.local.type = proxy->peer.nwad.type; | 			proxy->peer->local.type = proxy->peer->nwad.type; | ||||||
|  |  | ||||||
| 		proxy->flags |= PROXY_PEER_NAME_RESOLVED; | 		proxy->flags |= PROXY_PEER_NAME_RESOLVED; | ||||||
| 	} | 	} | ||||||
| @ -2006,7 +2030,7 @@ static void on_peer_name_resolved (qse_httpd_t* httpd, const qse_mchar_t* name, | |||||||
| 	if (proxy->flags & PROXY_PEER_NAME_RESOLVED) | 	if (proxy->flags & PROXY_PEER_NAME_RESOLVED) | ||||||
| 	{ | 	{ | ||||||
| 		qse_mchar_t tmp[128]; | 		qse_mchar_t tmp[128]; | ||||||
| 		qse_nwadtombs (&proxy->peer.nwad, tmp, 128, QSE_NWADTOMBS_ALL); | 		qse_nwadtombs (&proxy->peer->nwad, tmp, 128, QSE_NWADTOMBS_ALL); | ||||||
| 		HTTPD_DBGOUT2 ("Peer name [%hs] resolved to [%hs]\n", name, tmp); | 		HTTPD_DBGOUT2 ("Peer name [%hs] resolved to [%hs]\n", name, tmp); | ||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
| @ -2039,7 +2063,7 @@ static void on_url_rewritten (qse_httpd_t* httpd, const qse_mchar_t* url, const | |||||||
| 				qse_setnwadport (&nwad, qse_hton16(QSE_HTTPD_DEFAULT_PORT)); | 				qse_setnwadport (&nwad, qse_hton16(QSE_HTTPD_DEFAULT_PORT)); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			proxy->peer.nwad = nwad; | 			proxy->peer->nwad = nwad; | ||||||
| 			proxy->flags |= PROXY_URL_REWRITTEN; | 			proxy->flags |= PROXY_URL_REWRITTEN; | ||||||
| 			proxy->flags &= ~PROXY_RESOLVE_PEER_NAME; /* skip dns */ | 			proxy->flags &= ~PROXY_RESOLVE_PEER_NAME; /* skip dns */ | ||||||
| 		} | 		} | ||||||
| @ -2139,9 +2163,9 @@ static void on_url_rewritten (qse_httpd_t* httpd, const qse_mchar_t* url, const | |||||||
|  |  | ||||||
| /* TODO: antything todo when http is rewritten to HTTPS or vice versa */ | /* TODO: antything todo when http is rewritten to HTTPS or vice versa */ | ||||||
| 						if (proto_len == 8) | 						if (proto_len == 8) | ||||||
| 							proxy->peer.flags |= QSE_HTTPD_PEER_SECURE; | 							proxy->peer->flags |= QSE_HTTPD_PEER_SECURE; | ||||||
| 						else | 						else | ||||||
| 							proxy->peer.flags &= ~QSE_HTTPD_PEER_SECURE; | 							proxy->peer->flags &= ~QSE_HTTPD_PEER_SECURE; | ||||||
|  |  | ||||||
| 						if (qse_mbstonwad (tmp, &nwad) <= -1) | 						if (qse_mbstonwad (tmp, &nwad) <= -1) | ||||||
| 						{ | 						{ | ||||||
| @ -2157,14 +2181,14 @@ static void on_url_rewritten (qse_httpd_t* httpd, const qse_mchar_t* url, const | |||||||
| 								qse_setnwadport (&nwad, qse_hton16(proto_len == 8? QSE_HTTPD_DEFAULT_SECURE_PORT: QSE_HTTPD_DEFAULT_PORT)); | 								qse_setnwadport (&nwad, qse_hton16(proto_len == 8? QSE_HTTPD_DEFAULT_SECURE_PORT: QSE_HTTPD_DEFAULT_PORT)); | ||||||
| 							} | 							} | ||||||
|  |  | ||||||
| 							proxy->peer.nwad = nwad; | 							proxy->peer->nwad = nwad; | ||||||
| 							proxy->flags |= PROXY_URL_REWRITTEN; | 							proxy->flags |= PROXY_URL_REWRITTEN; | ||||||
| 							proxy->flags &= ~PROXY_RESOLVE_PEER_NAME; /* skip dns */ | 							proxy->flags &= ~PROXY_RESOLVE_PEER_NAME; /* skip dns */ | ||||||
|  |  | ||||||
| 						#if defined(QSE_HTTPD_DEBUG) | 						#if defined(QSE_HTTPD_DEBUG) | ||||||
| 							{ | 							{ | ||||||
| 								qse_mchar_t tmp[128]; | 								qse_mchar_t tmp[128]; | ||||||
| 								qse_nwadtombs (&proxy->peer.nwad, tmp, 128, QSE_NWADTOMBS_ALL); | 								qse_nwadtombs (&proxy->peer->nwad, tmp, 128, QSE_NWADTOMBS_ALL); | ||||||
| 								HTTPD_DBGOUT4 ("Peer name resolved to [%hs] in url rewriting. new_url [%hs] %d %d\n",  | 								HTTPD_DBGOUT4 ("Peer name resolved to [%hs] in url rewriting. new_url [%hs] %d %d\n",  | ||||||
| 									tmp, new_url, | 									tmp, new_url, | ||||||
| 									(int)proxy->qpath_pos_in_reqfwdbuf, | 									(int)proxy->qpath_pos_in_reqfwdbuf, | ||||||
| @ -2209,6 +2233,7 @@ static int task_main_proxy ( | |||||||
| 	proxy_peer_htrd_xtn_t* xtn; | 	proxy_peer_htrd_xtn_t* xtn; | ||||||
| 	int http_errnum = 500; | 	int http_errnum = 500; | ||||||
| 	int n; | 	int n; | ||||||
|  | 	qse_httpd_peer_t* peer_from_cache; | ||||||
|  |  | ||||||
| 	if (proxy->flags & PROXY_INIT_FAILED)  | 	if (proxy->flags & PROXY_INIT_FAILED)  | ||||||
| 	{ | 	{ | ||||||
| @ -2265,18 +2290,18 @@ static int task_main_proxy ( | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (proxy->dns_preresolve_mod && proxy->dns_preresolve_mod->dns_preresolve) | 		if (proxy->dns_preresolve_mod && proxy->dns_preresolve_mod->dns_preresolve) | ||||||
| 			x = proxy->dns_preresolve_mod->dns_preresolve (proxy->dns_preresolve_mod, client, proxy->peer_name, &proxy->peer.nwad); | 			x = proxy->dns_preresolve_mod->dns_preresolve (proxy->dns_preresolve_mod, client, proxy->peer_name, &proxy->peer->nwad); | ||||||
| 		else | 		else | ||||||
| 			x = httpd->opt.scb.dns.preresolve (httpd, client, proxy->peer_name, &proxy->peer.nwad); | 			x = httpd->opt.scb.dns.preresolve (httpd, client, proxy->peer_name, &proxy->peer->nwad); | ||||||
| 		if (x <= -1) goto oops; | 		if (x <= -1) goto oops; | ||||||
|  |  | ||||||
| 		if (x == 0) | 		if (x == 0) | ||||||
| 		{ | 		{ | ||||||
| 			/* preresolve() indicates that proxy->peer.nwad contains the | 			/* preresolve() indicates that proxy->peer->nwad contains the | ||||||
| 			 * final address. no actual dns resolution is required */ | 			 * final address. no actual dns resolution is required */ | ||||||
| 			proxy->flags |= PROXY_PEER_NAME_RESOLVED; | 			proxy->flags |= PROXY_PEER_NAME_RESOLVED; | ||||||
| 			proxy->flags &= ~PROXY_RESOLVE_PEER_NAME; | 			proxy->flags &= ~PROXY_RESOLVE_PEER_NAME; | ||||||
| 			qse_setnwadport (&proxy->peer.nwad, qse_hton16(proxy->peer_port)); | 			qse_setnwadport (&proxy->peer->nwad, qse_hton16(proxy->peer_port)); | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| @ -2330,37 +2355,84 @@ static int task_main_proxy ( | |||||||
| 	proxy->res_consumed = 0; | 	proxy->res_consumed = 0; | ||||||
| 	proxy->res_pending = 0; | 	proxy->res_pending = 0; | ||||||
|  |  | ||||||
| 	httpd->errnum = QSE_HTTPD_ENOERR; | 	/* get a cached peer connection */ | ||||||
| 	n = httpd->opt.scb.peer.open (httpd, &proxy->peer); | 	peer_from_cache = qse_httpd_decacheproxypeer (httpd, client, &proxy->peer->nwad, &proxy->peer->local, (proxy->peer->flags & QSE_HTTPD_PEER_SECURE)); | ||||||
| 	if (n <= -1) | 	if (peer_from_cache) | ||||||
| 	{ | 	{ | ||||||
| 		/* TODO: translate more error codes to http error codes... */ | 		qse_mchar_t tmpch; | ||||||
| 		if (httpd->errnum == QSE_HTTPD_ENOENT) http_errnum = 404; |  | ||||||
| 		else if (httpd->errnum == QSE_HTTPD_EACCES || | 		QSE_ASSERT (peer_from_cache->flags & QSE_HTTPD_PEER_CACHED); | ||||||
| 		         httpd->errnum == QSE_HTTPD_ECONN) http_errnum = 403; |  | ||||||
|  | 		/* test if the cached connection is still ok */ | ||||||
|  | 		if (httpd->opt.scb.peer.recv (httpd, peer_from_cache, &tmpch, 1) <= -1 &&  | ||||||
|  | 		    httpd->errnum == QSE_HTTPD_EAGAIN) | ||||||
|  | 		{ | ||||||
|  | 			/* this connection seems to be ok. it didn't return EOF nor any data.  | ||||||
|  | 			 * A valid connection can't return data yes as no request has been sent.*/ | ||||||
|  | 		#if defined(QSE_HTTPD_DEBUG) | ||||||
|  | 			{ | ||||||
|  | 				qse_mchar_t tmp[128]; | ||||||
|  | 				qse_nwadtombs (&peer_from_cache->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); | ||||||
|  | 				HTTPD_DBGOUT2 ("Decached peer [%hs] - %zd\n", tmp, (qse_size_t)peer_from_cache->handle); | ||||||
|  | 			} | ||||||
|  | 		#endif | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			/* the cached connection seems to be stale or invalid */ | ||||||
|  | 	#if defined(QSE_HTTPD_DEBUG) | ||||||
|  | 			{ | ||||||
|  | 				qse_mchar_t tmp[128]; | ||||||
|  | 				qse_nwadtombs (&peer_from_cache->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); | ||||||
|  | 				HTTPD_DBGOUT2 ("Decached and closed stale peer [%hs] - %zd\n", tmp, (qse_size_t)peer_from_cache->handle); | ||||||
|  | 			} | ||||||
|  | 	#endif | ||||||
|  | 			httpd->opt.scb.peer.close (httpd, peer_from_cache); | ||||||
|  | 			qse_httpd_freemem (httpd, peer_from_cache); | ||||||
|  |  | ||||||
|  | 			peer_from_cache = QSE_NULL; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (peer_from_cache) | ||||||
|  | 	{ | ||||||
|  | 		proxy->peer = peer_from_cache; /* switch the peer pointer to the one acquired from the cache */ | ||||||
|  | 		n = 1; /* act as if it just got connected */ | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
|  | 		n = httpd->opt.scb.peer.open (httpd, proxy->peer); | ||||||
|  | 		if (n <= -1) | ||||||
|  | 		{ | ||||||
|  | 			/* TODO: translate more error codes to http error codes... */ | ||||||
|  | 			if (httpd->errnum == QSE_HTTPD_ENOENT) http_errnum = 404; | ||||||
|  | 			else if (httpd->errnum == QSE_HTTPD_EACCES || | ||||||
|  | 					 httpd->errnum == QSE_HTTPD_ECONN) http_errnum = 403; | ||||||
|  |  | ||||||
|  | 		#if defined(QSE_HTTPD_DEBUG) | ||||||
|  | 			{ | ||||||
|  | 				qse_mchar_t tmp[128]; | ||||||
|  | 				qse_nwadtombs (&proxy->peer->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); | ||||||
|  | 				HTTPD_DBGOUT1 ("Cannnot open peer [%hs]\n", tmp); | ||||||
|  | 			} | ||||||
|  | 		#endif | ||||||
|  |  | ||||||
|  | 			goto oops; | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 	#if defined(QSE_HTTPD_DEBUG) | 	#if defined(QSE_HTTPD_DEBUG) | ||||||
| 		{ | 		{ | ||||||
| 			qse_mchar_t tmp[128]; | 			qse_mchar_t tmp[128]; | ||||||
| 			qse_nwadtombs (&proxy->peer.nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); | 			qse_nwadtombs (&proxy->peer->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); | ||||||
| 			HTTPD_DBGOUT1 ("Cannnot open peer [%hs]\n", tmp); | 			HTTPD_DBGOUT2 ("Opened peer [%hs] - %zd\n", tmp, (qse_size_t)proxy->peer->handle); | ||||||
| 		} | 		} | ||||||
| 	#endif | 	#endif | ||||||
|  |  | ||||||
| 		goto oops; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| #if defined(QSE_HTTPD_DEBUG) |  | ||||||
| 	{ |  | ||||||
| 		qse_mchar_t tmp[128]; |  | ||||||
| 		qse_nwadtombs (&proxy->peer.nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); |  | ||||||
| 		HTTPD_DBGOUT2 ("Opened peer [%hs] - %zd\n", tmp, (qse_size_t)proxy->peer.handle); |  | ||||||
| 	} |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	proxy->peer_status |= PROXY_PEER_OPEN; | 	proxy->peer_status |= PROXY_PEER_OPEN; | ||||||
| 	task->trigger.v[0].mask = QSE_HTTPD_TASK_TRIGGER_READ; | 	task->trigger.v[0].mask = QSE_HTTPD_TASK_TRIGGER_READ; | ||||||
| 	task->trigger.v[0].handle = proxy->peer.handle; | 	task->trigger.v[0].handle = proxy->peer->handle; | ||||||
| 	/*task->trigger.cmask = QSE_HTTPD_TASK_TRIGGER_READ;*/ | 	/*task->trigger.cmask = QSE_HTTPD_TASK_TRIGGER_READ;*/ | ||||||
| 	task->trigger.cmask = 0; | 	task->trigger.cmask = 0; | ||||||
|  |  | ||||||
|  | |||||||
| @ -814,10 +814,10 @@ static void tmr_dns_tmout_handle (qse_tmr_t* tmr, const qse_ntime_t* now, qse_tm | |||||||
| 	 *---------------------------------------------------------------- */ | 	 *---------------------------------------------------------------- */ | ||||||
| 	if (req->dns_retries > 0) | 	if (req->dns_retries > 0) | ||||||
| 	{ | 	{ | ||||||
| 		httpd_xtn_t* httpd_xtn; | 		/*httpd_xtn_t* httpd_xtn;*/ | ||||||
| 		qse_tmr_event_t tmout_event; | 		qse_tmr_event_t tmout_event; | ||||||
|  |  | ||||||
| 		httpd_xtn = qse_httpd_getxtn (dc->httpd); | 		/*httpd_xtn = qse_httpd_getxtn (dc->httpd);*/ | ||||||
|  |  | ||||||
| 		QSE_MEMSET (&tmout_event, 0, QSE_SIZEOF(tmout_event)); | 		QSE_MEMSET (&tmout_event, 0, QSE_SIZEOF(tmout_event)); | ||||||
| 		qse_gettime (&tmout_event.when); | 		qse_gettime (&tmout_event.when); | ||||||
|  | |||||||
| @ -274,7 +274,7 @@ static void urs_close (qse_httpd_t* httpd, qse_httpd_urs_t* urs) | |||||||
| static int urs_recv (qse_httpd_t* httpd, qse_httpd_urs_t* urs, qse_httpd_hnd_t handle) | static int urs_recv (qse_httpd_t* httpd, qse_httpd_urs_t* urs, qse_httpd_hnd_t handle) | ||||||
| { | { | ||||||
| 	urs_ctx_t* dc = (urs_ctx_t*)urs->ctx; | 	urs_ctx_t* dc = (urs_ctx_t*)urs->ctx; | ||||||
| 	httpd_xtn_t* httpd_xtn; | 	/*httpd_xtn_t* httpd_xtn;*/ | ||||||
|  |  | ||||||
| 	qse_skad_t fromaddr; | 	qse_skad_t fromaddr; | ||||||
| 	qse_sck_len_t fromlen; | 	qse_sck_len_t fromlen; | ||||||
| @ -285,9 +285,7 @@ static int urs_recv (qse_httpd_t* httpd, qse_httpd_urs_t* urs, qse_httpd_hnd_t h | |||||||
| 	urs_req_t* req; | 	urs_req_t* req; | ||||||
| 	qse_mchar_t* spc; | 	qse_mchar_t* spc; | ||||||
|  |  | ||||||
| printf ("URS_RECV............................................\n"); | 	/*httpd_xtn = qse_httpd_getxtn (httpd);*/ | ||||||
|  |  | ||||||
| 	httpd_xtn = qse_httpd_getxtn (httpd); |  | ||||||
|  |  | ||||||
| /* TODO: use recvmsg with MSG_ERRQUEUE... set socket option IP_RECVERR... */ | /* TODO: use recvmsg with MSG_ERRQUEUE... set socket option IP_RECVERR... */ | ||||||
| 	fromlen = QSE_SIZEOF(fromaddr); | 	fromlen = QSE_SIZEOF(fromaddr); | ||||||
| @ -359,10 +357,10 @@ static void tmr_urs_tmout_handle (qse_tmr_t* tmr, const qse_ntime_t* now, qse_tm | |||||||
| 	 *---------------------------------------------------------------- */ | 	 *---------------------------------------------------------------- */ | ||||||
| 	if (req->urs_retries > 0) | 	if (req->urs_retries > 0) | ||||||
| 	{ | 	{ | ||||||
| 		httpd_xtn_t* httpd_xtn; | 		/*httpd_xtn_t* httpd_xtn;*/ | ||||||
| 		qse_tmr_event_t tmout_event; | 		qse_tmr_event_t tmout_event; | ||||||
|  |  | ||||||
| 		httpd_xtn = qse_httpd_getxtn (dc->httpd); | 		/*httpd_xtn = qse_httpd_getxtn (dc->httpd);*/ | ||||||
|  |  | ||||||
| 		QSE_MEMSET (&tmout_event, 0, QSE_SIZEOF(tmout_event)); | 		QSE_MEMSET (&tmout_event, 0, QSE_SIZEOF(tmout_event)); | ||||||
| 		qse_gettime (&tmout_event.when); | 		qse_gettime (&tmout_event.when); | ||||||
|  | |||||||
| @ -1134,6 +1134,192 @@ oops: | |||||||
|  |  | ||||||
| /* ------------------------------------------------------------------- */ | /* ------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | static void client_close (qse_httpd_t* httpd, qse_httpd_client_t* client) | ||||||
|  | { | ||||||
|  | 	qse_shutsckhnd (client->handle, QSE_SHUTSCKHND_RW); | ||||||
|  | 	qse_closesckhnd (client->handle); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void client_shutdown (qse_httpd_t* httpd, qse_httpd_client_t* client) | ||||||
|  | { | ||||||
|  | 	qse_shutsckhnd (client->handle, QSE_SHUTSCKHND_RW); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static qse_ssize_t client_recv ( | ||||||
|  | 	qse_httpd_t* httpd, qse_httpd_client_t* client, | ||||||
|  | 	qse_mchar_t* buf, qse_size_t bufsize) | ||||||
|  | { | ||||||
|  | 	if (client->status & QSE_HTTPD_CLIENT_SECURE) | ||||||
|  | 	{ | ||||||
|  | 	#if defined(HAVE_SSL) | ||||||
|  | 		int ret = SSL_read (HANDLE_TO_SSL(client->handle2), buf, bufsize); | ||||||
|  | 		if (ret <= -1) | ||||||
|  | 		{ | ||||||
|  | 			int err = SSL_get_error(HANDLE_TO_SSL(client->handle2),ret); | ||||||
|  | 			if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) | ||||||
|  | 				qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN); | ||||||
|  | 			else | ||||||
|  | 				qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (SSL_pending (HANDLE_TO_SSL(client->handle2)) > 0)  | ||||||
|  | 			client->status |= QSE_HTTPD_CLIENT_PENDING; | ||||||
|  | 		else | ||||||
|  | 			client->status &= ~QSE_HTTPD_CLIENT_PENDING; | ||||||
|  |  | ||||||
|  | 		return ret; | ||||||
|  | 	#else | ||||||
|  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||||
|  | 		return -1; | ||||||
|  | 	#endif | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		qse_ssize_t ret; | ||||||
|  | 		ret = recv (client->handle, buf, bufsize, 0); | ||||||
|  | 		if (ret <= -1) qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static qse_ssize_t client_send ( | ||||||
|  | 	qse_httpd_t* httpd, qse_httpd_client_t* client, | ||||||
|  | 	const qse_mchar_t* buf, qse_size_t bufsize) | ||||||
|  | { | ||||||
|  | 	if (client->status & QSE_HTTPD_CLIENT_SECURE) | ||||||
|  | 	{ | ||||||
|  | 	#if defined(HAVE_SSL) | ||||||
|  | 		int ret = SSL_write (HANDLE_TO_SSL(client->handle2), buf, bufsize); | ||||||
|  | 		if (ret <= -1) | ||||||
|  | 		{ | ||||||
|  | 			int err = SSL_get_error(HANDLE_TO_SSL(client->handle2),ret); | ||||||
|  | 			if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) | ||||||
|  | 				qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN); | ||||||
|  | 			else | ||||||
|  | 				qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); | ||||||
|  | 		} | ||||||
|  | 		return ret; | ||||||
|  | 	#else | ||||||
|  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||||
|  | 		return -1; | ||||||
|  | 	#endif | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		qse_ssize_t ret = send (client->handle, buf, bufsize, 0); | ||||||
|  | 		if (ret <= -1) qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static qse_ssize_t client_sendfile ( | ||||||
|  | 	qse_httpd_t* httpd, qse_httpd_client_t* client, | ||||||
|  | 	qse_httpd_hnd_t handle, qse_foff_t* offset, qse_size_t count) | ||||||
|  | { | ||||||
|  | 	if (client->status & QSE_HTTPD_CLIENT_SECURE) | ||||||
|  | 	{ | ||||||
|  | 		return __send_file_ssl (httpd, (void*)client->handle2, handle, offset, count); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		return __send_file (httpd, client->handle, handle, offset, count); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client) | ||||||
|  | { | ||||||
|  | 	if (client->status & QSE_HTTPD_CLIENT_SECURE) | ||||||
|  | 	{ | ||||||
|  | 	#if defined(HAVE_SSL) | ||||||
|  | 		int ret; | ||||||
|  | 		SSL* ssl; | ||||||
|  | 		server_xtn_t* server_xtn; | ||||||
|  |  | ||||||
|  | 		server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, client->server); | ||||||
|  |  | ||||||
|  | 		 | ||||||
|  | 		if (!server_xtn->ssl_ctx) | ||||||
|  | 		{ | ||||||
|  | 			/* performed the delayed ssl initialization */ | ||||||
|  | 			if (init_server_ssl (httpd, client->server) <= -1) return -1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		QSE_ASSERT (server_xtn->ssl_ctx != QSE_NULL); | ||||||
|  | 		QSE_ASSERT (QSE_SIZEOF(client->handle2) >= QSE_SIZEOF(ssl)); | ||||||
|  |  | ||||||
|  | 		if (HANDLE_TO_SSL(client->handle2)) | ||||||
|  | 		{ | ||||||
|  | 			ssl = HANDLE_TO_SSL(client->handle2); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			ssl = SSL_new (server_xtn->ssl_ctx); | ||||||
|  | 			if (ssl == QSE_NULL)  | ||||||
|  | 			{ | ||||||
|  | 				httpd->errnum = QSE_HTTPD_ESYSERR; | ||||||
|  | 				return -1; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			client->handle2 = SSL_TO_HANDLE(ssl); | ||||||
|  | 			if (SSL_set_fd (ssl, client->handle) == 0) | ||||||
|  | 			{ | ||||||
|  | 				/* don't free ssl here since client_closed() | ||||||
|  | 				 * will free it */ | ||||||
|  | 				httpd->errnum = QSE_HTTPD_ESYSERR; | ||||||
|  | 				return -1; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			SSL_set_read_ahead (ssl, 0); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		ret = SSL_accept (ssl); | ||||||
|  | 		if (ret <= 0) | ||||||
|  | 		{ | ||||||
|  | 			int err = SSL_get_error(ssl, ret); | ||||||
|  | 			if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) | ||||||
|  | 			{ | ||||||
|  | 				/* handshaking isn't complete. */ | ||||||
|  | 				return 0; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||||
|  | 			{ | ||||||
|  | 				qse_httpd_act_t msg; | ||||||
|  | 				msg.code = QSE_HTTPD_CATCH_MERRMSG; | ||||||
|  | 				ERR_error_string_n (err, msg.u.merrmsg, QSE_COUNTOF(msg.u.merrmsg)); | ||||||
|  | 				httpd->opt.rcb.logact (httpd, &msg); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			/* client_closed() free this. no SSL_free() here. | ||||||
|  | 			SSL_free (ssl); */ | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	#else | ||||||
|  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||||
|  | 		return -1; | ||||||
|  | 	#endif | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return 1; /* accept completed */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void client_closed (qse_httpd_t* httpd, qse_httpd_client_t* client) | ||||||
|  | { | ||||||
|  | 	if (client->status & QSE_HTTPD_CLIENT_SECURE) | ||||||
|  | 	{ | ||||||
|  | 	#if defined(HAVE_SSL) | ||||||
|  | 		if ((SSL*)client->handle2) | ||||||
|  | 		{ | ||||||
|  | 			SSL_shutdown ((SSL*)client->handle2); /* is this needed? */ | ||||||
|  | 			SSL_free ((SSL*)client->handle2); | ||||||
|  | 		} | ||||||
|  | 	#endif | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* ------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
| static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | ||||||
| { | { | ||||||
| 	/* -------------------------------------------------------------------- */ | 	/* -------------------------------------------------------------------- */ | ||||||
| @ -2130,193 +2316,6 @@ static int dir_read (qse_httpd_t* httpd, qse_httpd_hnd_t handle, qse_httpd_diren | |||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* ------------------------------------------------------------------- */ |  | ||||||
|  |  | ||||||
| static void client_close (qse_httpd_t* httpd, qse_httpd_client_t* client) |  | ||||||
| { |  | ||||||
| 	qse_shutsckhnd (client->handle, QSE_SHUTSCKHND_RW); |  | ||||||
| 	qse_closesckhnd (client->handle); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void client_shutdown (qse_httpd_t* httpd, qse_httpd_client_t* client) |  | ||||||
| { |  | ||||||
| 	qse_shutsckhnd (client->handle, QSE_SHUTSCKHND_RW); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static qse_ssize_t client_recv ( |  | ||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client, |  | ||||||
| 	qse_mchar_t* buf, qse_size_t bufsize) |  | ||||||
| { |  | ||||||
| 	if (client->status & QSE_HTTPD_CLIENT_SECURE) |  | ||||||
| 	{ |  | ||||||
| 	#if defined(HAVE_SSL) |  | ||||||
| 		int ret = SSL_read (HANDLE_TO_SSL(client->handle2), buf, bufsize); |  | ||||||
| 		if (ret <= -1) |  | ||||||
| 		{ |  | ||||||
| 			int err = SSL_get_error(HANDLE_TO_SSL(client->handle2),ret); |  | ||||||
| 			if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) |  | ||||||
| 				qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN); |  | ||||||
| 			else |  | ||||||
| 				qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (SSL_pending (HANDLE_TO_SSL(client->handle2)) > 0)  |  | ||||||
| 			client->status |= QSE_HTTPD_CLIENT_PENDING; |  | ||||||
| 		else |  | ||||||
| 			client->status &= ~QSE_HTTPD_CLIENT_PENDING; |  | ||||||
|  |  | ||||||
| 		return ret; |  | ||||||
| 	#else |  | ||||||
| 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); |  | ||||||
| 		return -1; |  | ||||||
| 	#endif |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		qse_ssize_t ret; |  | ||||||
| 		ret = recv (client->handle, buf, bufsize, 0); |  | ||||||
| 		if (ret <= -1) qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); |  | ||||||
| 		return ret; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static qse_ssize_t client_send ( |  | ||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client, |  | ||||||
| 	const qse_mchar_t* buf, qse_size_t bufsize) |  | ||||||
| { |  | ||||||
| 	if (client->status & QSE_HTTPD_CLIENT_SECURE) |  | ||||||
| 	{ |  | ||||||
| 	#if defined(HAVE_SSL) |  | ||||||
| 		int ret = SSL_write (HANDLE_TO_SSL(client->handle2), buf, bufsize); |  | ||||||
| 		if (ret <= -1) |  | ||||||
| 		{ |  | ||||||
| 			int err = SSL_get_error(HANDLE_TO_SSL(client->handle2),ret); |  | ||||||
| 			if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) |  | ||||||
| 				qse_httpd_seterrnum (httpd, QSE_HTTPD_EAGAIN); |  | ||||||
| 			else |  | ||||||
| 				qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); |  | ||||||
| 		} |  | ||||||
| 		return ret; |  | ||||||
| 	#else |  | ||||||
| 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); |  | ||||||
| 		return -1; |  | ||||||
| 	#endif |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		qse_ssize_t ret = send (client->handle, buf, bufsize, 0); |  | ||||||
| 		if (ret <= -1) qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); |  | ||||||
| 		return ret; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static qse_ssize_t client_sendfile ( |  | ||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client, |  | ||||||
| 	qse_httpd_hnd_t handle, qse_foff_t* offset, qse_size_t count) |  | ||||||
| { |  | ||||||
| 	if (client->status & QSE_HTTPD_CLIENT_SECURE) |  | ||||||
| 	{ |  | ||||||
| 		return __send_file_ssl (httpd, (void*)client->handle2, handle, offset, count); |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		return __send_file (httpd, client->handle, handle, offset, count); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client) |  | ||||||
| { |  | ||||||
| 	if (client->status & QSE_HTTPD_CLIENT_SECURE) |  | ||||||
| 	{ |  | ||||||
| 	#if defined(HAVE_SSL) |  | ||||||
| 		int ret; |  | ||||||
| 		SSL* ssl; |  | ||||||
| 		server_xtn_t* server_xtn; |  | ||||||
|  |  | ||||||
| 		server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, client->server); |  | ||||||
|  |  | ||||||
| 		 |  | ||||||
| 		if (!server_xtn->ssl_ctx) |  | ||||||
| 		{ |  | ||||||
| 			/* performed the delayed ssl initialization */ |  | ||||||
| 			if (init_server_ssl (httpd, client->server) <= -1) return -1; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		QSE_ASSERT (server_xtn->ssl_ctx != QSE_NULL); |  | ||||||
| 		QSE_ASSERT (QSE_SIZEOF(client->handle2) >= QSE_SIZEOF(ssl)); |  | ||||||
|  |  | ||||||
| 		if (HANDLE_TO_SSL(client->handle2)) |  | ||||||
| 		{ |  | ||||||
| 			ssl = HANDLE_TO_SSL(client->handle2); |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			ssl = SSL_new (server_xtn->ssl_ctx); |  | ||||||
| 			if (ssl == QSE_NULL)  |  | ||||||
| 			{ |  | ||||||
| 				httpd->errnum = QSE_HTTPD_ESYSERR; |  | ||||||
| 				return -1; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			client->handle2 = SSL_TO_HANDLE(ssl); |  | ||||||
| 			if (SSL_set_fd (ssl, client->handle) == 0) |  | ||||||
| 			{ |  | ||||||
| 				/* don't free ssl here since client_closed() |  | ||||||
| 				 * will free it */ |  | ||||||
| 				httpd->errnum = QSE_HTTPD_ESYSERR; |  | ||||||
| 				return -1; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			SSL_set_read_ahead (ssl, 0); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		ret = SSL_accept (ssl); |  | ||||||
| 		if (ret <= 0) |  | ||||||
| 		{ |  | ||||||
| 			int err = SSL_get_error(ssl, ret); |  | ||||||
| 			if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) |  | ||||||
| 			{ |  | ||||||
| 				/* handshaking isn't complete. */ |  | ||||||
| 				return 0; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if (httpd->opt.trait & QSE_HTTPD_LOGACT) |  | ||||||
| 			{ |  | ||||||
| 				qse_httpd_act_t msg; |  | ||||||
| 				msg.code = QSE_HTTPD_CATCH_MERRMSG; |  | ||||||
| 				ERR_error_string_n (err, msg.u.merrmsg, QSE_COUNTOF(msg.u.merrmsg)); |  | ||||||
| 				httpd->opt.rcb.logact (httpd, &msg); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			/* client_closed() free this. no SSL_free() here. |  | ||||||
| 			SSL_free (ssl); */ |  | ||||||
| 			return -1; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 	#else |  | ||||||
| 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); |  | ||||||
| 		return -1; |  | ||||||
| 	#endif |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return 1; /* accept completed */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void client_closed (qse_httpd_t* httpd, qse_httpd_client_t* client) |  | ||||||
| { |  | ||||||
| 	if (client->status & QSE_HTTPD_CLIENT_SECURE) |  | ||||||
| 	{ |  | ||||||
| 	#if defined(HAVE_SSL) |  | ||||||
| 		if ((SSL*)client->handle2) |  | ||||||
| 		{ |  | ||||||
| 			SSL_shutdown ((SSL*)client->handle2); /* is this needed? */ |  | ||||||
| 			SSL_free ((SSL*)client->handle2); |  | ||||||
| 		} |  | ||||||
| 	#endif |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* ------------------------------------------------------------------- */ | /* ------------------------------------------------------------------- */ | ||||||
| #if 0 | #if 0 | ||||||
| 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) | ||||||
| @ -2606,6 +2605,18 @@ static qse_httpd_scb_t httpd_system_callbacks = | |||||||
| 		server_accept | 		server_accept | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
|  | 	/* client connection */ | ||||||
|  | 	{  | ||||||
|  | 		client_close, | ||||||
|  | 		client_shutdown, | ||||||
|  | 		client_recv, | ||||||
|  | 		client_send, | ||||||
|  | 		client_sendfile, | ||||||
|  | 		client_accepted, | ||||||
|  | 		client_closed | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	/* proxy peer */ | ||||||
| 	{  | 	{  | ||||||
| 		peer_open, | 		peer_open, | ||||||
| 		peer_close, | 		peer_close, | ||||||
| @ -2647,17 +2658,6 @@ static qse_httpd_scb_t httpd_system_callbacks = | |||||||
| 		dir_read | 		dir_read | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	/* client connection */ |  | ||||||
| 	{  |  | ||||||
| 		client_close, |  | ||||||
| 		client_shutdown, |  | ||||||
| 		client_recv, |  | ||||||
| 		client_send, |  | ||||||
| 		client_sendfile, |  | ||||||
| 		client_accepted, |  | ||||||
| 		client_closed |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	/* dns */ | 	/* dns */ | ||||||
| 	{ | 	{ | ||||||
| 		dns_open, | 		dns_open, | ||||||
|  | |||||||
| @ -406,8 +406,7 @@ static qse_httpd_real_task_t* enqueue_task ( | |||||||
| 	return new_task; | 	return new_task; | ||||||
| } | } | ||||||
|  |  | ||||||
| static QSE_INLINE int dequeue_task ( | static QSE_INLINE int dequeue_task (qse_httpd_t* httpd, qse_httpd_client_t* client) | ||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client) |  | ||||||
| { | { | ||||||
| 	qse_httpd_real_task_t* task; | 	qse_httpd_real_task_t* task; | ||||||
| 	qse_size_t i; | 	qse_size_t i; | ||||||
| @ -447,14 +446,134 @@ static QSE_INLINE int dequeue_task ( | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static QSE_INLINE void purge_tasks ( | static QSE_INLINE void purge_tasks (qse_httpd_t* httpd, qse_httpd_client_t* client) | ||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client) |  | ||||||
| { | { | ||||||
| 	while (dequeue_task (httpd, client) == 0); | 	while (dequeue_task (httpd, client) == 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* ----------------------------------------------------------------------- */ | /* ----------------------------------------------------------------------- */ | ||||||
|  |  | ||||||
|  | static QSE_INLINE void unchain_cached_proxy_peer (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_peer_t* peer) | ||||||
|  | { | ||||||
|  | 	QSE_ASSERT (peer->flags & QSE_HTTPD_PEER_CACHED); | ||||||
|  |  | ||||||
|  | 	if (peer->next) peer->next->prev = peer->prev; | ||||||
|  | 	else client->peer.last = peer->prev; | ||||||
|  |  | ||||||
|  | 	if (peer->prev) peer->prev->next = peer->next; | ||||||
|  | 	else client->peer.first = peer->next; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void purge_cached_proxy_peer (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_peer_t* peer) | ||||||
|  | { | ||||||
|  | 	unchain_cached_proxy_peer (httpd, client, peer); | ||||||
|  |  | ||||||
|  | #if defined(QSE_HTTPD_DEBUG) | ||||||
|  | 	{ | ||||||
|  | 		qse_mchar_t tmp[128]; | ||||||
|  |  | ||||||
|  | 		qse_nwadtombs (&peer->nwad, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); | ||||||
|  | 		HTTPD_DBGOUT2 ("Closing cached peer [%hs] - %zd\n", tmp, (qse_size_t)peer->handle); | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | 	httpd->opt.scb.peer.close (httpd, peer); | ||||||
|  | 	qse_httpd_freemem (httpd, peer); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void purge_cached_proxy_peers (qse_httpd_t* httpd, qse_httpd_client_t* client) | ||||||
|  | { | ||||||
|  | 	while (client->peer.first) | ||||||
|  | 	{ | ||||||
|  | 		purge_cached_proxy_peer (httpd, client, client->peer.first); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | qse_httpd_peer_t* qse_httpd_cacheproxypeer (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_peer_t* tmpl) | ||||||
|  | { | ||||||
|  | 	qse_httpd_peer_t* peer; | ||||||
|  |  | ||||||
|  | 	if (tmpl->flags & QSE_HTTPD_PEER_CACHED) | ||||||
|  | 	{ | ||||||
|  | 		/* If QSE_HTTPD_PEER_CACHED is set, tmpl points to a block allocated | ||||||
|  | 		 * here previously. Link such a block to the cache list */ | ||||||
|  | 		peer = tmpl; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		/* Clone the peer object if it's not previsouly allocated here */ | ||||||
|  | 		peer = qse_httpd_allocmem (httpd, QSE_SIZEOF(*peer)); | ||||||
|  | 		if (peer == QSE_NULL) goto oops; | ||||||
|  |  | ||||||
|  | 		QSE_MEMCPY (peer, tmpl, QSE_SIZEOF(*peer)); | ||||||
|  | 		peer->flags |= QSE_HTTPD_PEER_CACHED; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* place the peer at the back of the peer list of a client */ | ||||||
|  | 	if (client->peer.last) | ||||||
|  | 	{ | ||||||
|  | 		peer->next = QSE_NULL; | ||||||
|  | 		peer->prev = client->peer.last; | ||||||
|  | 		client->peer.last->next = peer; | ||||||
|  | 		client->peer.last = peer; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		peer->next = QSE_NULL; | ||||||
|  | 		peer->prev = QSE_NULL; | ||||||
|  | 		client->peer.first = peer; | ||||||
|  | 		client->peer.last = peer; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	qse_gettime (&peer->timestamp); | ||||||
|  | 	return peer; | ||||||
|  |  | ||||||
|  | oops: | ||||||
|  | 	if (peer) qse_httpd_freemem (httpd, peer); | ||||||
|  | 	return QSE_NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | qse_httpd_peer_t* qse_httpd_decacheproxypeer ( | ||||||
|  | 	qse_httpd_t* httpd, qse_httpd_client_t* client,  | ||||||
|  | 	const qse_nwad_t* nwad, const qse_nwad_t* local, int secure) | ||||||
|  | { | ||||||
|  | 	qse_httpd_peer_t* peer, * next; | ||||||
|  | 	qse_ntime_t now, diff; | ||||||
|  | 	static qse_ntime_t diff_limit = { 5, 0 }; /* TODO: make this configurable */ | ||||||
|  |  | ||||||
|  | 	qse_gettime (&now); | ||||||
|  |  | ||||||
|  | 	peer = client->peer.first; | ||||||
|  | 	while (peer) | ||||||
|  | 	{ | ||||||
|  | 		next = peer->next; | ||||||
|  |  | ||||||
|  | 		qse_subtime (&now, &peer->timestamp, &diff); | ||||||
|  | 		if (qse_cmptime(&diff, &diff_limit) >= 0) | ||||||
|  | 		{ | ||||||
|  | 			/* the entry is too old */ | ||||||
|  | 			purge_cached_proxy_peer (httpd, client, peer); | ||||||
|  | 		} | ||||||
|  | 		else if (qse_nwadequal (nwad, &peer->nwad) && qse_nwadequal (local, &peer->local)) | ||||||
|  | 		{ | ||||||
|  | 			if ((secure && (peer->flags & QSE_HTTPD_PEER_SECURE)) || | ||||||
|  | 			    (!secure && !(peer->flags & QSE_HTTPD_PEER_SECURE)))  | ||||||
|  | 			{ | ||||||
|  | 				unchain_cached_proxy_peer (httpd, client, peer); | ||||||
|  | 				peer->next = QSE_NULL; | ||||||
|  | 				peer->prev = QSE_NULL; | ||||||
|  | 				return peer; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		peer = next; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return QSE_NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* ----------------------------------------------------------------------- */ | ||||||
| static int htrd_peek_request (qse_htrd_t* htrd, qse_htre_t* req) | static int htrd_peek_request (qse_htrd_t* htrd, qse_htre_t* req) | ||||||
| { | { | ||||||
| 	htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (htrd); | 	htrd_xtn_t* xtn = (htrd_xtn_t*) qse_htrd_getxtn (htrd); | ||||||
| @ -560,12 +679,12 @@ oops: | |||||||
| 	return QSE_NULL; | 	return QSE_NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void free_client ( | static void free_client (qse_httpd_t* httpd, qse_httpd_client_t* client) | ||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client) |  | ||||||
| { | { | ||||||
| 	QSE_ASSERT (client->htrd != QSE_NULL); | 	QSE_ASSERT (client->htrd != QSE_NULL); | ||||||
|  |  | ||||||
| 	purge_tasks (httpd, client); | 	purge_tasks (httpd, client); | ||||||
|  | 	purge_cached_proxy_peers (httpd, client); | ||||||
|  |  | ||||||
| 	qse_htrd_close (client->htrd); | 	qse_htrd_close (client->htrd); | ||||||
|  |  | ||||||
| @ -611,7 +730,7 @@ static void purge_client (qse_httpd_t* httpd, qse_httpd_client_t* client) | |||||||
| 	{ | 	{ | ||||||
| 		qse_mchar_t tmp[128]; | 		qse_mchar_t tmp[128]; | ||||||
| 		qse_nwadtombs (&client->remote_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); | 		qse_nwadtombs (&client->remote_addr, tmp, QSE_COUNTOF(tmp), QSE_NWADTOMBS_ALL); | ||||||
| 		HTTPD_DBGOUT2 ("Purged client [%hs] - %zd\n", tmp, (qse_size_t)client->handle); | 		HTTPD_DBGOUT2 ("Purging client [%hs] - %zd\n", tmp, (qse_size_t)client->handle); | ||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | |||||||
| @ -192,6 +192,20 @@ void qse_httpd_remove_timer_event ( | |||||||
| 	qse_tmr_index_t  index | 	qse_tmr_index_t  index | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | qse_httpd_peer_t* qse_httpd_cacheproxypeer ( | ||||||
|  | 	qse_httpd_t*        httpd, | ||||||
|  | 	qse_httpd_client_t* client, | ||||||
|  | 	qse_httpd_peer_t*   tmpl | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | qse_httpd_peer_t* qse_httpd_decacheproxypeer ( | ||||||
|  | 	qse_httpd_t*        httpd, | ||||||
|  | 	qse_httpd_client_t* client,  | ||||||
|  | 	const qse_nwad_t*   nwad, | ||||||
|  | 	const qse_nwad_t*   local, | ||||||
|  | 	int                 secure | ||||||
|  | ); | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user