* [fix] Several updates to detect when __nopoll_conn_get_ssl_context fails
  to report a valid SSL_CTX (fixed updated test_19). 

* [fix] Updated header read handling to support all cases when a
  splitted/broken header is received. Added regression tests test_31,
  test_32, test_33, test_34 and test_35 to simulate and support different
  scenarios where part of the header is received and then the rest...
This commit is contained in:
Francis Brosnan Blázquez
2016-05-15 23:03:44 +02:00
parent d65ecb1726
commit 4bc7339708
2 changed files with 109 additions and 21 deletions

View File

@@ -602,6 +602,7 @@ nopoll_bool __nopoll_conn_set_ssl_client_options (noPollCtx * ctx, noPollConn *
} /* end if */
/* enable default verification paths */
/* printf ("conn = %p, conn->ssl_ctx = %p\n", conn, conn->ssl_ctx); */
if (SSL_CTX_set_default_verify_paths (conn->ssl_ctx) != 1) {
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to configure default verification paths, SSL_CTX_set_default_verify_paths () failed");
return nopoll_false;
@@ -774,10 +775,15 @@ noPollConn * __nopoll_conn_new_common (noPollCtx * ctx,
if (enable_tls) {
/* found TLS connection request, enable it */
conn->ssl_ctx = __nopoll_conn_get_ssl_context (ctx, conn, options, nopoll_true);
if (conn->ssl_ctx == NULL) {
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to enable TLS, internal __nopoll_conn_get_ssl_context (ctx=%p, conn=%p, options=%p, nopoll_true) failed",
ctx, conn, options);
goto fail_ssl_connection;
} /* end if */
/* check for client side SSL configuration */
if (! __nopoll_conn_set_ssl_client_options (ctx, conn, options)) {
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to configure additional SSL options, unable to continue",
nopoll_log (ctx, NOPOLL_LEVEL_CRITICAL, "Unable to configure additional SSL options, unable to continue, conn->ssl_ctx=%p, conn->ssl=%p",
conn->ssl_ctx, conn->ssl);
goto fail_ssl_connection;
} /* end if */
@@ -2885,11 +2891,21 @@ noPollMsg * nopoll_conn_get_msg (noPollConn * conn)
unsigned integer */
bytes = __nopoll_conn_receive (conn, buffer + 2, 2);
if (bytes != 2) {
nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Failed to get next 2 bytes to read header from the wire, failed to received content, shutting down id=%d the connection, errno=%d (%s)", conn->id, errno, strerror (errno));
if (errno == NOPOLL_EWOULDBLOCK) {
nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Failed to get next 2 bytes to read header from the wire, but received=%d, failed to received content, shutting down id=%d the connection, errno=%d (%s)",
bytes, conn->id, errno, strerror (errno));
if (errno == NOPOLL_EWOULDBLOCK || errno == 0) {
/* connection is not ready at this point */
conn->previous_msg = msg;
conn->read_pending_header = nopoll_true;
/* check amount of bytes to reuse them */
nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Detected broken WebSocket peer sending header content using different frames, trying to save and resume later");
if (bytes > 0) {
/* ok, store content read into the pending buffer for next call */
memcpy (conn->pending_buf + conn->pending_buf_bytes, buffer + 2, bytes);
conn->pending_buf_bytes += bytes;
}
return NULL;
}
@@ -2902,6 +2918,8 @@ noPollMsg * nopoll_conn_get_msg (noPollConn * conn)
header_size += bytes;
msg->payload_size = nopoll_get_16bit (buffer + 2);
nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "Received (%d) bytes in header (size %d) for payload size indication, which finally is: %d", bytes, header_size,(int) msg->payload_size);
} else if (msg->payload_size == 127) {
#if defined(NOPOLL_64BIT_PLATFORM)
@@ -3054,7 +3072,7 @@ read_payload:
/* flag that this message doesn't have FIN = 0 because
* we wasn't able to read it entirely */
msg->has_fin = 0;
/* msg->has_fin = 0; */
} /* end if */
/* flag the message was being a fragment according to previous flag */
@@ -3844,21 +3862,22 @@ int nopoll_conn_send_frame (noPollConn * conn, nopoll_bool fin, nopoll_bool mask
desp = 0;
tries = 0;
/***** BEGIN INTERNAL debug code for test_30 : nopoll-regression-client.c ******/
if (conn->__force_stop_after_header) {
nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Sending broken header and implement a pause on purpose...");
/***** BEGIN INTERNAL debug code for test_30, test_31, test_32, test_33, test_34, test_35 : nopoll-regression-client.c ******/
if ((conn->__force_stop_after_header > 0) && (conn->__force_stop_after_header < (length + header_size))) {
nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Sending broken header (just %d bytes) and implement a pause on purpose...", conn->__force_stop_after_header);
/* send just 2 bytes for the header and then implement a very long pause */
bytes_written = conn->send (conn, send_buffer, 2);
desp = 2;
if (bytes_written != 2) {
nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Requested to write 2 bytes for the header but %d were written",
bytes_written);
bytes_written = conn->send (conn, send_buffer, conn->__force_stop_after_header);
desp = conn->__force_stop_after_header;
if (bytes_written != conn->__force_stop_after_header) {
nopoll_log (conn->ctx, NOPOLL_LEVEL_WARNING, "Requested to write %d bytes for the header but %d were written",
conn->__force_stop_after_header, bytes_written);
desp = 0;
} /* end if */
/* sleep after header ... */
nopoll_sleep (5000); /* 5 seconds */
nopoll_sleep (5000000); /* 5 seconds */
} /* end if */
/****** END INTERNAL debug code for test_30 : nopoll-regression-client.c ******/

View File

@@ -2415,7 +2415,7 @@ nopoll_bool test_29 (void) {
relases ****/
#include <nopoll_private.h>
nopoll_bool test_30 (void) {
nopoll_bool test_30_common_header_stop (const char * label, int bytes_to_send_before_stop) {
noPollConn * conn;
noPollCtx * ctx;
@@ -2434,16 +2434,19 @@ nopoll_bool test_30 (void) {
return nopoll_false;
} /* end if */
printf ("Test 30: waiting until connection is ready..\n");
printf ("Test %s: waiting until connection is ready..\n", label);
/* wait until it is connected */
nopoll_conn_wait_until_connection_ready (conn, 5);
printf ("Test 30: ok..\n");
printf ("Test %s: ok..\n", label);
/* send a message to request connection close with a particular message */
conn->__force_stop_after_header = nopoll_true;
conn->__force_stop_after_header = bytes_to_send_before_stop;
printf ("Test 30: sending first message..\n");
length = strlen (msg);
printf ("Test %s: sending first message (of %d bytes, sending broken header of %d, pausing then, and then sending the rest..)\n",
label, length, bytes_to_send_before_stop);
if (nopoll_conn_send_text (conn, msg, length) != length) {
printf ("ERROR: failed to send message..");
return nopoll_false;
@@ -2455,7 +2458,7 @@ nopoll_bool test_30 (void) {
return nopoll_false;
} /* end if */
printf ("Test 30: getting reply to the message..\n");
printf ("Test %s: getting reply to the message..\n", label);
tries = 10;
while (tries > 0 ) {
/* get message */
@@ -2480,13 +2483,16 @@ nopoll_bool test_30 (void) {
/* release message */
nopoll_msg_unref (msg_ref);
printf ("Test 30: send second message..\n");
printf ("Test %s: sending second message (of %d bytes, sending broken header of %d, pausing then, and then sending the rest..)\n",
label, length, bytes_to_send_before_stop);
if (nopoll_conn_send_text (conn, msg, length) != length) {
printf ("ERROR: failed to send message..");
return nopoll_false;
} /* end while */
printf ("Test 30: getting reply to the message (to the second message)..\n");
printf ("Test %s: getting reply to the message (to the second message)..\n", label);
tries = 10;
while (tries > 0 ) {
/* get message */
@@ -2520,7 +2526,35 @@ nopoll_bool test_30 (void) {
return nopoll_true;
}
nopoll_bool test_30 (void) {
/* call to test send 1 byte and stop */
return test_30_common_header_stop ("30", 2);
}
nopoll_bool test_31 (void) {
/* call to test send 1 byte and stop */
return test_30_common_header_stop ("31", 1);
}
nopoll_bool test_32 (void) {
/* call to test send 1 byte and stop */
return test_30_common_header_stop ("32", 3);
}
nopoll_bool test_33 (void) {
/* call to test send 1 byte and stop */
return test_30_common_header_stop ("33", 4);
}
nopoll_bool test_34 (void) {
/* call to test send 1 byte and stop */
return test_30_common_header_stop ("34", 5);
}
nopoll_bool test_35 (void) {
/* call to test send 1 byte and stop */
return test_30_common_header_stop ("35", 8);
}
int main (int argc, char ** argv)
{
@@ -2832,6 +2866,41 @@ int main (int argc, char ** argv)
return -1;
} /* end if */
if (test_31 ()) {
printf ("Test 31: simulate stop in the middle of the header send (II) [ OK ]\n");
} else {
printf ("Test 31: simulate stop in the middle of the header send (II) [ FAILED ]\n");
return -1;
} /* end if */
if (test_32 ()) {
printf ("Test 32: simulate stop in the middle of the header send (III) [ OK ]\n");
} else {
printf ("Test 32: simulate stop in the middle of the header send (III) [ FAILED ]\n");
return -1;
} /* end if */
if (test_33 ()) {
printf ("Test 33: simulate stop in the middle of the header send (IV) [ OK ]\n");
} else {
printf ("Test 33: simulate stop in the middle of the header send (IV) [ FAILED ]\n");
return -1;
} /* end if */
if (test_34 ()) {
printf ("Test 34: simulate stop in the middle of the header send (V) [ OK ]\n");
} else {
printf ("Test 34: simulate stop in the middle of the header send (V) [ FAILED ]\n");
return -1;
} /* end if */
if (test_35 ()) {
printf ("Test 35: simulate stop in the middle of the header send (VI) [ OK ]\n");
} else {
printf ("Test 35: simulate stop in the middle of the header send (VI) [ FAILED ]\n");
return -1;
} /* end if */
/* add support to reply with redirect 301 to an opening
* request: page 19 and 22 */