LLVMFuzzerTestOneInput: 497| 43|{ 498| |#if defined(TEST_FUZZ1) 499| | /* fuzz target 1: different URI for HTTP/1 server */ 500| | return LLVMFuzzerTestOneInput_URI(data, size); 501| |#elif defined(TEST_FUZZ2) 502| | /* fuzz target 2: different requests for HTTP/1 server */ 503| | return LLVMFuzzerTestOneInput_REQUEST(data, size); 504| |#elif defined(TEST_FUZZ3) 505| | /* fuzz target 3: different responses for HTTP/1 client */ 506| 43| return LLVMFuzzerTestOneInput_RESPONSE(data, size); 507| |#elif defined(TEST_FUZZ4) 508| |#error "Only useful in HTTP/2 feature branch" 509| | /* fuzz target 4: different requests for HTTP/2 server */ 510| | return LLVMFuzzerTestOneInput_REQUEST_HTTP2(data, size); 511| |#elif defined(TEST_FUZZ5) 512| | /* fuzz target 5: calling an internal server test function, 513| | * bypassing network sockets */ 514| | return LLVMFuzzerTestOneInput_process_new_connection(data, size); 515| |#else 516| |/* planned targets */ 517| |#error "Unknown fuzz target" 518| |#endif 519| 43|} fuzzmain.c:LLVMFuzzerTestOneInput_RESPONSE: 452| 43|{ 453| 43| if (call_count == 0) { ------------------ | Branch (453:6): [True: 1, False: 42] ------------------ 454| 1| mock_server_init(); 455| 1| } 456| 43| call_count++; 457| | 458| 43| if (size > sizeof(RESPONSE.data)) { ------------------ | Branch (458:6): [True: 9, False: 34] ------------------ 459| 9| return 1; 460| 9| } 461| | 462| 34| memcpy(RESPONSE.data, data, size); 463| 34| RESPONSE.size = size; 464| | 465| 34| char errbuf[256]; 466| | 467| 34| struct mg_connection *conn = mg_connect_client( 468| 34| "127.0.0.1", PORT_NUM_HTTP, 0, errbuf, sizeof(errbuf)); 469| 34| if (!conn) { ------------------ | Branch (469:6): [True: 0, False: 34] ------------------ 470| 0| printf("Connect error: %s\n", errbuf); 471| 0| test_sleep(1); ------------------ | | 23| 0|#define test_sleep(x) (sleep(x)) ------------------ 472| 0| return 1; 473| 0| } 474| 34| mg_printf(conn, "GET / HTTP/1.0\r\n\r\n"); 475| | 476| 34| int r = mg_get_response(conn, errbuf, sizeof(errbuf), 1000); 477| 34| const struct mg_response_info *ri = mg_get_response_info(conn); 478| | 479| 34| (void)r; 480| 34| (void)ri; 481| | 482| 34| mg_close_connection(conn); 483| | 484| 34| return 0; 485| 34|} fuzzmain.c:mock_server_init: 377| 1|{ 378| 1| int r; 379| 1| int bind_success = 0; 380| 1| SOCKET sock = socket(AF_INET, SOCK_STREAM, 6); 381| 1| if (sock == -1) { ------------------ | Branch (381:6): [True: 0, False: 1] ------------------ 382| 0| r = errno; 383| 0| fprintf(stderr, "Error: Cannot create socket [%s]\n", strerror(r)); 384| 0| TESTabort(); ------------------ | | 41| 0| { \ | | 42| 0| fprintf(stderr, "!!! Precondition in test environment not met !!!\n"); \ | | 43| 0| fprintf(stderr, "!!! aborting fuzz test in line %u !!!", __LINE__); \ | | 44| 0| abort(); \ | | 45| 0| } ------------------ 385| 0| } 386| | 387| 1| for (PORT_NUM_HTTP = 1024; PORT_NUM_HTTP != 0; PORT_NUM_HTTP++) { ------------------ | Branch (387:29): [True: 1, False: 0] ------------------ 388| 1| struct sockaddr_in sin; 389| 1| memset(&sin, 0, sizeof(sin)); 390| 1| sin.sin_family = AF_INET; 391| 1| sin.sin_addr.s_addr = inet_addr("127.0.0.1"); 392| 1| sin.sin_port = htons(PORT_NUM_HTTP); 393| 1| r = bind(sock, (struct sockaddr *)&sin, sizeof(sin)); 394| 1| if (r == 0) { ------------------ | Branch (394:7): [True: 1, False: 0] ------------------ 395| 1| bind_success = 1; 396| 1| break; 397| 1| } 398| 0| r = errno; 399| 0| fprintf(stderr, "Warning: Cannot bind [%s]\n", strerror(r)); 400| 0| } 401| | 402| 1| if (!bind_success) { ------------------ | Branch (402:6): [True: 0, False: 1] ------------------ 403| 0| fprintf(stderr, "Error: Cannot bind to any port\n"); 404| 0| closesocket(sock); ------------------ | | 31| 0|#define closesocket(a) (close(a)) ------------------ 405| 0| TESTabort(); ------------------ | | 41| 0| { \ | | 42| 0| fprintf(stderr, "!!! Precondition in test environment not met !!!\n"); \ | | 43| 0| fprintf(stderr, "!!! aborting fuzz test in line %u !!!", __LINE__); \ | | 44| 0| abort(); \ | | 45| 0| } ------------------ 406| 0| } 407| | 408| 1| printf("MOCK server running on port %i\n", (int)PORT_NUM_HTTP); 409| | 410| 1| r = listen(sock, 128); 411| 1| if (r != 0) { ------------------ | Branch (411:6): [True: 0, False: 1] ------------------ 412| 0| r = errno; 413| 0| fprintf(stderr, "Error: Cannot listen [%s]\n", strerror(r)); 414| 0| closesocket(sock); ------------------ | | 31| 0|#define closesocket(a) (close(a)) ------------------ 415| 0| TESTabort(); ------------------ | | 41| 0| { \ | | 42| 0| fprintf(stderr, "!!! Precondition in test environment not met !!!\n"); \ | | 43| 0| fprintf(stderr, "!!! aborting fuzz test in line %u !!!", __LINE__); \ | | 44| 0| abort(); \ | | 45| 0| } ------------------ 416| 0| } 417| | 418| 1| pthread_t thread_id; 419| 1| pthread_attr_t attr; 420| 1| int result; 421| 1| struct tcp_func_prm *thread_prm; 422| | 423| 1| thread_prm = (struct tcp_func_prm *)malloc(sizeof(struct tcp_func_prm)); 424| 1| if (!thread_prm) { ------------------ | Branch (424:6): [True: 0, False: 1] ------------------ 425| 0| fprintf(stderr, "Error: Out of memory\n"); 426| 0| closesocket(sock); ------------------ | | 31| 0|#define closesocket(a) (close(a)) ------------------ 427| 0| TESTabort(); ------------------ | | 41| 0| { \ | | 42| 0| fprintf(stderr, "!!! Precondition in test environment not met !!!\n"); \ | | 43| 0| fprintf(stderr, "!!! aborting fuzz test in line %u !!!", __LINE__); \ | | 44| 0| abort(); \ | | 45| 0| } ------------------ 428| 0| } 429| 1| thread_prm->sock = sock; 430| | 431| 1| (void)pthread_attr_init(&attr); 432| 1| (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 433| 1| result = pthread_create(&thread_id, 434| 1| &attr, 435| 1| mock_server_thread, 436| 1| (void *)thread_prm); 437| 1| (void)pthread_attr_destroy(&attr); 438| 1| if (result != 0) { ------------------ | Branch (438:6): [True: 0, False: 1] ------------------ 439| 0| r = errno; 440| 0| fprintf(stderr, "Error: Cannot create thread [%s]\n", strerror(r)); 441| 0| closesocket(sock); ------------------ | | 31| 0|#define closesocket(a) (close(a)) ------------------ 442| 0| TESTabort(); ------------------ | | 41| 0| { \ | | 42| 0| fprintf(stderr, "!!! Precondition in test environment not met !!!\n"); \ | | 43| 0| fprintf(stderr, "!!! aborting fuzz test in line %u !!!", __LINE__); \ | | 44| 0| abort(); \ | | 45| 0| } ------------------ 443| 0| } 444| | 445| 1| test_sleep(3); ------------------ | | 23| 1|#define test_sleep(x) (sleep(x)) ------------------ 446| 1| atexit(mock_server_exit); 447| 1|} fuzzmain.c:mock_server_thread: 312| 1|{ 313| 1| char req[1024 * 16]; 314| 1| SOCKET svr = (SOCKET)(-1); 315| | 316| | /* Get thread parameters and free arg */ 317| 1| { 318| 1| struct tcp_func_prm *ptcp_func_prm = (struct tcp_func_prm *)arg; 319| 1| svr = ptcp_func_prm->sock; 320| 1| free(arg); 321| 1| } 322| | 323| 1| mock_server_stop_flag = 0; 324| 1| printf("MOCK server ready, sock %i\n", svr); 325| | 326| 1|next_request: 327| 35| while (!mock_server_stop_flag) { ------------------ | Branch (327:9): [True: 35, False: 0] ------------------ 328| 35| struct sockaddr_in cliadr; 329| 35| socklen_t adrlen = sizeof(cliadr); 330| 35| int buf_filled = 0; 331| 35| int req_ready = 0; 332| | 333| 35| memset(&cliadr, 0, sizeof(cliadr)); 334| | 335| 35| SOCKET cli = accept(svr, (struct sockaddr *)&cliadr, &adrlen); 336| | 337| 35| if (cli == -1) { ------------------ | Branch (337:7): [True: 0, False: 35] ------------------ 338| 0| int er = errno; 339| 0| fprintf(stderr, "Error: Accept failed [%s]\n", strerror(er)); 340| 0| test_sleep(1); ------------------ | | 23| 0|#define test_sleep(x) (sleep(x)) ------------------ 341| 0| goto next_request; 342| 0| } 343| | 344| | /* Read request */ 345| 35| do { 346| 35| int r = 347| 35| recv(cli, req + buf_filled, sizeof(req) - buf_filled - 1, 0); 348| 35| if (r > 0) { ------------------ | Branch (348:8): [True: 34, False: 1] ------------------ 349| 34| buf_filled += r; 350| 34| req[buf_filled] = 0; 351| 34| if (strstr(req, "\r\n\r\n") != NULL) { ------------------ | Branch (351:9): [True: 34, False: 0] ------------------ 352| 34| req_ready = 1; 353| 34| } 354| 34| } else { 355| | /* some error */ 356| 1| int er = errno; 357| 1| fprintf(stderr, "Error: Recv failed [%s]\n", strerror(er)); 358| 1| test_sleep(1); ------------------ | | 23| 1|#define test_sleep(x) (sleep(x)) ------------------ 359| 1| goto next_request; 360| 1| } 361| 35| } while (!req_ready); ------------------ | Branch (361:12): [True: 0, False: 34] ------------------ 362| | 363| | /* Request is complete here. 364| | * Now send response */ 365| 34| send(cli, RESPONSE.data, RESPONSE.size, MSG_NOSIGNAL); 366| | 367| | /* Close connection. */ 368| 34| shutdown(cli, SHUT_RDWR); 369| 34| closesocket(cli); ------------------ | | 31| 34|#define closesocket(a) (close(a)) ------------------ 370| 34| } 371| 0| return 0; 372| 1|} fuzzmain.c:mock_server_exit: 303| 1|{ 304| 1| printf("MOCK server exit\n"); 305| 1| mock_server_stop_flag = 1; 306| 1| test_sleep(5); ------------------ | | 23| 1|#define test_sleep(x) (sleep(x)) ------------------ 307| 1|} mg_set_user_connection_data: 3226| 34|{ 3227| 34| if (const_conn != NULL) { ------------------ | Branch (3227:6): [True: 34, False: 0] ------------------ 3228| | /* Const cast, since "const struct mg_connection *" does not mean 3229| | * the connection object is not modified. Here "const" is used, 3230| | * to indicate mg_read/mg_write/mg_send/.. must not be called. */ 3231| 34| struct mg_connection *conn = (struct mg_connection *)const_conn; 3232| 34| conn->request_info.conn_data = data; 3233| 34| } 3234| 34|} mg_get_response_info: 3562| 34|{ 3563| 34| if (!conn) { ------------------ | Branch (3563:6): [True: 0, False: 34] ------------------ 3564| 0| return NULL; 3565| 0| } 3566| 34| if (conn->connection_type != CONNECTION_TYPE_RESPONSE) { ------------------ | Branch (3566:6): [True: 0, False: 34] ------------------ 3567| 0| return NULL; 3568| 0| } 3569| 34| return &conn->response_info; 3570| 34|} mg_write: 6782| 34|{ 6783| 34| time_t now; 6784| 34| int n, total, allowed; 6785| | 6786| 34| if (conn == NULL) { ------------------ | Branch (6786:6): [True: 0, False: 34] ------------------ 6787| 0| return 0; 6788| 0| } 6789| 34| if (len > INT_MAX) { ------------------ | Branch (6789:6): [True: 0, False: 34] ------------------ 6790| 0| return -1; 6791| 0| } 6792| | 6793| | /* Mark connection as "data sent" */ 6794| 34| conn->request_state = 10; 6795| |#if defined(USE_HTTP2) 6796| | if (conn->protocol_type == PROTOCOL_TYPE_HTTP2) { 6797| | http2_data_frame_head(conn, len, 0); 6798| | } 6799| |#endif 6800| | 6801| 34| if (conn->throttle > 0) { ------------------ | Branch (6801:6): [True: 0, False: 34] ------------------ 6802| 0| if ((now = time(NULL)) != conn->last_throttle_time) { ------------------ | Branch (6802:7): [True: 0, False: 0] ------------------ 6803| 0| conn->last_throttle_time = now; 6804| 0| conn->last_throttle_bytes = 0; 6805| 0| } 6806| 0| allowed = conn->throttle - conn->last_throttle_bytes; 6807| 0| if (allowed > (int)len) { ------------------ | Branch (6807:7): [True: 0, False: 0] ------------------ 6808| 0| allowed = (int)len; 6809| 0| } 6810| | 6811| 0| total = push_all(conn->phys_ctx, 6812| 0| NULL, 6813| 0| conn->client.sock, 6814| 0| conn->ssl, 6815| 0| (const char *)buf, 6816| 0| allowed); 6817| | 6818| 0| if (total == allowed) { ------------------ | Branch (6818:7): [True: 0, False: 0] ------------------ 6819| | 6820| 0| buf = (const char *)buf + total; 6821| 0| conn->last_throttle_bytes += total; 6822| 0| while ((total < (int)len) ------------------ | Branch (6822:11): [True: 0, False: 0] ------------------ 6823| 0| && STOP_FLAG_IS_ZERO(&conn->phys_ctx->stop_flag)) { ------------------ | | 2322| 0|#define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0) | | ------------------ | | | Branch (2322:30): [True: 0, False: 0] | | ------------------ ------------------ 6824| 0| allowed = (conn->throttle > ((int)len - total)) ------------------ | Branch (6824:15): [True: 0, False: 0] ------------------ 6825| 0| ? (int)len - total 6826| 0| : conn->throttle; 6827| | 6828| 0| n = push_all(conn->phys_ctx, 6829| 0| NULL, 6830| 0| conn->client.sock, 6831| 0| conn->ssl, 6832| 0| (const char *)buf, 6833| 0| allowed); 6834| | 6835| 0| if (n != allowed) { ------------------ | Branch (6835:9): [True: 0, False: 0] ------------------ 6836| 0| break; 6837| 0| } 6838| 0| sleep(1); 6839| 0| conn->last_throttle_bytes = allowed; 6840| 0| conn->last_throttle_time = time(NULL); 6841| 0| buf = (const char *)buf + n; 6842| 0| total += n; 6843| 0| } 6844| 0| } 6845| 34| } else { 6846| 34| total = push_all(conn->phys_ctx, 6847| 34| NULL, 6848| 34| conn->client.sock, 6849| 34| conn->ssl, 6850| 34| (const char *)buf, 6851| 34| (int)len); 6852| 34| } 6853| 34| if (total > 0) { ------------------ | Branch (6853:6): [True: 34, False: 0] ------------------ 6854| 34| conn->num_bytes_sent += total; 6855| 34| } 6856| 34| return total; 6857| 34|} mg_printf: 7037| 34|{ 7038| 34| va_list ap; 7039| 34| int result; 7040| | 7041| 34| va_start(ap, fmt); 7042| 34| result = mg_vprintf(conn, fmt, ap); 7043| 34| va_end(ap); 7044| | 7045| 34| return result; 7046| 34|} mg_lock_connection: 12992| 34|{ 12993| 34| if (conn) { ------------------ | Branch (12993:6): [True: 34, False: 0] ------------------ 12994| 34| (void)pthread_mutex_lock(&conn->mutex); 12995| 34| } 12996| 34|} mg_unlock_connection: 13001| 34|{ 13002| 34| if (conn) { ------------------ | Branch (13002:6): [True: 34, False: 0] ------------------ 13003| 34| (void)pthread_mutex_unlock(&conn->mutex); 13004| 34| } 13005| 34|} mg_close_connection: 17930| 34|{ 17931| 34| if ((conn == NULL) || (conn->phys_ctx == NULL)) { ------------------ | Branch (17931:6): [True: 0, False: 34] | Branch (17931:24): [True: 0, False: 34] ------------------ 17932| 0| return; 17933| 0| } 17934| | 17935| |#if defined(USE_WEBSOCKET) 17936| | if (conn->phys_ctx->context_type == CONTEXT_SERVER) { 17937| | if (conn->in_websocket_handling) { 17938| | /* Set close flag, so the server thread can exit. */ 17939| | conn->must_close = 1; 17940| | return; 17941| | } 17942| | } 17943| | if (conn->phys_ctx->context_type == CONTEXT_WS_CLIENT) { 17944| | 17945| | unsigned int i; 17946| | 17947| | /* client context: loops must end */ 17948| | STOP_FLAG_ASSIGN(&conn->phys_ctx->stop_flag, 1); 17949| | conn->must_close = 1; 17950| | 17951| | /* We need to get the client thread out of the select/recv call 17952| | * here. */ 17953| | /* Since we use a sleep quantum of some seconds to check for recv 17954| | * timeouts, we will just wait a few seconds in mg_join_thread. */ 17955| | 17956| | /* join worker thread */ 17957| | for (i = 0; i < conn->phys_ctx->cfg_worker_threads; i++) { 17958| | mg_join_thread(conn->phys_ctx->worker_threadids[i]); 17959| | } 17960| | } 17961| |#endif /* defined(USE_WEBSOCKET) */ 17962| | 17963| 34| close_connection(conn); 17964| | 17965| 34|#if !defined(NO_SSL) && !defined(USE_MBEDTLS) // TODO: mbedTLS client 17966| 34| if (((conn->phys_ctx->context_type == CONTEXT_HTTP_CLIENT) ------------------ | Branch (17966:7): [True: 34, False: 0] ------------------ 17967| 34| || (conn->phys_ctx->context_type == CONTEXT_WS_CLIENT)) ------------------ | Branch (17967:10): [True: 0, False: 0] ------------------ 17968| 34| && (conn->phys_ctx->dd.ssl_ctx != NULL)) { ------------------ | Branch (17968:9): [True: 0, False: 34] ------------------ 17969| 0| SSL_CTX_free(conn->phys_ctx->dd.ssl_ctx); ------------------ | | 124| 0|#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr) ------------------ 17970| 0| } 17971| 34|#endif 17972| | 17973| |#if defined(USE_WEBSOCKET) 17974| | if (conn->phys_ctx->context_type == CONTEXT_WS_CLIENT) { 17975| | mg_free(conn->phys_ctx->worker_threadids); 17976| | (void)pthread_mutex_destroy(&conn->mutex); 17977| | mg_free(conn); 17978| | } else if (conn->phys_ctx->context_type == CONTEXT_HTTP_CLIENT) { 17979| | (void)pthread_mutex_destroy(&conn->mutex); 17980| | mg_free(conn); 17981| | } 17982| |#else 17983| 34| if (conn->phys_ctx->context_type == CONTEXT_HTTP_CLIENT) { /* Client */ ------------------ | Branch (17983:6): [True: 34, False: 0] ------------------ 17984| 34| (void)pthread_mutex_destroy(&conn->mutex); 17985| 34| mg_free(conn); 17986| 34| } 17987| 34|#endif /* defined(USE_WEBSOCKET) */ 17988| 34|} mg_connect_client: 18249| 34|{ 18250| 34| struct mg_client_options opts; 18251| 34| struct mg_init_data init; 18252| 34| struct mg_error_data error; 18253| | 18254| 34| memset(&init, 0, sizeof(init)); 18255| | 18256| 34| memset(&error, 0, sizeof(error)); 18257| 34| error.text_buffer_size = error_buffer_size; 18258| 34| error.text = error_buffer; 18259| | 18260| 34| memset(&opts, 0, sizeof(opts)); 18261| 34| opts.host = host; 18262| 34| opts.port = port; 18263| 34| if (use_ssl) { ------------------ | Branch (18263:6): [True: 0, False: 34] ------------------ 18264| 0| opts.host_name = host; 18265| 0| } 18266| | 18267| 34| return mg_connect_client_impl(&opts, use_ssl, &init, &error); 18268| 34|} mg_get_response: 18817| 34|{ 18818| 34| int err, ret; 18819| 34| char txt[32]; /* will not overflow */ 18820| 34| char *save_timeout; 18821| 34| char *new_timeout; 18822| | 18823| 34| if (ebuf_len > 0) { ------------------ | Branch (18823:6): [True: 34, False: 0] ------------------ 18824| 34| ebuf[0] = '\0'; 18825| 34| } 18826| | 18827| 34| if (!conn) { ------------------ | Branch (18827:6): [True: 0, False: 34] ------------------ 18828| 0| mg_snprintf(conn, 18829| 0| NULL, /* No truncation check for ebuf */ 18830| 0| ebuf, 18831| 0| ebuf_len, 18832| 0| "%s", 18833| 0| "Parameter error"); 18834| 0| return -1; 18835| 0| } 18836| | 18837| | /* Reset the previous responses */ 18838| 34| conn->data_len = 0; 18839| | 18840| | /* Implementation of API function for HTTP clients */ 18841| 34| save_timeout = conn->dom_ctx->config[REQUEST_TIMEOUT]; 18842| | 18843| 34| if (timeout >= 0) { ------------------ | Branch (18843:6): [True: 34, False: 0] ------------------ 18844| 34| mg_snprintf(conn, NULL, txt, sizeof(txt), "%i", timeout); 18845| 34| new_timeout = txt; 18846| 34| } else { 18847| 0| new_timeout = NULL; 18848| 0| } 18849| | 18850| 34| conn->dom_ctx->config[REQUEST_TIMEOUT] = new_timeout; 18851| 34| ret = get_response(conn, ebuf, ebuf_len, &err); 18852| 34| conn->dom_ctx->config[REQUEST_TIMEOUT] = save_timeout; 18853| | 18854| | /* TODO: here, the URI is the http response code */ 18855| 34| conn->request_info.local_uri_raw = conn->request_info.request_uri; 18856| 34| conn->request_info.local_uri = conn->request_info.local_uri_raw; 18857| | 18858| | /* TODO (mid): Define proper return values - maybe return length? 18859| | * For the first test use <0 for error and >0 for OK */ 18860| 34| return (ret == 0) ? -1 : +1; ------------------ | Branch (18860:9): [True: 33, False: 1] ------------------ 18861| 34|} civetweb.c:get_header: 3821| 2|{ 3822| 2| int i; 3823| 2| for (i = 0; i < num_hdr; i++) { ------------------ | Branch (3823:14): [True: 0, False: 2] ------------------ 3824| 0| if (!mg_strcasecmp(name, hdr[i].name)) { ------------------ | Branch (3824:7): [True: 0, False: 0] ------------------ 3825| 0| return hdr[i].value; 3826| 0| } 3827| 0| } 3828| | 3829| 2| return NULL; 3830| 2|} civetweb.c:mg_free: 1493| 34|{ 1494| 34| free(a); 1495| 34|} civetweb.c:mg_vsnprintf: 3100| 67|{ 3101| 67| int n, ok; 3102| | 3103| 67| if (buflen == 0) { ------------------ | Branch (3103:6): [True: 0, False: 67] ------------------ 3104| 0| if (truncated) { ------------------ | Branch (3104:7): [True: 0, False: 0] ------------------ 3105| 0| *truncated = 1; 3106| 0| } 3107| 0| return; 3108| 0| } 3109| | 3110| 67|#if defined(__clang__) 3111| 67|#pragma clang diagnostic push 3112| 67|#pragma clang diagnostic ignored "-Wformat-nonliteral" 3113| | /* Using fmt as a non-literal is intended here, since it is mostly called 3114| | * indirectly by mg_snprintf */ 3115| 67|#endif 3116| | 3117| 67| n = (int)vsnprintf_impl(buf, buflen, fmt, ap); ------------------ | | 897| 67|#define vsnprintf_impl vsnprintf ------------------ 3118| 67| ok = (n >= 0) && ((size_t)n < buflen); ------------------ | Branch (3118:7): [True: 67, False: 0] | Branch (3118:19): [True: 67, False: 0] ------------------ 3119| | 3120| 67|#if defined(__clang__) 3121| 67|#pragma clang diagnostic pop 3122| 67|#endif 3123| | 3124| 67| if (ok) { ------------------ | Branch (3124:6): [True: 67, False: 0] ------------------ 3125| 67| if (truncated) { ------------------ | Branch (3125:7): [True: 0, False: 67] ------------------ 3126| 0| *truncated = 0; 3127| 0| } 3128| 67| } else { 3129| 0| if (truncated) { ------------------ | Branch (3129:7): [True: 0, False: 0] ------------------ 3130| 0| *truncated = 1; 3131| 0| } 3132| 0| mg_cry_internal(conn, ------------------ | | 2584| 0| mg_cry_internal_wrap(conn, NULL, __func__, __LINE__, fmt, __VA_ARGS__) | | ------------------ | | | Branch (2584:60): [True: 0, False: 0] | | ------------------ ------------------ 3133| 0| "truncating vsnprintf buffer: [%.*s]", 3134| 0| (int)((buflen > 200) ? 200 : (buflen - 1)), 3135| 0| buf); 3136| 0| n = (int)buflen - 1; 3137| 0| } 3138| 67| buf[n] = '\0'; 3139| 67|} civetweb.c:set_close_on_exec: 5680| 34|{ 5681| |#if defined(__ZEPHYR__) 5682| | (void)fd; 5683| | (void)conn; 5684| | (void)ctx; 5685| |#else 5686| 34| if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { ------------------ | Branch (5686:6): [True: 0, False: 34] ------------------ 5687| 0| if (conn || ctx) { ------------------ | Branch (5687:7): [True: 0, False: 0] | Branch (5687:15): [True: 0, False: 0] ------------------ 5688| 0| struct mg_connection fc; 5689| 0| mg_cry_internal((conn ? conn : fake_connection(&fc, ctx)), ------------------ | | 2584| 0| mg_cry_internal_wrap(conn, NULL, __func__, __LINE__, fmt, __VA_ARGS__) | | ------------------ | | | Branch (2584:23): [True: 0, False: 0] | | ------------------ ------------------ 5690| 0| "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s", 5691| 0| __func__, 5692| 0| strerror(ERRNO)); 5693| 0| } 5694| 0| } 5695| 34|#endif 5696| 34|} civetweb.c:read_message: 11103| 34|{ 11104| 34| int request_len, n = 0; 11105| 34| struct timespec last_action_time; 11106| 34| double request_timeout; 11107| | 11108| 34| if (!conn) { ------------------ | Branch (11108:6): [True: 0, False: 34] ------------------ 11109| 0| return 0; 11110| 0| } 11111| | 11112| 34| memset(&last_action_time, 0, sizeof(last_action_time)); 11113| | 11114| 34| if (conn->dom_ctx->config[REQUEST_TIMEOUT]) { ------------------ | Branch (11114:6): [True: 34, False: 0] ------------------ 11115| | /* value of request_timeout is in seconds, config in milliseconds */ 11116| 34| request_timeout = 11117| 34| strtod(conn->dom_ctx->config[REQUEST_TIMEOUT], NULL) / 1000.0; 11118| 34| } else { 11119| 0| request_timeout = 11120| 0| strtod(config_options[REQUEST_TIMEOUT].default_value, NULL) 11121| 0| / 1000.0; 11122| 0| } 11123| 34| if (conn->handled_requests > 0) { ------------------ | Branch (11123:6): [True: 0, False: 34] ------------------ 11124| 0| if (conn->dom_ctx->config[KEEP_ALIVE_TIMEOUT]) { ------------------ | Branch (11124:7): [True: 0, False: 0] ------------------ 11125| 0| request_timeout = 11126| 0| strtod(conn->dom_ctx->config[KEEP_ALIVE_TIMEOUT], NULL) 11127| 0| / 1000.0; 11128| 0| } 11129| 0| } 11130| | 11131| 34| request_len = get_http_header_len(buf, *nread); 11132| | 11133| 68| while (request_len == 0) { ------------------ | Branch (11133:9): [True: 44, False: 24] ------------------ 11134| | /* Full request not yet received */ 11135| 44| if (!STOP_FLAG_IS_ZERO(&conn->phys_ctx->stop_flag)) { ------------------ | | 2322| 44|#define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0) ------------------ | Branch (11135:7): [True: 0, False: 44] ------------------ 11136| | /* Server is to be stopped. */ 11137| 0| return -1; 11138| 0| } 11139| | 11140| 44| if (*nread >= bufsiz) { ------------------ | Branch (11140:7): [True: 0, False: 44] ------------------ 11141| | /* Request too long */ 11142| 0| return -2; 11143| 0| } 11144| | 11145| 44| n = pull_inner( 11146| 44| fp, conn, buf + *nread, bufsiz - *nread, request_timeout); 11147| 44| if (n == -2) { ------------------ | Branch (11147:7): [True: 10, False: 34] ------------------ 11148| | /* Receive error */ 11149| 10| return -1; 11150| 10| } 11151| | 11152| | /* update clock after every read request */ 11153| 34| clock_gettime(CLOCK_MONOTONIC, &last_action_time); 11154| | 11155| 34| if (n > 0) { ------------------ | Branch (11155:7): [True: 34, False: 0] ------------------ 11156| 34| *nread += n; 11157| 34| request_len = get_http_header_len(buf, *nread); 11158| 34| } 11159| | 11160| 34| if ((request_len == 0) && (request_timeout >= 0)) { ------------------ | Branch (11160:7): [True: 10, False: 24] | Branch (11160:29): [True: 10, False: 0] ------------------ 11161| 10| if (mg_difftimespec(&last_action_time, &(conn->req_time)) ------------------ | Branch (11161:8): [True: 0, False: 10] ------------------ 11162| 10| > request_timeout) { 11163| | /* Timeout */ 11164| 0| return -1; 11165| 0| } 11166| 10| } 11167| 34| } 11168| | 11169| 24| return request_len; 11170| 34|} civetweb.c:get_http_header_len: 7952| 82|{ 7953| 82| int i; 7954| 11.6k| for (i = 0; i < buflen; i++) { ------------------ | Branch (7954:14): [True: 11.6k, False: 44] ------------------ 7955| | /* Do an unsigned comparison in some conditions below */ 7956| 11.6k| const unsigned char c = (unsigned char)buf[i]; 7957| | 7958| 11.6k| if ((c < 128) && ((char)c != '\r') && ((char)c != '\n') ------------------ | Branch (7958:7): [True: 5.88k, False: 5.75k] | Branch (7958:20): [True: 5.27k, False: 617] | Branch (7958:41): [True: 4.91k, False: 352] ------------------ 7959| 11.6k| && !isprint(c)) { ------------------ | Branch (7959:10): [True: 11, False: 4.90k] ------------------ 7960| | /* abort scan as soon as one malformed character is found */ 7961| 11| return -1; 7962| 11| } 7963| | 7964| 11.6k| if (i < buflen - 1) { ------------------ | Branch (7964:7): [True: 11.6k, False: 10] ------------------ 7965| 11.6k| if ((buf[i] == '\n') && (buf[i + 1] == '\n')) { ------------------ | Branch (7965:8): [True: 352, False: 11.2k] | Branch (7965:28): [True: 26, False: 326] ------------------ 7966| | /* Two newline, no carriage return - not standard compliant, 7967| | * but it should be accepted */ 7968| 26| return i + 2; 7969| 26| } 7970| 11.6k| } 7971| | 7972| 11.6k| if (i < buflen - 3) { ------------------ | Branch (7972:7): [True: 11.5k, False: 25] ------------------ 7973| 11.5k| if ((buf[i] == '\r') && (buf[i + 1] == '\n') && (buf[i + 2] == '\r') ------------------ | Branch (7973:8): [True: 615, False: 10.9k] | Branch (7973:28): [True: 8, False: 607] | Branch (7973:52): [True: 1, False: 7] ------------------ 7974| 11.5k| && (buf[i + 3] == '\n')) { ------------------ | Branch (7974:11): [True: 1, False: 0] ------------------ 7975| | /* Two \r\n - standard compliant */ 7976| 1| return i + 4; 7977| 1| } 7978| 11.5k| } 7979| 11.6k| } 7980| | 7981| 44| return 0; 7982| 82|} civetweb.c:pull_inner: 6215| 44|{ 6216| 44| int nread, err = 0; 6217| | 6218| |#if defined(_WIN32) 6219| | typedef int len_t; 6220| |#else 6221| 44| typedef size_t len_t; 6222| 44|#endif 6223| | 6224| | /* We need an additional wait loop around this, because in some cases 6225| | * with TLSwe may get data from the socket but not from SSL_read. 6226| | * In this case we need to repeat at least once. 6227| | */ 6228| | 6229| 44| if (fp != NULL) { ------------------ | Branch (6229:6): [True: 0, False: 44] ------------------ 6230| | /* Use read() instead of fread(), because if we're reading from the 6231| | * CGI pipe, fread() may block until IO buffer is filled up. We 6232| | * cannot afford to block and must pass all read bytes immediately 6233| | * to the client. */ 6234| 0| nread = (int)read(fileno(fp), buf, (size_t)len); 6235| | 6236| 0| err = (nread < 0) ? ERRNO : 0; ------------------ | | 924| 0|#define ERRNO (errno) ------------------ | Branch (6236:9): [True: 0, False: 0] ------------------ 6237| 0| if ((nread == 0) && (len > 0)) { ------------------ | Branch (6237:7): [True: 0, False: 0] | Branch (6237:23): [True: 0, False: 0] ------------------ 6238| | /* Should get data, but got EOL */ 6239| 0| return -2; 6240| 0| } 6241| | 6242| |#if defined(USE_MBEDTLS) 6243| | } else if (conn->ssl != NULL) { 6244| | struct mg_pollfd pfd[1]; 6245| | int to_read; 6246| | int pollres; 6247| | 6248| | to_read = mbedtls_ssl_get_bytes_avail(conn->ssl); 6249| | 6250| | if (to_read > 0) { 6251| | /* We already know there is no more data buffered in conn->buf 6252| | * but there is more available in the SSL layer. So don't poll 6253| | * conn->client.sock yet. */ 6254| | 6255| | pollres = 1; 6256| | if (to_read > len) 6257| | to_read = len; 6258| | } else { 6259| | pfd[0].fd = conn->client.sock; 6260| | pfd[0].events = POLLIN; 6261| | 6262| | to_read = len; 6263| | 6264| | pollres = mg_poll(pfd, 6265| | 1, 6266| | (int)(timeout * 1000.0), 6267| | &(conn->phys_ctx->stop_flag)); 6268| | 6269| | if (!STOP_FLAG_IS_ZERO(&conn->phys_ctx->stop_flag)) { 6270| | return -2; 6271| | } 6272| | } 6273| | 6274| | if (pollres > 0) { 6275| | nread = mbed_ssl_read(conn->ssl, (unsigned char *)buf, to_read); 6276| | if (nread <= 0) { 6277| | if ((nread == MBEDTLS_ERR_SSL_WANT_READ) 6278| | || (nread == MBEDTLS_ERR_SSL_WANT_WRITE) 6279| | || nread == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) { 6280| | nread = 0; 6281| | } else { 6282| | fprintf(stderr, "SSL read failed, error %d\n", nread); 6283| | return -2; 6284| | } 6285| | } else { 6286| | err = 0; 6287| | } 6288| | 6289| | } else if (pollres < 0) { 6290| | /* Error */ 6291| | return -2; 6292| | } else { 6293| | /* pollres = 0 means timeout */ 6294| | nread = 0; 6295| | } 6296| | 6297| |#elif !defined(NO_SSL) 6298| 44| } else if (conn->ssl != NULL) { ------------------ | Branch (6298:13): [True: 0, False: 44] ------------------ 6299| 0| int ssl_pending; 6300| 0| struct mg_pollfd pfd[1]; 6301| 0| int pollres; 6302| | 6303| 0| if ((ssl_pending = SSL_pending(conn->ssl)) > 0) { ------------------ | | 128| 0|#define SSL_pending (*(int (*)(SSL *))ssl_sw[17].ptr) ------------------ | Branch (6303:7): [True: 0, False: 0] ------------------ 6304| | /* We already know there is no more data buffered in conn->buf 6305| | * but there is more available in the SSL layer. So don't poll 6306| | * conn->client.sock yet. */ 6307| 0| if (ssl_pending > len) { ------------------ | Branch (6307:8): [True: 0, False: 0] ------------------ 6308| 0| ssl_pending = len; 6309| 0| } 6310| 0| pollres = 1; 6311| 0| } else { 6312| 0| pfd[0].fd = conn->client.sock; 6313| 0| pfd[0].events = POLLIN; 6314| 0| pollres = mg_poll(pfd, 6315| 0| 1, 6316| 0| (int)(timeout * 1000.0), 6317| 0| &(conn->phys_ctx->stop_flag)); 6318| 0| if (!STOP_FLAG_IS_ZERO(&conn->phys_ctx->stop_flag)) { ------------------ | | 2322| 0|#define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0) ------------------ | Branch (6318:8): [True: 0, False: 0] ------------------ 6319| 0| return -2; 6320| 0| } 6321| 0| } 6322| 0| if (pollres > 0) { ------------------ | Branch (6322:7): [True: 0, False: 0] ------------------ 6323| 0| ERR_clear_error(); ------------------ | | 232| 0|#define ERR_clear_error (*(void (*)(void))crypto_sw[15].ptr) ------------------ 6324| 0| nread = 6325| 0| SSL_read(conn->ssl, buf, (ssl_pending > 0) ? ssl_pending : len); ------------------ | | 107| 0|#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr) ------------------ | Branch (6325:33): [True: 0, False: 0] ------------------ 6326| 0| if (nread <= 0) { ------------------ | Branch (6326:8): [True: 0, False: 0] ------------------ 6327| 0| err = SSL_get_error(conn->ssl, nread); ------------------ | | 109| 0|#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr) ------------------ 6328| 0| if ((err == SSL_ERROR_SYSCALL) && (nread == -1)) { ------------------ | | 71| 0|#define SSL_ERROR_SYSCALL (5) /* see errno */ ------------------ | Branch (6328:9): [True: 0, False: 0] | Branch (6328:39): [True: 0, False: 0] ------------------ 6329| 0| err = ERRNO; ------------------ | | 924| 0|#define ERRNO (errno) ------------------ 6330| 0| } else if ((err == SSL_ERROR_WANT_READ) ------------------ | | 68| 0|#define SSL_ERROR_WANT_READ (2) ------------------ | Branch (6330:16): [True: 0, False: 0] ------------------ 6331| 0| || (err == SSL_ERROR_WANT_WRITE)) { ------------------ | | 69| 0|#define SSL_ERROR_WANT_WRITE (3) ------------------ | Branch (6331:19): [True: 0, False: 0] ------------------ 6332| 0| nread = 0; 6333| 0| } else { 6334| | /* All errors should return -2 */ 6335| 0| DEBUG_TRACE("SSL_read() failed, error %d", err); ------------------ | | 243| 0| do { \ | | 244| 0| } while (0) | | ------------------ | | | Branch (244:11): [Folded - Ignored] | | ------------------ ------------------ 6336| 0| ERR_clear_error(); ------------------ | | 232| 0|#define ERR_clear_error (*(void (*)(void))crypto_sw[15].ptr) ------------------ 6337| 0| return -2; 6338| 0| } 6339| 0| ERR_clear_error(); ------------------ | | 232| 0|#define ERR_clear_error (*(void (*)(void))crypto_sw[15].ptr) ------------------ 6340| 0| } else { 6341| 0| err = 0; 6342| 0| } 6343| 0| } else if (pollres < 0) { ------------------ | Branch (6343:14): [True: 0, False: 0] ------------------ 6344| | /* Error */ 6345| 0| return -2; 6346| 0| } else { 6347| | /* pollres = 0 means timeout */ 6348| 0| nread = 0; 6349| 0| } 6350| 0|#endif 6351| | 6352| 44| } else { 6353| 44| struct mg_pollfd pfd[1]; 6354| 44| int pollres; 6355| | 6356| 44| pfd[0].fd = conn->client.sock; 6357| 44| pfd[0].events = POLLIN; 6358| 44| pollres = mg_poll(pfd, 6359| 44| 1, 6360| 44| (int)(timeout * 1000.0), 6361| 44| &(conn->phys_ctx->stop_flag)); 6362| 44| if (!STOP_FLAG_IS_ZERO(&conn->phys_ctx->stop_flag)) { ------------------ | | 2322| 44|#define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0) ------------------ | Branch (6362:7): [True: 0, False: 44] ------------------ 6363| 0| return -2; 6364| 0| } 6365| 44| if (pollres > 0) { ------------------ | Branch (6365:7): [True: 44, False: 0] ------------------ 6366| 44| nread = (int)recv(conn->client.sock, buf, (len_t)len, 0); 6367| 44| err = (nread < 0) ? ERRNO : 0; ------------------ | | 924| 0|#define ERRNO (errno) ------------------ | Branch (6367:10): [True: 0, False: 44] ------------------ 6368| 44| if (nread <= 0) { ------------------ | Branch (6368:8): [True: 10, False: 34] ------------------ 6369| | /* shutdown of the socket at client side */ 6370| 10| return -2; 6371| 10| } 6372| 44| } else if (pollres < 0) { ------------------ | Branch (6372:14): [True: 0, False: 0] ------------------ 6373| | /* error calling poll */ 6374| 0| return -2; 6375| 0| } else { 6376| | /* pollres = 0 means timeout */ 6377| 0| nread = 0; 6378| 0| } 6379| 44| } 6380| | 6381| 34| if (!STOP_FLAG_IS_ZERO(&conn->phys_ctx->stop_flag)) { ------------------ | | 2322| 34|#define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0) ------------------ | Branch (6381:6): [True: 0, False: 34] ------------------ 6382| 0| return -2; 6383| 0| } 6384| | 6385| 34| if ((nread > 0) || ((nread == 0) && (len == 0))) { ------------------ | Branch (6385:6): [True: 34, False: 0] | Branch (6385:22): [True: 0, False: 0] | Branch (6385:38): [True: 0, False: 0] ------------------ 6386| | /* some data has been read, or no data was requested */ 6387| 34| return nread; 6388| 34| } 6389| | 6390| 0| if (nread < 0) { ------------------ | Branch (6390:6): [True: 0, False: 0] ------------------ 6391| | /* socket error - check errno */ 6392| |#if defined(_WIN32) 6393| | if (err == WSAEWOULDBLOCK) { 6394| | /* TODO (low): check if this is still required */ 6395| | /* standard case if called from close_socket_gracefully */ 6396| | return -2; 6397| | } else if (err == WSAETIMEDOUT) { 6398| | /* TODO (low): check if this is still required */ 6399| | /* timeout is handled by the while loop */ 6400| | return 0; 6401| | } else if (err == WSAECONNABORTED) { 6402| | /* See https://www.chilkatsoft.com/p/p_299.asp */ 6403| | return -2; 6404| | } else { 6405| | DEBUG_TRACE("recv() failed, error %d", err); 6406| | return -2; 6407| | } 6408| |#else 6409| | /* TODO: POSIX returns either EAGAIN or EWOULDBLOCK in both cases, 6410| | * if the timeout is reached and if the socket was set to non- 6411| | * blocking in close_socket_gracefully, so we can not distinguish 6412| | * here. We have to wait for the timeout in both cases for now. 6413| | */ 6414| 0| if (ERROR_TRY_AGAIN(err)) { ------------------ | | 448| 0| (((err) == EAGAIN) || ((err) == EWOULDBLOCK) || ((err) == EINTR)) | | ------------------ | | | Branch (448:3): [True: 0, False: 0] | | | Branch (448:24): [True: 0, False: 0] | | | Branch (448:50): [True: 0, False: 0] | | ------------------ ------------------ 6415| | /* TODO (low): check if this is still required */ 6416| | /* EAGAIN/EWOULDBLOCK: 6417| | * standard case if called from close_socket_gracefully 6418| | * => should return -1 */ 6419| | /* or timeout occurred 6420| | * => the code must stay in the while loop */ 6421| | 6422| | /* EINTR can be generated on a socket with a timeout set even 6423| | * when SA_RESTART is effective for all relevant signals 6424| | * (see signal(7)). 6425| | * => stay in the while loop */ 6426| 0| } else { 6427| 0| DEBUG_TRACE("recv() failed, error %d", err); ------------------ | | 243| 0| do { \ | | 244| 0| } while (0) | | ------------------ | | | Branch (244:11): [Folded - Ignored] | | ------------------ ------------------ 6428| 0| return -2; 6429| 0| } 6430| 0|#endif 6431| 0| } 6432| | 6433| | /* Timeout occurred, but no data available. */ 6434| 0| return -1; 6435| 0|} civetweb.c:mg_poll: 5942| 78|{ 5943| | /* Call poll, but only for a maximum time of a few seconds. 5944| | * This will allow to stop the server after some seconds, instead 5945| | * of having to wait for a long socket timeout. */ 5946| 78| int ms_now = SOCKET_TIMEOUT_QUANTUM; /* Sleep quantum in ms */ ------------------ | | 473| 78|#define SOCKET_TIMEOUT_QUANTUM (2000) /* in ms */ ------------------ 5947| | 5948| 78| int check_pollerr = 0; 5949| 78| if ((n == 1) && ((pfd[0].events & POLLERR) == 0)) { ------------------ | Branch (5949:6): [True: 78, False: 0] | Branch (5949:18): [True: 78, False: 0] ------------------ 5950| | /* If we wait for only one file descriptor, wait on error as well */ 5951| 78| pfd[0].events |= POLLERR; 5952| 78| check_pollerr = 1; 5953| 78| } 5954| | 5955| 78| do { 5956| 78| int result; 5957| | 5958| 78| if (!STOP_FLAG_IS_ZERO(&*stop_flag)) { ------------------ | | 2322| 78|#define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0) ------------------ | Branch (5958:7): [True: 0, False: 78] ------------------ 5959| | /* Shut down signal */ 5960| 0| return -2; 5961| 0| } 5962| | 5963| 78| if ((milliseconds >= 0) && (milliseconds < ms_now)) { ------------------ | Branch (5963:7): [True: 78, False: 0] | Branch (5963:30): [True: 44, False: 34] ------------------ 5964| 44| ms_now = milliseconds; 5965| 44| } 5966| | 5967| 78| result = poll(pfd, n, ms_now); 5968| 78| if (result != 0) { ------------------ | Branch (5968:7): [True: 78, False: 0] ------------------ 5969| 78| int err = ERRNO; ------------------ | | 924| 78|#define ERRNO (errno) ------------------ 5970| 78| if ((result == 1) || (!ERROR_TRY_AGAIN(err))) { ------------------ | | 448| 0| (((err) == EAGAIN) || ((err) == EWOULDBLOCK) || ((err) == EINTR)) | | ------------------ | | | Branch (448:3): [True: 0, False: 0] | | | Branch (448:24): [True: 0, False: 0] | | | Branch (448:50): [True: 0, False: 0] | | ------------------ ------------------ | Branch (5970:8): [True: 78, False: 0] ------------------ 5971| | /* Poll returned either success (1) or error (-1). 5972| | * Forward both to the caller. */ 5973| 78| if ((check_pollerr) ------------------ | Branch (5973:9): [True: 78, False: 0] ------------------ 5974| 78| && ((pfd[0].revents & (POLLIN | POLLOUT | POLLERR)) ------------------ | Branch (5974:12): [True: 0, False: 78] ------------------ 5975| 78| == POLLERR)) { 5976| | /* One and only file descriptor returned error */ 5977| 0| return -1; 5978| 0| } 5979| 78| return result; 5980| 78| } 5981| 78| } 5982| | 5983| | /* Poll returned timeout (0). */ 5984| 0| if (milliseconds > 0) { ------------------ | Branch (5984:7): [True: 0, False: 0] ------------------ 5985| 0| milliseconds -= ms_now; 5986| 0| } 5987| | 5988| 0| } while (milliseconds > 0); ------------------ | Branch (5988:11): [True: 0, False: 0] ------------------ 5989| | 5990| | /* timeout: return 0 */ 5991| 0| return 0; 5992| 78|} civetweb.c:mg_difftimespec: 3365| 10|{ 3366| 10| return (double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0E-9 3367| 10| + (double)(ts_now->tv_sec - ts_before->tv_sec); 3368| 10|} civetweb.c:mg_get_current_time_ns: 1677| 34|{ 1678| 34| struct timespec tsnow; 1679| 34| clock_gettime(CLOCK_REALTIME, &tsnow); 1680| 34| return (((uint64_t)tsnow.tv_sec) * 1000000000) + (uint64_t)tsnow.tv_nsec; 1681| 34|} civetweb.c:mg_snprintf: 3149| 67|{ 3150| 67| va_list ap; 3151| | 3152| 67| va_start(ap, fmt); 3153| 67| mg_vsnprintf(conn, truncated, buf, buflen, fmt, ap); 3154| 67| va_end(ap); 3155| 67|} civetweb.c:push_all: 6168| 34|{ 6169| 34| double timeout = -1.0; 6170| 34| int n, nwritten = 0; 6171| | 6172| 34| if (ctx == NULL) { ------------------ | Branch (6172:6): [True: 0, False: 34] ------------------ 6173| 0| return -1; 6174| 0| } 6175| | 6176| 34| if (ctx->dd.config[REQUEST_TIMEOUT]) { ------------------ | Branch (6176:6): [True: 0, False: 34] ------------------ 6177| 0| timeout = atoi(ctx->dd.config[REQUEST_TIMEOUT]) / 1000.0; 6178| 0| } 6179| 34| if (timeout <= 0.0) { ------------------ | Branch (6179:6): [True: 34, False: 0] ------------------ 6180| 34| timeout = strtod(config_options[REQUEST_TIMEOUT].default_value, NULL) 6181| 34| / 1000.0; 6182| 34| } 6183| | 6184| 68| while ((len > 0) && STOP_FLAG_IS_ZERO(&ctx->stop_flag)) { ------------------ | | 2322| 34|#define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0) | | ------------------ | | | Branch (2322:30): [True: 34, False: 0] | | ------------------ ------------------ | Branch (6184:9): [True: 34, False: 34] ------------------ 6185| 34| n = push_inner(ctx, fp, sock, ssl, buf + nwritten, len, timeout); 6186| 34| if (n < 0) { ------------------ | Branch (6186:7): [True: 0, False: 34] ------------------ 6187| 0| if (nwritten == 0) { ------------------ | Branch (6187:8): [True: 0, False: 0] ------------------ 6188| 0| nwritten = -1; /* Propagate the error */ 6189| 0| } 6190| 0| break; 6191| 34| } else if (n == 0) { ------------------ | Branch (6191:14): [True: 0, False: 34] ------------------ 6192| 0| break; /* No more data to write */ 6193| 34| } else { 6194| 34| nwritten += n; 6195| 34| len -= n; 6196| 34| } 6197| 34| } 6198| | 6199| 34| return nwritten; 6200| 34|} civetweb.c:push_inner: 6010| 34|{ 6011| 34| uint64_t start = 0, now = 0, timeout_ns = 0; 6012| 34| int n, err; 6013| 34| unsigned ms_wait = SOCKET_TIMEOUT_QUANTUM; /* Sleep quantum in ms */ ------------------ | | 473| 34|#define SOCKET_TIMEOUT_QUANTUM (2000) /* in ms */ ------------------ 6014| | 6015| |#if defined(_WIN32) 6016| | typedef int len_t; 6017| |#else 6018| 34| typedef size_t len_t; 6019| 34|#endif 6020| | 6021| 34| if (timeout > 0) { ------------------ | Branch (6021:6): [True: 34, False: 0] ------------------ 6022| 34| now = mg_get_current_time_ns(); 6023| 34| start = now; 6024| 34| timeout_ns = (uint64_t)(timeout * 1.0E9); 6025| 34| } 6026| | 6027| 34| if (ctx == NULL) { ------------------ | Branch (6027:6): [True: 0, False: 34] ------------------ 6028| 0| return -2; 6029| 0| } 6030| | 6031| |#if defined(NO_SSL) && !defined(USE_MBEDTLS) 6032| | if (ssl) { 6033| | return -2; 6034| | } 6035| |#endif 6036| | 6037| | /* Try to read until it succeeds, fails, times out, or the server 6038| | * shuts down. */ 6039| 34| for (;;) { 6040| | 6041| |#if defined(USE_MBEDTLS) 6042| | if (ssl != NULL) { 6043| | n = mbed_ssl_write(ssl, (const unsigned char *)buf, len); 6044| | if (n <= 0) { 6045| | if ((n == MBEDTLS_ERR_SSL_WANT_READ) 6046| | || (n == MBEDTLS_ERR_SSL_WANT_WRITE) 6047| | || n == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) { 6048| | n = 0; 6049| | } else { 6050| | fprintf(stderr, "SSL write failed, error %d\n", n); 6051| | return -2; 6052| | } 6053| | } else { 6054| | err = 0; 6055| | } 6056| | } else 6057| |#elif !defined(NO_SSL) 6058| 34| if (ssl != NULL) { ------------------ | Branch (6058:7): [True: 0, False: 34] ------------------ 6059| 0| ERR_clear_error(); ------------------ | | 232| 0|#define ERR_clear_error (*(void (*)(void))crypto_sw[15].ptr) ------------------ 6060| 0| n = SSL_write(ssl, buf, len); ------------------ | | 108| 0|#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr) ------------------ 6061| 0| if (n <= 0) { ------------------ | Branch (6061:8): [True: 0, False: 0] ------------------ 6062| 0| err = SSL_get_error(ssl, n); ------------------ | | 109| 0|#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr) ------------------ 6063| 0| if ((err == SSL_ERROR_SYSCALL) && (n == -1)) { ------------------ | | 71| 0|#define SSL_ERROR_SYSCALL (5) /* see errno */ ------------------ | Branch (6063:9): [True: 0, False: 0] | Branch (6063:39): [True: 0, False: 0] ------------------ 6064| 0| err = ERRNO; ------------------ | | 924| 0|#define ERRNO (errno) ------------------ 6065| 0| } else if ((err == SSL_ERROR_WANT_READ) ------------------ | | 68| 0|#define SSL_ERROR_WANT_READ (2) ------------------ | Branch (6065:16): [True: 0, False: 0] ------------------ 6066| 0| || (err == SSL_ERROR_WANT_WRITE)) { ------------------ | | 69| 0|#define SSL_ERROR_WANT_WRITE (3) ------------------ | Branch (6066:19): [True: 0, False: 0] ------------------ 6067| 0| n = 0; 6068| 0| } else { 6069| 0| DEBUG_TRACE("SSL_write() failed, error %d", err); ------------------ | | 243| 0| do { \ | | 244| 0| } while (0) | | ------------------ | | | Branch (244:11): [Folded - Ignored] | | ------------------ ------------------ 6070| 0| ERR_clear_error(); ------------------ | | 232| 0|#define ERR_clear_error (*(void (*)(void))crypto_sw[15].ptr) ------------------ 6071| 0| return -2; 6072| 0| } 6073| 0| ERR_clear_error(); ------------------ | | 232| 0|#define ERR_clear_error (*(void (*)(void))crypto_sw[15].ptr) ------------------ 6074| 0| } else { 6075| 0| err = 0; 6076| 0| } 6077| 0| } else 6078| 34|#endif 6079| | 6080| 34| if (fp != NULL) { ------------------ | Branch (6080:11): [True: 0, False: 34] ------------------ 6081| 0| n = (int)fwrite(buf, 1, (size_t)len, fp); 6082| 0| if (ferror(fp)) { ------------------ | Branch (6082:8): [True: 0, False: 0] ------------------ 6083| 0| n = -1; 6084| 0| err = ERRNO; ------------------ | | 924| 0|#define ERRNO (errno) ------------------ 6085| 0| } else { 6086| 0| err = 0; 6087| 0| } 6088| 34| } else { 6089| 34| n = (int)send(sock, buf, (len_t)len, MSG_NOSIGNAL); 6090| 34| err = (n < 0) ? ERRNO : 0; ------------------ | | 924| 0|#define ERRNO (errno) ------------------ | Branch (6090:10): [True: 0, False: 34] ------------------ 6091| 34| if (ERROR_TRY_AGAIN(err)) { ------------------ | | 448| 34| (((err) == EAGAIN) || ((err) == EWOULDBLOCK) || ((err) == EINTR)) | | ------------------ | | | Branch (448:3): [True: 0, False: 34] | | | Branch (448:24): [True: 0, False: 34] | | | Branch (448:50): [True: 0, False: 34] | | ------------------ ------------------ 6092| 0| err = 0; 6093| 0| n = 0; 6094| 0| } 6095| 34| if (n < 0) { ------------------ | Branch (6095:8): [True: 0, False: 34] ------------------ 6096| | /* shutdown of the socket at client side */ 6097| 0| return -2; 6098| 0| } 6099| 34| } 6100| | 6101| 34| if (!STOP_FLAG_IS_ZERO(&ctx->stop_flag)) { ------------------ | | 2322| 34|#define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0) ------------------ | Branch (6101:7): [True: 0, False: 34] ------------------ 6102| 0| return -2; 6103| 0| } 6104| | 6105| 34| if ((n > 0) || ((n == 0) && (len == 0))) { ------------------ | Branch (6105:7): [True: 34, False: 0] | Branch (6105:19): [True: 0, False: 0] | Branch (6105:31): [True: 0, False: 0] ------------------ 6106| | /* some data has been read, or no data was requested */ 6107| 34| return n; 6108| 34| } 6109| 0| if (n < 0) { ------------------ | Branch (6109:7): [True: 0, False: 0] ------------------ 6110| | /* socket error - check errno */ 6111| 0| DEBUG_TRACE("send() failed, error %d", err); ------------------ | | 243| 0| do { \ | | 244| 0| } while (0) | | ------------------ | | | Branch (244:11): [Folded - Ignored] | | ------------------ ------------------ 6112| | 6113| | /* TODO (mid): error handling depending on the error code. 6114| | * These codes are different between Windows and Linux. 6115| | * Currently there is no problem with failing send calls, 6116| | * if there is a reproducible situation, it should be 6117| | * investigated in detail. 6118| | */ 6119| 0| return -2; 6120| 0| } 6121| | 6122| | /* Only in case n=0 (timeout), repeat calling the write function */ 6123| | 6124| | /* If send failed, wait before retry */ 6125| 0| if (fp != NULL) { ------------------ | Branch (6125:7): [True: 0, False: 0] ------------------ 6126| | /* For files, just wait a fixed time. 6127| | * Maybe it helps, maybe not. */ 6128| 0| mg_sleep(5); ------------------ | | 920| 0|#define mg_sleep(x) (usleep((x)*1000)) ------------------ 6129| 0| } else { 6130| | /* For sockets, wait for the socket using poll */ 6131| 0| struct mg_pollfd pfd[1]; 6132| 0| int pollres; 6133| | 6134| 0| pfd[0].fd = sock; 6135| 0| pfd[0].events = POLLOUT; 6136| 0| pollres = mg_poll(pfd, 1, (int)(ms_wait), &(ctx->stop_flag)); 6137| 0| if (!STOP_FLAG_IS_ZERO(&ctx->stop_flag)) { ------------------ | | 2322| 0|#define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0) ------------------ | Branch (6137:8): [True: 0, False: 0] ------------------ 6138| 0| return -2; 6139| 0| } 6140| 0| if (pollres > 0) { ------------------ | Branch (6140:8): [True: 0, False: 0] ------------------ 6141| 0| continue; 6142| 0| } 6143| 0| } 6144| | 6145| 0| if (timeout > 0) { ------------------ | Branch (6145:7): [True: 0, False: 0] ------------------ 6146| 0| now = mg_get_current_time_ns(); 6147| 0| if ((now - start) > timeout_ns) { ------------------ | Branch (6147:8): [True: 0, False: 0] ------------------ 6148| | /* Timeout */ 6149| 0| break; 6150| 0| } 6151| 0| } 6152| 0| } 6153| | 6154| 0| (void)err; /* Avoid unused warning if NO_SSL is set and DEBUG_TRACE is not 6155| | used */ 6156| | 6157| 0| return -1; 6158| 34|} civetweb.c:mg_vprintf: 7019| 34|{ 7020| 34| char mem[MG_BUF_LEN]; 7021| 34| char *buf = NULL; 7022| 34| int len; 7023| | 7024| 34| if ((len = alloc_vprintf(&buf, mem, sizeof(mem), fmt, ap)) > 0) { ------------------ | Branch (7024:6): [True: 34, False: 0] ------------------ 7025| 34| len = mg_write(conn, buf, (size_t)len); 7026| 34| } 7027| 34| if (buf != mem) { ------------------ | Branch (7027:6): [True: 0, False: 34] ------------------ 7028| 0| mg_free(buf); 7029| 0| } 7030| | 7031| 34| return len; 7032| 34|} civetweb.c:alloc_vprintf: 6946| 34|{ 6947| 34| va_list ap_copy; 6948| 34| int len; 6949| | 6950| | /* Windows is not standard-compliant, and vsnprintf() returns -1 if 6951| | * buffer is too small. Also, older versions of msvcrt.dll do not have 6952| | * _vscprintf(). However, if size is 0, vsnprintf() behaves correctly. 6953| | * Therefore, we make two passes: on first pass, get required message 6954| | * length. 6955| | * On second pass, actually print the message. */ 6956| 34| va_copy(ap_copy, ap); 6957| 34| len = vsnprintf_impl(NULL, 0, fmt, ap_copy); ------------------ | | 897| 34|#define vsnprintf_impl vsnprintf ------------------ 6958| 34| va_end(ap_copy); 6959| | 6960| 34| if (len < 0) { ------------------ | Branch (6960:6): [True: 0, False: 34] ------------------ 6961| | /* C runtime is not standard compliant, vsnprintf() returned -1. 6962| | * Switch to alternative code path that uses incremental 6963| | * allocations. 6964| | */ 6965| 0| va_copy(ap_copy, ap); 6966| 0| len = alloc_vprintf2(out_buf, fmt, ap_copy); 6967| 0| va_end(ap_copy); 6968| | 6969| 34| } else if ((size_t)(len) >= prealloc_size) { ------------------ | Branch (6969:13): [True: 0, False: 34] ------------------ 6970| | /* The pre-allocated buffer not large enough. */ 6971| | /* Allocate a new buffer. */ 6972| 0| *out_buf = (char *)mg_malloc((size_t)(len) + 1); 6973| 0| if (!*out_buf) { ------------------ | Branch (6973:7): [True: 0, False: 0] ------------------ 6974| | /* Allocation failed. Return -1 as "out of memory" error. */ 6975| 0| return -1; 6976| 0| } 6977| | /* Buffer allocation successful. Store the string there. */ 6978| 0| va_copy(ap_copy, ap); 6979| 0| IGNORE_UNUSED_RESULT( ------------------ | | 291| 0|#define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1)) | | ------------------ | | | Branch (291:41): [True: 0, False: 0] | | | Branch (291:48): [Folded - Ignored] | | ------------------ ------------------ 6980| 0| vsnprintf_impl(*out_buf, (size_t)(len) + 1, fmt, ap_copy)); 6981| 0| va_end(ap_copy); 6982| | 6983| 34| } else { 6984| | /* The pre-allocated buffer is large enough. 6985| | * Use it to store the string and return the address. */ 6986| 34| va_copy(ap_copy, ap); 6987| 34| IGNORE_UNUSED_RESULT( ------------------ | | 291| 34|#define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1)) | | ------------------ | | | Branch (291:41): [True: 34, False: 0] | | | Branch (291:48): [Folded - Ignored] | | ------------------ ------------------ 6988| 34| vsnprintf_impl(prealloc_buf, prealloc_size, fmt, ap_copy)); 6989| 34| va_end(ap_copy); 6990| 34| *out_buf = prealloc_buf; 6991| 34| } 6992| | 6993| 34| return len; 6994| 34|} civetweb.c:mg_calloc: 1481| 34|{ 1482| 34| return calloc(a, b); 1483| 34|} civetweb.c:parse_http_headers: 10717| 3|{ 10718| 3| int i; 10719| 3| int num_headers = 0; 10720| | 10721| 58| for (i = 0; i < (int)MG_MAX_HEADERS; i++) { ------------------ | | 141| 58|#define MG_MAX_HEADERS (64) ------------------ | Branch (10721:14): [True: 58, False: 0] ------------------ 10722| 58| char *dp = *buf; 10723| | 10724| | /* Skip all ASCII characters (>SPACE, <127), to find a ':' */ 10725| 246| while ((*dp != ':') && (*dp >= 33) && (*dp <= 126)) { ------------------ | Branch (10725:10): [True: 245, False: 1] | Branch (10725:26): [True: 188, False: 57] | Branch (10725:41): [True: 188, False: 0] ------------------ 10726| 188| dp++; 10727| 188| } 10728| 58| if (dp == *buf) { ------------------ | Branch (10728:7): [True: 1, False: 57] ------------------ 10729| | /* End of headers reached. */ 10730| 1| break; 10731| 1| } 10732| | 10733| | /* Drop all spaces after header name before : */ 10734| 173| while (*dp == ' ') { ------------------ | Branch (10734:10): [True: 116, False: 57] ------------------ 10735| 116| *dp = 0; 10736| 116| dp++; 10737| 116| } 10738| 57| if (*dp != ':') { ------------------ | Branch (10738:7): [True: 2, False: 55] ------------------ 10739| | /* This is not a valid field. */ 10740| 2| return -1; 10741| 2| } 10742| | 10743| | /* End of header key (*dp == ':') */ 10744| | /* Truncate here and set the key name */ 10745| 55| *dp = 0; 10746| 55| hdr[i].name = *buf; 10747| | 10748| | /* Skip all spaces */ 10749| 88| do { 10750| 88| dp++; 10751| 88| } while ((*dp == ' ') || (*dp == '\t')); ------------------ | Branch (10751:12): [True: 33, False: 55] | Branch (10751:28): [True: 0, False: 55] ------------------ 10752| | 10753| | /* The rest of the line is the value */ 10754| 55| hdr[i].value = dp; 10755| | 10756| | /* Find end of line */ 10757| 1.47k| while ((*dp != 0) && (*dp != '\r') && (*dp != '\n')) { ------------------ | Branch (10757:10): [True: 1.47k, False: 0] | Branch (10757:24): [True: 1.47k, False: 0] | Branch (10757:41): [True: 1.42k, False: 55] ------------------ 10758| 1.42k| dp++; 10759| 1.42k| }; 10760| | 10761| | /* eliminate \r */ 10762| 55| if (*dp == '\r') { ------------------ | Branch (10762:7): [True: 0, False: 55] ------------------ 10763| 0| *dp = 0; 10764| 0| dp++; 10765| 0| if (*dp != '\n') { ------------------ | Branch (10765:8): [True: 0, False: 0] ------------------ 10766| | /* This is not a valid line. */ 10767| 0| return -1; 10768| 0| } 10769| 0| } 10770| | 10771| | /* here *dp is either 0 or '\n' */ 10772| | /* in any case, we have a new header */ 10773| 55| num_headers = i + 1; 10774| | 10775| 55| if (*dp) { ------------------ | Branch (10775:7): [True: 55, False: 0] ------------------ 10776| 55| *dp = 0; 10777| 55| dp++; 10778| 55| *buf = dp; 10779| | 10780| 55| if ((dp[0] == '\r') || (dp[0] == '\n')) { ------------------ | Branch (10780:8): [True: 0, False: 55] | Branch (10780:27): [True: 0, False: 55] ------------------ 10781| | /* This is the end of the header */ 10782| 0| break; 10783| 0| } 10784| 55| } else { 10785| 0| *buf = dp; 10786| 0| break; 10787| 0| } 10788| 55| } 10789| 1| return num_headers; 10790| 3|} civetweb.c:close_connection: 17856| 34|{ 17857| |#if defined(USE_SERVER_STATS) 17858| | conn->conn_state = 6; /* to close */ 17859| |#endif 17860| | 17861| |#if defined(USE_LUA) && defined(USE_WEBSOCKET) 17862| | if (conn->lua_websocket_state) { 17863| | lua_websocket_close(conn, conn->lua_websocket_state); 17864| | conn->lua_websocket_state = NULL; 17865| | } 17866| |#endif 17867| | 17868| 34| mg_lock_connection(conn); 17869| | 17870| | /* Set close flag, so keep-alive loops will stop */ 17871| 34| conn->must_close = 1; 17872| | 17873| | /* call the connection_close callback if assigned */ 17874| 34| if (conn->phys_ctx->callbacks.connection_close != NULL) { ------------------ | Branch (17874:6): [True: 0, False: 34] ------------------ 17875| 0| if (conn->phys_ctx->context_type == CONTEXT_SERVER) { ------------------ | Branch (17875:7): [True: 0, False: 0] ------------------ 17876| 0| conn->phys_ctx->callbacks.connection_close(conn); 17877| 0| } 17878| 0| } 17879| | 17880| | /* Reset user data, after close callback is called. 17881| | * Do not reuse it. If the user needs a destructor, 17882| | * it must be done in the connection_close callback. */ 17883| 34| mg_set_user_connection_data(conn, NULL); 17884| | 17885| |#if defined(USE_SERVER_STATS) 17886| | conn->conn_state = 7; /* closing */ 17887| |#endif 17888| | 17889| |#if defined(USE_MBEDTLS) 17890| | if (conn->ssl != NULL) { 17891| | mbed_ssl_close(conn->ssl); 17892| | conn->ssl = NULL; 17893| | } 17894| |#elif !defined(NO_SSL) 17895| 34| if (conn->ssl != NULL) { ------------------ | Branch (17895:6): [True: 0, False: 34] ------------------ 17896| | /* Run SSL_shutdown twice to ensure completely close SSL connection 17897| | */ 17898| 0| SSL_shutdown(conn->ssl); ------------------ | | 134| 0|#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[19].ptr) ------------------ 17899| 0| SSL_free(conn->ssl); ------------------ | | 104| 0|#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr) ------------------ 17900| 0| OPENSSL_REMOVE_THREAD_STATE(); 17901| 0| conn->ssl = NULL; 17902| 0| } 17903| 34|#endif 17904| 34| if (conn->client.sock != INVALID_SOCKET) { ------------------ | | 925| 34|#define INVALID_SOCKET (-1) ------------------ | Branch (17904:6): [True: 34, False: 0] ------------------ 17905| |#if defined(__ZEPHYR__) 17906| | closesocket(conn->client.sock); 17907| |#else 17908| 34| close_socket_gracefully(conn); 17909| 34|#endif 17910| 34| conn->client.sock = INVALID_SOCKET; ------------------ | | 925| 34|#define INVALID_SOCKET (-1) ------------------ 17911| 34| } 17912| | 17913| | /* call the connection_closed callback if assigned */ 17914| 34| if (conn->phys_ctx->callbacks.connection_closed != NULL) { ------------------ | Branch (17914:6): [True: 0, False: 34] ------------------ 17915| 0| if (conn->phys_ctx->context_type == CONTEXT_SERVER) { ------------------ | Branch (17915:7): [True: 0, False: 0] ------------------ 17916| 0| conn->phys_ctx->callbacks.connection_closed(conn); 17917| 0| } 17918| 0| } 17919| | 17920| 34| mg_unlock_connection(conn); 17921| | 17922| |#if defined(USE_SERVER_STATS) 17923| | conn->conn_state = 8; /* closed */ 17924| |#endif 17925| 34|} civetweb.c:close_socket_gracefully: 17732| 34|{ 17733| |#if defined(_WIN32) 17734| | char buf[MG_BUF_LEN]; 17735| | int n; 17736| |#endif 17737| 34| struct linger linger; 17738| 34| int error_code = 0; 17739| 34| int linger_timeout = -2; 17740| 34| socklen_t opt_len = sizeof(error_code); 17741| | 17742| 34| if (!conn) { ------------------ | Branch (17742:6): [True: 0, False: 34] ------------------ 17743| 0| return; 17744| 0| } 17745| | 17746| | /* http://msdn.microsoft.com/en-us/library/ms739165(v=vs.85).aspx: 17747| | * "Note that enabling a nonzero timeout on a nonblocking socket 17748| | * is not recommended.", so set it to blocking now */ 17749| 34| set_blocking_mode(conn->client.sock); 17750| | 17751| | /* Send FIN to the client */ 17752| 34| shutdown(conn->client.sock, SHUTDOWN_WR); ------------------ | | 517| 34|#define SHUTDOWN_WR (1) ------------------ 17753| | 17754| |#if defined(_WIN32) 17755| | /* Read and discard pending incoming data. If we do not do that and 17756| | * close 17757| | * the socket, the data in the send buffer may be discarded. This 17758| | * behaviour is seen on Windows, when client keeps sending data 17759| | * when server decides to close the connection; then when client 17760| | * does recv() it gets no data back. */ 17761| | do { 17762| | n = pull_inner(NULL, conn, buf, sizeof(buf), /* Timeout in s: */ 1.0); 17763| | } while (n > 0); 17764| |#endif 17765| | 17766| 34| if (conn->dom_ctx->config[LINGER_TIMEOUT]) { ------------------ | Branch (17766:6): [True: 0, False: 34] ------------------ 17767| 0| linger_timeout = atoi(conn->dom_ctx->config[LINGER_TIMEOUT]); 17768| 0| } 17769| | 17770| | /* Set linger option according to configuration */ 17771| 34| if (linger_timeout >= 0) { ------------------ | Branch (17771:6): [True: 0, False: 34] ------------------ 17772| | /* Set linger option to avoid socket hanging out after close. This 17773| | * prevent ephemeral port exhaust problem under high QPS. */ 17774| 0| linger.l_onoff = 1; 17775| | 17776| |#if defined(_MSC_VER) 17777| |#pragma warning(push) 17778| |#pragma warning(disable : 4244) 17779| |#endif 17780| |#if defined(GCC_DIAGNOSTIC) 17781| |#pragma GCC diagnostic push 17782| |#pragma GCC diagnostic ignored "-Wconversion" 17783| |#endif 17784| | /* Data type of linger structure elements may differ, 17785| | * so we don't know what cast we need here. 17786| | * Disable type conversion warnings. */ 17787| | 17788| 0| linger.l_linger = (linger_timeout + 999) / 1000; 17789| | 17790| |#if defined(GCC_DIAGNOSTIC) 17791| |#pragma GCC diagnostic pop 17792| |#endif 17793| |#if defined(_MSC_VER) 17794| |#pragma warning(pop) 17795| |#endif 17796| | 17797| 34| } else { 17798| 34| linger.l_onoff = 0; 17799| 34| linger.l_linger = 0; 17800| 34| } 17801| | 17802| 34| if (linger_timeout < -1) { ------------------ | Branch (17802:6): [True: 34, False: 0] ------------------ 17803| | /* Default: don't configure any linger */ 17804| 34| } else if (getsockopt(conn->client.sock, ------------------ | Branch (17804:13): [True: 0, False: 0] ------------------ 17805| 0| SOL_SOCKET, 17806| 0| SO_ERROR, 17807| |#if defined(_WIN32) /* WinSock uses different data type here */ 17808| | (char *)&error_code, 17809| |#else 17810| 0| &error_code, 17811| 0|#endif 17812| 0| &opt_len) 17813| 0| != 0) { 17814| | /* Cannot determine if socket is already closed. This should 17815| | * not occur and never did in a test. Log an error message 17816| | * and continue. */ 17817| 0| mg_cry_internal(conn, ------------------ | | 2584| 0| mg_cry_internal_wrap(conn, NULL, __func__, __LINE__, fmt, __VA_ARGS__) ------------------ 17818| 0| "%s: getsockopt(SOL_SOCKET SO_ERROR) failed: %s", 17819| 0| __func__, 17820| 0| strerror(ERRNO)); 17821| |#if defined(_WIN32) 17822| | } else if (error_code == WSAECONNRESET) { 17823| |#else 17824| 0| } else if (error_code == ECONNRESET) { ------------------ | Branch (17824:13): [True: 0, False: 0] ------------------ 17825| 0|#endif 17826| | /* Socket already closed by client/peer, close socket without linger 17827| | */ 17828| 0| } else { 17829| | 17830| | /* Set linger timeout */ 17831| 0| if (setsockopt(conn->client.sock, ------------------ | Branch (17831:7): [True: 0, False: 0] ------------------ 17832| 0| SOL_SOCKET, 17833| 0| SO_LINGER, 17834| 0| (char *)&linger, 17835| 0| sizeof(linger)) 17836| 0| != 0) { 17837| 0| mg_cry_internal( ------------------ | | 2584| 0| mg_cry_internal_wrap(conn, NULL, __func__, __LINE__, fmt, __VA_ARGS__) ------------------ 17838| 0| conn, 17839| 0| "%s: setsockopt(SOL_SOCKET SO_LINGER(%i,%i)) failed: %s", 17840| 0| __func__, 17841| 0| linger.l_onoff, 17842| 0| linger.l_linger, 17843| 0| strerror(ERRNO)); 17844| 0| } 17845| 0| } 17846| | 17847| | /* Now we know that our FIN is ACK-ed, safe to close */ 17848| 34| closesocket(conn->client.sock); ------------------ | | 917| 34|#define closesocket(a) (close(a)) ------------------ 17849| 34| conn->client.sock = INVALID_SOCKET; ------------------ | | 925| 34|#define INVALID_SOCKET (-1) ------------------ 17850| 34|} civetweb.c:set_blocking_mode: 5891| 34|{ 5892| 34| int flags = fcntl(sock, F_GETFL, 0); 5893| 34| if (flags < 0) { ------------------ | Branch (5893:6): [True: 0, False: 34] ------------------ 5894| 0| return -1; 5895| 0| } 5896| | 5897| 34| if (fcntl(sock, F_SETFL, flags & (~(int)(O_NONBLOCK))) < 0) { ------------------ | Branch (5897:6): [True: 0, False: 34] ------------------ 5898| 0| return -1; 5899| 0| } 5900| 34| return 0; 5901| 34|} civetweb.c:mg_connect_client_impl: 17996| 34|{ 17997| 34| struct mg_connection *conn = NULL; 17998| 34| SOCKET sock; 17999| 34| union usa sa; 18000| 34| struct sockaddr *psa; 18001| 34| socklen_t len; 18002| | 18003| 34| unsigned max_req_size = 18004| 34| (unsigned)atoi(config_options[MAX_REQUEST_SIZE].default_value); 18005| | 18006| | /* Size of structures, aligned to 8 bytes */ 18007| 34| size_t conn_size = ((sizeof(struct mg_connection) + 7) >> 3) << 3; 18008| 34| size_t ctx_size = ((sizeof(struct mg_context) + 7) >> 3) << 3; 18009| 34| size_t alloc_size = conn_size + ctx_size + max_req_size; 18010| | 18011| 34| (void)init; /* TODO: Implement required options */ 18012| | 18013| 34| conn = (struct mg_connection *)mg_calloc(1, alloc_size); 18014| | 18015| 34| if (error != NULL) { ------------------ | Branch (18015:6): [True: 34, False: 0] ------------------ 18016| 34| error->code = MG_ERROR_DATA_CODE_OK; 18017| 34| error->code_sub = 0; 18018| 34| if (error->text_buffer_size > 0) { ------------------ | Branch (18018:7): [True: 34, False: 0] ------------------ 18019| 34| error->text[0] = 0; 18020| 34| } 18021| 34| } 18022| | 18023| 34| if (conn == NULL) { ------------------ | Branch (18023:6): [True: 0, False: 34] ------------------ 18024| 0| if (error != NULL) { ------------------ | Branch (18024:7): [True: 0, False: 0] ------------------ 18025| 0| error->code = MG_ERROR_DATA_CODE_OUT_OF_MEMORY; 18026| 0| error->code_sub = (unsigned)alloc_size; 18027| 0| mg_snprintf(NULL, 18028| 0| NULL, /* No truncation check for ebuf */ 18029| 0| error->text, 18030| 0| error->text_buffer_size, 18031| 0| "calloc(): %s", 18032| 0| strerror(ERRNO)); ------------------ | | 924| 0|#define ERRNO (errno) ------------------ 18033| 0| } 18034| 0| return NULL; 18035| 0| } 18036| | 18037| |#if defined(GCC_DIAGNOSTIC) 18038| |#pragma GCC diagnostic push 18039| |#pragma GCC diagnostic ignored "-Wcast-align" 18040| |#endif /* defined(GCC_DIAGNOSTIC) */ 18041| | /* conn_size is aligned to 8 bytes */ 18042| | 18043| 34| conn->phys_ctx = (struct mg_context *)(((char *)conn) + conn_size); 18044| | 18045| |#if defined(GCC_DIAGNOSTIC) 18046| |#pragma GCC diagnostic pop 18047| |#endif /* defined(GCC_DIAGNOSTIC) */ 18048| | 18049| 34| conn->buf = (((char *)conn) + conn_size + ctx_size); 18050| 34| conn->buf_size = (int)max_req_size; 18051| 34| conn->phys_ctx->context_type = CONTEXT_HTTP_CLIENT; 18052| 34| conn->dom_ctx = &(conn->phys_ctx->dd); 18053| | 18054| 34| if (!connect_socket(conn->phys_ctx, ------------------ | Branch (18054:6): [True: 0, False: 34] ------------------ 18055| 34| client_options->host, 18056| 34| client_options->port, 18057| 34| use_ssl, 18058| 34| error, 18059| 34| &sock, 18060| 34| &sa)) { 18061| | /* "error" will be set by connect_socket. */ 18062| | /* free all memory and return NULL; */ 18063| 0| mg_free(conn); 18064| 0| return NULL; 18065| 0| } 18066| | 18067| 34|#if !defined(NO_SSL) && !defined(USE_MBEDTLS) // TODO: mbedTLS client 18068| 34|#if (defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)) \ 18069| 34| && !defined(NO_SSL_DL) 18070| | 18071| 34| if (use_ssl ------------------ | Branch (18071:6): [True: 0, False: 34] ------------------ 18072| 34| && (conn->dom_ctx->ssl_ctx = SSL_CTX_new(TLS_client_method())) ------------------ | | 112| 0|#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr) ------------------ && (conn->dom_ctx->ssl_ctx = SSL_CTX_new(TLS_client_method())) ------------------ | | 127| 0|#define TLS_client_method (*(SSL_METHOD * (*)(void)) ssl_sw[16].ptr) ------------------ | Branch (18072:9): [True: 0, False: 0] ------------------ 18073| 0| == NULL) { 18074| 0| if (error != NULL) { ------------------ | Branch (18074:7): [True: 0, False: 0] ------------------ 18075| 0| error->code = MG_ERROR_DATA_CODE_INIT_TLS_FAILED; 18076| 0| mg_snprintf(NULL, 18077| 0| NULL, /* No truncation check for ebuf */ 18078| 0| error->text, 18079| 0| error->text_buffer_size, 18080| 0| "SSL_CTX_new error: %s", 18081| 0| ssl_error()); 18082| 0| } 18083| | 18084| 0| closesocket(sock); ------------------ | | 917| 0|#define closesocket(a) (close(a)) ------------------ 18085| 0| mg_free(conn); 18086| 0| return NULL; 18087| 0| } 18088| | 18089| |#else 18090| | 18091| | if (use_ssl 18092| | && (conn->dom_ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) 18093| | == NULL) { 18094| | if (error != NULL) { 18095| | error->code = MG_ERROR_DATA_CODE_INIT_TLS_FAILED; 18096| | mg_snprintf(NULL, 18097| | NULL, /* No truncation check for ebuf */ 18098| | error->text, 18099| | error->text_buffer_size, 18100| | "SSL_CTX_new error: %s", 18101| | ssl_error()); 18102| | } 18103| | 18104| | closesocket(sock); 18105| | mg_free(conn); 18106| | return NULL; 18107| | } 18108| | 18109| |#endif /* OPENSSL_API_1_1 || OPENSSL_API_3_0 */ 18110| 34|#endif /* NO_SSL */ 18111| | 18112| |#if defined(USE_IPV6) 18113| | len = (sa.sa.sa_family == AF_INET) ? sizeof(conn->client.rsa.sin) 18114| | : sizeof(conn->client.rsa.sin6); 18115| | psa = (sa.sa.sa_family == AF_INET) 18116| | ? (struct sockaddr *)&(conn->client.rsa.sin) 18117| | : (struct sockaddr *)&(conn->client.rsa.sin6); 18118| |#else 18119| 34| len = sizeof(conn->client.rsa.sin); 18120| 34| psa = (struct sockaddr *)&(conn->client.rsa.sin); 18121| 34|#endif 18122| | 18123| 34| conn->client.sock = sock; 18124| 34| conn->client.lsa = sa; 18125| | 18126| 34| if (getsockname(sock, psa, &len) != 0) { ------------------ | Branch (18126:6): [True: 0, False: 34] ------------------ 18127| 0| mg_cry_internal(conn, ------------------ | | 2584| 0| mg_cry_internal_wrap(conn, NULL, __func__, __LINE__, fmt, __VA_ARGS__) ------------------ 18128| 0| "%s: getsockname() failed: %s", 18129| 0| __func__, 18130| 0| strerror(ERRNO)); 18131| 0| } 18132| | 18133| 34| conn->client.is_ssl = use_ssl ? 1 : 0; ------------------ | Branch (18133:24): [True: 0, False: 34] ------------------ 18134| 34| if (0 != pthread_mutex_init(&conn->mutex, &pthread_mutex_attr)) { ------------------ | Branch (18134:6): [True: 0, False: 34] ------------------ 18135| 0| if (error != NULL) { ------------------ | Branch (18135:7): [True: 0, False: 0] ------------------ 18136| 0| error->code = MG_ERROR_DATA_CODE_OS_ERROR; 18137| 0| error->code_sub = (unsigned)ERRNO; ------------------ | | 924| 0|#define ERRNO (errno) ------------------ 18138| 0| mg_snprintf(NULL, 18139| 0| NULL, /* No truncation check for ebuf */ 18140| 0| error->text, 18141| 0| error->text_buffer_size, 18142| 0| "Can not create mutex"); 18143| 0| } 18144| 0|#if !defined(NO_SSL) && !defined(USE_MBEDTLS) // TODO: mbedTLS client 18145| 0| SSL_CTX_free(conn->dom_ctx->ssl_ctx); ------------------ | | 124| 0|#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr) ------------------ 18146| 0|#endif 18147| 0| closesocket(sock); ------------------ | | 917| 0|#define closesocket(a) (close(a)) ------------------ 18148| 0| mg_free(conn); 18149| 0| return NULL; 18150| 0| } 18151| | 18152| 34|#if !defined(NO_SSL) && !defined(USE_MBEDTLS) // TODO: mbedTLS client 18153| 34| if (use_ssl) { ------------------ | Branch (18153:6): [True: 0, False: 34] ------------------ 18154| | /* TODO: Check ssl_verify_peer and ssl_ca_path here. 18155| | * SSL_CTX_set_verify call is needed to switch off server 18156| | * certificate checking, which is off by default in OpenSSL and 18157| | * on in yaSSL. */ 18158| | /* TODO: SSL_CTX_set_verify(conn->dom_ctx, 18159| | * SSL_VERIFY_PEER, verify_ssl_server); */ 18160| | 18161| 0| if (client_options->client_cert) { ------------------ | Branch (18161:7): [True: 0, False: 0] ------------------ 18162| 0| if (!ssl_use_pem_file(conn->phys_ctx, ------------------ | Branch (18162:8): [True: 0, False: 0] ------------------ 18163| 0| conn->dom_ctx, 18164| 0| client_options->client_cert, 18165| 0| NULL)) { 18166| 0| if (error != NULL) { ------------------ | Branch (18166:9): [True: 0, False: 0] ------------------ 18167| 0| error->code = MG_ERROR_DATA_CODE_TLS_CLIENT_CERT_ERROR; 18168| 0| mg_snprintf(NULL, 18169| 0| NULL, /* No truncation check for ebuf */ 18170| 0| error->text, 18171| 0| error->text_buffer_size, 18172| 0| "Can not use SSL client certificate"); 18173| 0| } 18174| | 18175| 0| SSL_CTX_free(conn->dom_ctx->ssl_ctx); ------------------ | | 124| 0|#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr) ------------------ 18176| 0| closesocket(sock); ------------------ | | 917| 0|#define closesocket(a) (close(a)) ------------------ 18177| 0| mg_free(conn); 18178| 0| return NULL; 18179| 0| } 18180| 0| } 18181| | 18182| 0| if (client_options->server_cert) { ------------------ | Branch (18182:7): [True: 0, False: 0] ------------------ 18183| 0| if (SSL_CTX_load_verify_locations(conn->dom_ctx->ssl_ctx, ------------------ | | 136| 0| (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[20].ptr) ------------------ | Branch (18183:8): [True: 0, False: 0] ------------------ 18184| 0| client_options->server_cert, 18185| 0| NULL) 18186| 0| != 1) { 18187| 0| if (error != NULL) { ------------------ | Branch (18187:9): [True: 0, False: 0] ------------------ 18188| 0| error->code = MG_ERROR_DATA_CODE_TLS_SERVER_CERT_ERROR; 18189| 0| mg_snprintf(NULL, 18190| 0| NULL, /* No truncation check for ebuf */ 18191| 0| error->text, 18192| 0| error->text_buffer_size, 18193| 0| "SSL_CTX_load_verify_locations error: %s", 18194| 0| ssl_error()); 18195| 0| } 18196| 0| SSL_CTX_free(conn->dom_ctx->ssl_ctx); ------------------ | | 124| 0|#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr) ------------------ 18197| 0| closesocket(sock); ------------------ | | 917| 0|#define closesocket(a) (close(a)) ------------------ 18198| 0| mg_free(conn); 18199| 0| return NULL; 18200| 0| } 18201| 0| SSL_CTX_set_verify(conn->dom_ctx->ssl_ctx, SSL_VERIFY_PEER, NULL); ------------------ | | 130| 0| (*(void (*)(SSL_CTX *, \ | | 131| 0| int, \ | | 132| 0| int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[18] \ | | 133| 0| .ptr) ------------------ SSL_CTX_set_verify(conn->dom_ctx->ssl_ctx, SSL_VERIFY_PEER, NULL); ------------------ | | 45| 0|#define SSL_VERIFY_PEER (1) ------------------ 18202| 0| } else { 18203| 0| SSL_CTX_set_verify(conn->dom_ctx->ssl_ctx, SSL_VERIFY_NONE, NULL); ------------------ | | 130| 0| (*(void (*)(SSL_CTX *, \ | | 131| 0| int, \ | | 132| 0| int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[18] \ | | 133| 0| .ptr) ------------------ SSL_CTX_set_verify(conn->dom_ctx->ssl_ctx, SSL_VERIFY_NONE, NULL); ------------------ | | 44| 0|#define SSL_VERIFY_NONE (0) ------------------ 18204| 0| } 18205| | 18206| 0| if (!sslize(conn, SSL_connect, client_options)) { ------------------ | | 106| 0|#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr) ------------------ | Branch (18206:7): [True: 0, False: 0] ------------------ 18207| 0| if (error != NULL) { ------------------ | Branch (18207:8): [True: 0, False: 0] ------------------ 18208| 0| error->code = MG_ERROR_DATA_CODE_TLS_CONNECT_ERROR; 18209| 0| mg_snprintf(NULL, 18210| 0| NULL, /* No truncation check for ebuf */ 18211| 0| error->text, 18212| 0| error->text_buffer_size, 18213| 0| "SSL connection error"); 18214| 0| } 18215| 0| SSL_CTX_free(conn->dom_ctx->ssl_ctx); ------------------ | | 124| 0|#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr) ------------------ 18216| 0| closesocket(sock); ------------------ | | 917| 0|#define closesocket(a) (close(a)) ------------------ 18217| 0| mg_free(conn); 18218| 0| return NULL; 18219| 0| } 18220| 0| } 18221| 34|#endif 18222| | 18223| 34| return conn; 18224| 34|} civetweb.c:connect_socket: 9288| 34|{ 9289| 34| int ip_ver = 0; 9290| 34| int conn_ret = -1; 9291| 34| int sockerr = 0; 9292| 34| *sock = INVALID_SOCKET; ------------------ | | 925| 34|#define INVALID_SOCKET (-1) ------------------ 9293| 34| memset(sa, 0, sizeof(*sa)); 9294| | 9295| 34| if (host == NULL) { ------------------ | Branch (9295:6): [True: 0, False: 34] ------------------ 9296| 0| if (error != NULL) { ------------------ | Branch (9296:7): [True: 0, False: 0] ------------------ 9297| 0| error->code = MG_ERROR_DATA_CODE_INVALID_PARAM; 9298| 0| mg_snprintf(NULL, 9299| 0| NULL, /* No truncation check for ebuf */ 9300| 0| error->text, 9301| 0| error->text_buffer_size, 9302| 0| "%s", 9303| 0| "NULL host"); 9304| 0| } 9305| 0| return 0; 9306| 0| } 9307| | 9308| |#if defined(USE_X_DOM_SOCKET) 9309| | if (port == -99) { 9310| | /* Unix domain socket */ 9311| | size_t hostlen = strlen(host); 9312| | if (hostlen >= sizeof(sa->sun.sun_path)) { 9313| | if (error != NULL) { 9314| | error->code = MG_ERROR_DATA_CODE_INVALID_PARAM; 9315| | mg_snprintf(NULL, 9316| | NULL, /* No truncation check for ebuf */ 9317| | error->text, 9318| | error->text_buffer_size, 9319| | "%s", 9320| | "host length exceeds limit"); 9321| | } 9322| | return 0; 9323| | } 9324| | } else 9325| |#endif 9326| 34| if ((port <= 0) || !is_valid_port((unsigned)port)) { ------------------ | Branch (9326:10): [True: 0, False: 34] | Branch (9326:25): [True: 0, False: 34] ------------------ 9327| 0| if (error != NULL) { ------------------ | Branch (9327:7): [True: 0, False: 0] ------------------ 9328| 0| error->code = MG_ERROR_DATA_CODE_INVALID_PARAM; 9329| 0| mg_snprintf(NULL, 9330| 0| NULL, /* No truncation check for ebuf */ 9331| 0| error->text, 9332| 0| error->text_buffer_size, 9333| 0| "%s", 9334| 0| "invalid port"); 9335| 0| } 9336| 0| return 0; 9337| 0| } 9338| | 9339| 34|#if !defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(NO_SSL_DL) 9340| 34|#if defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0) 9341| 34| if (use_ssl && (TLS_client_method == NULL)) { ------------------ | | 127| 0|#define TLS_client_method (*(SSL_METHOD * (*)(void)) ssl_sw[16].ptr) ------------------ | Branch (9341:6): [True: 0, False: 34] | Branch (9341:17): [True: 0, False: 0] ------------------ 9342| 0| if (error != NULL) { ------------------ | Branch (9342:7): [True: 0, False: 0] ------------------ 9343| 0| error->code = MG_ERROR_DATA_CODE_INIT_LIBRARY_FAILED; 9344| 0| mg_snprintf(NULL, 9345| 0| NULL, /* No truncation check for ebuf */ 9346| 0| error->text, 9347| 0| error->text_buffer_size, 9348| 0| "%s", 9349| 0| "SSL is not initialized"); 9350| 0| } 9351| 0| return 0; 9352| 0| } 9353| |#else 9354| | if (use_ssl && (SSLv23_client_method == NULL)) { 9355| | if (error != 0) { 9356| | error->code = MG_ERROR_DATA_CODE_INIT_LIBRARY_FAILED; 9357| | mg_snprintf(NULL, 9358| | NULL, /* No truncation check for ebuf */ 9359| | error->text, 9360| | error->text_buffer_size, 9361| | "%s", 9362| | "SSL is not initialized"); 9363| | } 9364| | return 0; 9365| | } 9366| |#endif /* OPENSSL_API_1_1 || OPENSSL_API_3_0*/ 9367| |#else 9368| | (void)use_ssl; 9369| |#endif /* NO SSL */ 9370| | 9371| |#if defined(USE_X_DOM_SOCKET) 9372| | if (port == -99) { 9373| | size_t hostlen = strlen(host); 9374| | /* check (hostlen < sizeof(sun.sun_path)) already passed above */ 9375| | ip_ver = -99; 9376| | sa->sun.sun_family = AF_UNIX; 9377| | memset(sa->sun.sun_path, 0, sizeof(sa->sun.sun_path)); 9378| | memcpy(sa->sun.sun_path, host, hostlen); 9379| | } else 9380| |#endif 9381| 34| if (mg_inet_pton(AF_INET, host, &sa->sin, sizeof(sa->sin), 1)) { ------------------ | Branch (9381:10): [True: 34, False: 0] ------------------ 9382| 34| sa->sin.sin_port = htons((uint16_t)port); 9383| 34| ip_ver = 4; 9384| |#if defined(USE_IPV6) 9385| | } else if (mg_inet_pton(AF_INET6, host, &sa->sin6, sizeof(sa->sin6), 1)) { 9386| | sa->sin6.sin6_port = htons((uint16_t)port); 9387| | ip_ver = 6; 9388| | } else if (host[0] == '[') { 9389| | /* While getaddrinfo on Windows will work with [::1], 9390| | * getaddrinfo on Linux only works with ::1 (without []). */ 9391| | size_t l = strlen(host + 1); 9392| | char *h = (l > 1) ? mg_strdup_ctx(host + 1, ctx) : NULL; 9393| | if (h) { 9394| | h[l - 1] = 0; 9395| | if (mg_inet_pton(AF_INET6, h, &sa->sin6, sizeof(sa->sin6), 0)) { 9396| | sa->sin6.sin6_port = htons((uint16_t)port); 9397| | ip_ver = 6; 9398| | } 9399| | mg_free(h); 9400| | } 9401| |#endif 9402| 34| } 9403| | 9404| 34| if (ip_ver == 0) { ------------------ | Branch (9404:6): [True: 0, False: 34] ------------------ 9405| 0| if (error != NULL) { ------------------ | Branch (9405:7): [True: 0, False: 0] ------------------ 9406| 0| error->code = MG_ERROR_DATA_CODE_HOST_NOT_FOUND; 9407| 0| mg_snprintf(NULL, 9408| 0| NULL, /* No truncation check for ebuf */ 9409| 0| error->text, 9410| 0| error->text_buffer_size, 9411| 0| "%s", 9412| 0| "host not found"); 9413| 0| } 9414| 0| return 0; 9415| 0| } 9416| | 9417| 34| if (ip_ver == 4) { ------------------ | Branch (9417:6): [True: 34, False: 0] ------------------ 9418| 34| *sock = socket(PF_INET, SOCK_STREAM, 0); 9419| 34| } 9420| |#if defined(USE_IPV6) 9421| | else if (ip_ver == 6) { 9422| | *sock = socket(PF_INET6, SOCK_STREAM, 0); 9423| | } 9424| |#endif 9425| |#if defined(USE_X_DOM_SOCKET) 9426| | else if (ip_ver == -99) { 9427| | *sock = socket(AF_UNIX, SOCK_STREAM, 0); 9428| | } 9429| |#endif 9430| | 9431| 34| if (*sock == INVALID_SOCKET) { ------------------ | | 925| 34|#define INVALID_SOCKET (-1) ------------------ | Branch (9431:6): [True: 0, False: 34] ------------------ 9432| 0| if (error != NULL) { ------------------ | Branch (9432:7): [True: 0, False: 0] ------------------ 9433| 0| error->code = MG_ERROR_DATA_CODE_OS_ERROR; 9434| 0| error->code_sub = ERRNO; ------------------ | | 924| 0|#define ERRNO (errno) ------------------ 9435| 0| mg_snprintf(NULL, 9436| 0| NULL, /* No truncation check for ebuf */ 9437| 0| error->text, 9438| 0| error->text_buffer_size, 9439| 0| "socket(): %s", 9440| 0| strerror(ERRNO)); ------------------ | | 924| 0|#define ERRNO (errno) ------------------ 9441| 0| } 9442| 0| return 0; 9443| 0| } 9444| | 9445| 34| if (0 != set_non_blocking_mode(*sock)) { ------------------ | Branch (9445:6): [True: 0, False: 34] ------------------ 9446| 0| if (error != NULL) { ------------------ | Branch (9446:7): [True: 0, False: 0] ------------------ 9447| 0| error->code = MG_ERROR_DATA_CODE_OS_ERROR; 9448| 0| error->code_sub = ERRNO; ------------------ | | 924| 0|#define ERRNO (errno) ------------------ 9449| 0| mg_snprintf(NULL, 9450| 0| NULL, /* No truncation check for ebuf */ 9451| 0| error->text, 9452| 0| error->text_buffer_size, 9453| 0| "Cannot set socket to non-blocking: %s", 9454| 0| strerror(ERRNO)); ------------------ | | 924| 0|#define ERRNO (errno) ------------------ 9455| 0| } 9456| 0| closesocket(*sock); ------------------ | | 917| 0|#define closesocket(a) (close(a)) ------------------ 9457| 0| *sock = INVALID_SOCKET; ------------------ | | 925| 0|#define INVALID_SOCKET (-1) ------------------ 9458| 0| return 0; 9459| 0| } 9460| | 9461| 34| set_close_on_exec(*sock, NULL, ctx); 9462| | 9463| 34| if (ip_ver == 4) { ------------------ | Branch (9463:6): [True: 34, False: 0] ------------------ 9464| | /* connected with IPv4 */ 9465| 34| conn_ret = connect(*sock, 9466| 34| (struct sockaddr *)((void *)&sa->sin), 9467| 34| sizeof(sa->sin)); 9468| 34| } 9469| |#if defined(USE_IPV6) 9470| | else if (ip_ver == 6) { 9471| | /* connected with IPv6 */ 9472| | conn_ret = connect(*sock, 9473| | (struct sockaddr *)((void *)&sa->sin6), 9474| | sizeof(sa->sin6)); 9475| | } 9476| |#endif 9477| |#if defined(USE_X_DOM_SOCKET) 9478| | else if (ip_ver == -99) { 9479| | /* connected to domain socket */ 9480| | conn_ret = connect(*sock, 9481| | (struct sockaddr *)((void *)&sa->sun), 9482| | sizeof(sa->sun)); 9483| | } 9484| |#endif 9485| | 9486| 34| if (conn_ret != 0) { ------------------ | Branch (9486:6): [True: 34, False: 0] ------------------ 9487| 34| sockerr = ERRNO; ------------------ | | 924| 34|#define ERRNO (errno) ------------------ 9488| 34| } 9489| | 9490| |#if defined(_WIN32) 9491| | if ((conn_ret != 0) && (sockerr == WSAEWOULDBLOCK)) { 9492| |#else 9493| 34| if ((conn_ret != 0) && (sockerr == EINPROGRESS)) { ------------------ | Branch (9493:6): [True: 34, False: 0] | Branch (9493:25): [True: 34, False: 0] ------------------ 9494| 34|#endif 9495| | /* Data for getsockopt */ 9496| 34| void *psockerr = &sockerr; 9497| 34| int ret; 9498| | 9499| |#if defined(_WIN32) 9500| | int len = (int)sizeof(sockerr); 9501| |#else 9502| 34| socklen_t len = (socklen_t)sizeof(sockerr); 9503| 34|#endif 9504| | 9505| | /* Data for poll */ 9506| 34| struct mg_pollfd pfd[1]; 9507| 34| int pollres; 9508| 34| int ms_wait = 10000; /* 10 second timeout */ 9509| 34| stop_flag_t nonstop; 9510| 34| STOP_FLAG_ASSIGN(&nonstop, 0); ------------------ | | 2324| 34|#define STOP_FLAG_ASSIGN(f, v) ((*(f)) = (v)) ------------------ 9511| | 9512| | /* For a non-blocking socket, the connect sequence is: 9513| | * 1) call connect (will not block) 9514| | * 2) wait until the socket is ready for writing (select or poll) 9515| | * 3) check connection state with getsockopt 9516| | */ 9517| 34| pfd[0].fd = *sock; 9518| 34| pfd[0].events = POLLOUT; 9519| 34| pollres = mg_poll(pfd, 1, ms_wait, ctx ? &(ctx->stop_flag) : &nonstop); ------------------ | Branch (9519:38): [True: 34, False: 0] ------------------ 9520| | 9521| 34| if (pollres != 1) { ------------------ | Branch (9521:7): [True: 0, False: 34] ------------------ 9522| | /* Not connected */ 9523| 0| if (error != NULL) { ------------------ | Branch (9523:8): [True: 0, False: 0] ------------------ 9524| 0| error->code = MG_ERROR_DATA_CODE_CONNECT_TIMEOUT; 9525| 0| mg_snprintf(NULL, 9526| 0| NULL, /* No truncation check for ebuf */ 9527| 0| error->text, 9528| 0| error->text_buffer_size, 9529| 0| "connect(%s:%d): timeout", 9530| 0| host, 9531| 0| port); 9532| 0| } 9533| 0| closesocket(*sock); ------------------ | | 917| 0|#define closesocket(a) (close(a)) ------------------ 9534| 0| *sock = INVALID_SOCKET; ------------------ | | 925| 0|#define INVALID_SOCKET (-1) ------------------ 9535| 0| return 0; 9536| 0| } 9537| | 9538| |#if defined(_WIN32) 9539| | ret = getsockopt(*sock, SOL_SOCKET, SO_ERROR, (char *)psockerr, &len); 9540| |#else 9541| 34| ret = getsockopt(*sock, SOL_SOCKET, SO_ERROR, psockerr, &len); 9542| 34|#endif 9543| | 9544| 34| if ((ret == 0) && (sockerr == 0)) { ------------------ | Branch (9544:7): [True: 34, False: 0] | Branch (9544:21): [True: 34, False: 0] ------------------ 9545| 34| conn_ret = 0; 9546| 34| } 9547| 34| } 9548| | 9549| 34| if (conn_ret != 0) { ------------------ | Branch (9549:6): [True: 0, False: 34] ------------------ 9550| | /* Not connected */ 9551| 0| if (error != NULL) { ------------------ | Branch (9551:7): [True: 0, False: 0] ------------------ 9552| 0| error->code = MG_ERROR_DATA_CODE_CONNECT_FAILED; 9553| 0| error->code_sub = ERRNO; ------------------ | | 924| 0|#define ERRNO (errno) ------------------ 9554| 0| mg_snprintf(NULL, 9555| 0| NULL, /* No truncation check for ebuf */ 9556| 0| error->text, 9557| 0| error->text_buffer_size, 9558| 0| "connect(%s:%d): error %s", 9559| 0| host, 9560| 0| port, 9561| 0| strerror(sockerr)); 9562| 0| } 9563| 0| closesocket(*sock); ------------------ | | 917| 0|#define closesocket(a) (close(a)) ------------------ 9564| 0| *sock = INVALID_SOCKET; ------------------ | | 925| 0|#define INVALID_SOCKET (-1) ------------------ 9565| 0| return 0; 9566| 0| } 9567| | 9568| 34| return 1; 9569| 34|} civetweb.c:is_valid_port: 9232| 34|{ 9233| 34| return (port <= 0xffff); 9234| 34|} civetweb.c:mg_inet_pton: 9239| 34|{ 9240| 34| struct addrinfo hints, *res, *ressave; 9241| 34| int func_ret = 0; 9242| 34| int gai_ret; 9243| | 9244| 34| memset(&hints, 0, sizeof(struct addrinfo)); 9245| 34| hints.ai_family = af; 9246| 34| if (!resolve_src) { ------------------ | Branch (9246:6): [True: 0, False: 34] ------------------ 9247| 0| hints.ai_flags = AI_NUMERICHOST; 9248| 0| } 9249| | 9250| 34| gai_ret = getaddrinfo(src, NULL, &hints, &res); 9251| 34| if (gai_ret != 0) { ------------------ | Branch (9251:6): [True: 0, False: 34] ------------------ 9252| | /* gai_strerror could be used to convert gai_ret to a string */ 9253| | /* POSIX return values: see 9254| | * http://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html 9255| | */ 9256| | /* Windows return values: see 9257| | * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx 9258| | */ 9259| 0| return 0; 9260| 0| } 9261| | 9262| 34| ressave = res; 9263| | 9264| 136| while (res) { ------------------ | Branch (9264:9): [True: 102, False: 34] ------------------ 9265| 102| if ((dstlen >= (size_t)res->ai_addrlen) ------------------ | Branch (9265:7): [True: 102, False: 0] ------------------ 9266| 102| && (res->ai_addr->sa_family == af)) { ------------------ | Branch (9266:10): [True: 102, False: 0] ------------------ 9267| 102| memcpy(dst, res->ai_addr, res->ai_addrlen); 9268| 102| func_ret = 1; 9269| 102| } 9270| 102| res = res->ai_next; 9271| 102| } 9272| | 9273| 34| freeaddrinfo(ressave); 9274| 34| return func_ret; 9275| 34|} civetweb.c:set_non_blocking_mode: 5877| 34|{ 5878| 34| int flags = fcntl(sock, F_GETFL, 0); 5879| 34| if (flags < 0) { ------------------ | Branch (5879:6): [True: 0, False: 34] ------------------ 5880| 0| return -1; 5881| 0| } 5882| | 5883| 34| if (fcntl(sock, F_SETFL, (flags | O_NONBLOCK)) < 0) { ------------------ | Branch (5883:6): [True: 0, False: 34] ------------------ 5884| 0| return -1; 5885| 0| } 5886| 34| return 0; 5887| 34|} civetweb.c:get_response: 18729| 34|{ 18730| 34| const char *cl; 18731| | 18732| 34| conn->connection_type = 18733| 34| CONNECTION_TYPE_RESPONSE; /* response (valid or not) */ 18734| | 18735| 34| if (!get_message(conn, ebuf, ebuf_len, err)) { ------------------ | Branch (18735:6): [True: 20, False: 14] ------------------ 18736| 20| return 0; 18737| 20| } 18738| | 18739| 14| if (parse_http_response(conn->buf, conn->buf_size, &conn->response_info) ------------------ | Branch (18739:6): [True: 13, False: 1] ------------------ 18740| 14| <= 0) { 18741| 13| mg_snprintf(conn, 18742| 13| NULL, /* No truncation check for ebuf */ 18743| 13| ebuf, 18744| 13| ebuf_len, 18745| 13| "%s", 18746| 13| "Bad response"); 18747| 13| *err = 400; 18748| 13| return 0; 18749| 13| } 18750| | 18751| | /* Message is a valid response */ 18752| | 18753| 1| if (((cl = get_header(conn->response_info.http_headers, ------------------ | Branch (18753:6): [True: 0, False: 1] ------------------ 18754| 1| conn->response_info.num_headers, 18755| 1| "Transfer-Encoding")) 18756| 1| != NULL) 18757| 1| && mg_strcasecmp(cl, "identity")) { ------------------ | Branch (18757:9): [True: 0, False: 0] ------------------ 18758| 0| if (mg_strcasecmp(cl, "chunked")) { ------------------ | Branch (18758:7): [True: 0, False: 0] ------------------ 18759| 0| mg_snprintf(conn, 18760| 0| NULL, /* No truncation check for ebuf */ 18761| 0| ebuf, 18762| 0| ebuf_len, 18763| 0| "%s", 18764| 0| "Bad request"); 18765| 0| *err = 400; 18766| 0| return 0; 18767| 0| } 18768| 0| conn->is_chunked = 1; 18769| 0| conn->content_len = 0; /* not yet read */ 18770| 1| } else if ((cl = get_header(conn->response_info.http_headers, ------------------ | Branch (18770:13): [True: 0, False: 1] ------------------ 18771| 1| conn->response_info.num_headers, 18772| 1| "Content-Length")) 18773| 1| != NULL) { 18774| 0| char *endptr = NULL; 18775| 0| conn->content_len = strtoll(cl, &endptr, 10); 18776| 0| if ((endptr == cl) || (conn->content_len < 0)) { ------------------ | Branch (18776:7): [True: 0, False: 0] | Branch (18776:25): [True: 0, False: 0] ------------------ 18777| 0| mg_snprintf(conn, 18778| 0| NULL, /* No truncation check for ebuf */ 18779| 0| ebuf, 18780| 0| ebuf_len, 18781| 0| "%s", 18782| 0| "Bad request"); 18783| 0| *err = 411; 18784| 0| return 0; 18785| 0| } 18786| | /* Publish the content length back to the response info. */ 18787| 0| conn->response_info.content_length = conn->content_len; 18788| | 18789| | /* TODO: check if it is still used in response_info */ 18790| 0| conn->request_info.content_length = conn->content_len; 18791| | 18792| | /* TODO: we should also consider HEAD method */ 18793| 0| if (conn->response_info.status_code == 304) { ------------------ | Branch (18793:7): [True: 0, False: 0] ------------------ 18794| 0| conn->content_len = 0; 18795| 0| } 18796| 1| } else { 18797| | /* TODO: we should also consider HEAD method */ 18798| 1| if (((conn->response_info.status_code >= 100) ------------------ | Branch (18798:8): [True: 1, False: 0] ------------------ 18799| 1| && (conn->response_info.status_code <= 199)) ------------------ | Branch (18799:11): [True: 0, False: 1] ------------------ 18800| 1| || (conn->response_info.status_code == 204) ------------------ | Branch (18800:10): [True: 0, False: 1] ------------------ 18801| 1| || (conn->response_info.status_code == 304)) { ------------------ | Branch (18801:10): [True: 0, False: 1] ------------------ 18802| 0| conn->content_len = 0; 18803| 1| } else { 18804| 1| conn->content_len = -1; /* unknown content length */ 18805| 1| } 18806| 1| } 18807| | 18808| 1| return 1; 18809| 1|} civetweb.c:get_message: 18561| 34|{ 18562| 34| if (ebuf_len > 0) { ------------------ | Branch (18562:6): [True: 34, False: 0] ------------------ 18563| 34| ebuf[0] = '\0'; 18564| 34| } 18565| 34| *err = 0; 18566| | 18567| 34| reset_per_request_attributes(conn); 18568| | 18569| 34| if (!conn) { ------------------ | Branch (18569:6): [True: 0, False: 34] ------------------ 18570| 0| mg_snprintf(conn, 18571| 0| NULL, /* No truncation check for ebuf */ 18572| 0| ebuf, 18573| 0| ebuf_len, 18574| 0| "%s", 18575| 0| "Internal error"); 18576| 0| *err = 500; 18577| 0| return 0; 18578| 0| } 18579| | 18580| | /* Set the time the request was received. This value should be used for 18581| | * timeouts. */ 18582| 34| clock_gettime(CLOCK_MONOTONIC, &(conn->req_time)); 18583| | 18584| 34| conn->request_len = 18585| 34| read_message(NULL, conn, conn->buf, conn->buf_size, &conn->data_len); 18586| 34| DEBUG_ASSERT(conn->request_len < 0 || conn->data_len >= conn->request_len); 18587| 34| if ((conn->request_len >= 0) && (conn->data_len < conn->request_len)) { ------------------ | Branch (18587:6): [True: 14, False: 20] | Branch (18587:34): [True: 0, False: 14] ------------------ 18588| 0| mg_snprintf(conn, 18589| 0| NULL, /* No truncation check for ebuf */ 18590| 0| ebuf, 18591| 0| ebuf_len, 18592| 0| "%s", 18593| 0| "Invalid message size"); 18594| 0| *err = 500; 18595| 0| return 0; 18596| 0| } 18597| | 18598| 34| if ((conn->request_len == 0) && (conn->data_len == conn->buf_size)) { ------------------ | Branch (18598:6): [True: 0, False: 34] | Branch (18598:34): [True: 0, False: 0] ------------------ 18599| 0| mg_snprintf(conn, 18600| 0| NULL, /* No truncation check for ebuf */ 18601| 0| ebuf, 18602| 0| ebuf_len, 18603| 0| "%s", 18604| 0| "Message too large"); 18605| 0| *err = 413; 18606| 0| return 0; 18607| 0| } 18608| | 18609| 34| if (conn->request_len <= 0) { ------------------ | Branch (18609:6): [True: 20, False: 14] ------------------ 18610| 20| if (conn->data_len > 0) { ------------------ | Branch (18610:7): [True: 20, False: 0] ------------------ 18611| 20| mg_snprintf(conn, 18612| 20| NULL, /* No truncation check for ebuf */ 18613| 20| ebuf, 18614| 20| ebuf_len, 18615| 20| "%s", 18616| 20| "Malformed message"); 18617| 20| *err = 400; 18618| 20| } else { 18619| | /* Server did not recv anything -> just close the connection */ 18620| 0| conn->must_close = 1; 18621| 0| mg_snprintf(conn, 18622| 0| NULL, /* No truncation check for ebuf */ 18623| 0| ebuf, 18624| 0| ebuf_len, 18625| 0| "%s", 18626| 0| "No data received"); 18627| 0| *err = 0; 18628| 0| } 18629| 20| return 0; 18630| 20| } 18631| 14| return 1; 18632| 34|} civetweb.c:reset_per_request_attributes: 17668| 34|{ 17669| 34| if (!conn) { ------------------ | Branch (17669:6): [True: 0, False: 34] ------------------ 17670| 0| return; 17671| 0| } 17672| | 17673| 34| conn->num_bytes_sent = conn->consumed_content = 0; 17674| | 17675| 34| conn->path_info = NULL; 17676| 34| conn->status_code = -1; 17677| 34| conn->content_len = -1; 17678| 34| conn->is_chunked = 0; 17679| 34| conn->must_close = 0; 17680| 34| conn->request_len = 0; 17681| 34| conn->request_state = 0; 17682| 34| conn->throttle = 0; 17683| 34| conn->accept_gzip = 0; 17684| | 17685| 34| conn->response_info.content_length = conn->request_info.content_length = -1; 17686| 34| conn->response_info.http_version = conn->request_info.http_version = NULL; 17687| 34| conn->response_info.num_headers = conn->request_info.num_headers = 0; 17688| 34| conn->response_info.status_text = NULL; 17689| 34| conn->response_info.status_code = 0; 17690| | 17691| 34| conn->request_info.remote_user = NULL; 17692| 34| conn->request_info.request_method = NULL; 17693| 34| conn->request_info.request_uri = NULL; 17694| | 17695| | /* Free cleaned local URI (if any) */ 17696| 34| if (conn->request_info.local_uri != conn->request_info.local_uri_raw) { ------------------ | Branch (17696:6): [True: 0, False: 34] ------------------ 17697| 0| mg_free((void *)conn->request_info.local_uri); 17698| 0| conn->request_info.local_uri = NULL; 17699| 0| } 17700| 34| conn->request_info.local_uri = NULL; 17701| | 17702| |#if defined(USE_SERVER_STATS) 17703| | conn->processing_time = 0; 17704| |#endif 17705| 34|} civetweb.c:parse_http_response: 10993| 14|{ 10994| 14| int response_length; 10995| 14| int init_skip = 0; 10996| 14| char *tmp, *tmp2; 10997| 14| long l; 10998| | 10999| | /* Initialize elements. */ 11000| 14| ri->http_version = ri->status_text = NULL; 11001| 14| ri->num_headers = ri->status_code = 0; 11002| | 11003| | /* RFC says that all initial whitespaces should be ignored */ 11004| | /* This included all leading \r and \n (isspace) */ 11005| | /* See table: http://www.cplusplus.com/reference/cctype/ */ 11006| 1.22k| while ((len > 0) && isspace((unsigned char)*buf)) { ------------------ | Branch (11006:9): [True: 1.22k, False: 0] ------------------ 11007| 1.20k| buf++; 11008| 1.20k| len--; 11009| 1.20k| init_skip++; 11010| 1.20k| } 11011| | 11012| 14| if (len == 0) { ------------------ | Branch (11012:6): [True: 0, False: 14] ------------------ 11013| | /* Incomplete request */ 11014| 0| return 0; 11015| 0| } 11016| | 11017| | /* Control characters are not allowed, including zero */ 11018| 14| if (iscntrl((unsigned char)*buf)) { 11019| 0| return -1; 11020| 0| } 11021| | 11022| | /* Find end of HTTP header */ 11023| 14| response_length = get_http_header_len(buf, len); 11024| 14| if (response_length <= 0) { ------------------ | Branch (11024:6): [True: 1, False: 13] ------------------ 11025| 1| return response_length; 11026| 1| } 11027| 13| buf[response_length - 1] = '\0'; 11028| | 11029| 13| if ((*buf == 0) || (*buf == '\r') || (*buf == '\n')) { ------------------ | Branch (11029:6): [True: 0, False: 13] | Branch (11029:21): [True: 0, False: 13] | Branch (11029:39): [True: 0, False: 13] ------------------ 11030| 0| return -1; 11031| 0| } 11032| | 11033| | /* The first word is the HTTP version */ 11034| | /* Check for a valid HTTP version key */ 11035| 13| if (strncmp(buf, "HTTP/", 5) != 0) { ------------------ | Branch (11035:6): [True: 8, False: 5] ------------------ 11036| | /* Invalid request */ 11037| 8| return -1; 11038| 8| } 11039| 5| buf += 5; 11040| 5| if (!isgraph((unsigned char)buf[0])) { ------------------ | Branch (11040:6): [True: 0, False: 5] ------------------ 11041| | /* Invalid request */ 11042| 0| return -1; 11043| 0| } 11044| 5| ri->http_version = buf; 11045| | 11046| 5| if (skip_to_end_of_word_and_terminate(&buf, 0) <= 0) { ------------------ | Branch (11046:6): [True: 0, False: 5] ------------------ 11047| 0| return -1; 11048| 0| } 11049| | 11050| | /* The second word is the status as a number */ 11051| 5| tmp = buf; 11052| | 11053| 5| if (skip_to_end_of_word_and_terminate(&buf, 0) <= 0) { ------------------ | Branch (11053:6): [True: 0, False: 5] ------------------ 11054| 0| return -1; 11055| 0| } 11056| | 11057| 5| l = strtol(tmp, &tmp2, 10); 11058| 5| if ((l < 100) || (l >= 1000) || ((tmp2 - tmp) != 3) || (*tmp2 != 0)) { ------------------ | Branch (11058:6): [True: 0, False: 5] | Branch (11058:19): [True: 1, False: 4] | Branch (11058:34): [True: 0, False: 4] | Branch (11058:57): [True: 0, False: 4] ------------------ 11059| | /* Everything else but a 3 digit code is invalid */ 11060| 1| return -1; 11061| 1| } 11062| 4| ri->status_code = (int)l; 11063| | 11064| | /* The rest of the line is the status text */ 11065| 4| ri->status_text = buf; 11066| | 11067| | /* Find end of status text */ 11068| | /* isgraph or isspace = isprint */ 11069| 20| while (isprint((unsigned char)*buf)) { 11070| 20| buf++; 11071| 20| } 11072| 4| if ((*buf != '\r') && (*buf != '\n')) { ------------------ | Branch (11072:6): [True: 4, False: 0] | Branch (11072:24): [True: 1, False: 3] ------------------ 11073| 1| return -1; 11074| 1| } 11075| | /* Terminate string and forward buf to next line */ 11076| 3| do { 11077| 3| *buf = 0; 11078| 3| buf++; 11079| 3| } while (isspace((unsigned char)*buf)); 11080| | 11081| | /* Parse all HTTP headers */ 11082| 3| ri->num_headers = parse_http_headers(&buf, ri->http_headers); 11083| 3| if (ri->num_headers < 0) { ------------------ | Branch (11083:6): [True: 2, False: 1] ------------------ 11084| | /* Error while parsing headers */ 11085| 2| return -1; 11086| 2| } 11087| | 11088| 1| return response_length + init_skip; 11089| 3|} civetweb.c:skip_to_end_of_word_and_terminate: 10672| 10|{ 10673| | /* Forward until a space is found - use isgraph here */ 10674| | /* See http://www.cplusplus.com/reference/cctype/ */ 10675| 41| while (isgraph((unsigned char)**ppw)) { 10676| 41| (*ppw)++; 10677| 41| } 10678| | 10679| | /* Check end of word */ 10680| 10| if (eol) { ------------------ | Branch (10680:6): [True: 0, False: 10] ------------------ 10681| | /* must be a end of line */ 10682| 0| if ((**ppw != '\r') && (**ppw != '\n')) { ------------------ | Branch (10682:7): [True: 0, False: 0] | Branch (10682:26): [True: 0, False: 0] ------------------ 10683| 0| return -1; 10684| 0| } 10685| 10| } else { 10686| | /* must be a end of a word, but not a line */ 10687| 10| if (**ppw != ' ') { ------------------ | Branch (10687:7): [True: 0, False: 10] ------------------ 10688| 0| return -1; 10689| 0| } 10690| 10| } 10691| | 10692| | /* Terminate and forward to the next word */ 10693| 10| do { 10694| 10| **ppw = 0; 10695| 10| (*ppw)++; 10696| 10| } while (isspace((unsigned char)**ppw)); 10697| | 10698| | /* Check after term */ 10699| 10| if (!eol) { ------------------ | Branch (10699:6): [True: 10, False: 0] ------------------ 10700| | /* if it's not the end of line, there must be a next word */ 10701| 10| if (!isgraph((unsigned char)**ppw)) { ------------------ | Branch (10701:7): [True: 0, False: 10] ------------------ 10702| 0| return -1; 10703| 0| } 10704| 10| } 10705| | 10706| | /* ok */ 10707| 10| return 1; 10708| 10|}