Copilot commented on code in PR #3606:
URL: https://github.com/apache/brpc/pull/3606#discussion_r4290679230


##########
src/brpc/details/http_message.cpp:
##########
@@ -186,6 +186,9 @@ int HttpMessage::on_headers_complete(http_parser *parser) {
         parser->http_major = 1;
     }
     HttpHeader& headers = http_message->header();
+    if (headers.HasSetCookieHeaders()) {
+        headers.SyncSetCookieHeaders();
+    }

Review Comment:
   `HttpMessage` calls `HttpHeader::HasSetCookieHeaders()` and 
`HttpHeader::SyncSetCookieHeaders()`. In `http_header.h` these helpers appear 
to be internal (defined alongside other non-public helpers), so this may fail 
to compile due to access control. Make these APIs publicly accessible in a 
controlled way (e.g., a public `FinalizeHeadersParsing()` that performs the 
sync), or explicitly grant friendship to the caller that needs it.



##########
test/brpc_http_message_unittest.cpp:
##########
@@ -879,9 +900,65 @@ TEST(HttpMessageTest, http_header) {
     }
     ASSERT_EQ(1, set_cookie_value2_count);
     ASSERT_EQ(1, set_cookie_value3_count);
+    brpc::HttpHeader copied_header(header);
+    copied_header.SetHeader(brpc::HttpHeader::SET_COOKIE, set_cookie_value1);
+    value = header.GetHeader(brpc::HttpHeader::SET_COOKIE);
+    ASSERT_TRUE(value && *value == set_cookie_value3);
+    value = copied_header.GetHeader(brpc::HttpHeader::SET_COOKIE);
+    ASSERT_TRUE(value && *value == set_cookie_value1);
+    brpc::HttpHeader assigned_header;
+    assigned_header = header;
+    assigned_header.SetHeader(brpc::HttpHeader::SET_COOKIE, set_cookie_value2);
+    value = header.GetHeader(brpc::HttpHeader::SET_COOKIE);
+    ASSERT_TRUE(value && *value == set_cookie_value3);
+    value = assigned_header.GetHeader(brpc::HttpHeader::SET_COOKIE);
+    ASSERT_TRUE(value && *value == set_cookie_value2);
     header.RemoveHeader(brpc::HttpHeader::SET_COOKIE);
     ASSERT_FALSE(header.GetHeader(brpc::HttpHeader::SET_COOKIE));
-    ASSERT_EQ(header._first_set_cookie, nullptr);
+    ASSERT_TRUE(header.GetAllSetCookieHeader().empty());
+
+    header.SetHeader(brpc::HttpHeader::SET_COOKIE, set_cookie_value1);
+    const std::string* first_set_cookie_after_reset =
+        header.GetHeader(brpc::HttpHeader::SET_COOKIE);
+    ASSERT_NE(nullptr, first_set_cookie_after_reset);
+    header.AppendHeader(brpc::HttpHeader::SET_COOKIE, set_cookie_value2);
+    const size_t bucket_count = header._headers.bucket_count();
+    for (int i = 0; i < 4096 &&
+             header._headers.bucket_count() == bucket_count; ++i) {
+        header.SetHeader("header" + std::to_string(i), "value");
+    }
+    ASSERT_NE(bucket_count, header._headers.bucket_count());

Review Comment:
   This test forces a `HeaderMap` growth by inserting up to 4096 headers and 
asserting `bucket_count()` changes. That assumption can be 
implementation-dependent (initial bucket counts / growth factors can vary), 
which may make the test flaky across platforms or future container changes. A 
more robust approach is to force rehash explicitly (if the container supports 
it), or to loop until a growth condition that is guaranteed by the container 
API, while keeping an upper bound and asserting based on an explicit rehash 
trigger rather than a hardcoded insert count.



##########
test/brpc_http_message_unittest.cpp:
##########
@@ -879,9 +900,65 @@ TEST(HttpMessageTest, http_header) {
     }
     ASSERT_EQ(1, set_cookie_value2_count);
     ASSERT_EQ(1, set_cookie_value3_count);
+    brpc::HttpHeader copied_header(header);
+    copied_header.SetHeader(brpc::HttpHeader::SET_COOKIE, set_cookie_value1);
+    value = header.GetHeader(brpc::HttpHeader::SET_COOKIE);
+    ASSERT_TRUE(value && *value == set_cookie_value3);
+    value = copied_header.GetHeader(brpc::HttpHeader::SET_COOKIE);
+    ASSERT_TRUE(value && *value == set_cookie_value1);
+    brpc::HttpHeader assigned_header;
+    assigned_header = header;
+    assigned_header.SetHeader(brpc::HttpHeader::SET_COOKIE, set_cookie_value2);
+    value = header.GetHeader(brpc::HttpHeader::SET_COOKIE);
+    ASSERT_TRUE(value && *value == set_cookie_value3);
+    value = assigned_header.GetHeader(brpc::HttpHeader::SET_COOKIE);
+    ASSERT_TRUE(value && *value == set_cookie_value2);
     header.RemoveHeader(brpc::HttpHeader::SET_COOKIE);
     ASSERT_FALSE(header.GetHeader(brpc::HttpHeader::SET_COOKIE));
-    ASSERT_EQ(header._first_set_cookie, nullptr);
+    ASSERT_TRUE(header.GetAllSetCookieHeader().empty());
+
+    header.SetHeader(brpc::HttpHeader::SET_COOKIE, set_cookie_value1);
+    const std::string* first_set_cookie_after_reset =
+        header.GetHeader(brpc::HttpHeader::SET_COOKIE);
+    ASSERT_NE(nullptr, first_set_cookie_after_reset);
+    header.AppendHeader(brpc::HttpHeader::SET_COOKIE, set_cookie_value2);
+    const size_t bucket_count = header._headers.bucket_count();
+    for (int i = 0; i < 4096 &&
+             header._headers.bucket_count() == bucket_count; ++i) {
+        header.SetHeader("header" + std::to_string(i), "value");
+    }
+    ASSERT_NE(bucket_count, header._headers.bucket_count());
+    ASSERT_EQ(set_cookie_value1, *first_set_cookie_after_reset);
+    value = header.GetHeader(brpc::HttpHeader::SET_COOKIE);
+    ASSERT_TRUE(value && *value == set_cookie_value1);
+    all_set_cookie = header.GetAllSetCookieHeader();
+    ASSERT_EQ(2u, all_set_cookie.size());
+    ASSERT_EQ(set_cookie_value1, *all_set_cookie[0]);
+    ASSERT_EQ(set_cookie_value2, *all_set_cookie[1]);
+    int set_cookie_value1_count = 0;
+    set_cookie_value2_count = 0;

Review Comment:
   The counting variables are handled inconsistently here: 
`set_cookie_value1_count` is declared locally, but `set_cookie_value2_count` is 
assigned without a local declaration in this block, which makes the code harder 
to follow and more sensitive to surrounding scope changes. Prefer declaring 
both counters in the same local scope (and similarly for any others) to keep 
the test self-contained and avoid accidental reuse of earlier variables.



##########
src/brpc/http_header.cpp:
##########
@@ -128,28 +161,29 @@ std::string& HttpHeader::GetOrAddHeader(const 
std::string& key) {
         return _content_type;
     }
 
-    bool is_set_cookie = IsSetCookie(key);
-    // Only returns the first Set-Cookie header field for compatibility.
-    if (is_set_cookie && nullptr != _first_set_cookie) {
-        return *_first_set_cookie;
-    }
-
     std::string* val = _headers.seek(key);
     if (nullptr == val) {
         val = _headers.insert({ key, "" });
-        if (is_set_cookie) {
-            _first_set_cookie = val;
-        }
     }
     return *val;
 }
 
 std::string& HttpHeader::AddHeader(const std::string& key) {
-    std::string* val = _headers.insert({ key, "" });
-    if (IsSetCookie(key) && nullptr == _first_set_cookie) {
-        _first_set_cookie = val;
+    if (!_set_cookie_headers) {
+        _set_cookie_headers.reset(new SetCookieHeaders);
+    }
+    _set_cookie_headers->push_back(std::make_pair(key, std::string()));
+    SyncSetCookieHeaders();
+    return _set_cookie_headers->back().second;
+}

Review Comment:
   `AddHeader()` now unconditionally appends into `_set_cookie_headers` and 
syncs `SET_COOKIE`, regardless of `key`. If `AddHeader()` is ever used for 
non-`Set-Cookie` headers, this will incorrectly route those headers into the 
`Set-Cookie` store and also mutate the `SET_COOKIE` entries in `_headers`. Fix 
by making `AddHeader()` conditional: only use `_set_cookie_headers` when 
`IsSetCookie(key)` is true; otherwise preserve the prior behavior of inserting 
into `_headers` and returning that value slot. Alternatively, split into 
`AddSetCookieHeader()` (new) and keep `AddHeader()` generic.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to