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:
@ -35,31 +35,31 @@ struct task_proxy_arg_t
|
||||
typedef struct task_proxy_t task_proxy_t;
|
||||
struct task_proxy_t
|
||||
{
|
||||
#define PROXY_INIT_FAILED (1 << 0)
|
||||
#define PROXY_RAW (1 << 1)
|
||||
#define PROXY_TRANSPARENT (1 << 2)
|
||||
#define PROXY_DNS_SERVER (1 << 3) /* dns server address specified */
|
||||
#define PROXY_URS_SERVER (1 << 4) /* urs server address specified */
|
||||
#define PROXY_OUTBAND_PEER_NAME (1 << 5) /* the peer_name pointer points to
|
||||
#define PROXY_INIT_FAILED (1u << 0)
|
||||
#define PROXY_RAW (1u << 1)
|
||||
#define PROXY_TRANSPARENT (1u << 2)
|
||||
#define PROXY_DNS_SERVER (1u << 3) /* dns server address specified */
|
||||
#define PROXY_URS_SERVER (1u << 4) /* urs server address specified */
|
||||
#define PROXY_OUTBAND_PEER_NAME (1u << 5) /* the peer_name pointer points to
|
||||
a separate memory chunk outside
|
||||
the task_proxy_t chunk. explicit
|
||||
deallocatin is required */
|
||||
#define PROXY_RESOLVE_PEER_NAME (1 << 6)
|
||||
#define PROXY_PEER_NAME_RESOLVING (1 << 7)
|
||||
#define PROXY_PEER_NAME_RESOLVED (1 << 8)
|
||||
#define PROXY_PEER_NAME_UNRESOLVED (1 << 9)
|
||||
#define PROXY_REWRITE_URL (1 << 10)
|
||||
#define PROXY_URL_REWRITING (1 << 11)
|
||||
#define PROXY_URL_PREREWRITTEN (1 << 12) /* URL has been prerewritten in prerewrite(). */
|
||||
#define PROXY_URL_REWRITTEN (1 << 13)
|
||||
#define PROXY_URL_REDIRECTED (1 << 14)
|
||||
#define PROXY_X_FORWARDED (1 << 15) /* Add X-Forwarded-For and X-Forwarded-Proto */
|
||||
#define PROXY_VIA (1 << 16) /* Via: added to the request */
|
||||
#define PROXY_VIA_RETURNING (1 << 17) /* Via: added to the response */
|
||||
#define PROXY_ALLOW_UPGRADE (1 << 18)
|
||||
#define PROXY_UPGRADE_REQUESTED (1 << 19)
|
||||
#define PROXY_PROTOCOL_SWITCHED (1 << 20)
|
||||
#define PROXY_GOT_BAD_REQUEST (1 << 21)
|
||||
#define PROXY_RESOLVE_PEER_NAME (1u << 6)
|
||||
#define PROXY_PEER_NAME_RESOLVING (1u << 7)
|
||||
#define PROXY_PEER_NAME_RESOLVED (1u << 8)
|
||||
#define PROXY_PEER_NAME_UNRESOLVED (1u << 9)
|
||||
#define PROXY_REWRITE_URL (1u << 10)
|
||||
#define PROXY_URL_REWRITING (1u << 11)
|
||||
#define PROXY_URL_PREREWRITTEN (1u << 12) /* URL has been prerewritten in prerewrite(). */
|
||||
#define PROXY_URL_REWRITTEN (1u << 13)
|
||||
#define PROXY_URL_REDIRECTED (1u << 14)
|
||||
#define PROXY_X_FORWARDED (1u << 15) /* Add X-Forwarded-For and X-Forwarded-Proto */
|
||||
#define PROXY_VIA (1u << 16) /* Via: added to the request */
|
||||
#define PROXY_VIA_RETURNING (1u << 17) /* Via: added to the response */
|
||||
#define PROXY_ALLOW_UPGRADE (1u << 18)
|
||||
#define PROXY_UPGRADE_REQUESTED (1u << 19)
|
||||
#define PROXY_PROTOCOL_SWITCHED (1u << 20)
|
||||
#define PROXY_GOT_BAD_REQUEST (1u << 21)
|
||||
unsigned int flags;
|
||||
qse_httpd_t* httpd;
|
||||
qse_httpd_client_t* client;
|
||||
@ -899,7 +899,13 @@ static void adjust_peer_name_and_port (task_proxy_t* proxy)
|
||||
else
|
||||
{
|
||||
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_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;
|
||||
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)
|
||||
{
|
||||
task_proxy_t* proxy = (task_proxy_t*)task->ctx;
|
||||
qse_ssize_t n;
|
||||
|
||||
#if 0
|
||||
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) &&
|
||||
proxy->buflen < QSE_SIZEOF(proxy->buf))
|
||||
{
|
||||
qse_ssize_t n;
|
||||
|
||||
reread:
|
||||
/* reading from the peer */
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
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
|
||||
* this task function is called. even if it's not writable,
|
||||
* it should still be ok as the client socket is non-blocking. */
|
||||
qse_ssize_t n;
|
||||
|
||||
httpd->errnum = QSE_HTTPD_ENOERR;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2059,17 +2084,20 @@ printf ("XXXXXXXXXXXXXXXXXXXXXXXXXX URL REWRITTEN TO [%s].....\n", new_url);
|
||||
}
|
||||
else
|
||||
{
|
||||
int proto_len;
|
||||
|
||||
QSE_ASSERT (QSE_STR_LEN(proxy->reqfwdbuf) > 0);
|
||||
|
||||
/* TODO: Host rewriting?? */
|
||||
/* TODO: Host rewriting - to support it, headers must be made available thru request cloning.
|
||||
* 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;
|
||||
|
||||
host = new_url + 7;
|
||||
host = new_url + proto_len;
|
||||
if (host[0] != QSE_MT('/') && host[0] != QSE_MT('\0'))
|
||||
{
|
||||
const qse_mchar_t* slash;
|
||||
@ -2093,6 +2121,12 @@ printf ("XXXXXXXXXXXXXXXXXXXXXXXXXX URL REWRITTEN TO [%s].....\n", new_url);
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
/* 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;
|
||||
|
@ -577,7 +577,8 @@ typedef struct httpd_xtn_t httpd_xtn_t;
|
||||
struct httpd_xtn_t
|
||||
{
|
||||
#if defined(HAVE_SSL)
|
||||
SSL_CTX* ssl_ctx;
|
||||
SSL_CTX* ssl_client_ctx;
|
||||
SSL_CTX* ssl_peer_ctx;
|
||||
#endif
|
||||
qse_httpd_ecb_t ecb;
|
||||
qse_httpd_dnsstd_t dns;
|
||||
@ -587,7 +588,8 @@ struct httpd_xtn_t
|
||||
#if defined(HAVE_SSL)
|
||||
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;
|
||||
server_xtn_t* server_xtn;
|
||||
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)
|
||||
{
|
||||
return -1;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (ssl.certfile == QSE_NULL || ssl.keyfile == QSE_NULL)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL);
|
||||
return -1;
|
||||
goto oops;
|
||||
}
|
||||
|
||||
ctx = SSL_CTX_new (SSLv23_server_method());
|
||||
if (ctx == QSE_NULL) return -1;
|
||||
client_ctx = SSL_CTX_new (SSLv23_server_method());
|
||||
if (!client_ctx)
|
||||
{
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
/*SSL_CTX_set_info_callback(ctx,ssl_info_callback);*/
|
||||
|
||||
if (SSL_CTX_use_certificate_file (ctx, ssl.certfile, SSL_FILETYPE_PEM) == 0 ||
|
||||
SSL_CTX_use_PrivateKey_file (ctx, ssl.keyfile, SSL_FILETYPE_PEM) == 0 ||
|
||||
SSL_CTX_check_private_key (ctx) == 0 /*||
|
||||
SSL_CTX_use_certificate_chain_file (ctx, chainfile) == 0*/)
|
||||
if (SSL_CTX_use_certificate_file (client_ctx, ssl.certfile, SSL_FILETYPE_PEM) == 0 ||
|
||||
SSL_CTX_use_PrivateKey_file (client_ctx, ssl.keyfile, SSL_FILETYPE_PEM) == 0 ||
|
||||
SSL_CTX_check_private_key (client_ctx) == 0 /*||
|
||||
SSL_CTX_use_certificate_chain_file (client_ctx, chainfile) == 0*/)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
SSL_CTX_free (ctx);
|
||||
return -1;
|
||||
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); /* TODO: define a better error code */
|
||||
goto oops;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: SSL_CTX_set_verify(); SSL_CTX_set_verify_depth() */
|
||||
/* TODO: CRYPTO_set_id_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;
|
||||
|
||||
oops:
|
||||
if (client_ctx) SSL_CTX_free (client_ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void fini_xtn_ssl (httpd_xtn_t* xtn)
|
||||
{
|
||||
/* TODO: CRYPTO_set_id_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
|
||||
|
||||
@ -656,7 +697,8 @@ static void cleanup_standard_httpd (qse_httpd_t* httpd)
|
||||
xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd);
|
||||
|
||||
#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
|
||||
|
||||
#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 connected = 1;
|
||||
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)
|
||||
unsigned long cmd;
|
||||
@ -1079,6 +1125,9 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
|
||||
#else
|
||||
int flag;
|
||||
#endif
|
||||
|
||||
/* turn off internally used bits */
|
||||
peer->flags &= ~QSE_HTTPD_PEER_ALL_INTERNALS;
|
||||
|
||||
connaddrsize = qse_nwadtoskad (&peer->nwad, &connaddr);
|
||||
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 (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 (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
|
||||
|
||||
/*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;
|
||||
if (peer->flags & QSE_HTTPD_PEER_SECURE)
|
||||
{
|
||||
#if defined(HAVE_SSL)
|
||||
peer->handle2 = SSL_TO_HANDLE(ssl);
|
||||
#endif
|
||||
}
|
||||
return connected;
|
||||
|
||||
oops:
|
||||
qse_httpd_seterrnum (httpd, SKERR_TO_ERRNUM());
|
||||
#if defined(HAVE_SSL)
|
||||
if (ssl) SSL_free (ssl);
|
||||
#endif
|
||||
if (qse_isvalidsckhnd(fd)) qse_closesckhnd (fd);
|
||||
return -1;
|
||||
|
||||
@ -1170,10 +1281,16 @@ oops:
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
int len;
|
||||
@ -1245,32 +1362,122 @@ static int peer_connected (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
|
||||
#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 (
|
||||
qse_httpd_t* httpd, qse_httpd_peer_t* peer,
|
||||
qse_mchar_t* buf, qse_size_t bufsize)
|
||||
{
|
||||
#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
|
||||
if (peer->flags & QSE_HTTPD_PEER_SECURE)
|
||||
{
|
||||
#if defined(HAVE_SSL)
|
||||
int ret = SSL_read (HANDLE_TO_SSL(peer->handle2), buf, bufsize);
|
||||
if (ret <= -1)
|
||||
{
|
||||
int err = SSL_get_error(HANDLE_TO_SSL(peer->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(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 (
|
||||
qse_httpd_t* httpd, qse_httpd_peer_t* peer,
|
||||
const qse_mchar_t* buf, qse_size_t bufsize)
|
||||
{
|
||||
#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
|
||||
if (peer->flags & QSE_HTTPD_PEER_SECURE)
|
||||
{
|
||||
#if defined(HAVE_SSL)
|
||||
int ret = SSL_write (HANDLE_TO_SSL(peer->handle2), buf, bufsize);
|
||||
if (ret <= -1)
|
||||
{
|
||||
int err = SSL_get_error(HANDLE_TO_SSL(peer->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
|
||||
{
|
||||
#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;
|
||||
|
||||
xtn = (httpd_xtn_t*) qse_httpd_getxtn (httpd);
|
||||
if (!xtn->ssl_ctx)
|
||||
if (!xtn->ssl_client_ctx)
|
||||
{
|
||||
/* delayed initialization of ssl */
|
||||
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));
|
||||
|
||||
if (HANDLE_TO_SSL(client->handle2))
|
||||
@ -2026,7 +2233,7 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client)
|
||||
}
|
||||
else
|
||||
{
|
||||
ssl = SSL_new (xtn->ssl_ctx);
|
||||
ssl = SSL_new (xtn->ssl_client_ctx);
|
||||
if (ssl == QSE_NULL) return -1;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* SSL_free (ssl); */
|
||||
/* client_closed() free this. no SSL_free() here.
|
||||
SSL_free (ssl); */
|
||||
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.
|
||||
* 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 record a record but it's given a
|
||||
* smaller buffer than the actuaal 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 set QSE_HTTPD_CLIENT_PENDING.
|
||||
* 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.
|
||||
*
|
||||
* TODO: Investigate if there is any starvation issues.
|
||||
* What if a single client never stops sending?
|
||||
|
@ -100,8 +100,8 @@ struct qse_httpd_real_task_t
|
||||
qse_httpd_real_task_t* next;
|
||||
};
|
||||
|
||||
#define MAX_SEND_SIZE 4096
|
||||
#define MAX_RECV_SIZE 4096
|
||||
#define MAX_SEND_SIZE (4096 * 4)
|
||||
#define MAX_RECV_SIZE (4096 * 2)
|
||||
|
||||
#define MAX_NWAD_TEXT_SIZE 96
|
||||
|
||||
|
Reference in New Issue
Block a user