From 6bad973a7c6692e2269c5b1d9c8a8775fb3ca316 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 16 Dec 2019 18:21:39 +0800 Subject: [PATCH] Fix HTTP parser bug for parsing header from multiple pieces of data. --- trunk/src/service/srs_service_http_conn.cpp | 23 +-- trunk/src/service/srs_service_http_conn.hpp | 2 - trunk/src/utest/srs_utest_http.cpp | 207 +++++++++++++++++++- 3 files changed, 218 insertions(+), 14 deletions(-) diff --git a/trunk/src/service/srs_service_http_conn.cpp b/trunk/src/service/srs_service_http_conn.cpp index 3cb58f54a..8919b6283 100644 --- a/trunk/src/service/srs_service_http_conn.cpp +++ b/trunk/src/service/srs_service_http_conn.cpp @@ -79,12 +79,10 @@ srs_error_t SrsHttpParser::parse_message(ISrsReader* reader, ISrsHttpMessage** p // Reset request data. state = SrsHttpParseStateInit; hp_header = http_parser(); - // Reset the message url. - url = ""; // The body that we have read from cache. pbody = NULL; - // Reset the temporarily parsed header field. - expect_field_name = true; + // We must reset the field name and value, because we may get a partial value in on_header_value. + field_name = field_value = ""; // The header of the request. srs_freep(header); header = new SrsHttpHeader(); @@ -144,6 +142,11 @@ srs_error_t SrsHttpParser::parse_message_imp(ISrsReader* reader) return srs_error_wrap(err, "grow buffer"); } } + + SrsHttpParser* obj = this; + if (!obj->field_value.empty()) { + obj->header->set(obj->field_name, obj->field_value); + } return err; } @@ -206,15 +209,14 @@ int SrsHttpParser::on_header_field(http_parser* parser, const char* at, size_t l { SrsHttpParser* obj = (SrsHttpParser*)parser->data; srs_assert(obj); - - // field value=>name, reap the field. - if (!obj->expect_field_name) { + + if (!obj->field_value.empty()) { obj->header->set(obj->field_name, obj->field_value); + obj->field_name = obj->field_value = ""; } - obj->expect_field_name = true; if (length > 0) { - obj->field_name = string(at, (int)length); + obj->field_name.append(at, (int)length); } srs_info("Header field(%d bytes): %.*s", (int)length, (int)length, at); @@ -227,9 +229,8 @@ int SrsHttpParser::on_header_value(http_parser* parser, const char* at, size_t l srs_assert(obj); if (length > 0) { - obj->field_value = string(at, (int)length); + obj->field_value.append(at, (int)length); } - obj->expect_field_name = false; srs_info("Header value(%d bytes): %.*s", (int)length, (int)length, at); return 0; diff --git a/trunk/src/service/srs_service_http_conn.hpp b/trunk/src/service/srs_service_http_conn.hpp index 6d956f1de..2313b0207 100644 --- a/trunk/src/service/srs_service_http_conn.hpp +++ b/trunk/src/service/srs_service_http_conn.hpp @@ -49,8 +49,6 @@ private: // Whether allow jsonp parse. bool jsonp; private: - // http parse data, reset before parse message. - bool expect_field_name; std::string field_name; std::string field_value; SrsHttpParseState state; diff --git a/trunk/src/utest/srs_utest_http.cpp b/trunk/src/utest/srs_utest_http.cpp index f620a5671..3ad6504f7 100644 --- a/trunk/src/utest/srs_utest_http.cpp +++ b/trunk/src/utest/srs_utest_http.cpp @@ -28,6 +28,8 @@ using namespace std; #include #include #include +#include +#include class MockResponseWriter : virtual public ISrsHttpResponseWriter, virtual public ISrsHttpHeaderFilter { @@ -156,8 +158,211 @@ VOID TEST(ProtocolHTTPTest, HTTPHeader) h.set_content_type("text/plain"); EXPECT_STREQ("text/plain", h.content_type().c_str()); EXPECT_EQ(2, h.count()); + + SrsJsonObject* o = SrsJsonAny::object(); + h.dumps(o); + EXPECT_EQ(2, o->count()); + srs_freep(o); +} + +class MockMSegmentsReader : public ISrsReader +{ +public: + vector in_bytes; +public: + MockMSegmentsReader(); + virtual ~MockMSegmentsReader(); +public: + virtual srs_error_t read(void* buf, size_t size, ssize_t* nread); +}; + +MockMSegmentsReader::MockMSegmentsReader() +{ +} + +MockMSegmentsReader::~MockMSegmentsReader() +{ +} + +srs_error_t MockMSegmentsReader::read(void* buf, size_t size, ssize_t* nread) +{ + srs_error_t err = srs_success; + + for (;;) { + if (in_bytes.empty() || size <= 0) { + return srs_error_new(-1, "EOF"); + } + + string v = in_bytes[0]; + if (v.empty()) { + in_bytes.erase(in_bytes.begin()); + continue; + } + + int nn = srs_min(size, v.length()); + memcpy(buf, v.data(), nn); + if (nread) { + *nread = nn; + } + + if (nn < (int)v.length()) { + in_bytes[0] = string(v.data() + nn, v.length() - nn); + } else { + in_bytes.erase(in_bytes.begin()); + } + break; + } + + return err; +} + +VOID TEST(ProtocolHTTPTest, MSegmentsReader) +{ + srs_error_t err; + + MockMSegmentsReader r; + r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); + r.in_bytes.push_back("Host: ossrs.net\r\n"); + + if (true) { + char buf[1024]; + HELPER_ARRAY_INIT(buf, 1024, 0); + + ssize_t nn = 0; + HELPER_EXPECT_SUCCESS(r.read(buf, 1024, &nn)); + ASSERT_EQ(31, nn); + EXPECT_STREQ("GET /api/v1/versions HTTP/1.1\r\n", buf); + } + + if (true) { + char buf[1024]; + HELPER_ARRAY_INIT(buf, 1024, 0); + + ssize_t nn = 0; + HELPER_EXPECT_SUCCESS(r.read(buf, 1024, &nn)); + ASSERT_EQ(17, nn); + EXPECT_STREQ("Host: ossrs.net\r\n", buf); + } } -VOID TEST(ProtocolHTTPTest, HTTPCommonHandler) +VOID TEST(ProtocolHTTPTest, HTTPMessageParser) { + srs_error_t err; + + if (true) { + MockMSegmentsReader r; + r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); + r.in_bytes.push_back("Host: ossrs"); + r.in_bytes.push_back(".net\r"); + r.in_bytes.push_back("\n"); + r.in_bytes.push_back("\r\n"); + + SrsHttpParser p; + HELPER_ASSERT_SUCCESS(p.initialize(HTTP_REQUEST, false)); + + ISrsHttpMessage* msg = NULL; + HELPER_ASSERT_SUCCESS(p.parse_message(&r, &msg)); + EXPECT_TRUE(msg->is_http_get()); + EXPECT_STREQ("/api/v1/versions", msg->path().c_str()); + EXPECT_STREQ("ossrs.net", msg->host().c_str()); + srs_freep(msg); + } + + if (true) { + MockMSegmentsReader r; + r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); + r.in_bytes.push_back("Host: ossrs"); + r.in_bytes.push_back(".net\r\n"); + r.in_bytes.push_back("\r\n"); + + SrsHttpParser p; + HELPER_ASSERT_SUCCESS(p.initialize(HTTP_REQUEST, false)); + + ISrsHttpMessage* msg = NULL; + HELPER_ASSERT_SUCCESS(p.parse_message(&r, &msg)); + EXPECT_TRUE(msg->is_http_get()); + EXPECT_STREQ("/api/v1/versions", msg->path().c_str()); + EXPECT_STREQ("ossrs.net", msg->host().c_str()); + srs_freep(msg); + } + + if (true) { + MockMSegmentsReader r; + r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); + r.in_bytes.push_back("User-Agent: curl/7.54.0\r\n"); + r.in_bytes.push_back("Host: ossrs"); + r.in_bytes.push_back(".net\r\n"); + r.in_bytes.push_back("\r\n"); + + SrsHttpParser p; + HELPER_ASSERT_SUCCESS(p.initialize(HTTP_REQUEST, false)); + + ISrsHttpMessage* msg = NULL; + HELPER_ASSERT_SUCCESS(p.parse_message(&r, &msg)); + EXPECT_TRUE(msg->is_http_get()); + EXPECT_STREQ("/api/v1/versions", msg->path().c_str()); + EXPECT_STREQ("ossrs.net", msg->host().c_str()); + EXPECT_STREQ("curl/7.54.0", msg->header()->get("User-Agent").c_str()); + srs_freep(msg); + } + + if (true) { + MockMSegmentsReader r; + r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); + r.in_bytes.push_back("User-"); + r.in_bytes.push_back("Agent: curl/7.54.0\r\n"); + r.in_bytes.push_back("Host: ossrs"); + r.in_bytes.push_back(".net\r\n"); + r.in_bytes.push_back("\r\n"); + + SrsHttpParser p; + HELPER_ASSERT_SUCCESS(p.initialize(HTTP_REQUEST, false)); + + ISrsHttpMessage* msg = NULL; + HELPER_ASSERT_SUCCESS(p.parse_message(&r, &msg)); + EXPECT_TRUE(msg->is_http_get()); + EXPECT_STREQ("/api/v1/versions", msg->path().c_str()); + EXPECT_STREQ("ossrs.net", msg->host().c_str()); + EXPECT_STREQ("curl/7.54.0", msg->header()->get("User-Agent").c_str()); + srs_freep(msg); + } + + if (true) { + MockMSegmentsReader r; + r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); + r.in_bytes.push_back("User-"); + r.in_bytes.push_back("Agent: curl"); + r.in_bytes.push_back("/7.54.0\r\n"); + r.in_bytes.push_back("Host: ossrs"); + r.in_bytes.push_back(".net\r\n"); + r.in_bytes.push_back("\r\n"); + + SrsHttpParser p; + HELPER_ASSERT_SUCCESS(p.initialize(HTTP_REQUEST, false)); + + ISrsHttpMessage* msg = NULL; + HELPER_ASSERT_SUCCESS(p.parse_message(&r, &msg)); + EXPECT_TRUE(msg->is_http_get()); + EXPECT_STREQ("/api/v1/versions", msg->path().c_str()); + EXPECT_STREQ("ossrs.net", msg->host().c_str()); + EXPECT_STREQ("curl/7.54.0", msg->header()->get("User-Agent").c_str()); + srs_freep(msg); + } + + if (true) { + MockMSegmentsReader r; + r.in_bytes.push_back("GET /api/v1/versions HTTP/1.1\r\n"); + r.in_bytes.push_back("Host: ossrs.net\r\n"); + r.in_bytes.push_back("\r\n"); + + SrsHttpParser p; + HELPER_ASSERT_SUCCESS(p.initialize(HTTP_REQUEST, false)); + + ISrsHttpMessage* msg = NULL; + HELPER_ASSERT_SUCCESS(p.parse_message(&r, &msg)); + EXPECT_TRUE(msg->is_http_get()); + EXPECT_STREQ("/api/v1/versions", msg->path().c_str()); + EXPECT_STREQ("ossrs.net", msg->host().c_str()); + srs_freep(msg); + } }