Extracts out a helper method to determine whether a chunk extension character is valid.

There is a very small change in behavior, in that the `last_char_was_slash_r_` member will be updated even if `HttpValidationPolicy::disallow_lone_cr_in_chunk_extension` is not set.

Protected by refactoring, no functional change intended; not protected.

PiperOrigin-RevId: 704499760
diff --git a/quiche/balsa/balsa_frame.cc b/quiche/balsa/balsa_frame.cc
index c93ff94..8098d36 100644
--- a/quiche/balsa/balsa_frame.cc
+++ b/quiche/balsa/balsa_frame.cc
@@ -1249,22 +1249,12 @@
             return current - input;
           }
           const char c = *current;
-          if (http_validation_policy_.disallow_lone_cr_in_chunk_extension) {
-            // This is a CR character and the next one is not LF.
-            const bool cr_followed_by_non_lf =
-                c == '\r' && current + 1 < end && *(current + 1) != '\n';
-            // The last character processed by the last ProcessInput() call was
-            // CR, this is the first character of the current ProcessInput()
-            // call, and it is not LF.
-            const bool previous_cr_followed_by_non_lf =
-                last_char_was_slash_r_ && current == input && c != '\n';
-            if (cr_followed_by_non_lf || previous_cr_followed_by_non_lf) {
-              HandleError(BalsaFrameEnums::INVALID_CHUNK_EXTENSION);
-              return current - input;
-            }
-            if (current + 1 == end) {
-              last_char_was_slash_r_ = c == '\r';
-            }
+          if (!IsValidChunkExtensionCharacter(c, current, input, end)) {
+            HandleError(BalsaFrameEnums::INVALID_CHUNK_EXTENSION);
+            return current - input;
+          }
+          if (current + 1 == end) {
+            last_char_was_slash_r_ = c == '\r';
           }
           if (c == '\r' || c == '\n') {
             extensions_length = (extensions_start == current)
@@ -1501,6 +1491,25 @@
   HandleError(BalsaFrameEnums::HEADERS_TOO_LONG);
 }
 
+bool BalsaFrame::IsValidChunkExtensionCharacter(char c, const char* current,
+                                                const char* begin,
+                                                const char* end) {
+  if (http_validation_policy_.disallow_lone_cr_in_chunk_extension) {
+    // This is a CR character and the next one is not LF.
+    const bool cr_followed_by_non_lf =
+        c == '\r' && current + 1 < end && *(current + 1) != '\n';
+    // The last character processed by the last ProcessInput() call was
+    // CR, this is the first character of the current ProcessInput()
+    // call, and it is not LF.
+    const bool previous_cr_followed_by_non_lf =
+        last_char_was_slash_r_ && current == begin && c != '\n';
+    if (cr_followed_by_non_lf || previous_cr_followed_by_non_lf) {
+      return false;
+    }
+  }
+  return true;
+}
+
 const int32_t BalsaFrame::kValidTerm1;
 const int32_t BalsaFrame::kValidTerm1Mask;
 const int32_t BalsaFrame::kValidTerm2;
diff --git a/quiche/balsa/balsa_frame.h b/quiche/balsa/balsa_frame.h
index 73c266d..4902ab8 100644
--- a/quiche/balsa/balsa_frame.h
+++ b/quiche/balsa/balsa_frame.h
@@ -266,6 +266,10 @@
 
   void HandleHeadersTooLongError();
 
+  inline bool IsValidChunkExtensionCharacter(char c, const char* current,
+                                             const char* begin,
+                                             const char* end);
+
   BalsaVisitorInterface* visitor_;
   BalsaHeaders* continue_headers_;  // This is not reset to nullptr in Reset().
   BalsaHeaders* headers_;           // This is not reset to nullptr in Reset().