From da7e76c96a4cfe8a0c14599c84c98a4f1145a2ba Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 20 Dec 2019 16:48:51 +0800 Subject: [PATCH] For#1508, check the error correctly for strtol. --- trunk/src/service/srs_service_http_conn.cpp | 15 +- trunk/src/utest/srs_utest_http.cpp | 56 ++++++++ trunk/src/utest/srs_utest_service.cpp | 148 ++++++++++++++++++++ 3 files changed, 211 insertions(+), 8 deletions(-) diff --git a/trunk/src/service/srs_service_http_conn.cpp b/trunk/src/service/srs_service_http_conn.cpp index 52d2b6014..9503c19d0 100644 --- a/trunk/src/service/srs_service_http_conn.cpp +++ b/trunk/src/service/srs_service_http_conn.cpp @@ -992,15 +992,14 @@ srs_error_t SrsHttpResponseReader::read_chunked(char* data, int nb_data, int* nb at[length - 1] = 0; at[length - 2] = 0; - // The at is length in string, it must be all digital. - if (!srs_is_digit_number(at)) { - return srs_error_new(ERROR_HTTP_INVALID_CHUNK_HEADER, "invalid length=%s", at); - } - // size is the bytes size, excludes the chunk header and end CRLF. - int ilength = (int)::strtol(at, NULL, 16); - if (ilength < 0) { - return srs_error_new(ERROR_HTTP_INVALID_CHUNK_HEADER, "invalid length=%s as %d", at, ilength); + // @remark It must be hex format, please read https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding#Directives + // @remark For strtol, note that: If no conversion could be performed, 0 is returned and the global variable errno is set to EINVAL. + char* at_parsed = at; errno = 0; + int ilength = (int)::strtol(at, &at_parsed, 16); + if (ilength < 0 || errno != 0 || at_parsed - at != length - 2) { + return srs_error_new(ERROR_HTTP_INVALID_CHUNK_HEADER, "invalid length %s as %d, parsed=%.*s, errno=%d", + at, ilength, (int)(at_parsed-at), at, errno); } // all bytes in chunk is left now. diff --git a/trunk/src/utest/srs_utest_http.cpp b/trunk/src/utest/srs_utest_http.cpp index c1d49fcc4..778db7e63 100644 --- a/trunk/src/utest/srs_utest_http.cpp +++ b/trunk/src/utest/srs_utest_http.cpp @@ -251,6 +251,26 @@ VOID TEST(ProtocolHTTPTest, ResponseWriter) __MOCK_HTTP_EXPECT_STREQ2(200, "5\r\nHello\r\n8\r\n, world!\r\n0\r\n\r\n", w); } + if (true) { + MockResponseWriter w; + + w.header()->set_content_type("application/octet-stream"); + w.write_header(SRS_CONSTS_HTTP_OK); + w.write((char*)"Hello, world!", 13); + w.final_request(); + + __MOCK_HTTP_EXPECT_STREQ2(200, "d\r\nHello, world!\r\n0\r\n\r\n", w); + } + if (true) { + MockResponseWriter w; + + w.header()->set_content_type("application/octet-stream"); + w.write_header(SRS_CONSTS_HTTP_OK); + w.write((char*)"Hello, world!", 13); + w.final_request(); + + __MOCK_HTTP_EXPECT_STREQ2(200, "d\r\nHello, world!\r\n0\r\n\r\n", w); + } // If directly write empty string, sent an empty response with content-length 0 if (true) { @@ -267,6 +287,42 @@ VOID TEST(ProtocolHTTPTest, ResponseWriter) } } +VOID TEST(ProtocolHTTPTest, ClientRequest) +{ + srs_error_t err; + + // Normal case, with chunked encoding. + if (true) { + MockBufferIO io; io.append(mock_http_response2(200, "0d\r\nHello, world!\r\n0\r\n\r\n")); + SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); + ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); + string res; HELPER_ASSERT_SUCCESS(msg->body_read_all(res)); + EXPECT_EQ(200, msg->status_code()); + EXPECT_STREQ("Hello, world!", res.c_str()); + srs_freep(msg); + } + if (true) { + MockBufferIO io; io.append(mock_http_response2(200, "6\r\nHello!\r\n0\r\n\r\n")); + SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); + ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); + string res; HELPER_ASSERT_SUCCESS(msg->body_read_all(res)); + EXPECT_EQ(200, msg->status_code()); + EXPECT_STREQ("Hello!", res.c_str()); + srs_freep(msg); + } + + // Normal case, with specified content-length. + if (true) { + MockBufferIO io; io.append(mock_http_response(200, "Hello, world!")); + SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); + ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); + string res; HELPER_ASSERT_SUCCESS(msg->body_read_all(res)); + EXPECT_EQ(200, msg->status_code()); + EXPECT_STREQ("Hello, world!", res.c_str()); + srs_freep(msg); + } +} + VOID TEST(ProtocolHTTPTest, ResponseHTTPError) { srs_error_t err; diff --git a/trunk/src/utest/srs_utest_service.cpp b/trunk/src/utest/srs_utest_service.cpp index ef47c5942..5d1acb102 100644 --- a/trunk/src/utest/srs_utest_service.cpp +++ b/trunk/src/utest/srs_utest_service.cpp @@ -27,6 +27,7 @@ using namespace std; #include #include #include +#include // Disable coroutine test for OSX. #if !defined(SRS_OSX) @@ -225,6 +226,153 @@ VOID TEST(TCPServerTest, PingPongWithTimeout) } } +VOID TEST(TCPServerTest, StringIsDigital) +{ + EXPECT_EQ(0, ::atoi("0")); + EXPECT_EQ(0, ::atoi("0000000000")); + EXPECT_EQ(1, ::atoi("01")); + EXPECT_EQ(12, ::atoi("012")); + EXPECT_EQ(1234567890L, ::atol("1234567890")); + EXPECT_EQ(123456789L, ::atol("0123456789")); + EXPECT_EQ(1234567890, ::atoi("1234567890a")); + EXPECT_EQ(10, ::atoi("10e3")); + EXPECT_EQ(0, ::atoi("!1234567890")); + EXPECT_EQ(0, ::atoi("")); + + EXPECT_TRUE(srs_is_digit_number("0")); + EXPECT_TRUE(srs_is_digit_number("0000000000")); + EXPECT_TRUE(srs_is_digit_number("1234567890")); + EXPECT_TRUE(srs_is_digit_number("0123456789")); + EXPECT_FALSE(srs_is_digit_number("1234567890a")); + EXPECT_FALSE(srs_is_digit_number("a1234567890")); + EXPECT_FALSE(srs_is_digit_number("10e3")); + EXPECT_FALSE(srs_is_digit_number("!1234567890")); + EXPECT_FALSE(srs_is_digit_number("")); +} + +VOID TEST(TCPServerTest, StringIsHex) +{ + if (true) { + char* str = (char*)"0"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x0, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str + 1, parsed); + } + + if (true) { + char* str = (char*)"0"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x0, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str + 1, parsed); + } + + if (true) { + char* str = (char*)"0000000000"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x0, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str + 10, parsed); + } + + if (true) { + char* str = (char*)"01"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x1, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str + 2, parsed); + } + + if (true) { + char* str = (char*)"012"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x12, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str + 3, parsed); + } + + if (true) { + char* str = (char*)"1234567890"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x1234567890L, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str + 10, parsed); + } + + if (true) { + char* str = (char*)"0123456789"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x123456789L, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str + 10, parsed); + } + + if (true) { + char* str = (char*)"1234567890a"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x1234567890a, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str + 11, parsed); + } + + if (true) { + char* str = (char*)"0x1234567890a"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x1234567890a, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str + 13, parsed); + } + + if (true) { + char* str = (char*)"1234567890f"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x1234567890f, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str + 11, parsed); + } + + if (true) { + char* str = (char*)"10e3"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x10e3, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str + 4, parsed); + } + + if (true) { + char* str = (char*)"!1234567890"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x0, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str, parsed); + } + + if (true) { + char* str = (char*)"1234567890g"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x1234567890, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str + 10, parsed); + } + + if (true) { + char* str = (char*)""; + char* parsed = str; errno = 0; + EXPECT_EQ(0x0, ::strtol(str, &parsed, 16)); + EXPECT_EQ(0, errno); + EXPECT_EQ(str, parsed); + } + + if (true) { + char* str = (char*)"1fffffffffffffffffffffffffffff"; + char* parsed = str; errno = 0; + EXPECT_EQ(0x7fffffffffffffff, ::strtol(str, &parsed, 16)); + EXPECT_NE(0, errno); + EXPECT_EQ(str+30, parsed); + } +} + VOID TEST(TCPServerTest, WritevIOVC) { srs_error_t err;