diff --git a/include/boost/beast/http/parser.hpp b/include/boost/beast/http/parser.hpp index 3e00a15e..a470ba8a 100644 --- a/include/boost/beast/http/parser.hpp +++ b/include/boost/beast/http/parser.hpp @@ -498,11 +498,23 @@ private: string_view value, error_code& ec) override { + // Drop fields not advertised in the Trailer header if(! token_list{m_[field::trailer]}.exists(name_string)) return; switch(name) { + // Drop fields that govern message framing or connection handling + case field::connection: + case field::proxy_connection: + case field::upgrade: + case field::transfer_encoding: + case field::content_length: + case field::trailer: + case field::host: + return; + + // Safe and well-known trailer fields case field::digest: // RFC 3230, Section 2 (obsolete) case field::content_digest: // RFC 9530, Section 2 case field::repr_digest: // RFC 9530, Section 3 @@ -513,6 +525,7 @@ private: case field::link: // RFC 8288, Section 3 case field::alt_svc: // RFC 7838, Section 3 break; + default: if(! merge_all_trailers_) return; diff --git a/test/beast/http/parser.cpp b/test/beast/http/parser.cpp index 59ecb237..a0c979b0 100644 --- a/test/beast/http/parser.cpp +++ b/test/beast/http/parser.cpp @@ -441,6 +441,44 @@ public: // Upgrade in the trailer must not mark the message as upgrade BEAST_EXPECT(! p.upgrade()); } + + // framing/connection control fields are dropped even when they + // are listed in `Trailer` and merge_all_trailers(true) is set + { + error_code ec; + parser_type p; + p.eager(true); + p.merge_all_trailers(true); + p.put( + buf("HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "Trailer: Connection, Proxy-Connection, Upgrade, " + "Transfer-Encoding, Content-Length, Trailer, Host\r\n" + "\r\n" + "0\r\n" + "Connection: close\r\n" + "Proxy-Connection: close\r\n" + "Upgrade: websocket\r\n" + "Transfer-Encoding: gzip\r\n" + "Content-Length: 42\r\n" + "Trailer: Evil\r\n" + "Host: evil.example\r\n" + "\r\n"), + ec); + BEAST_EXPECT(p.is_done()); + + // fields absent from the header must not be added + BEAST_EXPECT(! p.get().contains(field::connection)); + BEAST_EXPECT(! p.get().contains(field::proxy_connection)); + BEAST_EXPECT(! p.get().contains(field::upgrade)); + BEAST_EXPECT(! p.get().contains(field::content_length)); + BEAST_EXPECT(! p.get().contains(field::host)); + + // fields present in the header must not be duplicated + BEAST_EXPECT(p.get().count(field::transfer_encoding) == 1); + BEAST_EXPECT(p.get()[field::transfer_encoding] == "chunked"); + BEAST_EXPECT(p.get().count(field::trailer) == 1); + } } void