From 9ff8bff6011e471e1d0250739c1ceb580bd5de2e Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 2 Jul 2020 12:41:08 +0800 Subject: [PATCH] RTC: Fix the OPTIONS read, no infinited chunked mode --- trunk/src/protocol/srs_service_http_conn.cpp | 11 ++++ trunk/src/protocol/srs_service_http_conn.hpp | 5 ++ trunk/src/utest/srs_utest_service.cpp | 60 ++++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/trunk/src/protocol/srs_service_http_conn.cpp b/trunk/src/protocol/srs_service_http_conn.cpp index de493f22c..dccca73a6 100644 --- a/trunk/src/protocol/srs_service_http_conn.cpp +++ b/trunk/src/protocol/srs_service_http_conn.cpp @@ -334,6 +334,12 @@ void SrsHttpMessage::set_header(SrsHttpHeader* header, bool keep_alive) if (!clv.empty()) { _content_length = ::atoll(clv.c_str()); } + + // If method is OPTIONS, and no size(content-length or chunked), it's not infinite chunked, + // it means there is no body, so we must close the body reader. + if (_method == SRS_CONSTS_HTTP_OPTIONS && !chunked && _content_length == -1) { + _body->close(); + } } srs_error_t SrsHttpMessage::set_url(string url, bool allow_jsonp) @@ -921,6 +927,11 @@ SrsHttpResponseReader::~SrsHttpResponseReader() { } +void SrsHttpResponseReader::close() +{ + is_eof = true; +} + bool SrsHttpResponseReader::eof() { return is_eof; diff --git a/trunk/src/protocol/srs_service_http_conn.hpp b/trunk/src/protocol/srs_service_http_conn.hpp index 5c8d9e0f1..ddddc022d 100644 --- a/trunk/src/protocol/srs_service_http_conn.hpp +++ b/trunk/src/protocol/srs_service_http_conn.hpp @@ -264,6 +264,11 @@ public: // while buffer is a fast cache which may have cached some data from reader. SrsHttpResponseReader(SrsHttpMessage* msg, ISrsReader* reader, SrsFastStream* buffer); virtual ~SrsHttpResponseReader(); +public: + // User close the HTTP response reader. + // For example, OPTIONS has no body, no content-length and not chunked, + // so we must close it(set to eof) to avoid reading the response body. + void close(); // Interface ISrsHttpResponseReader public: virtual bool eof(); diff --git a/trunk/src/utest/srs_utest_service.cpp b/trunk/src/utest/srs_utest_service.cpp index df21fbc92..497c48829 100644 --- a/trunk/src/utest/srs_utest_service.cpp +++ b/trunk/src/utest/srs_utest_service.cpp @@ -678,6 +678,7 @@ VOID TEST(HTTPServerTest, InfiniteChunked) SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_RESPONSE, false)); ISrsHttpMessage* msg = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &msg)); + SrsAutoFree(ISrsHttpMessage, msg); char buf[32]; ssize_t nread = 0; ISrsHttpResponseReader* r = msg->body_reader(); @@ -696,6 +697,65 @@ VOID TEST(HTTPServerTest, InfiniteChunked) } } +VOID TEST(HTTPServerTest, OPTIONSRead) +{ + srs_error_t err; + + // If OPTIONS, it has no content-length, not chunkted, but not infinite chunked, + // instead, it has no body. + if (true) { + MockBufferIO io; + io.append("OPTIONS /rtc/v1/play HTTP/1.1\r\n\r\n"); + + SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_REQUEST, false)); + ISrsHttpMessage* req = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &req)); + SrsAutoFree(ISrsHttpMessage, req); + + ISrsHttpResponseReader* br = req->body_reader(); + EXPECT_TRUE(br->eof()); + } + + // So if OPTIONS has body, with chunked or content-length, it's ok to parsing it. + if (true) { + MockBufferIO io; + io.append("OPTIONS /rtc/v1/play HTTP/1.1\r\nContent-Length: 5\r\n\r\nHello"); + + SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_REQUEST, false)); + ISrsHttpMessage* req = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &req)); + SrsAutoFree(ISrsHttpMessage, req); + + ISrsHttpResponseReader* br = req->body_reader(); + EXPECT_FALSE(br->eof()); + + string b; HELPER_ASSERT_SUCCESS(req->body_read_all(b)); + EXPECT_STREQ("Hello", b.c_str()); + + // The body will use as next HTTP request message. + io.append("GET /rtc/v1/play HTTP/1.1\r\n\r\n"); + ISrsHttpMessage* req2 = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &req2)); + SrsAutoFree(ISrsHttpMessage, req2); + } + + // So if OPTIONS has body, but not specified the size, we think it has no body, + // and the body is parsed fail as the next parsing. + if (true) { + MockBufferIO io; + io.append("OPTIONS /rtc/v1/play HTTP/1.1\r\n\r\n"); + + SrsHttpParser hp; HELPER_ASSERT_SUCCESS(hp.initialize(HTTP_REQUEST, false)); + ISrsHttpMessage* req = NULL; HELPER_ASSERT_SUCCESS(hp.parse_message(&io, &req)); + SrsAutoFree(ISrsHttpMessage, req); + + ISrsHttpResponseReader* br = req->body_reader(); + EXPECT_TRUE(br->eof()); + + // The body will use as next HTTP request message. + io.append("Hello"); + ISrsHttpMessage* req2 = NULL; HELPER_ASSERT_FAILED(hp.parse_message(&io, &req2)); + SrsAutoFree(ISrsHttpMessage, req2); + } +} + VOID TEST(HTTPServerTest, MessageWritev) { srs_error_t err;