Fix `BalsaFrame` token corruption when sanitizing first line with multiple spaces.

**Key Changes:**

- Fixes a bug in `BalsaFrame::ParseHTTPFirstLine` where token extraction arithmetic applied indices from a new, sanitized storage block to the pointer of the original, un-sanitized raw buffer block. This yielded corrupted parser tokens (e.g., getting `" "` instead of `"/"` for a URL in `GET  /  HTTP/1.1`).
- Passes `begin` by reference `(char*&)` to update it to the new buffer allocation, ensuring indices remain perfectly tied to their active memory block container.
- Updates `balsa_frame_test.cc` to explicitly verify visitor callbacks (`OnRequestFirstLineInput` / `OnResponseFirstLineInput`) receive clean, uncorrupted component data.
- Adds `SanitizeFirstlineSpaces_Request_Served` and `SanitizeFirstlineSpaces_Response_Served` to Envoy integration tests to verify the hook works seamlessly at the gateway level.

Protected by sanitize_firstline_spaces (The flag is not in production yet).

PiperOrigin-RevId: 966603762
diff --git a/quiche/balsa/balsa_frame.cc b/quiche/balsa/balsa_frame.cc
index 60a3e36..747711b 100644
--- a/quiche/balsa/balsa_frame.cc
+++ b/quiche/balsa/balsa_frame.cc
@@ -161,7 +161,7 @@
 //  ProcessFirstLine(begin, end, is_request, &headers, &error_code);
 //
 
-bool ParseHTTPFirstLine(char* begin, char* end, bool is_request,
+bool ParseHTTPFirstLine(char*& begin, char* end, bool is_request,
                         BalsaHeaders* headers,
                         BalsaFrameEnums::ErrorCode* error_code,
                         FirstLineValidationOption whitespace_option,
@@ -266,6 +266,8 @@
                         : BalsaFrameEnums::MULTIPLE_SPACES_IN_STATUS_LINE;
       return false;
     }
+    QUICHE_DCHECK(multiple_spaces_option ==
+                  FirstLineValidationOption::SANITIZE);
     const absl::string_view part1(
         begin + headers->non_whitespace_1_idx_,
         headers->whitespace_2_idx_ - headers->non_whitespace_1_idx_);
@@ -278,6 +280,7 @@
 
     QUICHE_CODE_COUNT(sanitize_firstline_spaces_sanitized);
     headers->SetRequestFirstlineFromStringPieces(part1, part2, part3);
+    begin = headers->BeginningOfFirstLine();
   }
 
   return true;
diff --git a/quiche/balsa/balsa_frame_test.cc b/quiche/balsa/balsa_frame_test.cc
index 5799eef..962ec61 100644
--- a/quiche/balsa/balsa_frame_test.cc
+++ b/quiche/balsa/balsa_frame_test.cc
@@ -2414,6 +2414,8 @@
   balsa_frame_.set_http_validation_policy(http_validation_policy);
   EXPECT_CALL(visitor_mock_, ProcessHeaders(_));
   EXPECT_CALL(visitor_mock_, HeaderDone());
+  EXPECT_CALL(visitor_mock_, OnRequestFirstLineInput("GET / HTTP/1.1", "GET",
+                                                     "/", "HTTP/1.1"));
   const std::string message1 =
       "GET  / HTTP/1.1\r\n"
       "Host: 1.1.1.1\r\n"
@@ -2473,6 +2475,8 @@
   balsa_frame_.set_is_request(false);
   EXPECT_CALL(visitor_mock_, ProcessHeaders(_));
   EXPECT_CALL(visitor_mock_, HeaderDone());
+  EXPECT_CALL(visitor_mock_, OnResponseFirstLineInput("HTTP/1.1 200 OK",
+                                                      "HTTP/1.1", "200", "OK"));
   const std::string message1 =
       "HTTP/1.1 200  OK\r\n"
       "Content-Type: text/html\r\n"
diff --git a/quiche/balsa/balsa_headers.h b/quiche/balsa/balsa_headers.h
index 9f63838..b4664ca 100644
--- a/quiche/balsa/balsa_headers.h
+++ b/quiche/balsa/balsa_headers.h
@@ -1062,7 +1062,7 @@
   friend class test::BalsaHeadersTestPeer;
 
   friend bool ParseHTTPFirstLine(
-      char* begin, char* end, bool is_request, BalsaHeaders* headers,
+      char*& begin, char* end, bool is_request, BalsaHeaders* headers,
       BalsaFrameEnums::ErrorCode* error_code,
       HttpValidationPolicy::FirstLineValidationOption whitespace_option,
       HttpValidationPolicy::FirstLineValidationOption multiple_spaces_option,