static void test_mg_download(void) { char *p1, *p2, ebuf[100]; int len1, len2, port = atoi(HTTPS_PORT); struct mg_connection *conn; struct mg_context *ctx; ASSERT((ctx = mg_start(event_handler, NULL, OPTIONS)) != NULL); ASSERT(mg_download(NULL, port, 0, ebuf, sizeof(ebuf), "") == NULL); ASSERT(mg_download("localhost", 0, 0, ebuf, sizeof(ebuf), "") == NULL); ASSERT(mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "") == NULL); // Fetch nonexistent file, should see 404 ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s", "GET /gimbec HTTP/1.0\r\n\r\n")) != NULL); ASSERT(strcmp(conn->request_info.uri, "404") == 0); mg_close_connection(conn); // Fetch mongoose.c, should succeed ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s", "GET /mongoose.c HTTP/1.0\r\n\r\n")) != NULL); ASSERT(!strcmp(conn->request_info.uri, "200")); ASSERT((p1 = read_conn(conn, &len1)) != NULL); ASSERT((p2 = read_file("mongoose.c", &len2)) != NULL); ASSERT(len1 == len2); ASSERT(memcmp(p1, p2, len1) == 0); free(p1), free(p2); mg_close_connection(conn); // Fetch in-memory file, should succeed. ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s", "GET /blah HTTP/1.1\r\n\r\n")) != NULL); ASSERT((p1 = read_conn(conn, &len1)) != NULL); ASSERT(len1 == (int) strlen(inmemory_file_data)); ASSERT(memcmp(p1, inmemory_file_data, len1) == 0); free(p1); mg_close_connection(conn); // Test SSL redirect, IP address ASSERT((conn = mg_download("localhost", atoi(HTTP_PORT), 0, ebuf, sizeof(ebuf), "%s", "GET /foo HTTP/1.1\r\n\r\n")) != NULL); ASSERT(strcmp(conn->request_info.uri, "302") == 0); ASSERT(strcmp(mg_get_header(conn, "Location"), "https://127.0.0.1:" HTTPS_PORT "/foo") == 0); mg_close_connection(conn); // Test SSL redirect, Host: ASSERT((conn = mg_download("localhost", atoi(HTTP_PORT), 0, ebuf, sizeof(ebuf), "%s", "GET /foo HTTP/1.1\r\nHost: a.b:77\n\n")) != NULL); ASSERT(strcmp(conn->request_info.uri, "302") == 0); ASSERT(strcmp(mg_get_header(conn, "Location"), "https://a.b:" HTTPS_PORT "/foo") == 0); mg_close_connection(conn); mg_stop(ctx); }
int CloseHandler(struct mg_connection *conn, void *cbdata) { /* Handler may access the request info using mg_get_request_info */ const struct mg_request_info *req_info = mg_get_request_info(conn); mg_printf(conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: " "close\r\n\r\n"); mg_printf(conn, "<html><body>"); mg_printf(conn, "<h2>This handler will close the connection in a second</h2>"); #ifdef _WIN32 Sleep(1000); #else sleep(1); #endif mg_printf(conn, "bye"); printf("CloseHandler: close connection\n"); mg_close_connection(conn); printf("CloseHandler: wait 10 sec\n"); #ifdef _WIN32 Sleep(10000); #else sleep(10); #endif printf("CloseHandler: return from function\n"); return 1; }
static void test_mg_upload(void) { static const char *boundary = "OOO___MY_BOUNDARY___OOO"; struct mg_context *ctx; struct mg_connection *conn; char ebuf[100], buf[20], *file_data, *post_data = NULL; int file_len, post_data_len; ASSERT((ctx = mg_start(&CALLBACKS, NULL, OPTIONS)) != NULL); ASSERT((file_data = read_file("mongoose.c", &file_len)) != NULL); post_data_len = alloc_printf(&post_data, 0, "--%s\r\n" "Content-Disposition: form-data; " "name=\"file\"; " "filename=\"%s\"\r\n\r\n" "%.*s\r\n" "--%s\r\n", boundary, upload_filename, file_len, file_data, boundary); ASSERT(post_data_len > 0); ASSERT((conn = mg_download("localhost", atoi(HTTPS_PORT), 1, ebuf, sizeof(ebuf), "POST /upload HTTP/1.1\r\n" "Content-Length: %d\r\n" "Content-Type: multipart/form-data; " "boundary=%s\r\n\r\n" "%.*s", post_data_len, boundary, post_data_len, post_data)) != NULL); free(file_data), free(post_data); ASSERT(mg_read(conn, buf, sizeof(buf)) == (int) strlen(upload_ok_message)); ASSERT(memcmp(buf, upload_ok_message, strlen(upload_ok_message)) == 0); mg_close_connection(conn); mg_stop(ctx); }
static void test_api_calls(void) { char ebuf[100]; struct mg_connection *conn; struct mg_context *ctx; static const char *fmt = "POST %s HTTP/1.0\r\n" "Host: blah.com\n" // More spaces before "content-length: 3\r\n" // Lower case header name "\r\nb=123456"; // Content size > content-length, test for mg_read() ASSERT((ctx = mg_start(OPTIONS, api_cb, (void *) 123)) != NULL); ASSERT((conn = mg_download("localhost", atoi(HTTPS_PORT), 1, ebuf, sizeof(ebuf), fmt, api_uri)) != NULL); mg_close_connection(conn); mg_stop(ctx); }
static void test_api_calls(void) { char ebuf[100]; struct mg_callbacks callbacks; struct mg_connection *conn; struct mg_context *ctx; static const char *request = "POST /?a=%20&b=&c=xx HTTP/1.0\r\n" "Host: blah.com\n" // More spaces before "content-length: 3\r\n" // Lower case header name "\r\nb=123456"; // Content size > content-length, test for mg_read() memset(&callbacks, 0, sizeof(callbacks)); callbacks.begin_request = api_callback; ASSERT((ctx = mg_start(&callbacks, (void *) 123, OPTIONS)) != NULL); ASSERT((conn = mg_download("localhost", atoi(HTTPS_PORT), 1, ebuf, sizeof(ebuf), "%s", request)) != NULL); mg_close_connection(conn); mg_stop(ctx); }
struct mg_connection *mg_download(const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, const char *fmt, ...) { struct mg_connection *conn; va_list ap; va_start(ap, fmt); ebuf[0] = '\0'; if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) { } else if (mg_vprintf(conn, fmt, ap) <= 0) { snprintf(ebuf, ebuf_len, "%s", "Error sending request"); } else { getreq(conn, ebuf, ebuf_len); } if (ebuf[0] != '\0' && conn != NULL) { mg_close_connection(conn); conn = NULL; } return conn; }
static void test_request_replies(void) { char ebuf[100]; int i, port = atoi(HTTPS_PORT); struct mg_connection *conn; struct mg_context *ctx; static struct { const char *request, *reply_regex; } tests[] = { { "GET test/hello.txt HTTP/1.0\r\nRange: bytes=3-5\r\n\r\n", "^HTTP/1.1 206 Partial Content" }, {NULL, NULL}, }; ASSERT((ctx = mg_start(&CALLBACKS, NULL, OPTIONS)) != NULL); for (i = 0; tests[i].request != NULL; i++) { ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s", tests[i].request)) != NULL); mg_close_connection(conn); } mg_stop(ctx); }
static void test_mg_upload(void) { static const char *boundary = "OOO___MY_BOUNDARY___OOO"; struct mg_context *ctx; struct mg_connection *conn; char ebuf[100], buf[20], *file_data, *file2_data, *post_data; int file_len, file2_len, post_data_len; ASSERT((ctx = mg_start(OPTIONS, event_handler, NULL)) != NULL); // Upload two files ASSERT((file_data = read_file("lua_5.2.1.h", &file_len)) != NULL); ASSERT((file2_data = read_file("lsqlite3.c", &file2_len)) != NULL); post_data = NULL; post_data_len = alloc_printf(&post_data, 0, // First file "--%s\r\n" "Content-Disposition: form-data; " "name=\"file\"; " "filename=\"%s\"\r\n\r\n" "%.*s\r\n" // Second file "--%s\r\n" "Content-Disposition: form-data; " "name=\"file\"; " "filename=\"%s\"\r\n\r\n" "%.*s\r\n" // Final boundary "--%s--\r\n", boundary, "f1.txt", file_len, file_data, boundary, "f2.txt", file2_len, file2_data, boundary); ASSERT(post_data_len > 0); ASSERT((conn = mg_download("localhost", atoi(HTTPS_PORT), 1, ebuf, sizeof(ebuf), "POST /upload HTTP/1.1\r\n" "Content-Length: %d\r\n" "Content-Type: multipart/form-data; " "boundary=%s\r\n\r\n" "%.*s", post_data_len, boundary, post_data_len, post_data)) != NULL); ASSERT(mg_read(conn, buf, sizeof(buf)) == (int) strlen(upload_ok_message)); ASSERT(memcmp(buf, upload_ok_message, strlen(upload_ok_message)) == 0); mg_close_connection(conn); mg_stop(ctx); }
void HttpRequest::ThreadFunction() { String protocol = "http"; String host; String path = "/"; int port = 80; unsigned protocolEnd = url_.Find("://"); if (protocolEnd != String::NPOS) { protocol = url_.Substring(0, protocolEnd); host = url_.Substring(protocolEnd + 3); } else host = url_; unsigned pathStart = host.Find('/'); if (pathStart != String::NPOS) { path = host.Substring(pathStart); host = host.Substring(0, pathStart); } unsigned portStart = host.Find(':'); if (portStart != String::NPOS) { port = ToInt(host.Substring(portStart + 1)); host = host.Substring(0, portStart); } char errorBuffer[ERROR_BUFFER_SIZE]; memset(errorBuffer, 0, sizeof(errorBuffer)); String headersStr; for (unsigned i = 0; i < headers_.Size(); ++i) { // Trim and only add non-empty header strings String header = headers_[i].Trimmed(); if (header.Length()) headersStr += header + "\r\n"; } // Initiate the connection. This may block due to DNS query /// \todo SSL mode will not actually work unless Civetweb's SSL mode is initialized with an external SSL DLL mg_connection* connection = 0; if (postData_.Empty()) { connection = mg_download(host.CString(), port, protocol.Compare("https", false) ? 0 : 1, errorBuffer, sizeof(errorBuffer), "%s %s HTTP/1.0\r\n" "Host: %s\r\n" "%s" "\r\n", verb_.CString(), path.CString(), host.CString(), headersStr.CString()); } else { connection = mg_download(host.CString(), port, protocol.Compare("https", false) ? 0 : 1, errorBuffer, sizeof(errorBuffer), "%s %s HTTP/1.0\r\n" "Host: %s\r\n" "%s" "Content-Length: %d\r\n" "\r\n" "%s", verb_.CString(), path.CString(), host.CString(), headersStr.CString(), postData_.Length(), postData_.CString()); } { MutexLock lock(mutex_); state_ = connection ? HTTP_OPEN : HTTP_ERROR; // If no connection could be made, store the error and exit if (state_ == HTTP_ERROR) { error_ = String(&errorBuffer[0]); return; } } // Loop while should run, read data from the connection, copy to the main thread buffer if there is space while (shouldRun_) { // Read less than full buffer to be able to distinguish between full and empty ring buffer. Reading may block int bytesRead = mg_read(connection, httpReadBuffer_.Get(), READ_BUFFER_SIZE / 4); if (bytesRead <= 0) break; mutex_.Acquire(); // Wait until enough space in the main thread's ring buffer for (;;) { unsigned spaceInBuffer = READ_BUFFER_SIZE - ((writePosition_ - readPosition_) & (READ_BUFFER_SIZE - 1)); if ((int)spaceInBuffer > bytesRead || !shouldRun_) break; mutex_.Release(); Time::Sleep(5); mutex_.Acquire(); } if (!shouldRun_) { mutex_.Release(); break; } if (writePosition_ + bytesRead <= READ_BUFFER_SIZE) memcpy(readBuffer_.Get() + writePosition_, httpReadBuffer_.Get(), bytesRead); else { // Handle ring buffer wrap unsigned part1 = READ_BUFFER_SIZE - writePosition_; unsigned part2 = bytesRead - part1; memcpy(readBuffer_.Get() + writePosition_, httpReadBuffer_.Get(), part1); memcpy(readBuffer_.Get(), httpReadBuffer_.Get() + part1, part2); } writePosition_ += bytesRead; writePosition_ &= READ_BUFFER_SIZE - 1; mutex_.Release(); } // Close the connection mg_close_connection(connection); { MutexLock lock(mutex_); state_ = HTTP_CLOSED; } }
END_TEST START_TEST(test_mg_server_and_client_tls) { #ifndef NO_SSL struct mg_context *ctx; int ports_cnt; struct mg_server_ports ports[16]; struct mg_callbacks callbacks; char errmsg[256]; struct mg_connection *client_conn; char client_err[256]; const struct mg_request_info *client_ri; int client_res; struct mg_client_options client_options; const char *OPTIONS[32]; /* initializer list here is rejected by CI test */ int opt_idx = 0; char server_cert[256]; char client_cert[256]; const char *res_dir = locate_resources(); ck_assert(res_dir != NULL); strcpy(server_cert, res_dir); strcpy(client_cert, res_dir); #ifdef _WIN32 strcat(server_cert, "cert\\server.pem"); strcat(client_cert, "cert\\client.pem"); #else strcat(server_cert, "cert/server.pem"); strcat(client_cert, "cert/client.pem"); #endif memset((void *)OPTIONS, 0, sizeof(OPTIONS)); #if !defined(NO_FILES) OPTIONS[opt_idx++] = "document_root"; OPTIONS[opt_idx++] = "."; #endif OPTIONS[opt_idx++] = "listening_ports"; OPTIONS[opt_idx++] = "8080r,8443s"; OPTIONS[opt_idx++] = "ssl_certificate"; OPTIONS[opt_idx++] = server_cert; OPTIONS[opt_idx++] = "ssl_verify_peer"; OPTIONS[opt_idx++] = "yes"; OPTIONS[opt_idx++] = "ssl_ca_file"; OPTIONS[opt_idx++] = client_cert; ck_assert_int_le(opt_idx, (int)(sizeof(OPTIONS) / sizeof(OPTIONS[0]))); ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 1] == NULL); ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 2] == NULL); memset(ports, 0, sizeof(ports)); memset(&callbacks, 0, sizeof(callbacks)); memset(errmsg, 0, sizeof(errmsg)); callbacks.log_message = log_msg_func; ctx = mg_start(&callbacks, (void *)errmsg, OPTIONS); mark_point(); test_sleep(1); ck_assert_str_eq(errmsg, ""); ck_assert(ctx != NULL); ports_cnt = mg_get_server_ports(ctx, 16, ports); ck_assert_int_eq(ports_cnt, 2); ck_assert_int_eq(ports[0].protocol, 1); ck_assert_int_eq(ports[0].port, 8080); ck_assert_int_eq(ports[0].is_ssl, 0); ck_assert_int_eq(ports[0].is_redirect, 1); ck_assert_int_eq(ports[1].protocol, 1); ck_assert_int_eq(ports[1].port, 8443); ck_assert_int_eq(ports[1].is_ssl, 1); ck_assert_int_eq(ports[1].is_redirect, 0); ck_assert_int_eq(ports[2].protocol, 0); ck_assert_int_eq(ports[2].port, 0); ck_assert_int_eq(ports[2].is_ssl, 0); ck_assert_int_eq(ports[2].is_redirect, 0); test_sleep(1); mark_point(); memset(client_err, 0, sizeof(client_err)); client_conn = mg_connect_client("127.0.0.1", 8443, 1, client_err, sizeof(client_err)); ck_assert(client_conn == NULL); ck_assert_str_ne(client_err, ""); memset(client_err, 0, sizeof(client_err)); memset(&client_options, 0, sizeof(client_options)); client_options.host = "127.0.0.1"; client_options.port = 8443; client_options.client_cert = client_cert; client_options.server_cert = server_cert; client_conn = mg_connect_client_secure(&client_options, client_err, sizeof(client_err)); ck_assert(client_conn != NULL); ck_assert_str_eq(client_err, ""); mg_printf(client_conn, "GET / HTTP/1.0\r\n\r\n"); client_res = mg_get_response(client_conn, client_err, sizeof(client_err), 10000); ck_assert_int_ge(client_res, 0); ck_assert_str_eq(client_err, ""); client_ri = mg_get_request_info(client_conn); ck_assert(client_ri != NULL); #if defined(NO_FILES) ck_assert_str_eq(client_ri->uri, "404"); #else ck_assert_str_eq(client_ri->uri, "200"); /* TODO: ck_assert_str_eq(client_ri->request_method, "HTTP/1.0"); */ client_res = (int)mg_read(client_conn, client_err, sizeof(client_err)); ck_assert_int_gt(client_res, 0); ck_assert_int_le(client_res, sizeof(client_err)); #endif mg_close_connection(client_conn); /* TODO: A client API using a client certificate is missing */ mark_point(); test_sleep(1); mark_point(); mg_stop(ctx); #endif }
END_TEST START_TEST(test_mg_start_stop_https_server) { #ifndef NO_SSL struct mg_context *ctx; size_t ports_cnt; int ports[16]; int ssl[16]; struct mg_callbacks callbacks; char errmsg[256]; const char *OPTIONS[8]; /* initializer list here is rejected by CI test */ int opt_idx = 0; const char *ssl_cert = locate_ssl_cert(); struct mg_connection *client_conn; char client_err[256]; const struct mg_request_info *client_ri; int client_res; ck_assert(ssl_cert != NULL); memset((void *)OPTIONS, 0, sizeof(OPTIONS)); #if !defined(NO_FILES) OPTIONS[opt_idx++] = "document_root"; OPTIONS[opt_idx++] = "."; #endif OPTIONS[opt_idx++] = "listening_ports"; OPTIONS[opt_idx++] = "8080r,8443s"; OPTIONS[opt_idx++] = "ssl_certificate"; OPTIONS[opt_idx++] = ssl_cert; ck_assert_int_le(opt_idx, (int)(sizeof(OPTIONS) / sizeof(OPTIONS[0]))); ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 1] == NULL); ck_assert(OPTIONS[sizeof(OPTIONS) / sizeof(OPTIONS[0]) - 2] == NULL); memset(ports, 0, sizeof(ports)); memset(ssl, 0, sizeof(ssl)); memset(&callbacks, 0, sizeof(callbacks)); memset(errmsg, 0, sizeof(errmsg)); callbacks.log_message = log_msg_func; ctx = mg_start(&callbacks, (void *)errmsg, OPTIONS); mark_point(); test_sleep(1); ck_assert_str_eq(errmsg, ""); ck_assert(ctx != NULL); ports_cnt = mg_get_ports(ctx, 16, ports, ssl); ck_assert_uint_eq(ports_cnt, 2); ck_assert_int_eq(ports[0], 8080); ck_assert_int_eq(ssl[0], 0); ck_assert_int_eq(ports[1], 8443); ck_assert_int_eq(ssl[1], 1); ck_assert_int_eq(ports[2], 0); ck_assert_int_eq(ssl[2], 0); test_sleep(1); mark_point(); memset(client_err, 0, sizeof(client_err)); client_conn = mg_connect_client("127.0.0.1", 8443, 1, client_err, sizeof(client_err)); ck_assert(client_conn != NULL); ck_assert_str_eq(client_err, ""); mg_printf(client_conn, "GET / HTTP/1.0\r\n\r\n"); client_res = mg_get_response(client_conn, client_err, sizeof(client_err), 10000); ck_assert_int_ge(client_res, 0); ck_assert_str_eq(client_err, ""); client_ri = mg_get_request_info(client_conn); ck_assert(client_ri != NULL); #if defined(NO_FILES) ck_assert_str_eq(client_ri->uri, "404"); #else ck_assert_str_eq(client_ri->uri, "200"); /* TODO: ck_assert_str_eq(client_ri->request_method, "HTTP/1.0"); */ client_res = (int)mg_read(client_conn, client_err, sizeof(client_err)); ck_assert_int_gt(client_res, 0); ck_assert_int_le(client_res, sizeof(client_err)); #endif mg_close_connection(client_conn); mark_point(); test_sleep(1); mark_point(); mg_stop(ctx); #endif }
int main(int argc, char *argv[]) { struct mg_context *ctx = NULL; struct tclient_data client1_data = {NULL, 0, 0}; struct tclient_data client2_data = {NULL, 0, 0}; struct tclient_data client3_data = {NULL, 0, 0}; struct mg_connection* newconn1 = NULL; struct mg_connection* newconn2 = NULL; struct mg_connection* newconn3 = NULL; char ebuf[100] = {0}; assert(websocket_welcome_msg_len == strlen(websocket_welcome_msg)); /* First set up a websocket server */ ctx = start_websocket_server(); assert(ctx != NULL); printf("Server init\n\n"); /* Then connect a first client */ newconn1 = mg_connect_websocket_client("localhost", atoi(PORT), 0, ebuf, sizeof(ebuf), "/websocket", NULL, websocket_client_data_handler, websocket_client_close_handler, &client1_data); if (newconn1 == NULL) { printf("Error: %s", ebuf); return 1; } sleep(1); /* Should get the websocket welcome message */ assert(client1_data.closed == 0); assert(client2_data.closed == 0); assert(client2_data.data == NULL); assert(client2_data.len == 0); assert(client1_data.data != NULL); assert(client1_data.len == websocket_welcome_msg_len); assert(!memcmp(client1_data.data, websocket_welcome_msg, websocket_welcome_msg_len)); free(client1_data.data); client1_data.data = NULL; client1_data.len = 0; mg_websocket_write(newconn1, WEBSOCKET_OPCODE_TEXT, "data1", 5); sleep(1); /* Should get the acknowledge message */ assert(client1_data.closed == 0); assert(client2_data.closed == 0); assert(client2_data.data == NULL); assert(client2_data.len == 0); assert(client1_data.data != NULL); assert(client1_data.len == websocket_acknowledge_msg_len); assert(!memcmp(client1_data.data, websocket_acknowledge_msg, websocket_acknowledge_msg_len)); free(client1_data.data); client1_data.data = NULL; client1_data.len = 0; /* Now connect a second client */ newconn2 = mg_connect_websocket_client("localhost", atoi(PORT), 0, ebuf, sizeof(ebuf), "/websocket", NULL, websocket_client_data_handler, websocket_client_close_handler, &client2_data); if (newconn2 == NULL) { printf("Error: %s", ebuf); return 1; } sleep(1); /* Client 2 should get the websocket welcome message */ assert(client1_data.closed == 0); assert(client2_data.closed == 0); assert(client1_data.data == NULL); assert(client1_data.len == 0); assert(client2_data.data != NULL); assert(client2_data.len == websocket_welcome_msg_len); assert(!memcmp(client2_data.data, websocket_welcome_msg, websocket_welcome_msg_len)); free(client2_data.data); client2_data.data = NULL; client2_data.len = 0; mg_websocket_write(newconn1, WEBSOCKET_OPCODE_TEXT, "data2", 5); sleep(1); /* Should get the acknowledge message */ assert(client1_data.closed == 0); assert(client2_data.closed == 0); assert(client2_data.data == NULL); assert(client2_data.len == 0); assert(client1_data.data != NULL); assert(client1_data.len == websocket_acknowledge_msg_len); assert(!memcmp(client1_data.data, websocket_acknowledge_msg, websocket_acknowledge_msg_len)); free(client1_data.data); client1_data.data = NULL; client1_data.len = 0; mg_websocket_write(newconn1, WEBSOCKET_OPCODE_TEXT, "bye", 3); sleep(1); /* Should get the goodbye message */ assert(client1_data.closed == 0); assert(client2_data.closed == 0); assert(client2_data.data == NULL); assert(client2_data.len == 0); assert(client1_data.data != NULL); assert(client1_data.len == websocket_goodbye_msg_len); assert(!memcmp(client1_data.data, websocket_goodbye_msg, websocket_goodbye_msg_len)); free(client1_data.data); client1_data.data = NULL; client1_data.len = 0; mg_close_connection(newconn1); sleep(1); /* Won't get any message */ assert(client1_data.closed == 1); assert(client2_data.closed == 0); assert(client1_data.data == NULL); assert(client1_data.len == 0); assert(client2_data.data == NULL); assert(client2_data.len == 0); mg_websocket_write(newconn2, WEBSOCKET_OPCODE_TEXT, "bye", 3); sleep(1); /* Should get the goodbye message */ assert(client1_data.closed == 1); assert(client2_data.closed == 0); assert(client1_data.data == NULL); assert(client1_data.len == 0); assert(client2_data.data != NULL); assert(client2_data.len == websocket_goodbye_msg_len); assert(!memcmp(client2_data.data, websocket_goodbye_msg, websocket_goodbye_msg_len)); free(client2_data.data); client2_data.data = NULL; client2_data.len = 0; mg_close_connection(newconn2); sleep(1); /* Won't get any message */ assert(client1_data.closed == 1); assert(client2_data.closed == 1); assert(client1_data.data == NULL); assert(client1_data.len == 0); assert(client2_data.data == NULL); assert(client2_data.len == 0); /* Connect client 3 */ newconn3 = mg_connect_websocket_client("localhost", atoi(PORT), 0, ebuf, sizeof(ebuf), "/websocket", NULL, websocket_client_data_handler, websocket_client_close_handler, &client3_data); sleep(1); /* Client 3 should get the websocket welcome message */ assert(client1_data.closed == 1); assert(client2_data.closed == 1); assert(client3_data.closed == 0); assert(client1_data.data == NULL); assert(client1_data.len == 0); assert(client2_data.data == NULL); assert(client2_data.len == 0); assert(client3_data.data != NULL); assert(client3_data.len == websocket_welcome_msg_len); assert(!memcmp(client3_data.data, websocket_welcome_msg, websocket_welcome_msg_len)); free(client3_data.data); client3_data.data = NULL; client3_data.len = 0; mg_stop(ctx); printf("Server shutdown\n"); sleep(10); assert(client3_data.closed == 1); return 0; }
static void test_mg_download(void) { char *p1, *p2, ebuf[100]; int len1, len2, port = atoi(HTTPS_PORT); struct mg_connection *conn; struct mg_context *ctx; ASSERT((ctx = mg_start(OPTIONS, event_handler, NULL)) != NULL); ASSERT(mg_download(NULL, port, 0, ebuf, sizeof(ebuf), "%s", "") == NULL); ASSERT(mg_download("localhost", 0, 0, ebuf, sizeof(ebuf), "%s", "") == NULL); ASSERT(mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s", "") == NULL); // Fetch nonexistent file, should see 404 ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s", "GET /gimbec HTTP/1.0\r\n\r\n")) != NULL); ASSERT(strcmp(conn->request_info.uri, "404") == 0); mg_close_connection(conn); ASSERT((conn = mg_download("google.com", 443, 1, ebuf, sizeof(ebuf), "%s", "GET / HTTP/1.0\r\n\r\n")) != NULL); mg_close_connection(conn); // POST with "Content-Length: 0", must not block ASSERT((conn = mg_download("localhost", atoi(HTTPS_PORT), 1, ebuf, sizeof(ebuf), "%s", "POST /zerolen HTTP/1.1\r\n" "Content-Lengh: 0\r\n\r\n ")) != NULL); ASSERT((p1 = read_conn(conn, &len1)) != NULL); ASSERT(len1 = 2); ASSERT(memcmp(p1, "ok", 2) == 0); mg_close_connection(conn); // Fetch main.c, should succeed ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s", "GET /main.c HTTP/1.0\r\n\r\n")) != NULL); ASSERT(!strcmp(conn->request_info.uri, "200")); ASSERT((p1 = read_conn(conn, &len1)) != NULL); ASSERT((p2 = read_file("main.c", &len2)) != NULL); ASSERT(len1 == len2); ASSERT(memcmp(p1, p2, len1) == 0); free(p1), free(p2); mg_close_connection(conn); // Test SSL redirect, IP address ASSERT((conn = mg_download("localhost", atoi(HTTP_PORT), 0, ebuf, sizeof(ebuf), "%s", "GET /foo HTTP/1.1\r\n\r\n")) != NULL); ASSERT(strcmp(conn->request_info.uri, "302") == 0); ASSERT(strcmp(mg_get_header(conn, "Location"), "https://127.0.0.1:" HTTPS_PORT "/foo") == 0); mg_close_connection(conn); // Test SSL redirect, Host: ASSERT((conn = mg_download("localhost", atoi(HTTP_PORT), 0, ebuf, sizeof(ebuf), "%s", "GET /foo HTTP/1.1\r\nHost: a.b:77\n\n")) != NULL); ASSERT(strcmp(conn->request_info.uri, "302") == 0); ASSERT(strcmp(mg_get_header(conn, "Location"), "https://a.b:" HTTPS_PORT "/foo") == 0); mg_close_connection(conn); mg_stop(ctx); }
int WebInterface_websocket_data_handler(struct mg_connection *conn) { WebInterface* pThis = (WebInterface*)mg_get_user_info(conn); // only allow 1 connection.. if (conn!=pThis->getConnection()) { if (pThis->getConnection()) { mg_close_connection(pThis->getConnection()); } pThis->setConnection(conn); } // Read the message from the client // For now we will assume that this is a string of text // Read in the header and size unsigned char header[10]; int totalRead = 0; while ( totalRead < 2 ) { int bytesRead = mg_read(conn, header+totalRead, 2-totalRead); if ( bytesRead <=0 ) return nullptr; totalRead += bytesRead; } // Check the data received if ( header[0] != 0x81 ) return nullptr; long long messageLength = header[1] & 127; int maskLength = (header[1] & 128) ? 4 : 0; if ( messageLength == 126 ) // Large message { totalRead = 0; while ( totalRead < 2 ) { int bytesRead = mg_read(conn, header+totalRead, 2-totalRead); if ( bytesRead <=0 ) return nullptr; totalRead += bytesRead; } messageLength = (((int) header[0]) << 8) + header[1]; } else if ( messageLength > 126 ) // Very large message { totalRead = 0; while ( totalRead < 8 ) { int bytesRead = mg_read(conn, header+totalRead, 8-totalRead); if ( bytesRead <=0 ) return nullptr; totalRead += bytesRead; } messageLength = (((long long) htonl(*(int*)&header[0])) << 32) | htonl(*(int*)&header[4]); } // Now read the data unsigned char* buf = new unsigned char[messageLength+maskLength]; totalRead = 0; while ( totalRead < messageLength+maskLength ) { int bytesRead = mg_read(conn, buf+totalRead, messageLength+maskLength-totalRead); if ( bytesRead <=0 ) { delete[] buf; return nullptr; } totalRead += bytesRead; } char* message = new char[messageLength+1]; for ( int i=0; i<messageLength; ++i ) { int x0r = (maskLength==0 ? 0 : buf[i%4]); message[i] = buf[i+maskLength] ^ x0r; } message[messageLength] = '\0'; delete[] buf; printf("rec: %s\n",message); pThis->parseCommand(message); delete[] message; ///////////////////////////////////////// /*printf("send ack\n"); // acknowledge unsigned char outbuf[40]; outbuf[0] = 0x81; outbuf[1] = snprintf((char *) outbuf + 2, sizeof(outbuf) - 2, "%s", "ACK"); mg_write(conn, outbuf, 2 + outbuf[1]); printf("ack ok\n");*/ return 1; // return 0 close websocket }