1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-08 15:02:10 +03:00

mod_lua: Figure out a way to read from SSL connections with WebSockets. Brigades ain't my strong side, so if someone could adjust it a bit, that'd be swell. It _works_, but I'm sure it could be improved upon. Also make r:wsclose() work properly with SSL.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1523432 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Daniel Gruno
2013-09-15 12:47:50 +00:00
parent b2e9d12685
commit 5929a20fe0

View File

@@ -1990,6 +1990,29 @@ static int lua_websocket_greet(lua_State *L)
return 0; return 0;
} }
static apr_status_t lua_websocket_readbytes(conn_rec* c, char* buffer,
apr_off_t len)
{
apr_bucket_brigade *brigade = apr_brigade_create(c->pool, c->bucket_alloc);
apr_status_t rv;
rv = ap_get_brigade(c->input_filters, brigade, AP_MODE_READBYTES,
APR_BLOCK_READ, len);
if (rv == APR_SUCCESS) {
if (!APR_BRIGADE_EMPTY(brigade)) {
apr_bucket* bucket = APR_BRIGADE_FIRST(brigade);
const char* data = NULL;
apr_size_t data_length = 0;
rv = apr_bucket_read(bucket, &data, &data_length, APR_BLOCK_READ);
if (rv == APR_SUCCESS) {
memcpy(buffer, data, len);
}
apr_bucket_delete(bucket);
}
}
apr_brigade_cleanup(brigade);
return rv;
}
static int lua_websocket_read(lua_State *L) static int lua_websocket_read(lua_State *L)
{ {
apr_socket_t *sock; apr_socket_t *sock;
@@ -2007,24 +2030,29 @@ static int lua_websocket_read(lua_State *L)
request_rec *r = ap_lua_check_request_rec(L, 1); request_rec *r = ap_lua_check_request_rec(L, 1);
plaintext = ap_lua_ssl_is_https(r->connection) ? 0 : 1; plaintext = ap_lua_ssl_is_https(r->connection) ? 0 : 1;
if (!plaintext) {
ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r,
"Websocket: WSS protocol reading not yet supported!");
return 0;
}
mask_bytes = apr_pcalloc(r->pool, 4); mask_bytes = apr_pcalloc(r->pool, 4);
sock = ap_get_conn_socket(r->connection); sock = ap_get_conn_socket(r->connection);
/* Get opcode and FIN bit */ /* Get opcode and FIN bit */
rv = apr_socket_recv(sock, &byte, &len); if (plaintext) {
rv = apr_socket_recv(sock, &byte, &len);
}
else {
rv = lua_websocket_readbytes(r->connection, &byte, 1);
}
if (rv == APR_SUCCESS) { if (rv == APR_SUCCESS) {
unsigned char fin, opcode, mask, payload; unsigned char fin, opcode, mask, payload;
fin = byte >> 7; fin = byte >> 7;
opcode = (byte << 4) >> 4; opcode = (byte << 4) >> 4;
/* Get the payload length and mask bit */ /* Get the payload length and mask bit */
rv = apr_socket_recv(sock, &byte, &len); if (plaintext) {
rv = apr_socket_recv(sock, &byte, &len);
}
else {
rv = lua_websocket_readbytes(r->connection, &byte, 1);
}
if (rv == APR_SUCCESS) { if (rv == APR_SUCCESS) {
mask = byte >> 7; mask = byte >> 7;
payload = byte - 128; payload = byte - 128;
@@ -2033,7 +2061,13 @@ static int lua_websocket_read(lua_State *L)
/* Extended payload? */ /* Extended payload? */
if (payload == 126) { if (payload == 126) {
len = 2; len = 2;
rv = apr_socket_recv(sock, (char*) &payload_short, &len); if (plaintext) {
rv = apr_socket_recv(sock, (char*) &payload_short, &len);
}
else {
rv = lua_websocket_readbytes(r->connection,
(char*) &payload_short, 2);
}
payload_short = ntohs(payload_short); payload_short = ntohs(payload_short);
if (rv == APR_SUCCESS) { if (rv == APR_SUCCESS) {
@@ -2046,7 +2080,13 @@ static int lua_websocket_read(lua_State *L)
/* Super duper extended payload? */ /* Super duper extended payload? */
if (payload == 127) { if (payload == 127) {
len = 8; len = 8;
rv = apr_socket_recv(sock, (char*) &payload_long, &len); if (plaintext) {
rv = apr_socket_recv(sock, (char*) &payload_long, &len);
}
else {
rv = lua_websocket_readbytes(r->connection,
(char*) &payload_long, 8);
}
if (rv == APR_SUCCESS) { if (rv == APR_SUCCESS) {
plen = ap_ntoh64(&payload_long); plen = ap_ntoh64(&payload_long);
} }
@@ -2062,7 +2102,13 @@ static int lua_websocket_read(lua_State *L)
fin ? "This is a final frame" : "more to follow"); fin ? "This is a final frame" : "more to follow");
if (mask) { if (mask) {
len = 4; len = 4;
rv = apr_socket_recv(sock, (char*) mask_bytes, &len); if (plaintext) {
rv = apr_socket_recv(sock, (char*) mask_bytes, &len);
}
else {
rv = lua_websocket_readbytes(r->connection,
(char*) mask_bytes, 4);
}
if (rv != APR_SUCCESS) { if (rv != APR_SUCCESS) {
return 0; return 0;
} }
@@ -2088,11 +2134,12 @@ static int lua_websocket_read(lua_State *L)
at); at);
} }
else { else {
at = ap_get_client_block(r, buffer, plen); rv = lua_websocket_readbytes(r->connection, buffer,
remaining);
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
"Websocket: SSL Frame contained %lu bytes, "\ "Websocket: SSL Frame contained %lu bytes, "\
"pushed to Lua stack", "pushed to Lua stack",
at); remaining);
} }
if (mask) { if (mask) {
for (n = 0; n < plen; n++) { for (n = 0; n < plen; n++) {
@@ -2100,7 +2147,7 @@ static int lua_websocket_read(lua_State *L)
} }
} }
lua_pushlstring(L, buffer, (size_t) plen); /* push string to stack */ lua_pushlstring(L, buffer, (size_t) plen); /* push to stack */
lua_pushboolean(L, fin); /* push FIN bit to stack as boolean */ lua_pushboolean(L, fin); /* push FIN bit to stack as boolean */
return 2; return 2;
} }
@@ -2176,16 +2223,15 @@ static int lua_websocket_write(lua_State *L)
static int lua_websocket_close(lua_State *L) static int lua_websocket_close(lua_State *L)
{ {
apr_socket_t *sock; apr_socket_t *sock;
apr_size_t plen;
char prelude[2]; char prelude[2];
request_rec *r = ap_lua_check_request_rec(L, 1); request_rec *r = ap_lua_check_request_rec(L, 1);
sock = ap_get_conn_socket(r->connection); sock = ap_get_conn_socket(r->connection);
/* Send a header that says: socket is closing. */ /* Send a header that says: socket is closing. */
prelude[0] = 0x88; /* closing socket opcode */ prelude[0] = 0x88; /* closing socket opcode */
prelude[1] = 0; /* zero length frame */ prelude[1] = 0; /* zero length frame */
plen = 2; ap_rwrite(prelude, 2, r);
apr_socket_send(sock, prelude, &plen);
/* Close up tell the MPM and filters to back off */ /* Close up tell the MPM and filters to back off */
apr_socket_close(sock); apr_socket_close(sock);