From a273298e637da10334e6b48e1efecf16923ffcfa Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 30 Jun 2020 19:29:23 +0800 Subject: [PATCH] HTTP: Enable infinite_chunked by default --- trunk/src/app/srs_app_http_api.cpp | 5 +- trunk/src/protocol/srs_http_stack.hpp | 12 +- trunk/src/protocol/srs_service_http_conn.cpp | 38 +------ trunk/src/protocol/srs_service_http_conn.hpp | 7 -- trunk/src/utest/srs_utest_service.cpp | 113 +++++++++++-------- 5 files changed, 75 insertions(+), 100 deletions(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index fd0f57c64..88b7dc235 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1773,9 +1773,8 @@ srs_error_t SrsHttpApi::process_request(ISrsHttpResponseWriter* w, ISrsHttpMessa SrsHttpMessage* hm = dynamic_cast(r); srs_assert(hm); - srs_trace("HTTP API %s %s, content-length=%" PRId64 ", chunked=%d/%d", - r->method_str().c_str(), r->url().c_str(), r->content_length(), - hm->is_chunked(), hm->is_infinite_chunked()); + srs_trace("HTTP API %s %s, content-length=%" PRId64 ", chunked=%d", r->method_str().c_str(), r->url().c_str(), + r->content_length(), hm->is_chunked()); // use cors server mux to serve http request, which will proxy to mux. if ((err = cors->serve_http(w, r)) != srs_success) { diff --git a/trunk/src/protocol/srs_http_stack.hpp b/trunk/src/protocol/srs_http_stack.hpp index 6d5e6b336..0bd712714 100644 --- a/trunk/src/protocol/srs_http_stack.hpp +++ b/trunk/src/protocol/srs_http_stack.hpp @@ -449,15 +449,11 @@ public: // // There are some modes to determine the length of body: // 1. content-length and chunked. -// 2. user confirmed infinite chunked. -// 3. no body or user not confirmed infinite chunked. +// 2. infinite chunked. +// 3. no body. // For example: // ISrsHttpMessage* r = ...; // while (!r->eof()) r->read(); // Read in mode 1 or 3. -// For some server, we can confirm the body is infinite chunked: -// ISrsHttpMessage* r = ...; -// r->enter_infinite_chunked(); -// while (!r->eof()) r->read(); // Read in mode 2 // @rmark for mode 2, the infinite chunked, all left data is body. class ISrsHttpMessage { @@ -492,10 +488,6 @@ public: // @return the REST id; -1 if not matched. virtual std::string parse_rest_id(std::string pattern) = 0; public: - // The left all data is chunked body, the infinite chunked mode, - // which is chunked encoding without chunked header. - // @remark error when message is in chunked or content-length specified. - virtual srs_error_t enter_infinite_chunked() = 0; // Read body to string. // @remark for small http body. virtual srs_error_t body_read_all(std::string& body) = 0; diff --git a/trunk/src/protocol/srs_service_http_conn.cpp b/trunk/src/protocol/srs_service_http_conn.cpp index acaf7c935..de493f22c 100644 --- a/trunk/src/protocol/srs_service_http_conn.cpp +++ b/trunk/src/protocol/srs_service_http_conn.cpp @@ -291,7 +291,6 @@ SrsHttpMessage::SrsHttpMessage(ISrsReader* reader, SrsFastStream* buffer) : ISrs { owner_conn = NULL; chunked = false; - infinite_chunked = false; _uri = new SrsHttpUri(); _body = new SrsHttpResponseReader(this, reader, buffer); @@ -476,11 +475,6 @@ bool SrsHttpMessage::is_keep_alive() return _keep_alive; } -bool SrsHttpMessage::is_infinite_chunked() -{ - return infinite_chunked; -} - string SrsHttpMessage::uri() { std::string uri = _uri->get_schema(); @@ -550,23 +544,6 @@ std::string SrsHttpMessage::parse_rest_id(string pattern) return ""; } -srs_error_t SrsHttpMessage::enter_infinite_chunked() -{ - srs_error_t err = srs_success; - - if (infinite_chunked) { - return err; - } - - if (is_chunked() || content_length() != -1) { - return srs_error_new(ERROR_HTTP_DATA_INVALID, "not infinited chunked"); - } - - infinite_chunked = true; - - return err; -} - srs_error_t SrsHttpMessage::body_read_all(string& body) { srs_error_t err = srs_success; @@ -975,17 +952,10 @@ srs_error_t SrsHttpResponseReader::read(void* data, size_t nb_data, ssize_t* nb_ return read_specified(data, nb_data, nb_read); } - // infinite chunked mode, directly read. - if (owner->is_infinite_chunked()) { - srs_assert(!owner->is_chunked() && owner->content_length() == -1); - return read_specified(data, nb_data, nb_read); - } - - // infinite chunked mode, but user not set it, - // we think there is no data left. - is_eof = true; - - return err; + // Infinite chunked mode. + // If not chunked encoding, and no content-length, it's infinite chunked. + // In this mode, all body is data and never EOF util socket closed. + return read_specified(data, nb_data, nb_read); } srs_error_t SrsHttpResponseReader::read_chunked(void* data, size_t nb_data, ssize_t* nb_read) diff --git a/trunk/src/protocol/srs_service_http_conn.hpp b/trunk/src/protocol/srs_service_http_conn.hpp index fc49d10d5..5c8d9e0f1 100644 --- a/trunk/src/protocol/srs_service_http_conn.hpp +++ b/trunk/src/protocol/srs_service_http_conn.hpp @@ -99,8 +99,6 @@ private: // The body object, reader object. // @remark, user can get body in string by get_body(). SrsHttpResponseReader* _body; - // Whether the body is infinite chunked. - bool infinite_chunked; // Use a buffer to read and send ts file. // The transport connection, can be NULL. ISrsConnection* owner_conn; @@ -157,9 +155,6 @@ public: virtual bool is_http_options(); // Whether body is chunked encoding, for reader only. virtual bool is_chunked(); - // Whether body is infinite chunked encoding. - // @remark set by enter_infinite_chunked. - virtual bool is_infinite_chunked(); // Whether should keep the connection alive. virtual bool is_keep_alive(); // The uri contains the host and path. @@ -173,8 +168,6 @@ public: virtual std::string ext(); // Get the RESTful matched id. virtual std::string parse_rest_id(std::string pattern); -public: - virtual srs_error_t enter_infinite_chunked(); public: // Read body to string. // @remark for small http body. diff --git a/trunk/src/utest/srs_utest_service.cpp b/trunk/src/utest/srs_utest_service.cpp index 5cc78b968..df21fbc92 100644 --- a/trunk/src/utest/srs_utest_service.cpp +++ b/trunk/src/utest/srs_utest_service.cpp @@ -480,7 +480,7 @@ VOID TEST(TCPServerTest, WritevIOVC) } } -VOID TEST(TCPServerTest, MessageConnection) +VOID TEST(HTTPServerTest, MessageConnection) { srs_error_t err; @@ -534,7 +534,6 @@ VOID TEST(TCPServerTest, MessageConnection) if (true) { SrsHttpMessage m; EXPECT_TRUE(m.is_keep_alive()); - EXPECT_FALSE(m.is_infinite_chunked()); } if (true) { @@ -562,42 +561,7 @@ VOID TEST(TCPServerTest, MessageConnection) } } -VOID TEST(TCPServerTest, MessageInfinityChunked) -{ - srs_error_t err; - - if (true) { - SrsHttpMessage m; - EXPECT_FALSE(m.is_infinite_chunked()); - HELPER_EXPECT_SUCCESS(m.enter_infinite_chunked()); - EXPECT_TRUE(m.is_infinite_chunked()); - } - - if (true) { - SrsHttpMessage m; - HELPER_EXPECT_SUCCESS(m.enter_infinite_chunked()); - HELPER_EXPECT_SUCCESS(m.enter_infinite_chunked()); - EXPECT_TRUE(m.is_infinite_chunked()); - } - - if (true) { - SrsHttpMessage m; - SrsHttpHeader hdr; - hdr.set("Transfer-Encoding", "chunked"); - m.set_header(&hdr, false); - HELPER_EXPECT_FAILED(m.enter_infinite_chunked()); - } - - if (true) { - SrsHttpMessage m; - SrsHttpHeader hdr; - hdr.set("Content-Length", "100"); - m.set_header(&hdr, false); - HELPER_EXPECT_FAILED(m.enter_infinite_chunked()); - } -} - -VOID TEST(TCPServerTest, MessageTurnRequest) +VOID TEST(HTTPServerTest, MessageTurnRequest) { srs_error_t err; @@ -645,23 +609,75 @@ VOID TEST(TCPServerTest, MessageTurnRequest) } } -VOID TEST(TCPServerTest, MessageWritev) +VOID TEST(HTTPServerTest, ContentLength) { srs_error_t err; // For infinite chunked mode, all data is content. if (true) { MockBufferIO io; - io.append("HTTP/1.1 200 OK\r\n\r\n"); + io.append("HTTP/1.1 200 OK\r\nContent-Length: 11\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)); - if (true) { - SrsHttpMessage* hm = dynamic_cast(msg); - ASSERT_TRUE(hm != NULL); - hm->enter_infinite_chunked(); - } + char buf[32]; ssize_t nread = 0; + ISrsHttpResponseReader* r = msg->body_reader(); + + io.append("Hello"); + HELPER_ARRAY_INIT(buf, sizeof(buf), 0); + HELPER_ASSERT_SUCCESS(r->read(buf, 5, &nread)); + EXPECT_EQ(5, nread); + EXPECT_STREQ("Hello", buf); + + io.append("World!"); + HELPER_ARRAY_INIT(buf, sizeof(buf), 0); + HELPER_ASSERT_SUCCESS(r->read(buf, 6, &nread)); + EXPECT_EQ(6, nread); + EXPECT_STREQ("World!", buf); + } +} + +VOID TEST(HTTPServerTest, HTTPChunked) +{ + srs_error_t err; + + // For infinite chunked mode, all data is content. + if (true) { + MockBufferIO io; + io.append("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\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)); + + char buf[32]; ssize_t nread = 0; + ISrsHttpResponseReader* r = msg->body_reader(); + + io.append("5\r\nHello\r\n"); + HELPER_ARRAY_INIT(buf, sizeof(buf), 0); + HELPER_ASSERT_SUCCESS(r->read(buf, 5, &nread)); + EXPECT_EQ(5, nread); + EXPECT_STREQ("Hello", buf); + + io.append("6\r\nWorld!\r\n"); + HELPER_ARRAY_INIT(buf, sizeof(buf), 0); + HELPER_ASSERT_SUCCESS(r->read(buf, 6, &nread)); + EXPECT_EQ(6, nread); + EXPECT_STREQ("World!", buf); + } +} + +VOID TEST(HTTPServerTest, InfiniteChunked) +{ + srs_error_t err; + + // For infinite chunked mode, all data is content. + if (true) { + MockBufferIO io; + io.append("HTTP/1.1 200 OK\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)); char buf[32]; ssize_t nread = 0; ISrsHttpResponseReader* r = msg->body_reader(); @@ -678,6 +694,11 @@ VOID TEST(TCPServerTest, MessageWritev) EXPECT_EQ(8, nread); EXPECT_STREQ("\r\nWorld!", buf); } +} + +VOID TEST(HTTPServerTest, MessageWritev) +{ + srs_error_t err; // Directly writev, merge to one chunk. if (true) { @@ -1174,7 +1195,7 @@ public: } }; -VOID TEST(TCPServerTest, HTTPClientUtility) +VOID TEST(HTTPClientTest, HTTPClientUtility) { srs_error_t err;