Adds a new SpdySerializedFrame constructor that makes memory ownership clear.

Also migrates all uses of the old constructor.

A future change will remove the old constructor along with the `owns_buffer_` member.

Protected by refactoring, not protected.

PiperOrigin-RevId: 623626698
diff --git a/quiche/spdy/core/spdy_frame_builder.h b/quiche/spdy/core/spdy_frame_builder.h
index 69cf352..52cb1b0 100644
--- a/quiche/spdy/core/spdy_frame_builder.h
+++ b/quiche/spdy/core/spdy_frame_builder.h
@@ -68,7 +68,7 @@
     QUICHE_BUG_IF(spdy_bug_39_2, kMaxFrameSizeLimit < length_)
         << "Frame length " << length_
         << " is longer than the maximum possible allowed length.";
-    SpdySerializedFrame rv(buffer_.release(), length(), true);
+    SpdySerializedFrame rv(std::move(buffer_), length());
     capacity_ = 0;
     length_ = 0;
     offset_ = 0;
diff --git a/quiche/spdy/core/spdy_frame_builder_test.cc b/quiche/spdy/core/spdy_frame_builder_test.cc
index 60e12c8..647d084 100644
--- a/quiche/spdy/core/spdy_frame_builder_test.cc
+++ b/quiche/spdy/core/spdy_frame_builder_test.cc
@@ -13,6 +13,7 @@
 #include "quiche/common/platform/api/quiche_test.h"
 #include "quiche/spdy/core/array_output_buffer.h"
 #include "quiche/spdy/core/spdy_protocol.h"
+#include "quiche/spdy/test_tools/spdy_test_utils.h"
 
 namespace spdy {
 
@@ -49,8 +50,7 @@
   SpdySerializedFrame frame(builder.take());
   char expected[kBuilderSize];
   memset(expected, ~1, kBuilderSize);
-  EXPECT_EQ(absl::string_view(expected, kBuilderSize),
-            absl::string_view(frame.data(), kBuilderSize));
+  EXPECT_EQ(absl::string_view(expected, kBuilderSize), frame);
 }
 
 // Verifies that SpdyFrameBuilder::GetWritableBuffer() can be used to build a
@@ -64,11 +64,10 @@
       &builder, kBuilderSize, &actual_size);
   memset(writable_buffer, ~1, kBuilderSize);
   EXPECT_TRUE(builder.Seek(kBuilderSize));
-  SpdySerializedFrame frame(output.Begin(), kBuilderSize, false);
+  SpdySerializedFrame frame = MakeSerializedFrame(output.Begin(), kBuilderSize);
   char expected[kBuilderSize];
   memset(expected, ~1, kBuilderSize);
-  EXPECT_EQ(absl::string_view(expected, kBuilderSize),
-            absl::string_view(frame.data(), kBuilderSize));
+  EXPECT_EQ(absl::string_view(expected, kBuilderSize), frame);
 }
 
 // Verifies the case that the buffer's capacity is too small.
diff --git a/quiche/spdy/core/spdy_framer_test.cc b/quiche/spdy/core/spdy_framer_test.cc
index 56d0207..d9283de 100644
--- a/quiche/spdy/core/spdy_framer_test.cc
+++ b/quiche/spdy/core/spdy_framer_test.cc
@@ -119,8 +119,8 @@
       size_t size_before = frame_list_buffer.Size();
       EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u);
       frame_list.emplace_back(
-          SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
-                              frame_list_buffer.Size() - size_before, false));
+          MakeSerializedFrame(frame_list_buffer.Begin() + size_before,
+                              frame_list_buffer.Size() - size_before));
     }
     framer->debug_visitor_ = saved_debug_visitor;
 
@@ -136,8 +136,8 @@
     }
     output->Reset();
     EXPECT_TRUE(framer->SerializeHeaders(headers, output));
-    SpdySerializedFrame serialized_headers_old_version(output->Begin(),
-                                                       output->Size(), false);
+    SpdySerializedFrame serialized_headers_old_version =
+        MakeSerializedFrame(output->Begin(), output->Size());
     framer->hpack_encoder_.reset(nullptr);
     auto* saved_debug_visitor = framer->debug_visitor_;
     framer->debug_visitor_ = nullptr;
@@ -149,8 +149,8 @@
       size_t size_before = frame_list_buffer.Size();
       EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u);
       frame_list.emplace_back(
-          SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
-                              frame_list_buffer.Size() - size_before, false));
+          MakeSerializedFrame(frame_list_buffer.Begin() + size_before,
+                              frame_list_buffer.Size() - size_before));
     }
     framer->debug_visitor_ = saved_debug_visitor;
 
@@ -187,8 +187,8 @@
       size_t size_before = frame_list_buffer.Size();
       EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u);
       frame_list.emplace_back(
-          SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
-                              frame_list_buffer.Size() - size_before, false));
+          MakeSerializedFrame(frame_list_buffer.Begin() + size_before,
+                              frame_list_buffer.Size() - size_before));
     }
     framer->debug_visitor_ = saved_debug_visitor;
 
@@ -219,8 +219,8 @@
       size_t size_before = frame_list_buffer.Size();
       EXPECT_GT(it.NextFrame(&frame_list_buffer), 0u);
       frame_list.emplace_back(
-          SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
-                              frame_list_buffer.Size() - size_before, false));
+          MakeSerializedFrame(frame_list_buffer.Begin() + size_before,
+                              frame_list_buffer.Size() - size_before));
     }
     framer->debug_visitor_ = saved_debug_visitor;
 
@@ -983,7 +983,7 @@
   SpdySerializedFrame frame(framer_.SerializeFrame(priority_ir));
   if (use_output_) {
     EXPECT_EQ(framer_.SerializeFrame(priority_ir, &output_), frame.size());
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
 
   // We shouldn't have to read the whole frame before we signal an error.
@@ -1008,7 +1008,7 @@
   SpdySerializedFrame frame(framer_.SerializeRstStream(rst_stream_ir));
   if (use_output_) {
     EXPECT_TRUE(framer_.SerializeRstStream(rst_stream_ir, &output_));
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
 
   // We shouldn't have to read the whole frame before we signal an error.
@@ -1097,7 +1097,7 @@
   SpdySerializedFrame frame(framer_.SerializeContinuation(continuation));
   if (use_output_) {
     ASSERT_TRUE(framer_.SerializeContinuation(continuation, &output_));
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
 
   // We shouldn't have to read the whole frame before we signal an error.
@@ -1498,7 +1498,7 @@
   SpdySerializedFrame frame(framer_.SerializeWindowUpdate(window_update));
   if (use_output_) {
     ASSERT_TRUE(framer_.SerializeWindowUpdate(window_update, &output_));
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
 
   const char kDescription[] = "WINDOW_UPDATE frame, stream 1, delta 0x12345678";
@@ -1738,7 +1738,7 @@
     SpdySerializedFrame frame(framer_.SerializeRstStream(rst_stream));
     if (use_output_) {
       ASSERT_TRUE(framer_.SerializeRstStream(rst_stream, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     CompareFrame(kDescription, frame, kH2FrameData,
                  ABSL_ARRAYSIZE(kH2FrameData));
@@ -1759,7 +1759,7 @@
     if (use_output_) {
       output_.Reset();
       ASSERT_TRUE(framer_.SerializeRstStream(rst_stream, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     CompareFrame(kDescription, frame, kH2FrameData,
                  ABSL_ARRAYSIZE(kH2FrameData));
@@ -1780,7 +1780,7 @@
     if (use_output_) {
       output_.Reset();
       ASSERT_TRUE(framer_.SerializeRstStream(rst_stream, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     CompareFrame(kDescription, frame, kH2FrameData,
                  ABSL_ARRAYSIZE(kH2FrameData));
@@ -1808,7 +1808,7 @@
     SpdySerializedFrame frame(framer_.SerializeSettings(settings_ir));
     if (use_output_) {
       ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     CompareFrame(kDescription, frame, kH2FrameData,
                  ABSL_ARRAYSIZE(kH2FrameData));
@@ -1843,7 +1843,7 @@
     if (use_output_) {
       output_.Reset();
       ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
 
     CompareFrame(kDescription, frame, kH2FrameData,
@@ -1863,7 +1863,7 @@
     if (use_output_) {
       output_.Reset();
       ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
 
     CompareFrame(kDescription, frame, kH2FrameData,
@@ -1897,7 +1897,7 @@
     SpdySerializedFrame frame(framer_.SerializePing(ping_ir));
     if (use_output_) {
       ASSERT_TRUE(framer_.SerializePing(ping_ir, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     CompareFrame(kDescription, frame, kH2FrameData,
                  ABSL_ARRAYSIZE(kH2FrameData));
@@ -1908,7 +1908,7 @@
     if (use_output_) {
       output_.Reset();
       ASSERT_TRUE(framer_.SerializePing(ping_ir, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     CompareFrame(kDescription, frame, kH2FrameDataWithAck,
                  ABSL_ARRAYSIZE(kH2FrameDataWithAck));
@@ -1932,7 +1932,7 @@
     SpdySerializedFrame frame(framer_.SerializeGoAway(goaway_ir));
     if (use_output_) {
       ASSERT_TRUE(framer_.SerializeGoAway(goaway_ir, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     CompareFrame(kDescription, frame, kH2FrameData,
                  ABSL_ARRAYSIZE(kH2FrameData));
@@ -1955,7 +1955,7 @@
     if (use_output_) {
       output_.Reset();
       ASSERT_TRUE(framer_.SerializeGoAway(goaway_ir, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     CompareFrame(kDescription, frame, kH2FrameData,
                  ABSL_ARRAYSIZE(kH2FrameData));
@@ -2232,7 +2232,7 @@
       output_.Reset();
       ASSERT_TRUE(framer_.SerializeWindowUpdate(
           SpdyWindowUpdateIR(/* stream_id = */ 1, /* delta = */ 1), &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     CompareFrame(kDescription, frame, kH2FrameData,
                  ABSL_ARRAYSIZE(kH2FrameData));
@@ -2254,7 +2254,7 @@
       ASSERT_TRUE(framer_.SerializeWindowUpdate(
           SpdyWindowUpdateIR(/* stream_id = */ 0x7FFFFFFF, /* delta = */ 1),
           &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     CompareFrame(kDescription, frame, kH2FrameData,
                  ABSL_ARRAYSIZE(kH2FrameData));
@@ -2276,7 +2276,7 @@
       ASSERT_TRUE(framer_.SerializeWindowUpdate(
           SpdyWindowUpdateIR(/* stream_id = */ 1, /* delta = */ 0x7FFFFFFF),
           &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     CompareFrame(kDescription, frame, kH2FrameData,
                  ABSL_ARRAYSIZE(kH2FrameData));
@@ -2468,7 +2468,7 @@
   SpdySerializedFrame frame(framer.SerializeContinuation(continuation));
   if (use_output_) {
     ASSERT_TRUE(framer.SerializeContinuation(continuation, &output_));
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   CompareFrame(kDescription, frame, kFrameData, ABSL_ARRAYSIZE(kFrameData));
 }
@@ -2637,7 +2637,7 @@
   SpdySerializedFrame frame(framer_.SerializeFrame(altsvc_ir));
   if (use_output_) {
     EXPECT_EQ(framer_.SerializeFrame(altsvc_ir, &output_), frame.size());
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   CompareFrame(kDescription, frame, kFrameData, ABSL_ARRAYSIZE(kFrameData));
 }
@@ -2659,7 +2659,7 @@
   SpdySerializedFrame frame(framer_.SerializeFrame(priority_ir));
   if (use_output_) {
     EXPECT_EQ(framer_.SerializeFrame(priority_ir, &output_), frame.size());
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   CompareFrame(kDescription, frame, kFrameData, ABSL_ARRAYSIZE(kFrameData));
 }
@@ -2682,7 +2682,7 @@
   if (use_output_) {
     EXPECT_EQ(framer_.SerializeFrame(priority_update_ir, &output_),
               frame.size());
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   CompareFrame(kDescription, frame, kFrameData, ABSL_ARRAYSIZE(kFrameData));
 }
@@ -2712,7 +2712,7 @@
   SpdySerializedFrame frame(framer_.SerializeFrame(accept_ch_ir));
   if (use_output_) {
     EXPECT_EQ(framer_.SerializeFrame(accept_ch_ir, &output_), frame.size());
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   CompareFrame(kDescription, frame, kFrameData, ABSL_ARRAYSIZE(kFrameData));
 }
@@ -2739,7 +2739,7 @@
   SpdySerializedFrame frame(framer_.SerializeFrame(unknown_ir));
   if (use_output_) {
     EXPECT_EQ(framer_.SerializeFrame(unknown_ir, &output_), frame.size());
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   CompareFrame(kDescription, frame, kFrameData, ABSL_ARRAYSIZE(kFrameData));
 }
@@ -2771,7 +2771,7 @@
   SpdySerializedFrame frame(framer_.SerializeFrame(unknown_ir));
   if (use_output_) {
     EXPECT_EQ(framer_.SerializeFrame(unknown_ir, &output_), frame.size());
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   CompareFrame(kDescription, frame, kFrameData, ABSL_ARRAYSIZE(kFrameData));
 }
@@ -3120,7 +3120,7 @@
   SpdySerializedFrame control_frame(framer_.SerializeSettings(settings_ir));
   if (use_output_) {
     ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_));
-    control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    control_frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   SetFrameLength(&control_frame, 0);
   TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
@@ -3143,7 +3143,7 @@
   SpdySerializedFrame control_frame(framer_.SerializeSettings(settings_ir));
   if (use_output_) {
     ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_));
-    control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    control_frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   const size_t kNewLength = 8;
   SetFrameLength(&control_frame, kNewLength);
@@ -3170,7 +3170,7 @@
   SpdySerializedFrame control_frame(framer_.SerializeSettings(settings_ir));
   if (use_output_) {
     ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_));
-    control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    control_frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
 
   TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
@@ -3398,7 +3398,7 @@
   if (use_output_) {
     ASSERT_TRUE(framer_.SerializeWindowUpdate(
         SpdyWindowUpdateIR(/* stream_id = */ 1, /* delta = */ 2), &output_));
-    control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    control_frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
   visitor.SimulateInFramer(
@@ -3840,7 +3840,7 @@
   SpdySerializedFrame control_frame(framer_.SerializeSettings(settings_ir));
   if (use_output_) {
     ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_));
-    control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    control_frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   visitor.SimulateInFramer(
       reinterpret_cast<unsigned char*>(control_frame.data()),
@@ -4091,7 +4091,7 @@
     if (use_output_) {
       output_.Reset();
       ASSERT_TRUE(framer_.SerializeRstStream(rst_stream, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     SetFrameFlags(&frame, flags);
 
@@ -4123,7 +4123,7 @@
     if (use_output_) {
       output_.Reset();
       ASSERT_TRUE(framer_.SerializeSettings(settings_ir, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     SetFrameFlags(&frame, flags);
 
@@ -4171,7 +4171,7 @@
     if (use_output_) {
       output_.Reset();
       ASSERT_TRUE(framer_.SerializeGoAway(goaway_ir, &output_));
-      frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame = MakeSerializedFrame(output_.Begin(), output_.Size());
     }
     SetFrameFlags(&frame, flags);
 
@@ -4379,7 +4379,7 @@
     SpdySerializedFrame frame0;
     if (use_output_) {
       EXPECT_TRUE(framer.SerializeHeaders(headers_ir, &output_));
-      frame0 = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+      frame0 = MakeSerializedFrame(output_.Begin(), output_.Size());
     } else {
       frame0 = framer.SerializeHeaders(headers_ir);
     }
@@ -4390,8 +4390,7 @@
     if (use_output_) {
       char* begin = output_.Begin() + output_.Size();
       ASSERT_TRUE(framer.SerializeContinuation(continuation, &output_));
-      frame1 =
-          SpdySerializedFrame(begin, output_.Size() - frame0.size(), false);
+      frame1 = MakeSerializedFrame(begin, output_.Size() - frame0.size());
     } else {
       frame1 = framer.SerializeContinuation(continuation);
     }
@@ -4537,7 +4536,7 @@
   if (use_output_) {
     output_.Reset();
     EXPECT_EQ(framer_.SerializeFrame(altsvc_ir, &output_), frame.size());
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   deframer_->ProcessInput(frame.data(), frame.size());
 
@@ -4598,7 +4597,7 @@
   if (use_output_) {
     output_.Reset();
     EXPECT_EQ(framer_.SerializeFrame(altsvc_ir, &output_), frame.size());
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   deframer_->ProcessInput(frame.data(), frame.size());
 
@@ -4842,7 +4841,7 @@
   if (use_output_) {
     output_.Reset();
     ASSERT_TRUE(framer_.SerializePriority(priority, &output_));
-    frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
+    frame = MakeSerializedFrame(output_.Begin(), output_.Size());
   }
   testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
   deframer_->set_visitor(&visitor);
diff --git a/quiche/spdy/core/spdy_protocol.h b/quiche/spdy/core/spdy_protocol.h
index 3e9dd34..ebcb21a 100644
--- a/quiche/spdy/core/spdy_protocol.h
+++ b/quiche/spdy/core/spdy_protocol.h
@@ -996,6 +996,10 @@
   SpdySerializedFrame()
       : frame_(const_cast<char*>("")), size_(0), owns_buffer_(false) {}
 
+  // Creates a valid SpdySerializedFrame using a pre-created buffer.
+  SpdySerializedFrame(std::unique_ptr<char[]> data, size_t size)
+      : frame_(data.release()), size_(size), owns_buffer_(true) {}
+
   // Create a valid SpdySerializedFrame using a pre-created buffer.
   // If |owns_buffer| is true, this class takes ownership of the buffer and will
   // delete it on cleanup.  The buffer must have been created using new char[].
@@ -1063,10 +1067,8 @@
     return buffer;
   }
 
- protected:
-  char* frame_;
-
  private:
+  char* frame_;
   size_t size_;
   bool owns_buffer_;
 };
diff --git a/quiche/spdy/test_tools/spdy_test_utils.cc b/quiche/spdy/test_tools/spdy_test_utils.cc
index 43d97d0..fed9c16 100644
--- a/quiche/spdy/test_tools/spdy_test_utils.cc
+++ b/quiche/spdy/test_tools/spdy_test_utils.cc
@@ -97,5 +97,11 @@
   }
 }
 
+SpdySerializedFrame MakeSerializedFrame(const char* data, size_t length) {
+  std::unique_ptr<char[]> copy = std::make_unique<char[]>(length);
+  std::copy(data, data + length, copy.get());
+  return SpdySerializedFrame(std::move(copy), length);
+}
+
 }  // namespace test
 }  // namespace spdy
diff --git a/quiche/spdy/test_tools/spdy_test_utils.h b/quiche/spdy/test_tools/spdy_test_utils.h
index 366f249..5cf40cf 100644
--- a/quiche/spdy/test_tools/spdy_test_utils.h
+++ b/quiche/spdy/test_tools/spdy_test_utils.h
@@ -35,6 +35,10 @@
 
 void SetFrameLength(SpdySerializedFrame* frame, size_t length);
 
+// Makes a SpdySerializedFrame by copying the memory identified by `data` and
+// `length`.
+SpdySerializedFrame MakeSerializedFrame(const char* data, size_t length);
+
 }  // namespace test
 }  // namespace spdy