summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authormbelshe@google.com <mbelshe@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-20 15:32:32 +0000
committermbelshe@google.com <mbelshe@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-20 15:32:32 +0000
commit289b93d79e3e7a55553ae0c41fd48461e43e9d8e (patch)
tree6899338a89e927f6eff837d49ad39f91e84b4846 /net
parent9194b3fc91953bb1472d8671d2322ac5616ee0b4 (diff)
downloadchromium_src-289b93d79e3e7a55553ae0c41fd48461e43e9d8e.zip
chromium_src-289b93d79e3e7a55553ae0c41fd48461e43e9d8e.tar.gz
chromium_src-289b93d79e3e7a55553ae0c41fd48461e43e9d8e.tar.bz2
Fixup the flip_framer eof-handling semantics now that we have
the FIN bit in place. The FlipFrameVisitor will always inject a zero-length data packet to the Visitor as a signal that the data stream is complete. Even if the FIN packet was set on a SYN_REPLY (e.g. there are no data packets), the FlipFramer will simulate a zero-length read to the caller. Likewise, zero-length reads are never sent to the visitor unless the FIN packet has been received. This means that the FlipFramer must swallow zero-length data packets. Also merged in changes from server. BUG=none TEST=flip_framer_test.cc Review URL: http://codereview.chromium.org/294015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29513 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/flip/flip_frame_builder.cc2
-rw-r--r--net/flip/flip_frame_builder.h15
-rw-r--r--net/flip/flip_framer.cc97
-rw-r--r--net/flip/flip_framer.h56
-rw-r--r--net/flip/flip_framer_test.cc154
-rw-r--r--net/flip/flip_protocol.h20
-rw-r--r--net/flip/flip_session.cc3
7 files changed, 257 insertions, 90 deletions
diff --git a/net/flip/flip_frame_builder.cc b/net/flip/flip_frame_builder.cc
index 50d9607..61851b5 100644
--- a/net/flip/flip_frame_builder.cc
+++ b/net/flip/flip_frame_builder.cc
@@ -9,7 +9,7 @@
namespace flip {
- // We mark a read only FlipFrameBuilder with a special capacity_.
+// We mark a read only FlipFrameBuilder with a special capacity_.
static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max();
FlipFrameBuilder::FlipFrameBuilder()
diff --git a/net/flip/flip_frame_builder.h b/net/flip/flip_frame_builder.h
index 0640630..fa59c45 100644
--- a/net/flip/flip_frame_builder.h
+++ b/net/flip/flip_frame_builder.h
@@ -19,9 +19,7 @@
namespace flip {
// This class provides facilities for basic binary value packing and unpacking
-// into Flip frames. Note: this is similar to Chrome's pickle class, but is
-// simplified to work in both the client and server, and without excess
-// padding.
+// into Flip frames.
//
// The FlipFrameBuilder supports appending primitive values (int, string, etc)
// to a frame instance. The FlipFrameBuilder grows its internal memory buffer
@@ -86,11 +84,16 @@ class FlipFrameBuilder {
// Write an integer to a particular offset in the data buffer.
bool WriteUInt32ToOffset(int offset, uint32 value) {
- if (offset + sizeof(value) > length_)
- return false;
value = htonl(value);
+ return WriteBytesToOffset(offset, &value, sizeof(value));
+ }
+
+ // Write to a particular offset in the data buffer.
+ bool WriteBytesToOffset(int offset, const void* data, uint32 data_len) {
+ if (offset + data_len > length_)
+ return false;
char *ptr = buffer_ + offset;
- memcpy(ptr, &value, sizeof(value));
+ memcpy(ptr, data, data_len);
return true;
}
diff --git a/net/flip/flip_framer.cc b/net/flip/flip_framer.cc
index b5b611f..c0136d0 100644
--- a/net/flip/flip_framer.cc
+++ b/net/flip/flip_framer.cc
@@ -262,19 +262,29 @@ size_t FlipFramer::ProcessInput(const char* data, size_t len) {
}
size_t decompressed_size = decompressed_max_size -
decompressor_->avail_out;
- visitor_->OnStreamFrameData(current_data_frame->stream_id(),
- decompressed.get(),
- decompressed_size);
+ // Only inform the visitor if there is data.
+ if (decompressed_size)
+ visitor_->OnStreamFrameData(current_data_frame->stream_id(),
+ decompressed.get(),
+ decompressed_size);
amount_to_forward -= decompressor_->avail_in;
} else {
- // The data frame was not compressed
- visitor_->OnStreamFrameData(current_data_frame->stream_id(),
- data, amount_to_forward);
+ // The data frame was not compressed.
+ // Only inform the visitor if there is data.
+ if (amount_to_forward)
+ visitor_->OnStreamFrameData(current_data_frame->stream_id(),
+ data, amount_to_forward);
}
}
data += amount_to_forward;
len -= amount_to_forward;
remaining_payload_ -= amount_to_forward;
+ // If the FIN flag is set, and there is no more data in this data
+ // frame, inform the visitor of EOF via a 0-length data frame.
+ if (!remaining_payload_ &&
+ current_data_frame->flags() & DATA_FLAG_FIN)
+ visitor_->OnStreamFrameData(current_data_frame->stream_id(), NULL,
+ 0);
} else {
CHANGE_STATE(FLIP_AUTO_RESET);
}
@@ -305,11 +315,12 @@ size_t FlipFramer::ProcessCommonHeader(const char* data, size_t len) {
current_frame_len_ += bytes_to_append;
data += bytes_to_append;
len -= bytes_to_append;
- // Check for an empty data packet.
+ // Check for an empty data frame.
if (current_frame_len_ == sizeof(FlipFrame) &&
!current_frame->is_control_frame() &&
current_frame->length() == 0) {
- visitor_->OnStreamFrameData(current_frame->stream_id(), NULL, 0);
+ if (current_frame->flags() & CONTROL_FLAG_FIN)
+ visitor_->OnStreamFrameData(current_frame->stream_id(), NULL, 0);
CHANGE_STATE(FLIP_RESET);
}
break;
@@ -343,6 +354,12 @@ size_t FlipFramer::ProcessControlFramePayload(const char* data, size_t len) {
FlipControlFrame* control_frame =
reinterpret_cast<FlipControlFrame*>(current_frame_buffer_);
visitor_->OnControl(control_frame);
+
+ // If this is a FIN, tell the caller.
+ if (control_frame->type() == SYN_REPLY &&
+ control_frame->flags() & CONTROL_FLAG_FIN)
+ visitor_->OnStreamFrameData(control_frame->stream_id(), NULL, 0);
+
CHANGE_STATE(FLIP_IGNORE_REMAINING_PAYLOAD);
} while (false);
return original_len - len;
@@ -403,15 +420,13 @@ bool FlipFramer::ParseHeaderBlock(const FlipFrame* frame,
}
FlipSynStreamControlFrame* FlipFramer::CreateSynStream(
- int stream_id,
- int priority,
- bool compress,
- FlipHeaderBlock* headers) {
+ FlipStreamId stream_id, int priority, FlipControlFlags flags,
+ bool compressed, FlipHeaderBlock* headers) {
FlipFrameBuilder frame;
frame.WriteUInt16(kControlFlagMask | kFlipProtocolVersion);
frame.WriteUInt16(SYN_STREAM);
- frame.WriteUInt32(0); // Placeholder for the length.
+ frame.WriteUInt32(0); // Placeholder for the length and flags
frame.WriteUInt32(stream_id);
frame.WriteUInt16(ntohs(priority) << 6); // Priority.
@@ -421,9 +436,16 @@ FlipSynStreamControlFrame* FlipFramer::CreateSynStream(
frame.WriteString(it->first);
frame.WriteString(it->second);
}
- // write the length
- frame.WriteUInt32ToOffset(4, frame.length() - sizeof(FlipFrame));
- if (compress) {
+
+ // Write the length and flags.
+ size_t length = frame.length() - sizeof(FlipFrame);
+ DCHECK(length < static_cast<size_t>(kLengthMask));
+ FlagsAndLength flags_length;
+ flags_length.length_ = htonl(static_cast<uint32>(length));
+ flags_length.flags_[0] = flags;
+ frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length));
+
+ if (compressed) {
FlipSynStreamControlFrame* new_frame =
reinterpret_cast<FlipSynStreamControlFrame*>(
CompressFrame(frame.data()));
@@ -434,7 +456,7 @@ FlipSynStreamControlFrame* FlipFramer::CreateSynStream(
}
/* static */
-FlipFinStreamControlFrame* FlipFramer::CreateFinStream(int stream_id,
+FlipFinStreamControlFrame* FlipFramer::CreateFinStream(FlipStreamId stream_id,
int status) {
FlipFrameBuilder frame;
frame.WriteUInt16(kControlFlagMask | kFlipProtocolVersion);
@@ -445,16 +467,16 @@ FlipFinStreamControlFrame* FlipFramer::CreateFinStream(int stream_id,
return reinterpret_cast<FlipFinStreamControlFrame*>(frame.take());
}
-FlipSynReplyControlFrame* FlipFramer::CreateSynReply(int stream_id,
- bool compressed, FlipHeaderBlock* headers) {
+FlipSynReplyControlFrame* FlipFramer::CreateSynReply(FlipStreamId stream_id,
+ FlipControlFlags flags, bool compressed, FlipHeaderBlock* headers) {
FlipFrameBuilder frame;
frame.WriteUInt16(kControlFlagMask | kFlipProtocolVersion);
frame.WriteUInt16(SYN_REPLY);
- frame.WriteUInt32(0); // Placeholder for the length.
+ frame.WriteUInt32(0); // Placeholder for the length and flags.
frame.WriteUInt32(stream_id);
- frame.WriteUInt16(0); // Priority.
+ frame.WriteUInt16(0); // Unused
frame.WriteUInt16(headers->size()); // Number of headers.
FlipHeaderBlock::iterator it;
@@ -463,28 +485,49 @@ FlipSynReplyControlFrame* FlipFramer::CreateSynReply(int stream_id,
frame.WriteString(it->first);
frame.WriteString(it->second);
}
- // write the length
- frame.WriteUInt32ToOffset(4, frame.length() - sizeof(FlipFrame));
+
+ // Write the length
+ size_t length = frame.length() - sizeof(FlipFrame);
+ DCHECK(length < static_cast<size_t>(kLengthMask));
+ FlagsAndLength flags_length;
+ flags_length.length_ = htonl(static_cast<uint32>(length));
+ flags_length.flags_[0] = flags;
+ frame.WriteBytesToOffset(4, &flags_length, sizeof(flags_length));
+
if (compressed)
return reinterpret_cast<FlipSynReplyControlFrame*>(
CompressFrame(frame.data()));
return reinterpret_cast<FlipSynReplyControlFrame*>(frame.take());
}
-FlipDataFrame* FlipFramer::CreateDataFrame(int stream_id,
+FlipDataFrame* FlipFramer::CreateDataFrame(FlipStreamId stream_id,
const char* data,
- int len, bool compressed) {
+ uint32 len, FlipDataFlags flags) {
FlipFrameBuilder frame;
frame.WriteUInt32(stream_id);
- frame.WriteUInt32(len);
+ DCHECK(len < static_cast<size_t>(kLengthMask));
+ FlagsAndLength flags_length;
+ flags_length.length_ = htonl(len);
+ flags_length.flags_[0] = flags;
+ frame.WriteBytes(&flags_length, sizeof(flags_length));
+
frame.WriteBytes(data, len);
- if (compressed)
+ if (flags & DATA_FLAG_COMPRESSED)
return reinterpret_cast<FlipDataFrame*>(CompressFrame(frame.data()));
return reinterpret_cast<FlipDataFrame*>(frame.take());
}
+/* static */
+FlipControlFrame* FlipFramer::CreateNopFrame() {
+ FlipFrameBuilder frame;
+ frame.WriteUInt16(kControlFlagMask | kFlipProtocolVersion);
+ frame.WriteUInt16(NOOP);
+ frame.WriteUInt32(0);
+ return reinterpret_cast<FlipControlFrame*>(frame.take());
+}
+
static const int kCompressorLevel = Z_DEFAULT_COMPRESSION;
// This is just a hacked dictionary to use for shrinking HTTP-like headers.
// TODO(mbelshe): Use a scientific methodology for computing the dictionary.
diff --git a/net/flip/flip_framer.h b/net/flip/flip_framer.h
index 5275017..8f89c30 100644
--- a/net/flip/flip_framer.h
+++ b/net/flip/flip_framer.h
@@ -29,6 +29,7 @@ namespace flip {
class FlipFramer;
class FlipFramerTest;
+class TestFlipVisitor;
// A datastructure for holding a set of headers from either a
// SYN_STREAM or SYN_REPLY frame.
@@ -48,6 +49,11 @@ class FlipFramerVisitorInterface {
virtual void OnControl(const FlipControlFrame* frame) = 0;
// Called when data is received.
+ // |stream_id| The stream receiving data.
+ // |data| A buffer containing the data received.
+ // |len| The length of the data buffer.
+ // When the other side has finished sending data on this stream,
+ // this method will be called with a zero-length buffer.
virtual void OnStreamFrameData(flip::FlipStreamId stream_id,
const char* data,
size_t len) = 0;
@@ -120,24 +126,44 @@ class FlipFramer {
// Returns true if successfully parsed, false otherwise.
bool ParseHeaderBlock(const FlipFrame* frame, FlipHeaderBlock* block);
- // Frame creation utilities
- // Create a FlipSynStreamControlFrame. The resulting frame will be
- // compressed if |compressed| is true.
- FlipSynStreamControlFrame* CreateSynStream(int stream_id, int priority,
- bool compress,
+ // Create a FlipSynStreamControlFrame.
+ // |stream_id| is the stream for this frame.
+ // |priority| is the priority (0-3) for this frame.
+ // |flags| is the flags to use with the data.
+ // To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
+ // |compressed| specifies whether the frame should be compressed.
+ // |headers| is the header block to include in the frame.
+ FlipSynStreamControlFrame* CreateSynStream(FlipStreamId stream_id,
+ int priority,
+ FlipControlFlags flags,
+ bool compressed,
FlipHeaderBlock* headers);
- static FlipFinStreamControlFrame* CreateFinStream(int stream_id, int status);
- // Create a FlipSynReplyControlFrame.The resulting frame will be
- // compressed if |compressed| is true.
- FlipSynReplyControlFrame* CreateSynReply(int stream_id,
- bool compress,
+ static FlipFinStreamControlFrame* CreateFinStream(FlipStreamId stream_id,
+ int status);
+
+ // Create a FlipSynReplyControlFrame.
+ // |stream_id| is the stream for this frame.
+ // |flags| is the flags to use with the data.
+ // To mark this frame as the last frame, enable CONTROL_FLAG_FIN.
+ // |compressed| specifies whether the frame should be compressed.
+ // |headers| is the header block to include in the frame.
+ FlipSynReplyControlFrame* CreateSynReply(FlipStreamId stream_id,
+ FlipControlFlags flags,
+ bool compressed,
FlipHeaderBlock* headers);
- // Create a FlipDataFrame. The resulting frame will be
- // compressed if |compressed| is true.
- FlipDataFrame* CreateDataFrame(int stream_id, const char* data,
- int len, bool compressed);
+ // Create a data frame.
+ // |stream_id| is the stream for this frame
+ // |data| is the data to be included in the frame.
+ // |len| is the length of the data
+ // |flags| is the flags to use with the data.
+ // To create a compressed frame, enable DATA_FLAG_COMPRESSED.
+ // To mark this frame as the last data frame, enable DATA_FLAG_FIN.
+ FlipDataFrame* CreateDataFrame(FlipStreamId stream_id, const char* data,
+ uint32 len, FlipDataFlags flags);
+
+ static FlipControlFrame* CreateNopFrame();
// NOTES about frame compression.
// We want flip to compress headers across the entire session. As long as
@@ -172,9 +198,9 @@ class FlipFramer {
static const char* ErrorCodeToString(int error_code);
protected:
- FRIEND_TEST(FlipFramerTest, Basic);
FRIEND_TEST(FlipFramerTest, HeaderBlockBarfsOnOutOfOrderHeaders);
friend class net::FlipNetworkTransactionTest;
+ friend class flip::TestFlipVisitor;
// For ease of testing we can tweak compression on/off.
void set_enable_compression(bool value);
diff --git a/net/flip/flip_framer_test.cc b/net/flip/flip_framer_test.cc
index 979c541..bee0432 100644
--- a/net/flip/flip_framer_test.cc
+++ b/net/flip/flip_framer_test.cc
@@ -19,22 +19,27 @@ class FlipFramerTest : public PlatformTest {
class TestFlipVisitor : public FlipFramerVisitorInterface {
public:
- explicit TestFlipVisitor(FlipFramer* framer)
- : framer_(framer),
- error_count_(0),
+ explicit TestFlipVisitor()
+ : error_count_(0),
syn_frame_count_(0),
syn_reply_frame_count_(0),
- data_frame_count_(0),
- fin_frame_count_(0) {
+ data_bytes_(0),
+ fin_frame_count_(0),
+ fin_flag_count_(0),
+ zero_length_data_frame_count_(0) {
}
void OnError(FlipFramer* f) {
error_count_++;
}
+
void OnStreamFrameData(FlipStreamId stream_id,
const char* data,
size_t len) {
- data_frame_count_++;
+ if (len == 0)
+ zero_length_data_frame_count_++;
+
+ data_bytes_ += len;
#ifdef TEST_LOGGING
std::cerr << "OnStreamFrameData(" << stream_id << ", \"";
if (len > 0) {
@@ -51,13 +56,13 @@ class TestFlipVisitor : public FlipFramerVisitorInterface {
bool parsed_headers = false;
switch (frame->type()) {
case SYN_STREAM:
- parsed_headers = framer_->ParseHeaderBlock(
+ parsed_headers = framer_.ParseHeaderBlock(
reinterpret_cast<const FlipFrame*>(frame), &headers);
DCHECK(parsed_headers);
syn_frame_count_++;
break;
case SYN_REPLY:
- parsed_headers = framer_->ParseHeaderBlock(
+ parsed_headers = framer_.ParseHeaderBlock(
reinterpret_cast<const FlipFrame*>(frame), &headers);
DCHECK(parsed_headers);
syn_reply_frame_count_++;
@@ -68,18 +73,44 @@ class TestFlipVisitor : public FlipFramerVisitorInterface {
default:
DCHECK(false); // Error!
}
+ if (frame->flags() & CONTROL_FLAG_FIN)
+ fin_flag_count_++;
}
void OnLameDuck() {
}
- FlipFramer* framer_;
+ // Convenience function which runs a framer simulation with particular input.
+ void SimulateInFramer(const unsigned char* input, size_t size) {
+ framer_.set_enable_compression(false);
+ framer_.set_visitor(this);
+ size_t input_remaining = size;
+ const char* input_ptr = reinterpret_cast<const char*>(input);
+ while (input_remaining > 0 &&
+ framer_.error_code() == FlipFramer::FLIP_NO_ERROR) {
+ // To make the tests more interesting, we feed random (amd small) chunks
+ // into the framer. This simulates getting strange-sized reads from
+ // the socket.
+ const size_t kMaxReadSize = 32;
+ size_t bytes_read =
+ (rand() % std::min(input_remaining, kMaxReadSize)) + 1;
+ size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read);
+ input_remaining -= bytes_processed;
+ input_ptr += bytes_processed;
+ if (framer_.state() == FlipFramer::FLIP_DONE)
+ framer_.Reset();
+ }
+ }
+
+ FlipFramer framer_;
// Counters from the visitor callbacks.
int error_count_;
int syn_frame_count_;
int syn_reply_frame_count_;
- int data_frame_count_;
- int fin_frame_count_;
+ int data_bytes_;
+ int fin_frame_count_; // The count of FIN_STREAM type frames received.
+ int fin_flag_count_; // The count of frames with the FIN flag set.
+ int zero_length_data_frame_count_; // The count of zero-length data frames.
};
// Test our protocol constants
@@ -125,7 +156,7 @@ TEST_F(FlipFramerTest, ControlFrameStructs) {
FlipHeaderBlock headers;
scoped_array<FlipSynStreamControlFrame> syn_frame(
- framer.CreateSynStream(123, 2, false, &headers));
+ framer.CreateSynStream(123, 2, CONTROL_FLAG_NONE, false, &headers));
EXPECT_EQ(kFlipProtocolVersion, syn_frame.get()->version());
EXPECT_EQ(true, syn_frame.get()->is_control_frame());
EXPECT_EQ(SYN_STREAM, syn_frame.get()->type());
@@ -134,7 +165,7 @@ TEST_F(FlipFramerTest, ControlFrameStructs) {
EXPECT_EQ(2, syn_frame.get()->header_block_len());
scoped_array<FlipSynReplyControlFrame> syn_reply(
- framer.CreateSynReply(123, false, &headers));
+ framer.CreateSynReply(123, CONTROL_FLAG_NONE, false, &headers));
EXPECT_EQ(kFlipProtocolVersion, syn_reply.get()->version());
EXPECT_EQ(true, syn_reply.get()->is_control_frame());
EXPECT_EQ(SYN_REPLY, syn_reply.get()->type());
@@ -161,7 +192,7 @@ TEST_F(FlipFramerTest, HeaderBlock) {
// Encode the header block into a SynStream frame.
scoped_array<FlipSynStreamControlFrame> frame(
- framer.CreateSynStream(1, 1, true, &headers));
+ framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, true, &headers));
EXPECT_TRUE(frame.get() != NULL);
FlipHeaderBlock new_headers;
@@ -209,9 +240,9 @@ TEST_F(FlipFramerTest, BasicCompression) {
FlipFramer framer;
scoped_array<FlipSynStreamControlFrame>
- frame1(framer.CreateSynStream(1, 1, true, &headers));
+ frame1(framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, true, &headers));
scoped_array<FlipSynStreamControlFrame>
- frame2(framer.CreateSynStream(1, 1, true, &headers));
+ frame2(framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, true, &headers));
// Expect the second frame to be more compact than the first.
EXPECT_LE(frame2.get()->length(), frame1.get()->length());
@@ -273,25 +304,86 @@ TEST_F(FlipFramerTest, Basic) {
0x00, 0x00, 0x00, 0x00,
};
- FlipFramer framer;
- framer.set_enable_compression(false);
- TestFlipVisitor visitor(&framer);
- framer.set_visitor(&visitor);
- size_t input_remaining = sizeof(input);
- const char* input_ptr = reinterpret_cast<const char*>(input);
- while (input_remaining > 0 &&
- framer.error_code() == FlipFramer::FLIP_NO_ERROR) {
- size_t bytes_processed = framer.ProcessInput(input_ptr, sizeof(input));
- input_remaining -= bytes_processed;
- input_ptr += bytes_processed;
- if (framer.state() == FlipFramer::FLIP_DONE)
- framer.Reset();
- }
+ TestFlipVisitor visitor;
+ visitor.SimulateInFramer(input, sizeof(input));
+
EXPECT_EQ(0, visitor.error_count_);
EXPECT_EQ(2, visitor.syn_frame_count_);
EXPECT_EQ(0, visitor.syn_reply_frame_count_);
- EXPECT_EQ(4, visitor.data_frame_count_);
+ EXPECT_EQ(24, visitor.data_bytes_);
EXPECT_EQ(2, visitor.fin_frame_count_);
+ EXPECT_EQ(0, visitor.fin_flag_count_);
+ EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
+}
+
+// Test that the FIN flag on a data frame signifies EOF.
+TEST_F(FlipFramerTest, FinOnDataFrame) {
+ const unsigned char input[] = {
+ 0x80, 0x01, 0x00, 0x01, // SYN Stream #1
+ 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x02, 'h', 'h',
+ 0x00, 0x02, 'v', 'v',
+
+ 0x80, 0x01, 0x00, 0x02, // SYN REPLY Stream #1
+ 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x02, 'a', 'a',
+ 0x00, 0x02, 'b', 'b',
+
+ 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1
+ 0x00, 0x00, 0x00, 0x0c,
+ 0xde, 0xad, 0xbe, 0xef,
+ 0xde, 0xad, 0xbe, 0xef,
+ 0xde, 0xad, 0xbe, 0xef,
+
+ 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1, with EOF
+ 0x01, 0x00, 0x00, 0x04,
+ 0xde, 0xad, 0xbe, 0xef,
+ };
+
+ TestFlipVisitor visitor;
+ visitor.SimulateInFramer(input, sizeof(input));
+
+ EXPECT_EQ(0, visitor.error_count_);
+ EXPECT_EQ(1, visitor.syn_frame_count_);
+ EXPECT_EQ(1, visitor.syn_reply_frame_count_);
+ EXPECT_EQ(16, visitor.data_bytes_);
+ EXPECT_EQ(0, visitor.fin_frame_count_);
+ EXPECT_EQ(0, visitor.fin_flag_count_);
+ EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
+}
+
+// Test that the FIN flag on a SYN reply frame signifies EOF.
+TEST_F(FlipFramerTest, FinOnSynReplyFrame) {
+ const unsigned char input[] = {
+ 0x80, 0x01, 0x00, 0x01, // SYN Stream #1
+ 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x02, 'h', 'h',
+ 0x00, 0x02, 'v', 'v',
+
+ 0x80, 0x01, 0x00, 0x02, // SYN REPLY Stream #1
+ 0x01, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x02, 'a', 'a',
+ 0x00, 0x02, 'b', 'b',
+ };
+
+ TestFlipVisitor visitor;
+ visitor.SimulateInFramer(input, sizeof(input));
+
+ EXPECT_EQ(0, visitor.error_count_);
+ EXPECT_EQ(1, visitor.syn_frame_count_);
+ EXPECT_EQ(1, visitor.syn_reply_frame_count_);
+ EXPECT_EQ(0, visitor.data_bytes_);
+ EXPECT_EQ(0, visitor.fin_frame_count_);
+ EXPECT_EQ(1, visitor.fin_flag_count_);
+ EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
}
} // namespace flip
diff --git a/net/flip/flip_protocol.h b/net/flip/flip_protocol.h
index c737473..8a585bc 100644
--- a/net/flip/flip_protocol.h
+++ b/net/flip/flip_protocol.h
@@ -89,23 +89,25 @@ const int kFlipProtocolVersion = 1;
// accessors provided or call ntohX() functions.
// Types of Flip Control Frames.
-typedef enum {
+enum FlipControlType {
SYN_STREAM = 1,
SYN_REPLY,
FIN_STREAM,
NOOP
-} FlipControlType;
+};
// Flags on data packets
-typedef enum {
+enum FlipDataFlags {
+ DATA_FLAG_NONE = 0,
DATA_FLAG_FIN = 1,
DATA_FLAG_COMPRESSED = 2 // TODO(mbelshe): remove me.
-} FlipDataFlags;
+};
// Flags on control packets
-typedef enum {
+enum FlipControlFlags {
+ CONTROL_FLAG_NONE = 0,
CONTROL_FLAG_FIN = 1
-} FlipControlFlags;
+};
// A FLIP stream id is a 31 bit entity.
typedef uint32 FlipStreamId;
@@ -115,10 +117,10 @@ typedef uint32 FlipStreamId;
#define FLIP_PRIORITY_HIGHEST 0
// A special structure for the 8 bit flags and 24 bit length fields.
-typedef union {
+union FlagsAndLength {
uint8 flags_[4]; // 8 bits
uint32 length_; // 24 bits
-} FlagsLength;
+};
// All Flip Frame types derive from the FlipFrame struct.
typedef struct {
@@ -146,7 +148,7 @@ typedef struct {
FlipStreamId stream_id_;
} data_;
};
- FlagsLength flags_length_;
+ FlagsAndLength flags_length_;
} FlipFrame;
// A Data Frame.
diff --git a/net/flip/flip_session.cc b/net/flip/flip_session.cc
index 51631f9..c8cb53d 100644
--- a/net/flip/flip_session.cc
+++ b/net/flip/flip_session.cc
@@ -267,7 +267,8 @@ int FlipSession::CreateStream(FlipDelegate* delegate) {
// Create a SYN_STREAM packet and add to the output queue.
flip::FlipSynStreamControlFrame* syn_frame =
- flip_framer_.CreateSynStream(stream_id, priority, false, &headers);
+ flip_framer_.CreateSynStream(stream_id, priority,
+ flip::CONTROL_FLAG_NONE, false, &headers);
int length = sizeof(flip::FlipFrame) + syn_frame->length();
IOBufferWithSize* buffer =
new IOBufferWithSize(length);