diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index 295b1e923..9dcdb918e 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -7,6 +7,7 @@ The changelog for SRS. ## SRS 5.0 Changelog +* v5.0, 2022-09-30, HTTP: Support HTTP header in creating order. v5.0.68 * v5.0, 2022-09-27, For [#2899](https://github.com/ossrs/srs/issues/2899): API: Support exporter for Prometheus. v5.0.67 * v5.0, 2022-09-27, For [#3167](https://github.com/ossrs/srs/issues/3167): WebRTC: Refine sequence jitter algorithm. v5.0.66 * v5.0, 2022-09-22, Fix [#3164](https://github.com/ossrs/srs/issues/3164): SRT: Choppy when audio ts gap is too large. v5.0.65 diff --git a/trunk/src/core/srs_core_version5.hpp b/trunk/src/core/srs_core_version5.hpp index 2c26b8e5e..beb8e6eb3 100644 --- a/trunk/src/core/srs_core_version5.hpp +++ b/trunk/src/core/srs_core_version5.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 5 #define VERSION_MINOR 0 -#define VERSION_REVISION 67 +#define VERSION_REVISION 68 #endif diff --git a/trunk/src/protocol/srs_protocol_http_stack.cpp b/trunk/src/protocol/srs_protocol_http_stack.cpp index 1786765da..b9b88d6f8 100644 --- a/trunk/src/protocol/srs_protocol_http_stack.cpp +++ b/trunk/src/protocol/srs_protocol_http_stack.cpp @@ -152,6 +152,10 @@ void SrsHttpHeader::set(string key, string value) pchar = ch; } + if (headers.find(key) == headers.end()) { + keys_.push_back(key); + } + headers[key] = value; } @@ -169,9 +173,18 @@ string SrsHttpHeader::get(string key) void SrsHttpHeader::del(string key) { - map::iterator it = headers.find(key); - if (it != headers.end()) { - headers.erase(it); + if (true) { + vector::iterator it = std::find(keys_.begin(), keys_.end(), key); + if (it != keys_.end()) { + it = keys_.erase(it); + } + } + + if (true) { + map::iterator it = headers.find(key); + if (it != headers.end()) { + headers.erase(it); + } } } @@ -182,10 +195,11 @@ int SrsHttpHeader::count() void SrsHttpHeader::dumps(SrsJsonObject* o) { - map::iterator it; - for (it = headers.begin(); it != headers.end(); ++it) { - string v = it->second; - o->set(it->first, SrsJsonAny::str(v.c_str())); + vector::iterator it; + for (it = keys_.begin(); it != keys_.end(); ++it) { + const string& key = *it; + const string& value = headers[key]; + o->set(key, SrsJsonAny::str(value.c_str())); } } @@ -217,9 +231,11 @@ void SrsHttpHeader::set_content_type(string ct) void SrsHttpHeader::write(stringstream& ss) { - map::iterator it; - for (it = headers.begin(); it != headers.end(); ++it) { - ss << it->first << ": " << it->second << SRS_HTTP_CRLF; + vector::iterator it; + for (it = keys_.begin(); it != keys_.end(); ++it) { + const string& key = *it; + const string& value = headers[key]; + ss << key << ": " << value << SRS_HTTP_CRLF; } } @@ -657,7 +673,7 @@ void SrsHttpServeMux::unhijack(ISrsHttpMatchHijacker* h) if (it == hijackers.end()) { return; } - hijackers.erase(it); + it = hijackers.erase(it); } srs_error_t SrsHttpServeMux::handle(std::string pattern, ISrsHttpHandler* handler) diff --git a/trunk/src/protocol/srs_protocol_http_stack.hpp b/trunk/src/protocol/srs_protocol_http_stack.hpp index 1ebac924f..493235242 100644 --- a/trunk/src/protocol/srs_protocol_http_stack.hpp +++ b/trunk/src/protocol/srs_protocol_http_stack.hpp @@ -93,6 +93,8 @@ private: // header fields, and ending with the entity-header fields. // @doc https://tools.ietf.org/html/rfc2616#section-4.2 std::map headers; + // Store keys to keep fields in order. + std::vector keys_; public: SrsHttpHeader(); virtual ~SrsHttpHeader(); diff --git a/trunk/src/utest/srs_utest_http.cpp b/trunk/src/utest/srs_utest_http.cpp index 50f8bb5d6..05313ae1c 100644 --- a/trunk/src/utest/srs_utest_http.cpp +++ b/trunk/src/utest/srs_utest_http.cpp @@ -608,6 +608,58 @@ VOID TEST(ProtocolHTTPTest, HTTPHeader) srs_freep(o); } +VOID TEST(ProtocolHTTPTest, HTTPHeaderOrder) +{ + SrsHttpHeader h; + h.set("User-Agent", RTMP_SIG_SRS_SERVER); + h.set("Server", "SRS"); + h.set("Connection", "Close"); + + if (true) { + SrsJsonObject* o = SrsJsonObject::object(); + SrsAutoFree(SrsJsonObject, o); + h.dumps(o); + + ASSERT_EQ(3, o->count()); + EXPECT_STREQ("User-Agent", o->key_at(0).c_str()); + EXPECT_STREQ("Server", o->key_at(1).c_str()); + EXPECT_STREQ("Connection", o->key_at(2).c_str()); + } + + if (true) { + h.del("User-Agent"); + + SrsJsonObject* o = SrsJsonObject::object(); + SrsAutoFree(SrsJsonObject, o); + h.dumps(o); + + ASSERT_EQ(2, o->count()); + EXPECT_STREQ("Server", o->key_at(0).c_str()); + EXPECT_STREQ("Connection", o->key_at(1).c_str()); + } + + if (true) { + h.del("Server"); + + SrsJsonObject* o = SrsJsonObject::object(); + SrsAutoFree(SrsJsonObject, o); + h.dumps(o); + + ASSERT_EQ(1, o->count()); + EXPECT_STREQ("Connection", o->key_at(0).c_str()); + } + + if (true) { + h.del("Connection"); + + SrsJsonObject* o = SrsJsonObject::object(); + SrsAutoFree(SrsJsonObject, o); + h.dumps(o); + + ASSERT_EQ(0, o->count()); + } +} + VOID TEST(ProtocolHTTPTest, HTTPServerMuxerVhost) { srs_error_t err;