Merge commit '6c0edd2190bfd18ffc523f486367da3724cf98a3' into develop

This commit is contained in:
Vinnie Falco
2014-03-06 21:22:22 -08:00
parent 4e3dcd1ce6
commit 956f2b98b8
7 changed files with 225 additions and 74 deletions

View File

@@ -12,3 +12,16 @@ parsertrace_g
*.Makefile
*.so.*
*.a
# Visual Studio uglies
*.suo
*.sln
*.vcxproj
*.vcxproj.filters
*.vcxproj.user
*.opensdf
*.ncrunchsolution*
*.sdf
*.vsp
*.psess

View File

@@ -39,3 +39,11 @@ BogDan Vatra <bogdan@kde.org>
Peter Faiman <peter@thepicard.org>
Corey Richardson <corey@octayn.net>
Tóth Tamás <tomika_nospam@freemail.hu>
Patrik Stutz <patrik.stutz@gmail.com>
Cam Swords <cam.swords@gmail.com>
Chris Dickinson <christopher.s.dickinson@gmail.com>
Uli Köhler <ukoehler@btronik.de>
Charlie Somerville <charlie@charliesomerville.com>
Fedor Indutny <fedor.indutny@gmail.com>
runner <runner.mei@gmail.com>
Alexis Campailla <alexis@janeasystems.com>

View File

@@ -19,7 +19,7 @@
# IN THE SOFTWARE.
PLATFORM ?= $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"')
SONAME ?= libhttp_parser.so.2.1
SONAME ?= libhttp_parser.so.2.2.1
CC?=gcc
AR?=ar

View File

@@ -36,7 +36,7 @@ Usage
One `http_parser` object is used per TCP connection. Initialize the struct
using `http_parser_init()` and set the callbacks. That might look something
like this for a request parser:
```c
http_parser_settings settings;
settings.on_url = my_url_callback;
settings.on_header_field = my_header_field_callback;
@@ -45,9 +45,11 @@ like this for a request parser:
http_parser *parser = malloc(sizeof(http_parser));
http_parser_init(parser, HTTP_REQUEST);
parser->data = my_socket;
```
When data is received on the socket execute the parser and check for errors.
```c
size_t len = 80*1024, nparsed;
char buf[len];
ssize_t recved;
@@ -68,6 +70,7 @@ When data is received on the socket execute the parser and check for errors.
} else if (nparsed != recved) {
/* Handle error. Usually just close the connection. */
}
```
HTTP needs to know where the end of the stream is. For example, sometimes
servers send responses without Content-Length and expect the client to

View File

@@ -248,6 +248,7 @@ enum state
, s_res_http_minor
, s_res_first_status_code
, s_res_status_code
, s_res_status_start
, s_res_status
, s_res_line_almost_done
@@ -581,6 +582,7 @@ size_t http_parser_execute (http_parser *parser,
const char *header_value_mark = 0;
const char *url_mark = 0;
const char *body_mark = 0;
const char *status_mark = 0;
/* We're in an error state. Don't bother doing anything. */
if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
@@ -627,6 +629,9 @@ size_t http_parser_execute (http_parser *parser,
case s_req_fragment:
url_mark = data;
break;
case s_res_status:
status_mark = data;
break;
}
for (p=data; p != data + len; p++) {
@@ -634,7 +639,17 @@ size_t http_parser_execute (http_parser *parser,
if (PARSING_HEADER(parser->state)) {
++parser->nread;
/* Buffer overflow attack */
/* Don't allow the total size of the HTTP headers (including the status
* line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect
* embedders against denial-of-service attacks where the attacker feeds
* us a never-ending header that the embedder keeps buffering.
*
* This check is arguably the responsibility of embedders but we're doing
* it on the embedder's behalf because most won't bother and this way we
* make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger
* than any reasonable request or response so this should never affect
* day-to-day operation.
*/
if (parser->nread > HTTP_MAX_HEADER_SIZE) {
SET_ERRNO(HPE_HEADER_OVERFLOW);
goto error;
@@ -823,7 +838,7 @@ size_t http_parser_execute (http_parser *parser,
if (!IS_NUM(ch)) {
switch (ch) {
case ' ':
parser->state = s_res_status;
parser->state = s_res_status_start;
break;
case CR:
parser->state = s_res_line_almost_done;
@@ -849,9 +864,8 @@ size_t http_parser_execute (http_parser *parser,
break;
}
case s_res_status:
/* the human readable status. e.g. "NOT FOUND"
* we are not humans so just ignore this */
case s_res_status_start:
{
if (ch == CR) {
parser->state = s_res_line_almost_done;
break;
@@ -861,12 +875,31 @@ size_t http_parser_execute (http_parser *parser,
parser->state = s_header_field_start;
break;
}
MARK(status);
parser->state = s_res_status;
parser->index = 0;
break;
}
case s_res_status:
if (ch == CR) {
parser->state = s_res_line_almost_done;
CALLBACK_DATA(status);
break;
}
if (ch == LF) {
parser->state = s_header_field_start;
CALLBACK_DATA(status);
break;
}
break;
case s_res_line_almost_done:
STRICT_CHECK(ch != LF);
parser->state = s_header_field_start;
CALLBACK_NOTIFY(status_complete);
break;
case s_start_req:
@@ -1476,8 +1509,8 @@ size_t http_parser_execute (http_parser *parser,
t *= 10;
t += ch - '0';
/* Overflow? */
if (t < parser->content_length || t == ULLONG_MAX) {
/* Overflow? Test against a conservative limit for simplicity. */
if ((ULLONG_MAX - 10) / 10 < parser->content_length) {
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
goto error;
}
@@ -1749,8 +1782,8 @@ size_t http_parser_execute (http_parser *parser,
t *= 16;
t += unhex_val;
/* Overflow? */
if (t < parser->content_length || t == ULLONG_MAX) {
/* Overflow? Test against a conservative limit for simplicity. */
if ((ULLONG_MAX - 16) / 16 < parser->content_length) {
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
goto error;
}
@@ -1844,12 +1877,14 @@ size_t http_parser_execute (http_parser *parser,
assert(((header_field_mark ? 1 : 0) +
(header_value_mark ? 1 : 0) +
(url_mark ? 1 : 0) +
(body_mark ? 1 : 0)) <= 1);
(body_mark ? 1 : 0) +
(status_mark ? 1 : 0)) <= 1);
CALLBACK_DATA_NOADVANCE(header_field);
CALLBACK_DATA_NOADVANCE(header_value);
CALLBACK_DATA_NOADVANCE(url);
CALLBACK_DATA_NOADVANCE(body);
CALLBACK_DATA_NOADVANCE(status);
return len;

View File

@@ -26,8 +26,8 @@ extern "C" {
/* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2
#define HTTP_PARSER_VERSION_MINOR 1
#define HTTP_PARSER_VERSION_PATCH 0
#define HTTP_PARSER_VERSION_MINOR 2
#define HTTP_PARSER_VERSION_PATCH 1
#include <sys/types.h>
#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
@@ -143,13 +143,13 @@ enum flags
\
/* Callback-related errors */ \
XX(CB_message_begin, "the on_message_begin callback failed") \
XX(CB_status_complete, "the on_status_complete callback failed") \
XX(CB_url, "the on_url callback failed") \
XX(CB_header_field, "the on_header_field callback failed") \
XX(CB_header_value, "the on_header_value callback failed") \
XX(CB_headers_complete, "the on_headers_complete callback failed") \
XX(CB_body, "the on_body callback failed") \
XX(CB_message_complete, "the on_message_complete callback failed") \
XX(CB_status, "the on_status callback failed") \
\
/* Parsing-related errors */ \
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
@@ -193,11 +193,11 @@ enum http_errno {
struct http_parser {
/** PRIVATE **/
unsigned char type : 2; /* enum http_parser_type */
unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */
unsigned char state; /* enum state from http_parser.c */
unsigned char header_state; /* enum header_state from http_parser.c */
unsigned char index; /* index into current matcher */
unsigned int type : 2; /* enum http_parser_type */
unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */
unsigned int state : 8; /* enum state from http_parser.c */
unsigned int header_state : 8; /* enum header_state from http_parser.c */
unsigned int index : 8; /* index into current matcher */
uint32_t nread; /* # bytes read in various scenarios */
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
@@ -205,16 +205,16 @@ struct http_parser {
/** READ-ONLY **/
unsigned short http_major;
unsigned short http_minor;
unsigned short status_code; /* responses only */
unsigned char method; /* requests only */
unsigned char http_errno : 7;
unsigned int status_code : 16; /* responses only */
unsigned int method : 8; /* requests only */
unsigned int http_errno : 7;
/* 1 = Upgrade header was present and the parser has exited because of that.
* 0 = No upgrade header present.
* Should be checked when http_parser_execute() returns in addition to
* error checking.
*/
unsigned char upgrade : 1;
unsigned int upgrade : 1;
/** PUBLIC **/
void *data; /* A pointer to get hook to the "connection" or "socket" object */
@@ -224,7 +224,7 @@ struct http_parser {
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_cb on_status_complete;
http_data_cb on_status;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;

View File

@@ -26,6 +26,12 @@
#include <string.h>
#include <stdarg.h>
#if defined(__APPLE__)
# undef strlcat
# undef strlncpy
# undef strlcpy
#endif /* defined(__APPLE__) */
#undef TRUE
#define TRUE 1
#undef FALSE
@@ -44,6 +50,7 @@ struct message {
enum http_parser_type type;
enum http_method method;
int status_code;
char response_status[MAX_ELEMENT_SIZE];
char request_path[MAX_ELEMENT_SIZE];
char request_url[MAX_ELEMENT_SIZE];
char fragment[MAX_ELEMENT_SIZE];
@@ -927,6 +934,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 301
,.response_status= "Moved Permanently"
,.num_headers= 8
,.headers=
{ { "Location", "http://www.google.com/" }
@@ -975,6 +983,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 200
,.response_status= "OK"
,.num_headers= 5
,.headers=
{ { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" }
@@ -1003,6 +1012,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 404
,.response_status= "Not Found"
,.num_headers= 0
,.headers= {}
,.body_size= 0
@@ -1018,6 +1028,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 301
,.response_status= ""
,.num_headers= 0
,.headers= {}
,.body= ""
@@ -1043,6 +1054,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 200
,.response_status= "OK"
,.num_headers= 2
,.headers=
{ {"Content-Type", "text/plain" }
@@ -1068,6 +1080,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 200
,.response_status= "OK"
,.num_headers= 2
,.headers=
{ {"Content-Type", "text/html; charset=utf-8" }
@@ -1091,6 +1104,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 200
,.response_status= "OK"
,.num_headers= 4
,.headers=
{ {"Content-Type", "text/html; charset=UTF-8" }
@@ -1116,6 +1130,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 200
,.response_status= "OK"
,.num_headers= 4
,.headers=
{ {"Server", "DCLK-AdSvr" }
@@ -1148,6 +1163,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 0
,.status_code= 301
,.response_status= "Moved Permanently"
,.num_headers= 9
,.headers=
{ { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" }
@@ -1186,6 +1202,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 200
,.response_status= "OK"
,.num_headers= 11
,.headers=
{ { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" }
@@ -1217,6 +1234,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 500
,.response_status= "Oriëntatieprobleem"
,.num_headers= 3
,.headers=
{ { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" }
@@ -1237,6 +1255,7 @@ const struct message responses[] =
,.http_major= 0
,.http_minor= 9
,.status_code= 200
,.response_status= "OK"
,.num_headers= 0
,.headers=
{}
@@ -1259,6 +1278,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 200
,.response_status= "OK"
,.num_headers= 1
,.headers=
{ { "Content-Type", "text/plain" }
@@ -1277,6 +1297,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 0
,.status_code= 200
,.response_status= "OK"
,.num_headers= 1
,.headers=
{ { "Connection", "keep-alive" }
@@ -1296,6 +1317,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 0
,.status_code= 204
,.response_status= "No content"
,.num_headers= 1
,.headers=
{ { "Connection", "keep-alive" }
@@ -1314,6 +1336,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 200
,.response_status= "OK"
,.num_headers= 0
,.headers={}
,.body_size= 0
@@ -1330,6 +1353,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 204
,.response_status= "No content"
,.num_headers= 0
,.headers={}
,.body_size= 0
@@ -1347,6 +1371,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 204
,.response_status= "No content"
,.num_headers= 1
,.headers=
{ { "Connection", "close" }
@@ -1368,6 +1393,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 200
,.response_status= "OK"
,.num_headers= 1
,.headers=
{ { "Transfer-Encoding", "chunked" }
@@ -1396,6 +1422,7 @@ const struct message responses[] =
,.http_major= 1
,.http_minor= 1
,.status_code= 200
,.response_status= "OK"
,.num_headers= 7
,.headers=
{ { "Server", "Microsoft-IIS/6.0" }
@@ -1410,6 +1437,60 @@ const struct message responses[] =
}
#endif /* !HTTP_PARSER_STRICT */
#define AMAZON_COM 20
, {.name= "amazon.com"
,.type= HTTP_RESPONSE
,.raw= "HTTP/1.1 301 MovedPermanently\r\n"
"Date: Wed, 15 May 2013 17:06:33 GMT\r\n"
"Server: Server\r\n"
"x-amz-id-1: 0GPHKXSJQ826RK7GZEB2\r\n"
"p3p: policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"\r\n"
"x-amz-id-2: STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD\r\n"
"Location: http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846\r\n"
"Vary: Accept-Encoding,User-Agent\r\n"
"Content-Type: text/html; charset=ISO-8859-1\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"1\r\n"
"\n\r\n"
"0\r\n"
"\r\n"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.status_code= 301
,.response_status= "MovedPermanently"
,.num_headers= 9
,.headers= { { "Date", "Wed, 15 May 2013 17:06:33 GMT" }
, { "Server", "Server" }
, { "x-amz-id-1", "0GPHKXSJQ826RK7GZEB2" }
, { "p3p", "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" }
, { "x-amz-id-2", "STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD" }
, { "Location", "http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846" }
, { "Vary", "Accept-Encoding,User-Agent" }
, { "Content-Type", "text/html; charset=ISO-8859-1" }
, { "Transfer-Encoding", "chunked" }
}
,.body= "\n"
}
#define EMPTY_REASON_PHRASE_AFTER_SPACE 20
, {.name= "empty reason phrase after space"
,.type= HTTP_RESPONSE
,.raw= "HTTP/1.1 200 \r\n"
"\r\n"
,.should_keep_alive= FALSE
,.message_complete_on_eof= TRUE
,.http_major= 1
,.http_minor= 1
,.status_code= 200
,.response_status= ""
,.num_headers= 0
,.headers= {}
,.body= ""
}
, {.name= NULL } /* sentinel */
};
@@ -1491,13 +1572,6 @@ request_url_cb (http_parser *p, const char *buf, size_t len)
return 0;
}
int
status_complete_cb (http_parser *p) {
assert(p == parser);
p->data++;
return 0;
}
int
header_field_cb (http_parser *p, const char *buf, size_t len)
{
@@ -1623,6 +1697,17 @@ message_complete_cb (http_parser *p)
return 0;
}
int
response_status_cb (http_parser *p, const char *buf, size_t len)
{
assert(p == parser);
strlncat(messages[num_messages].response_status,
sizeof(messages[num_messages].response_status),
buf,
len);
return 0;
}
/* These dontcall_* callbacks exist so that we can verify that when we're
* paused, no additional callbacks are invoked */
int
@@ -1683,11 +1768,20 @@ dontcall_message_complete_cb (http_parser *p)
abort();
}
int
dontcall_response_status_cb (http_parser *p, const char *buf, size_t len)
{
if (p || buf || len) { } // gcc
fprintf(stderr, "\n\n*** on_status() called on paused parser ***\n\n");
abort();
}
static http_parser_settings settings_dontcall =
{.on_message_begin = dontcall_message_begin_cb
,.on_header_field = dontcall_header_field_cb
,.on_header_value = dontcall_header_value_cb
,.on_url = dontcall_request_url_cb
,.on_status = dontcall_response_status_cb
,.on_body = dontcall_body_cb
,.on_headers_complete = dontcall_headers_complete_cb
,.on_message_complete = dontcall_message_complete_cb
@@ -1753,11 +1847,20 @@ pause_message_complete_cb (http_parser *p)
return message_complete_cb(p);
}
int
pause_response_status_cb (http_parser *p, const char *buf, size_t len)
{
http_parser_pause(p, 1);
*current_pause_parser = settings_dontcall;
return response_status_cb(p, buf, len);
}
static http_parser_settings settings_pause =
{.on_message_begin = pause_message_begin_cb
,.on_header_field = pause_header_field_cb
,.on_header_value = pause_header_value_cb
,.on_url = pause_request_url_cb
,.on_status = pause_response_status_cb
,.on_body = pause_body_cb
,.on_headers_complete = pause_headers_complete_cb
,.on_message_complete = pause_message_complete_cb
@@ -1768,6 +1871,7 @@ static http_parser_settings settings =
,.on_header_field = header_field_cb
,.on_header_value = header_value_cb
,.on_url = request_url_cb
,.on_status = response_status_cb
,.on_body = body_cb
,.on_headers_complete = headers_complete_cb
,.on_message_complete = message_complete_cb
@@ -1778,6 +1882,7 @@ static http_parser_settings settings_count_body =
,.on_header_field = header_field_cb
,.on_header_value = header_value_cb
,.on_url = request_url_cb
,.on_status = response_status_cb
,.on_body = count_body_cb
,.on_headers_complete = headers_complete_cb
,.on_message_complete = message_complete_cb
@@ -1788,6 +1893,7 @@ static http_parser_settings settings_null =
,.on_header_field = 0
,.on_header_value = 0
,.on_url = 0
,.on_status = 0
,.on_body = 0
,.on_headers_complete = 0
,.on_message_complete = 0
@@ -1911,6 +2017,7 @@ message_eq (int index, const struct message *expected)
MESSAGE_CHECK_NUM_EQ(expected, m, method);
} else {
MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
MESSAGE_CHECK_STR_EQ(expected, m, response_status);
}
MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive);
@@ -2831,7 +2938,7 @@ test_header_content_length_overflow_error (void)
"HTTP/1.1 200 OK\r\n" \
"Content-Length: " #size "\r\n" \
"\r\n"
const char a[] = X(18446744073709551614); /* 2^64-2 */
const char a[] = X(1844674407370955160); /* 2^64 / 10 - 1 */
const char b[] = X(18446744073709551615); /* 2^64-1 */
const char c[] = X(18446744073709551616); /* 2^64 */
#undef X
@@ -2849,7 +2956,7 @@ test_chunk_content_length_overflow_error (void)
"\r\n" \
#size "\r\n" \
"..."
const char a[] = X(FFFFFFFFFFFFFFFE); /* 2^64-2 */
const char a[] = X(FFFFFFFFFFFFFFE); /* 2^64 / 16 - 1 */
const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */
const char c[] = X(10000000000000000); /* 2^64 */
#undef X
@@ -3096,20 +3203,6 @@ create_large_chunked_message (int body_size_in_kb, const char* headers)
return buf;
}
void
test_status_complete (void)
{
parser_init(HTTP_RESPONSE);
parser->data = 0;
http_parser_settings settings = settings_null;
settings.on_status_complete = status_complete_cb;
char *response = "don't mind me, just a simple response";
http_parser_execute(parser, &settings, response, strlen(response));
assert(parser->data == (void*)0); // the status_complete callback was never called
assert(parser->http_errno == HPE_INVALID_CONSTANT); // the errno for an invalid status line
}
/* Verify that we can pause parsing at any of the bytes in the
* message and still get the result that we're expecting. */
void
@@ -3243,6 +3336,7 @@ main (void)
,.http_major= 1
,.http_minor= 0
,.status_code= 200
,.response_status= "OK"
,.num_headers= 2
,.headers=
{ { "Transfer-Encoding", "chunked" }
@@ -3431,8 +3525,6 @@ main (void)
, &requests[CONNECT_REQUEST]
);
test_status_complete();
puts("requests okay");
return 0;