added https proxying without certificate check. this is different from CONNECT. when this feature is used, the proxy establishes a https connection to the origin server
This commit is contained in:
		| @ -199,6 +199,7 @@ struct loccfg_t | |||||||
| 	struct | 	struct | ||||||
| 	{ | 	{ | ||||||
| 		unsigned int allow_http: 1; | 		unsigned int allow_http: 1; | ||||||
|  | 		unsigned int allow_https: 1; | ||||||
| 		unsigned int allow_connect: 1; | 		unsigned int allow_connect: 1; | ||||||
| 		unsigned int allow_intercept: 2; /* 0: no, 1: proxy, 2: local */ | 		unsigned int allow_intercept: 2; /* 0: no, 1: proxy, 2: local */ | ||||||
| 		unsigned int allow_upgrade: 1; | 		unsigned int allow_upgrade: 1; | ||||||
| @ -468,6 +469,7 @@ static int get_server_root ( | |||||||
| { | { | ||||||
| 	qse_http_method_t mth; | 	qse_http_method_t mth; | ||||||
| 	qse_mchar_t* qpath; | 	qse_mchar_t* qpath; | ||||||
|  | 	int proto_len; | ||||||
|  |  | ||||||
| 	qse_memset (root, 0, QSE_SIZEOF(*root)); | 	qse_memset (root, 0, QSE_SIZEOF(*root)); | ||||||
| 	mth = qse_htre_getqmethodtype (qinfo->req); | 	mth = qse_htre_getqmethodtype (qinfo->req); | ||||||
| @ -534,13 +536,12 @@ static int get_server_root ( | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| /* TODO: handle https:// .... */ | 	if ((loccfg->proxy.allow_http && qse_mbszcasecmp (qpath, QSE_MT("http://"), (proto_len = 7)) == 0) || | ||||||
| 	if (loccfg->proxy.allow_http && | 	    (loccfg->proxy.allow_https && qse_mbszcasecmp (qpath, QSE_MT("https://"), (proto_len = 8)) == 0)) | ||||||
| 	    qse_mbszcasecmp (qpath, QSE_MT("http://"), 7) == 0) |  | ||||||
| 	{ | 	{ | ||||||
| 		qse_mchar_t* host, * slash; | 		qse_mchar_t* host, * slash; | ||||||
|  |  | ||||||
| 		host = qpath + 7; | 		host = qpath + proto_len; | ||||||
| 		slash = qse_mbschr (host, QSE_MT('/')); | 		slash = qse_mbschr (host, QSE_MT('/')); | ||||||
|  |  | ||||||
| 		if (slash && slash - host > 0) | 		if (slash && slash - host > 0) | ||||||
| @ -561,6 +562,7 @@ static int get_server_root ( | |||||||
| 			host = host - 1; | 			host = host - 1; | ||||||
| 			root->u.proxy.host = host; | 			root->u.proxy.host = host; | ||||||
|  |  | ||||||
|  | 			if (proto_len == 8) root->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_DST_SECURE; | ||||||
| 			if (qse_mbstonwad (host, &root->u.proxy.dst.nwad) <= -1)  | 			if (qse_mbstonwad (host, &root->u.proxy.dst.nwad) <= -1)  | ||||||
| 			{ | 			{ | ||||||
| 				root->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_DST_STR; | 				root->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_DST_STR; | ||||||
| @ -576,7 +578,6 @@ static int get_server_root ( | |||||||
|  |  | ||||||
| /* TODO: refrain from manipulating the request like this */ | /* TODO: refrain from manipulating the request like this */ | ||||||
| 			qinfo->req->u.q.path = slash; /* TODO: use setqpath or something... */ | 			qinfo->req->u.q.path = slash; /* TODO: use setqpath or something... */ | ||||||
|  |  | ||||||
| 			goto proxy_ok; | 			goto proxy_ok; | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| @ -1513,6 +1514,11 @@ static int load_loccfg_proxy (qse_httpd_t* httpd, qse_xli_t* xli, qse_xli_list_t | |||||||
| 	if (!pair && default_proxy) pair = qse_xli_findpair (xli, default_proxy, QSE_T("http")); /* server-default.proxy.http */ | 	if (!pair && default_proxy) pair = qse_xli_findpair (xli, default_proxy, QSE_T("http")); /* server-default.proxy.http */ | ||||||
| 	if (pair) cfg->proxy.allow_http = get_boolean ((qse_xli_str_t*)pair->val); | 	if (pair) cfg->proxy.allow_http = get_boolean ((qse_xli_str_t*)pair->val); | ||||||
|  |  | ||||||
|  | 	pair = QSE_NULL; | ||||||
|  | 	if (proxy) pair = qse_xli_findpair (xli, proxy, QSE_T("https")); /* server.host[].location[].proxy.https */ | ||||||
|  | 	if (!pair && default_proxy) pair = qse_xli_findpair (xli, default_proxy, QSE_T("https")); /* server-default.proxy.https */ | ||||||
|  | 	if (pair) cfg->proxy.allow_https = get_boolean ((qse_xli_str_t*)pair->val); | ||||||
|  |  | ||||||
| 	pair = QSE_NULL; | 	pair = QSE_NULL; | ||||||
| 	if (proxy) pair = qse_xli_findpair (xli, proxy, QSE_T("connect")); | 	if (proxy) pair = qse_xli_findpair (xli, proxy, QSE_T("connect")); | ||||||
| 	if (!pair && default_proxy) pair = qse_xli_findpair (xli, default_proxy, QSE_T("connect")); | 	if (!pair && default_proxy) pair = qse_xli_findpair (xli, default_proxy, QSE_T("connect")); | ||||||
| @ -2067,6 +2073,7 @@ static int open_config_file (qse_httpd_t* httpd) | |||||||
| 		{ QSE_T("server-default.error-foot"),                        { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | 		{ QSE_T("server-default.error-foot"),                        { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | ||||||
| 		{ QSE_T("server-default.proxy"),                             { QSE_XLI_SCM_VALLIST | QSE_XLI_SCM_KEYNODUP, 0, 0      }  }, | 		{ QSE_T("server-default.proxy"),                             { QSE_XLI_SCM_VALLIST | QSE_XLI_SCM_KEYNODUP, 0, 0      }  }, | ||||||
| 		{ QSE_T("server-default.proxy.http"),                        { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | 		{ QSE_T("server-default.proxy.http"),                        { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | ||||||
|  | 		{ QSE_T("server-default.proxy.https"),                       { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | ||||||
| 		{ QSE_T("server-default.proxy.connect"),                     { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | 		{ QSE_T("server-default.proxy.connect"),                     { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | ||||||
| 		{ QSE_T("server-default.proxy.intercept"),                   { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | 		{ QSE_T("server-default.proxy.intercept"),                   { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | ||||||
| 		{ QSE_T("server-default.proxy.upgrade"),                     { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | 		{ QSE_T("server-default.proxy.upgrade"),                     { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | ||||||
| @ -2125,6 +2132,7 @@ static int open_config_file (qse_httpd_t* httpd) | |||||||
| 		{ QSE_T("server.host.location.error-foot"),                  { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | 		{ QSE_T("server.host.location.error-foot"),                  { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | ||||||
| 		{ QSE_T("server.host.location.proxy"),                       { QSE_XLI_SCM_VALLIST | QSE_XLI_SCM_KEYNODUP, 0, 0      }  }, | 		{ QSE_T("server.host.location.proxy"),                       { QSE_XLI_SCM_VALLIST | QSE_XLI_SCM_KEYNODUP, 0, 0      }  }, | ||||||
| 		{ QSE_T("server.host.location.proxy.http"),                  { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | 		{ QSE_T("server.host.location.proxy.http"),                  { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | ||||||
|  | 		{ QSE_T("server.host.location.proxy.https"),                 { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | ||||||
| 		{ QSE_T("server.host.location.proxy.connect"),               { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | 		{ QSE_T("server.host.location.proxy.connect"),               { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | ||||||
| 		{ QSE_T("server.host.location.proxy.intercept"),             { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | 		{ QSE_T("server.host.location.proxy.intercept"),             { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | ||||||
| 		{ QSE_T("server.host.location.proxy.upgrade"),               { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | 		{ QSE_T("server.host.location.proxy.upgrade"),               { QSE_XLI_SCM_VALSTR  | QSE_XLI_SCM_KEYNODUP, 1, 1      }  }, | ||||||
|  | |||||||
| @ -58,7 +58,8 @@ enum qse_httpd_errnum_t | |||||||
| 	QSE_HTTPD_EAGAIN, | 	QSE_HTTPD_EAGAIN, | ||||||
|  |  | ||||||
| 	QSE_HTTPD_ENOSVR,  /* no active servers */ | 	QSE_HTTPD_ENOSVR,  /* no active servers */ | ||||||
| 	QSE_HTTPD_ECONN, | 	QSE_HTTPD_ECONN,   /* connection failure */ | ||||||
|  | 	QSE_HTTPD_ESCONN,  /* secure connection failure */ | ||||||
| 	QSE_HTTPD_ENOBUF,  /* no buffer available */ | 	QSE_HTTPD_ENOBUF,  /* no buffer available */ | ||||||
| 	QSE_HTTPD_EDISCON, /* client disconnnected */ | 	QSE_HTTPD_EDISCON, /* client disconnnected */ | ||||||
| 	QSE_HTTPD_EBADREQ, /* bad request */ | 	QSE_HTTPD_EBADREQ, /* bad request */ | ||||||
| @ -146,12 +147,31 @@ struct qse_httpd_stat_t | |||||||
| 	qse_ntime_t mtime; | 	qse_ntime_t mtime; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | enum qse_httpd_peer_flag_t | ||||||
|  | { | ||||||
|  | 	QSE_HTTPD_PEER_SECURE = (1 << 0), | ||||||
|  |  | ||||||
|  | 	/* ---------------------------------- */ | ||||||
|  |  | ||||||
|  | 	/* indicate the underlying socket is connected. internal use only. don't set it */ | ||||||
|  | 	QSE_HTTPD_PEER_CONNECTED = (1 << 20), | ||||||
|  | 	 | ||||||
|  | 	/* internal use only */ | ||||||
|  | 	QSE_HTTPD_PEER_PENDING = (1 << 21), | ||||||
|  |  | ||||||
|  | 	/* all internal enumerators */ | ||||||
|  | 	QSE_HTTPD_PEER_ALL_INTERNALS = (QSE_HTTPD_PEER_CONNECTED | QSE_HTTPD_PEER_PENDING) | ||||||
|  | }; | ||||||
|  | typedef enum qse_httpd_peer_flag_t qse_httpd_peer_flag_t; | ||||||
|  |  | ||||||
| typedef struct qse_httpd_peer_t qse_httpd_peer_t; | 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 */ | ||||||
| 	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 */ | ||||||
| 	qse_httpd_hnd_t  handle; | 	qse_httpd_hnd_t handle; | ||||||
|  | 	qse_httpd_hnd_t handle2; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| enum qse_httpd_mux_mask_t | enum qse_httpd_mux_mask_t | ||||||
| @ -529,7 +549,7 @@ typedef struct qse_httpd_task_trigger_t qse_httpd_task_trigger_t; | |||||||
| struct qse_httpd_task_trigger_t | struct qse_httpd_task_trigger_t | ||||||
| { | { | ||||||
| 	int flags; /**< [IN] bitwise-ORed of #qse_httpd_task_trigger_flag_t enumerators*/ | 	int flags; /**< [IN] bitwise-ORed of #qse_httpd_task_trigger_flag_t enumerators*/ | ||||||
| 	int cmask; /* client mask - QSE_HTTPD_TASK_TRIGGER_READ | QSE_HTTPD_TASK_TRIGGER_WRITE */ | 	unsigned int cmask; /* client mask - QSE_HTTPD_TASK_TRIGGER_READ | QSE_HTTPD_TASK_TRIGGER_WRITE */ | ||||||
| 	struct | 	struct | ||||||
| 	{ | 	{ | ||||||
| 		int       mask; /* QSE_HTTPD_TASK_TRIGGER_READ | QSE_HTTPD_TASK_TRIGGER_WRITE */ | 		int       mask; /* QSE_HTTPD_TASK_TRIGGER_READ | QSE_HTTPD_TASK_TRIGGER_WRITE */ | ||||||
| @ -772,10 +792,11 @@ enum qse_httpd_rsrc_proxy_flag_t | |||||||
| 	QSE_HTTPD_RSRC_PROXY_ALLOW_UPGRADE   = (1 << 2), /* allow protocol upgrade */ | 	QSE_HTTPD_RSRC_PROXY_ALLOW_UPGRADE   = (1 << 2), /* allow protocol upgrade */ | ||||||
| 	QSE_HTTPD_RSRC_PROXY_X_FORWARDED     = (1 << 3), /* add x-forwarded-for and x-forwarded-proto */ | 	QSE_HTTPD_RSRC_PROXY_X_FORWARDED     = (1 << 3), /* add x-forwarded-for and x-forwarded-proto */ | ||||||
| 	QSE_HTTPD_RSRC_PROXY_DST_STR         = (1 << 4), /* destination is an unresovled string pointed to by dst.str */ | 	QSE_HTTPD_RSRC_PROXY_DST_STR         = (1 << 4), /* destination is an unresovled string pointed to by dst.str */ | ||||||
| 	QSE_HTTPD_RSRC_PROXY_ENABLE_DNS      = (1 << 5), /* dns service enabled (udp) */ | 	QSE_HTTPD_RSRC_PROXY_DST_SECURE      = (1 << 5), /* use secure connection to destination */ | ||||||
| 	QSE_HTTPD_RSRC_PROXY_ENABLE_URS      = (1 << 6), /* url rewriting enabled (udp) */ | 	QSE_HTTPD_RSRC_PROXY_ENABLE_DNS      = (1 << 6), /* dns service enabled (udp) */ | ||||||
| 	QSE_HTTPD_RSRC_PROXY_DNS_SERVER      = (1 << 7), /* dns address specified */ | 	QSE_HTTPD_RSRC_PROXY_ENABLE_URS      = (1 << 7), /* url rewriting enabled (udp) */ | ||||||
| 	QSE_HTTPD_RSRC_PROXY_URS_SERVER      = (1 << 8), /* urs address specified */ | 	QSE_HTTPD_RSRC_PROXY_DNS_SERVER      = (1 << 8), /* dns address specified */ | ||||||
|  | 	QSE_HTTPD_RSRC_PROXY_URS_SERVER      = (1 << 9), /* urs address specified */ | ||||||
| }; | }; | ||||||
| typedef enum qse_httpd_rsrc_proxy_flag_t qse_httpd_rsrc_proxy_flag_t; | typedef enum qse_httpd_rsrc_proxy_flag_t qse_httpd_rsrc_proxy_flag_t; | ||||||
|  |  | ||||||
|  | |||||||
| @ -35,31 +35,31 @@ struct task_proxy_arg_t | |||||||
| typedef struct task_proxy_t task_proxy_t; | typedef struct task_proxy_t task_proxy_t; | ||||||
| struct task_proxy_t | struct task_proxy_t | ||||||
| { | { | ||||||
| #define PROXY_INIT_FAILED          (1 << 0) | #define PROXY_INIT_FAILED          (1u << 0) | ||||||
| #define PROXY_RAW                  (1 << 1) | #define PROXY_RAW                  (1u << 1) | ||||||
| #define PROXY_TRANSPARENT          (1 << 2) | #define PROXY_TRANSPARENT          (1u << 2) | ||||||
| #define PROXY_DNS_SERVER           (1 << 3) /* dns server address specified */ | #define PROXY_DNS_SERVER           (1u << 3) /* dns server address specified */ | ||||||
| #define PROXY_URS_SERVER           (1 << 4) /* urs server address specified */ | #define PROXY_URS_SERVER           (1u << 4) /* urs server address specified */ | ||||||
| #define PROXY_OUTBAND_PEER_NAME    (1 << 5) /* the peer_name pointer points to | #define PROXY_OUTBAND_PEER_NAME    (1u << 5) /* the peer_name pointer points to | ||||||
|                                                a separate memory chunk outside |                                                a separate memory chunk outside | ||||||
|                                                the task_proxy_t chunk. explicit |                                                the task_proxy_t chunk. explicit | ||||||
|                                                deallocatin is required */ |                                                deallocatin is required */ | ||||||
| #define PROXY_RESOLVE_PEER_NAME    (1 << 6) | #define PROXY_RESOLVE_PEER_NAME    (1u << 6) | ||||||
| #define PROXY_PEER_NAME_RESOLVING  (1 << 7) | #define PROXY_PEER_NAME_RESOLVING  (1u << 7) | ||||||
| #define PROXY_PEER_NAME_RESOLVED   (1 << 8) | #define PROXY_PEER_NAME_RESOLVED   (1u << 8) | ||||||
| #define PROXY_PEER_NAME_UNRESOLVED (1 << 9) | #define PROXY_PEER_NAME_UNRESOLVED (1u << 9) | ||||||
| #define PROXY_REWRITE_URL          (1 << 10) | #define PROXY_REWRITE_URL          (1u << 10) | ||||||
| #define PROXY_URL_REWRITING        (1 << 11) | #define PROXY_URL_REWRITING        (1u << 11) | ||||||
| #define PROXY_URL_PREREWRITTEN     (1 << 12) /* URL has been prerewritten in prerewrite(). */ | #define PROXY_URL_PREREWRITTEN     (1u << 12) /* URL has been prerewritten in prerewrite(). */ | ||||||
| #define PROXY_URL_REWRITTEN        (1 << 13) | #define PROXY_URL_REWRITTEN        (1u << 13) | ||||||
| #define PROXY_URL_REDIRECTED       (1 << 14) | #define PROXY_URL_REDIRECTED       (1u << 14) | ||||||
| #define PROXY_X_FORWARDED          (1 << 15) /* Add X-Forwarded-For and X-Forwarded-Proto */ | #define PROXY_X_FORWARDED          (1u << 15) /* Add X-Forwarded-For and X-Forwarded-Proto */ | ||||||
| #define PROXY_VIA                  (1 << 16) /* Via: added to the request */ | #define PROXY_VIA                  (1u << 16) /* Via: added to the request */ | ||||||
| #define PROXY_VIA_RETURNING        (1 << 17) /* Via: added to the response */ | #define PROXY_VIA_RETURNING        (1u << 17) /* Via: added to the response */ | ||||||
| #define PROXY_ALLOW_UPGRADE        (1 << 18) | #define PROXY_ALLOW_UPGRADE        (1u << 18) | ||||||
| #define PROXY_UPGRADE_REQUESTED    (1 << 19) | #define PROXY_UPGRADE_REQUESTED    (1u << 19) | ||||||
| #define PROXY_PROTOCOL_SWITCHED    (1 << 20) | #define PROXY_PROTOCOL_SWITCHED    (1u << 20) | ||||||
| #define PROXY_GOT_BAD_REQUEST      (1 << 21) | #define PROXY_GOT_BAD_REQUEST      (1u << 21) | ||||||
| 	unsigned int flags; | 	unsigned int flags; | ||||||
| 	qse_httpd_t* httpd; | 	qse_httpd_t* httpd; | ||||||
| 	qse_httpd_client_t* client; | 	qse_httpd_client_t* client; | ||||||
| @ -899,7 +899,13 @@ static void adjust_peer_name_and_port (task_proxy_t* proxy) | |||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		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 proxy->peer_port = QSE_HTTPD_DEFAULT_PORT; | 		else  | ||||||
|  | 		{ | ||||||
|  | 			if (proxy->peer.flags & QSE_HTTPD_PEER_SECURE) | ||||||
|  | 				proxy->peer_port = QSE_HTTPD_DEFAULT_SECURE_PORT; | ||||||
|  | 			else | ||||||
|  | 				proxy->peer_port = QSE_HTTPD_DEFAULT_PORT; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -940,6 +946,8 @@ 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.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) | ||||||
| 	{ | 	{ | ||||||
| @ -1414,6 +1422,7 @@ static int task_main_proxy_4 ( | |||||||
| 	qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) | 	qse_httpd_t* httpd, qse_httpd_client_t* client, qse_httpd_task_t* task) | ||||||
| { | { | ||||||
| 	task_proxy_t* proxy = (task_proxy_t*)task->ctx; | 	task_proxy_t* proxy = (task_proxy_t*)task->ctx; | ||||||
|  | 	qse_ssize_t n; | ||||||
|  |  | ||||||
| #if 0 | #if 0 | ||||||
| printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=%d\n",  | printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=%d\n",  | ||||||
| @ -1425,8 +1434,7 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% | |||||||
| 	if ((task->trigger.v[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) && | 	if ((task->trigger.v[0].mask & QSE_HTTPD_TASK_TRIGGER_READABLE) && | ||||||
| 	    proxy->buflen < QSE_SIZEOF(proxy->buf)) | 	    proxy->buflen < QSE_SIZEOF(proxy->buf)) | ||||||
| 	{ | 	{ | ||||||
| 		qse_ssize_t n; | 	reread: | ||||||
|  |  | ||||||
| 		/* 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 ( | ||||||
| @ -1521,7 +1529,6 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% | |||||||
| 		 * side is writable. it should be safe to write whenever | 		 * side is writable. it should be safe to write whenever | ||||||
| 		 * this task function is called. even if it's not writable, | 		 * this task function is called. even if it's not writable, | ||||||
| 		 * it should still be ok as the client socket is non-blocking. */ | 		 * it should still be ok as the client socket is non-blocking. */ | ||||||
| 		qse_ssize_t n; |  | ||||||
|  |  | ||||||
| 		httpd->errnum = QSE_HTTPD_ENOERR; | 		httpd->errnum = QSE_HTTPD_ENOERR; | ||||||
| 		n = httpd->opt.scb.client.send (httpd, client, proxy->buf, proxy->buflen); | 		n = httpd->opt.scb.client.send (httpd, client, proxy->buf, proxy->buflen); | ||||||
| @ -1542,6 +1549,24 @@ printf ("task_main_proxy_4 trigger[0].mask=%d trigger[1].mask=%d trigger.cmask=% | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if (proxy->peer.flags & QSE_HTTPD_PEER_PENDING) | ||||||
|  | 	{ | ||||||
|  | 		/* this QSE_HTTPD_CLIENT_PENDING thing is a dirty hack for SSL. | ||||||
|  | 		 * In SSL, data is transmitted in a record. a record can be | ||||||
|  | 		 * as large as 16K bytes since its length field is 2 bytes. | ||||||
|  | 		 * If SSL_read() has a record but it's given a smaller buffer | ||||||
|  | 		 * than the actual record, the next call to select() won't return.  | ||||||
|  | 		 * there is no data to read at the socket layer. SSL_pending() can  | ||||||
|  | 		 * tell you the amount of data in the SSL buffer. I try to consume | ||||||
|  | 		 * the pending data if the client.recv handler has set QSE_HTTPD_CLIENT_PENDING. */ | ||||||
|  |  | ||||||
|  | 		/* BUG BUG BUG. | ||||||
|  | 		 * it jumps back to read more. If the client-side is not writable, | ||||||
|  | 		 * unnecessary loop is made between this 'goto' and the target label.  | ||||||
|  | 		 * HOW SHOULD I SOLVE THIS? USE A BIG BUFFER AS LARGE AS 16K? */ | ||||||
|  | 		/*if (proxy->buflen < QSE_SIZEOF(proxy->buf))*/ goto reread; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -2059,17 +2084,20 @@ printf ("XXXXXXXXXXXXXXXXXXXXXXXXXX URL REWRITTEN TO [%s].....\n", new_url); | |||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
|  | 				int proto_len; | ||||||
|  |  | ||||||
| 				QSE_ASSERT (QSE_STR_LEN(proxy->reqfwdbuf) > 0); | 				QSE_ASSERT (QSE_STR_LEN(proxy->reqfwdbuf) > 0); | ||||||
|  |  | ||||||
| 				/* TODO: Host rewriting?? */ | 				/* TODO: Host rewriting?? */ | ||||||
| 			/* TODO: Host rewriting - to support it, headers must be made available thru request cloning.  | 			/* TODO: Host rewriting - to support it, headers must be made available thru request cloning.  | ||||||
| 			 *                        the request may not be valid after task_init_proxy */ | 			 *                        the request may not be valid after task_init_proxy */ | ||||||
|  |  | ||||||
| 				if (qse_mbszcasecmp (new_url, QSE_MT("http://"), 7) == 0) | 				if (qse_mbszcasecmp (new_url, QSE_MT("http://"), (proto_len = 7)) == 0 || | ||||||
|  | 				    qse_mbszcasecmp (new_url, QSE_MT("https://"), (proto_len = 8)) == 0) | ||||||
| 				{ | 				{ | ||||||
| 					const qse_mchar_t* host; | 					const qse_mchar_t* host; | ||||||
|  |  | ||||||
| 					host = new_url + 7; | 					host = new_url + proto_len; | ||||||
| 					if (host[0] != QSE_MT('/') && host[0] != QSE_MT('\0')) | 					if (host[0] != QSE_MT('/') && host[0] != QSE_MT('\0')) | ||||||
| 					{ | 					{ | ||||||
| 						const qse_mchar_t* slash; | 						const qse_mchar_t* slash; | ||||||
| @ -2093,6 +2121,12 @@ printf ("XXXXXXXXXXXXXXXXXXXXXXXXXX URL REWRITTEN TO [%s].....\n", new_url); | |||||||
| 							goto fail; | 							goto fail; | ||||||
| 						} | 						} | ||||||
|  |  | ||||||
|  | /* TODO: antything todo when http is rewritten to HTTPS or vice versa */ | ||||||
|  | 						if (proto_len == 8) | ||||||
|  | 							proxy->peer.flags |= QSE_HTTPD_PEER_SECURE; | ||||||
|  | 						else | ||||||
|  | 							proxy->peer.flags &= ~QSE_HTTPD_PEER_SECURE; | ||||||
|  |  | ||||||
| 						if (qse_mbstonwad (tmp, &nwad) <= -1) | 						if (qse_mbstonwad (tmp, &nwad) <= -1) | ||||||
| 						{ | 						{ | ||||||
| 							proxy->flags |= PROXY_RESOLVE_PEER_NAME | PROXY_OUTBAND_PEER_NAME; | 							proxy->flags |= PROXY_RESOLVE_PEER_NAME | PROXY_OUTBAND_PEER_NAME; | ||||||
| @ -2104,7 +2138,7 @@ printf ("XXXXXXXXXXXXXXXXXXXXXXXXXX URL REWRITTEN TO [%s].....\n", new_url); | |||||||
| 							if (qse_getnwadport(&nwad) == 0)  | 							if (qse_getnwadport(&nwad) == 0)  | ||||||
| 							{ | 							{ | ||||||
| 								/* i don't care if tmp is X.X.X.X:0 or just X.X.X.X */ | 								/* i don't care if tmp is X.X.X.X:0 or just X.X.X.X */ | ||||||
| 								qse_setnwadport (&nwad, qse_hton16(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; | ||||||
|  | |||||||
| @ -577,7 +577,8 @@ typedef struct httpd_xtn_t httpd_xtn_t; | |||||||
| struct httpd_xtn_t | struct httpd_xtn_t | ||||||
| { | { | ||||||
| #if defined(HAVE_SSL) | #if defined(HAVE_SSL) | ||||||
| 	SSL_CTX* ssl_ctx; | 	SSL_CTX* ssl_client_ctx; | ||||||
|  | 	SSL_CTX* ssl_peer_ctx; | ||||||
| #endif | #endif | ||||||
| 	qse_httpd_ecb_t ecb; | 	qse_httpd_ecb_t ecb; | ||||||
| 	qse_httpd_dnsstd_t dns; | 	qse_httpd_dnsstd_t dns; | ||||||
| @ -587,7 +588,8 @@ struct httpd_xtn_t | |||||||
| #if defined(HAVE_SSL) | #if defined(HAVE_SSL) | ||||||
| static int init_xtn_ssl (qse_httpd_t* httpd, qse_httpd_server_t* server) | static int init_xtn_ssl (qse_httpd_t* httpd, qse_httpd_server_t* server) | ||||||
| { | { | ||||||
| 	SSL_CTX* ctx; | /* BUG BUG BUG. SSL context for client must exist inside the seerver, i guess */ | ||||||
|  | 	SSL_CTX* client_ctx = QSE_NULL; | ||||||
| 	httpd_xtn_t* xtn; | 	httpd_xtn_t* xtn; | ||||||
| 	server_xtn_t* server_xtn; | 	server_xtn_t* server_xtn; | ||||||
| 	qse_httpd_serverstd_ssl_t ssl; | 	qse_httpd_serverstd_ssl_t ssl; | ||||||
| @ -597,24 +599,28 @@ static int init_xtn_ssl (qse_httpd_t* httpd, qse_httpd_server_t* server) | |||||||
|  |  | ||||||
| 	if (server_xtn->query (httpd, server, QSE_HTTPD_SERVERSTD_SSL, QSE_NULL, &ssl) <= -1) | 	if (server_xtn->query (httpd, server, QSE_HTTPD_SERVERSTD_SSL, QSE_NULL, &ssl) <= -1) | ||||||
| 	{ | 	{ | ||||||
| 		return -1; | 		goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (ssl.certfile == QSE_NULL || ssl.keyfile == QSE_NULL) | 	if (ssl.certfile == QSE_NULL || ssl.keyfile == QSE_NULL) | ||||||
| 	{ | 	{ | ||||||
| 		qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); | ||||||
| 		return -1; | 		goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ctx = SSL_CTX_new (SSLv23_server_method()); | 	client_ctx = SSL_CTX_new (SSLv23_server_method()); | ||||||
| 	if (ctx == QSE_NULL) return -1; | 	if (!client_ctx)  | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM); | ||||||
|  | 		goto oops; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/*SSL_CTX_set_info_callback(ctx,ssl_info_callback);*/ | 	/*SSL_CTX_set_info_callback(ctx,ssl_info_callback);*/ | ||||||
|  |  | ||||||
| 	if (SSL_CTX_use_certificate_file (ctx, ssl.certfile, SSL_FILETYPE_PEM) == 0 || | 	if (SSL_CTX_use_certificate_file (client_ctx, ssl.certfile, SSL_FILETYPE_PEM) == 0 || | ||||||
| 	    SSL_CTX_use_PrivateKey_file (ctx, ssl.keyfile, SSL_FILETYPE_PEM) == 0 || | 	    SSL_CTX_use_PrivateKey_file (client_ctx, ssl.keyfile, SSL_FILETYPE_PEM) == 0 || | ||||||
| 	    SSL_CTX_check_private_key (ctx) == 0 /*|| | 	    SSL_CTX_check_private_key (client_ctx) == 0 /*|| | ||||||
| 	    SSL_CTX_use_certificate_chain_file (ctx, chainfile) == 0*/) | 	    SSL_CTX_use_certificate_chain_file (client_ctx, chainfile) == 0*/) | ||||||
| 	{ | 	{ | ||||||
| 		if (httpd->opt.trait & QSE_HTTPD_LOGACT) | 		if (httpd->opt.trait & QSE_HTTPD_LOGACT) | ||||||
| 		{ | 		{ | ||||||
| @ -626,25 +632,60 @@ static int init_xtn_ssl (qse_httpd_t* httpd, qse_httpd_server_t* server) | |||||||
| 			httpd->opt.rcb.logact (httpd, &msg); | 			httpd->opt.rcb.logact (httpd, &msg); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		SSL_CTX_free (ctx); | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); /* TODO: define a better error code */ | ||||||
| 		return -1; | 		goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	/* TODO: SSL_CTX_set_verify(); SSL_CTX_set_verify_depth() */ | 	/* TODO: SSL_CTX_set_verify(); SSL_CTX_set_verify_depth() */ | ||||||
| 	/* TODO: CRYPTO_set_id_callback (); */ | 	/* TODO: CRYPTO_set_id_callback (); */ | ||||||
| 	/* TODO: CRYPTO_set_locking_callback (); */ | 	/* TODO: CRYPTO_set_locking_callback (); */ | ||||||
|  | 	SSL_CTX_set_read_ahead (client_ctx, 0); | ||||||
|  |  | ||||||
|  | 	xtn->ssl_client_ctx = client_ctx; | ||||||
|  |  | ||||||
| 	SSL_CTX_set_read_ahead (ctx, 0); |  | ||||||
| 	xtn->ssl_ctx = ctx; |  | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | oops: | ||||||
|  | 	if (client_ctx) SSL_CTX_free (client_ctx); | ||||||
|  | 	return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void fini_xtn_ssl (httpd_xtn_t* xtn) | static void fini_xtn_ssl (httpd_xtn_t* xtn) | ||||||
| { | { | ||||||
| 	/* TODO: CRYPTO_set_id_callback (QSE_NULL); */ | 	/* TODO: CRYPTO_set_id_callback (QSE_NULL); */ | ||||||
| 	/* TODO: CRYPTO_set_locking_callback (QSE_NULL); */ | 	/* TODO: CRYPTO_set_locking_callback (QSE_NULL); */ | ||||||
| 	SSL_CTX_free (xtn->ssl_ctx); | 	SSL_CTX_free (xtn->ssl_client_ctx); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int init_xtn_peer_ssl (qse_httpd_t* httpd) | ||||||
|  | { | ||||||
|  | 	SSL_CTX* peer_ctx = QSE_NULL; | ||||||
|  | 	httpd_xtn_t* xtn; | ||||||
|  |  | ||||||
|  | 	xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); | ||||||
|  |  | ||||||
|  | 	peer_ctx = SSL_CTX_new (SSLv23_client_method()); | ||||||
|  | 	if (!peer_ctx)  | ||||||
|  | 	{ | ||||||
|  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM); | ||||||
|  | 		goto oops; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	xtn->ssl_peer_ctx = peer_ctx; | ||||||
|  |  | ||||||
|  | printf ("SSL PEER CTX ============>%p\n", xtn->ssl_peer_ctx); | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  | oops: | ||||||
|  | 	if (peer_ctx) SSL_CTX_free (peer_ctx); | ||||||
|  | 	return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void fini_xtn_peer_ssl (httpd_xtn_t* xtn) | ||||||
|  | { | ||||||
|  | 	/* TODO: CRYPTO_set_id_callback (QSE_NULL); */ | ||||||
|  | 	/* TODO: CRYPTO_set_locking_callback (QSE_NULL); */ | ||||||
|  | 	SSL_CTX_free (xtn->ssl_peer_ctx); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @ -656,7 +697,8 @@ static void cleanup_standard_httpd (qse_httpd_t* httpd) | |||||||
| 	xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); | 	xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); | ||||||
|  |  | ||||||
| #if defined(HAVE_SSL) | #if defined(HAVE_SSL) | ||||||
| 	if (xtn->ssl_ctx) fini_xtn_ssl (xtn); | 	if (xtn->ssl_peer_ctx) fini_xtn_peer_ssl (xtn); | ||||||
|  | 	if (xtn->ssl_client_ctx) fini_xtn_ssl (xtn); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #if defined(USE_LTDL) | #if defined(USE_LTDL) | ||||||
| @ -1069,6 +1111,10 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | |||||||
| 	int connaddrsize, bindaddrsize; | 	int connaddrsize, bindaddrsize; | ||||||
| 	int connected = 1; | 	int connected = 1; | ||||||
| 	qse_sck_hnd_t fd = QSE_INVALID_SCKHND; | 	qse_sck_hnd_t fd = QSE_INVALID_SCKHND; | ||||||
|  | 	SSL* ssl = QSE_NULL; | ||||||
|  | 	httpd_xtn_t* xtn; | ||||||
|  |  | ||||||
|  | 	xtn = (httpd_xtn_t*) qse_httpd_getxtn (httpd); | ||||||
|  |  | ||||||
| #if defined(_WIN32) | #if defined(_WIN32) | ||||||
| 	unsigned long cmd; | 	unsigned long cmd; | ||||||
| @ -1080,6 +1126,9 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | |||||||
| 	int flag; | 	int flag; | ||||||
| #endif | #endif | ||||||
| 	 | 	 | ||||||
|  | 	/* turn off internally used bits */ | ||||||
|  | 	peer->flags &= ~QSE_HTTPD_PEER_ALL_INTERNALS; | ||||||
|  |  | ||||||
| 	connaddrsize = qse_nwadtoskad (&peer->nwad, &connaddr); | 	connaddrsize = qse_nwadtoskad (&peer->nwad, &connaddr); | ||||||
| 	if (connaddrsize <= -1) | 	if (connaddrsize <= -1) | ||||||
| 	{ | 	{ | ||||||
| @ -1117,6 +1166,33 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | |||||||
|  |  | ||||||
| 	if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops; | 	if (set_socket_nonblock (httpd, fd, 1) <= -1) goto oops; | ||||||
|  |  | ||||||
|  | 	if (peer->flags & QSE_HTTPD_PEER_SECURE) | ||||||
|  | 	{ | ||||||
|  | 	#if defined(HAVE_SSL) | ||||||
|  | 		if (!xtn->ssl_peer_ctx) | ||||||
|  | 		{ | ||||||
|  | 			/* TODO: peer ssl initialization doesn't have to be delayed... */ | ||||||
|  | 			if (init_xtn_peer_ssl (httpd) <= -1) goto oops; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		ssl = SSL_new (xtn->ssl_peer_ctx); | ||||||
|  | 		if (ssl == QSE_NULL)  | ||||||
|  | 		{ | ||||||
|  | 			qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); /* TODO: better error code */ | ||||||
|  | 			goto oops; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (SSL_set_fd (ssl, fd) == 0)  | ||||||
|  | 		{ | ||||||
|  | 			qse_httpd_seterrnum (httpd, QSE_HTTPD_ESYSERR); /* TODO: better error code */ | ||||||
|  | 			goto oops; | ||||||
|  | 		} | ||||||
|  | 	#else | ||||||
|  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||||
|  | 		goto oops; | ||||||
|  | 	#endif | ||||||
|  | 	} | ||||||
|  |  | ||||||
| #if defined(_WIN32) | #if defined(_WIN32) | ||||||
| 	if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) <= -1) | 	if (connect (fd, (struct sockaddr*)&connaddr, connaddrsize) <= -1) | ||||||
| 	{ | 	{ | ||||||
| @ -1154,13 +1230,48 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | |||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| 	/*if (set_socket_nonblock (httpd, fd, 0) <= -1) goto oops;*/ | 	if ((peer->flags & QSE_HTTPD_PEER_SECURE) && connected) | ||||||
|  | 	{ | ||||||
|  | 	#if defined(HAVE_SSL) | ||||||
|  | 		int ret = SSL_connect (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. */ | ||||||
|  | 				peer->flags |= QSE_HTTPD_PEER_CONNECTED; | ||||||
|  | 				connected = 0; /* not fully connected yet */ | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				qse_httpd_seterrnum (httpd, QSE_HTTPD_ESCONN); | ||||||
|  | 				goto oops; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			peer->flags |= QSE_HTTPD_PEER_CONNECTED; | ||||||
|  | 			/* socket connected + ssl connected */ | ||||||
|  | 		} | ||||||
|  | 	#endif | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* take note the socket handle is in the non-blocking mode here */ | ||||||
| 	peer->handle = fd; | 	peer->handle = fd; | ||||||
|  | 	if (peer->flags & QSE_HTTPD_PEER_SECURE) | ||||||
|  | 	{ | ||||||
|  | 	#if defined(HAVE_SSL) | ||||||
|  | 		peer->handle2 = SSL_TO_HANDLE(ssl); | ||||||
|  | 	#endif | ||||||
|  | 	} | ||||||
| 	return connected; | 	return connected; | ||||||
|  |  | ||||||
| oops: | oops: | ||||||
| 	qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | 	qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | #if defined(HAVE_SSL) | ||||||
|  | 	if (ssl) SSL_free (ssl); | ||||||
|  | #endif | ||||||
| 	if (qse_isvalidsckhnd(fd)) qse_closesckhnd (fd); | 	if (qse_isvalidsckhnd(fd)) qse_closesckhnd (fd); | ||||||
| 	return -1; | 	return -1; | ||||||
|  |  | ||||||
| @ -1170,10 +1281,16 @@ oops: | |||||||
|  |  | ||||||
| static void peer_close (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | static void peer_close (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | ||||||
| { | { | ||||||
|  | 	if (peer->flags & QSE_HTTPD_PEER_SECURE) | ||||||
|  | 	{ | ||||||
|  | 	#if defined(HAVE_SSL) | ||||||
|  | 		SSL_free (HANDLE_TO_SSL(peer->handle2)); | ||||||
|  | 	#endif | ||||||
|  | 	} | ||||||
| 	qse_closesckhnd (peer->handle); | 	qse_closesckhnd (peer->handle); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | static int is_peer_socket_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | ||||||
| { | { | ||||||
| #if defined(_WIN32) | #if defined(_WIN32) | ||||||
| 	int len; | 	int len; | ||||||
| @ -1245,32 +1362,122 @@ static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | |||||||
| #endif | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int is_peer_connected_securely (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | ||||||
|  | { | ||||||
|  | 	int ret = SSL_connect (HANDLE_TO_SSL(peer->handle2)); | ||||||
|  | 	if (ret <= 0) | ||||||
|  | 	{ | ||||||
|  | 		int err = SSL_get_error(HANDLE_TO_SSL(peer->handle2), ret); | ||||||
|  | 		if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) | ||||||
|  | 		{ | ||||||
|  | 			/* handshaking isn't complete. */ | ||||||
|  | 			return 0; /* not connected */ | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			qse_httpd_seterrnum (httpd, QSE_HTTPD_ESCONN); | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer) | ||||||
|  | { | ||||||
|  | 	if (peer->flags & QSE_HTTPD_PEER_SECURE) | ||||||
|  | 	{ | ||||||
|  | 		if (peer->flags & QSE_HTTPD_PEER_CONNECTED) | ||||||
|  | 		{ | ||||||
|  | 			return is_peer_connected_securely (httpd, peer); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			int ret = is_peer_socket_connected (httpd, peer); | ||||||
|  | 			if (ret <= 0) return ret; | ||||||
|  | 			peer->flags |= QSE_HTTPD_PEER_CONNECTED; | ||||||
|  | 			return 0; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		return is_peer_socket_connected (httpd, peer); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| static qse_ssize_t peer_recv ( | static qse_ssize_t peer_recv ( | ||||||
| 	qse_httpd_t* httpd, qse_httpd_peer_t* peer, | 	qse_httpd_t* httpd, qse_httpd_peer_t* peer, | ||||||
| 	qse_mchar_t* buf, qse_size_t bufsize) | 	qse_mchar_t* buf, qse_size_t bufsize) | ||||||
| { | { | ||||||
| #if defined(__DOS__) | 	if (peer->flags & QSE_HTTPD_PEER_SECURE) | ||||||
| 	qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | 	{ | ||||||
| 	return -1; | 	#if defined(HAVE_SSL) | ||||||
| #else | 		int ret = SSL_read (HANDLE_TO_SSL(peer->handle2), buf, bufsize); | ||||||
| 	qse_ssize_t ret = recv (peer->handle, buf, bufsize, 0); | 		if (ret <= -1) | ||||||
| 	if (ret <= -1) qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | 		{ | ||||||
| 	return ret; | 			int err = SSL_get_error(HANDLE_TO_SSL(peer->handle2),ret); | ||||||
| #endif | 			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(peer->handle2)) > 0)  | ||||||
|  | 			peer->flags |= QSE_HTTPD_PEER_PENDING; | ||||||
|  | 		else | ||||||
|  | 			peer->flags &= ~QSE_HTTPD_PEER_PENDING; | ||||||
|  |  | ||||||
|  | 		return ret; | ||||||
|  | 	#else | ||||||
|  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||||
|  | 		return -1; | ||||||
|  | 	#endif | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 	#if defined(__DOS__) | ||||||
|  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||||
|  | 		return -1; | ||||||
|  | 	#else | ||||||
|  | 		qse_ssize_t ret = recv (peer->handle, buf, bufsize, 0); | ||||||
|  | 		if (ret <= -1) qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 		return ret; | ||||||
|  | 	#endif | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| static qse_ssize_t peer_send ( | static qse_ssize_t peer_send ( | ||||||
| 	qse_httpd_t* httpd, qse_httpd_peer_t* peer, | 	qse_httpd_t* httpd, qse_httpd_peer_t* peer, | ||||||
| 	const qse_mchar_t* buf, qse_size_t bufsize) | 	const qse_mchar_t* buf, qse_size_t bufsize) | ||||||
| { | { | ||||||
| #if defined(__DOS__) | 	if (peer->flags & QSE_HTTPD_PEER_SECURE) | ||||||
| 	qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | 	{ | ||||||
| 	return -1; | 	#if defined(HAVE_SSL) | ||||||
| #else | 		int ret = SSL_write (HANDLE_TO_SSL(peer->handle2), buf, bufsize); | ||||||
| 	qse_ssize_t ret = send (peer->handle, buf, bufsize, 0); | 		if (ret <= -1) | ||||||
| 	if (ret <= -1) qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | 		{ | ||||||
| 	return ret; | 			int err = SSL_get_error(HANDLE_TO_SSL(peer->handle2),ret); | ||||||
| #endif | 			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 | ||||||
|  | 	{ | ||||||
|  | 	#if defined(__DOS__) | ||||||
|  | 		qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOIMPL); | ||||||
|  | 		return -1; | ||||||
|  | 	#else | ||||||
|  | 		qse_ssize_t ret = send (peer->handle, buf, bufsize, 0); | ||||||
|  | 		if (ret <= -1) qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM()); | ||||||
|  | 		return ret; | ||||||
|  | 	#endif | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| /* ------------------------------------------------------------------- */ | /* ------------------------------------------------------------------- */ | ||||||
| @ -2008,7 +2215,7 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client) | |||||||
| 		httpd_xtn_t* xtn; | 		httpd_xtn_t* xtn; | ||||||
|  |  | ||||||
| 		xtn = (httpd_xtn_t*) qse_httpd_getxtn (httpd); | 		xtn = (httpd_xtn_t*) qse_httpd_getxtn (httpd); | ||||||
| 		if (!xtn->ssl_ctx) | 		if (!xtn->ssl_client_ctx) | ||||||
| 		{ | 		{ | ||||||
| 			/* delayed initialization of ssl */ | 			/* delayed initialization of ssl */ | ||||||
| 			if (init_xtn_ssl (httpd, client->server) <= -1)  | 			if (init_xtn_ssl (httpd, client->server) <= -1)  | ||||||
| @ -2017,7 +2224,7 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client) | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		QSE_ASSERT (xtn->ssl_ctx != QSE_NULL); | 		QSE_ASSERT (xtn->ssl_client_ctx != QSE_NULL); | ||||||
| 		QSE_ASSERT (QSE_SIZEOF(client->handle2) >= QSE_SIZEOF(ssl)); | 		QSE_ASSERT (QSE_SIZEOF(client->handle2) >= QSE_SIZEOF(ssl)); | ||||||
|  |  | ||||||
| 		if (HANDLE_TO_SSL(client->handle2)) | 		if (HANDLE_TO_SSL(client->handle2)) | ||||||
| @ -2026,7 +2233,7 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client) | |||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			ssl = SSL_new (xtn->ssl_ctx); | 			ssl = SSL_new (xtn->ssl_client_ctx); | ||||||
| 			if (ssl == QSE_NULL) return -1; | 			if (ssl == QSE_NULL) return -1; | ||||||
|  |  | ||||||
| 			client->handle2 = SSL_TO_HANDLE(ssl); | 			client->handle2 = SSL_TO_HANDLE(ssl); | ||||||
| @ -2058,7 +2265,8 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client) | |||||||
| 				httpd->opt.rcb.logact (httpd, &msg); | 				httpd->opt.rcb.logact (httpd, &msg); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			/* SSL_free (ssl); */ | 			/* client_closed() free this. no SSL_free() here. | ||||||
|  | 			SSL_free (ssl); */ | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | |||||||
| @ -1103,12 +1103,11 @@ qse_printf (QSE_T("!!!!!FEEDING OK OK OK OK %d from %d\n"), (int)m, (int)client- | |||||||
| 		/* 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 | ||||||
| 		 * as large as 16K bytes since its length field is 2 bytes. | 		 * as large as 16K bytes since its length field is 2 bytes. | ||||||
| 		 * If SSL_read() has record a record but it's given a | 		 * If SSL_read() has a record but it's given a smaller buffer | ||||||
| 		 * smaller buffer than the actuaal record, the next call | 		 * than the actual record, the next call to select() won't return.  | ||||||
| 		 * to select() won't return. there is no data to read | 		 * there is no data to read at the socket layer. SSL_pending() can  | ||||||
| 		 * at the socket layer. SSL_pending() can tell you the | 		 * tell you the amount of data in the SSL buffer. I try to consume | ||||||
| 		 * amount of data in the SSL buffer. I try to consume | 		 * the pending data if the client.recv handler has set QSE_HTTPD_CLIENT_PENDING. | ||||||
| 		 * the pending data if the client.recv handler set QSE_HTTPD_CLIENT_PENDING. |  | ||||||
| 		 * | 		 * | ||||||
| 		 * TODO: Investigate if there is any starvation issues. | 		 * TODO: Investigate if there is any starvation issues. | ||||||
| 		 *       What if a single client never stops sending?  | 		 *       What if a single client never stops sending?  | ||||||
|  | |||||||
| @ -100,8 +100,8 @@ struct qse_httpd_real_task_t | |||||||
| 	qse_httpd_real_task_t* next; | 	qse_httpd_real_task_t* next; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #define MAX_SEND_SIZE 4096 | #define MAX_SEND_SIZE (4096 * 4) | ||||||
| #define MAX_RECV_SIZE 4096 | #define MAX_RECV_SIZE (4096 * 2) | ||||||
|  |  | ||||||
| #define MAX_NWAD_TEXT_SIZE 96 | #define MAX_NWAD_TEXT_SIZE 96 | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user