diff options
Diffstat (limited to 'net/flip')
-rw-r--r-- | net/flip/flip_frame_builder.h | 7 | ||||
-rw-r--r-- | net/flip/flip_framer.cc | 353 | ||||
-rw-r--r-- | net/flip/flip_framer.h | 16 | ||||
-rw-r--r-- | net/flip/flip_framer_test.cc | 164 | ||||
-rw-r--r-- | net/flip/flip_protocol.h | 262 | ||||
-rw-r--r-- | net/flip/flip_protocol_test.cc | 182 | ||||
-rw-r--r-- | net/flip/flip_session.cc | 31 | ||||
-rw-r--r-- | net/flip/flip_session.h | 1 |
8 files changed, 362 insertions, 654 deletions
diff --git a/net/flip/flip_frame_builder.h b/net/flip/flip_frame_builder.h index 32b6035..fa59c45 100644 --- a/net/flip/flip_frame_builder.h +++ b/net/flip/flip_frame_builder.h @@ -43,9 +43,14 @@ class FlipFrameBuilder { // Returns the size of the FlipFrameBuilder's data. int length() const { return length_; } + // Returns the data for this FlipFrameBuilder. + const FlipFrame* data() const { + return reinterpret_cast<FlipFrame*>(buffer_); + } + // Takes the buffer from the FlipFrameBuilder. FlipFrame* take() { - FlipFrame* rv = new FlipFrame(buffer_, true); + FlipFrame* rv = reinterpret_cast<FlipFrame*>(buffer_); buffer_ = NULL; capacity_ = 0; length_ = 0; diff --git a/net/flip/flip_framer.cc b/net/flip/flip_framer.cc index 31d1234..c0136d0 100644 --- a/net/flip/flip_framer.cc +++ b/net/flip/flip_framer.cc @@ -105,8 +105,8 @@ size_t FlipFramer::BytesSafeToRead() const { case FLIP_RESET: return 0; case FLIP_READING_COMMON_HEADER: - DCHECK(current_frame_len_ < FlipFrame::size()); - return FlipFrame::size() - current_frame_len_; + DCHECK(current_frame_len_ < sizeof(FlipFrame)); + return sizeof(FlipFrame) - current_frame_len_; case FLIP_INTERPRET_CONTROL_FRAME_COMMON_HEADER: return 0; case FLIP_CONTROL_FRAME_PAYLOAD: @@ -151,6 +151,11 @@ size_t FlipFramer::ProcessInput(const char* data, size_t len) { size_t original_len = len; while (len != 0) { + FlipControlFrame* current_control_frame = + reinterpret_cast<FlipControlFrame*>(current_frame_buffer_); + FlipDataFrame* current_data_frame = + reinterpret_cast<FlipDataFrame*>(current_frame_buffer_); + switch (state_) { case FLIP_ERROR: case FLIP_DONE: @@ -173,7 +178,52 @@ size_t FlipFramer::ProcessInput(const char* data, size_t len) { // I felt it was a nice partitioning, however (which probably indicates // that it should be refactored into its own function!) case FLIP_INTERPRET_CONTROL_FRAME_COMMON_HEADER: - ProcessControlFrameHeader(); + DCHECK(error_code_ == 0); + DCHECK(current_frame_len_ >= sizeof(FlipFrame)); + // Do some sanity checking on the control frame sizes. + switch (current_control_frame->type()) { + case SYN_STREAM: + // NOTE: sizeof(FlipSynStreamControlFrame) is not accurate. + if (current_control_frame->length() < + sizeof(FlipSynStreamControlFrame) - sizeof(FlipControlFrame)) + set_error(FLIP_INVALID_CONTROL_FRAME); + break; + case SYN_REPLY: + if (current_control_frame->length() < + sizeof(FlipSynReplyControlFrame) - sizeof(FlipControlFrame)) + set_error(FLIP_INVALID_CONTROL_FRAME); + break; + case FIN_STREAM: + if (current_control_frame->length() != + sizeof(FlipFinStreamControlFrame) - sizeof(FlipFrame)) + set_error(FLIP_INVALID_CONTROL_FRAME); + break; + case NOOP: + // NOP. Swallow it. + CHANGE_STATE(FLIP_AUTO_RESET); + continue; + default: + set_error(FLIP_UNKNOWN_CONTROL_TYPE); + break; + } + + // We only support version 1 of this protocol. + if (current_control_frame->version() != kFlipProtocolVersion) + set_error(FLIP_UNSUPPORTED_VERSION); + + if (error_code_) { + CHANGE_STATE(FLIP_ERROR); + goto bottom; + } + + remaining_control_payload_ = current_control_frame->length(); + if (remaining_control_payload_ > kControlFrameBufferMaxSize) { + set_error(FLIP_CONTROL_PAYLOAD_TOO_LARGE); + CHANGE_STATE(FLIP_ERROR); + goto bottom; + } + ExpandControlFrameBuffer(remaining_control_payload_); + CHANGE_STATE(FLIP_CONTROL_FRAME_PAYLOAD); continue; case FLIP_CONTROL_FRAME_PAYLOAD: { @@ -185,12 +235,60 @@ size_t FlipFramer::ProcessInput(const char* data, size_t len) { case FLIP_IGNORE_REMAINING_PAYLOAD: // control frame has too-large payload // intentional fallthrough - case FLIP_FORWARD_STREAM_FRAME: { - int bytes_read = ProcessDataFramePayload(data, len); - len -= bytes_read; - data += bytes_read; + case FLIP_FORWARD_STREAM_FRAME: + if (remaining_payload_) { + size_t amount_to_forward = std::min(remaining_payload_, len); + if (amount_to_forward && state_ != FLIP_IGNORE_REMAINING_PAYLOAD) { + const FlipDataFrame* data_frame = + reinterpret_cast<const FlipDataFrame*>(current_data_frame); + if (data_frame->flags() & DATA_FLAG_COMPRESSED) { + // TODO(mbelshe): Assert that the decompressor is init'ed. + if (!InitializeDecompressor()) + return NULL; + + size_t decompressed_max_size = amount_to_forward * 100; + scoped_array<char> decompressed(new char[decompressed_max_size]); + decompressor_->next_in = reinterpret_cast<Bytef*>( + const_cast<char*>(data)); + decompressor_->avail_in = amount_to_forward; + decompressor_->next_out = + reinterpret_cast<Bytef*>(decompressed.get()); + decompressor_->avail_out = decompressed_max_size; + + int rv = inflate(decompressor_.get(), Z_SYNC_FLUSH); + if (rv != Z_OK) { + set_error(FLIP_DECOMPRESS_FAILURE); + goto bottom; + } + size_t decompressed_size = decompressed_max_size - + decompressor_->avail_out; + // 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. + // 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); + } continue; - } default: break; } @@ -205,11 +303,12 @@ size_t FlipFramer::ProcessCommonHeader(const char* data, size_t len) { DCHECK(state_ == FLIP_READING_COMMON_HEADER); int original_len = len; - FlipFrame current_frame(current_frame_buffer_, false); + FlipDataFrame* current_frame = + reinterpret_cast<FlipDataFrame*>(current_frame_buffer_); do { - if (current_frame_len_ < FlipFrame::size()) { - size_t bytes_desired = FlipFrame::size() - current_frame_len_; + if (current_frame_len_ < sizeof(FlipFrame)) { + size_t bytes_desired = sizeof(FlipFrame) - current_frame_len_; size_t bytes_to_append = std::min(bytes_desired, len); char* header_buffer = current_frame_buffer_; memcpy(&header_buffer[current_frame_len_], data, bytes_to_append); @@ -217,20 +316,18 @@ size_t FlipFramer::ProcessCommonHeader(const char* data, size_t len) { data += bytes_to_append; len -= bytes_to_append; // Check for an empty data frame. - if (current_frame_len_ == FlipFrame::size() && - !current_frame.is_control_frame() && - current_frame.length() == 0) { - if (current_frame.flags() & CONTROL_FLAG_FIN) { - FlipDataFrame data_frame(current_frame_buffer_, false); - visitor_->OnStreamFrameData(data_frame.stream_id(), NULL, 0); - } + if (current_frame_len_ == sizeof(FlipFrame) && + !current_frame->is_control_frame() && + current_frame->length() == 0) { + if (current_frame->flags() & CONTROL_FLAG_FIN) + visitor_->OnStreamFrameData(current_frame->stream_id(), NULL, 0); CHANGE_STATE(FLIP_RESET); } break; } - remaining_payload_ = current_frame.length(); + remaining_payload_ = current_frame->length(); // if we're here, then we have the common header all received. - if (!current_frame.is_control_frame()) + if (!current_frame->is_control_frame()) CHANGE_STATE(FLIP_FORWARD_STREAM_FRAME); else CHANGE_STATE(FLIP_INTERPRET_CONTROL_FRAME_COMMON_HEADER); @@ -239,55 +336,6 @@ size_t FlipFramer::ProcessCommonHeader(const char* data, size_t len) { return original_len - len; } -void FlipFramer::ProcessControlFrameHeader() { - FlipControlFrame current_control_frame(current_frame_buffer_, false); - DCHECK_EQ(FLIP_NO_ERROR, error_code_); - DCHECK_LE(FlipFrame::size(), current_frame_len_); - // Do some sanity checking on the control frame sizes. - switch (current_control_frame.type()) { - case SYN_STREAM: - if (current_control_frame.length() < - FlipSynStreamControlFrame::size() - FlipControlFrame::size()) - set_error(FLIP_INVALID_CONTROL_FRAME); - break; - case SYN_REPLY: - if (current_control_frame.length() < - FlipSynReplyControlFrame::size() - FlipControlFrame::size()) - set_error(FLIP_INVALID_CONTROL_FRAME); - break; - case FIN_STREAM: - if (current_control_frame.length() != - FlipFinStreamControlFrame::size() - FlipFrame::size()) - set_error(FLIP_INVALID_CONTROL_FRAME); - break; - case NOOP: - // NOP. Swallow it. - CHANGE_STATE(FLIP_AUTO_RESET); - return; - default: - set_error(FLIP_UNKNOWN_CONTROL_TYPE); - break; - } - - // We only support version 1 of this protocol. - if (current_control_frame.version() != kFlipProtocolVersion) - set_error(FLIP_UNSUPPORTED_VERSION); - - if (error_code_) { - CHANGE_STATE(FLIP_ERROR); - return; - } - - remaining_control_payload_ = current_control_frame.length(); - if (remaining_control_payload_ > kControlFrameBufferMaxSize) { - set_error(FLIP_CONTROL_PAYLOAD_TOO_LARGE); - CHANGE_STATE(FLIP_ERROR); - return; - } - ExpandControlFrameBuffer(remaining_control_payload_); - CHANGE_STATE(FLIP_CONTROL_FRAME_PAYLOAD); -} - size_t FlipFramer::ProcessControlFramePayload(const char* data, size_t len) { size_t original_len = len; do { @@ -303,85 +351,26 @@ size_t FlipFramer::ProcessControlFramePayload(const char* data, size_t len) { if (remaining_control_payload_) break; } - FlipControlFrame control_frame(current_frame_buffer_, false); - visitor_->OnControl(&control_frame); + 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); + 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; } -size_t FlipFramer::ProcessDataFramePayload(const char* data, size_t len) { - size_t original_len = len; - - FlipDataFrame current_data_frame(current_frame_buffer_, false); - if (remaining_payload_) { - size_t amount_to_forward = std::min(remaining_payload_, len); - if (amount_to_forward && state_ != FLIP_IGNORE_REMAINING_PAYLOAD) { - if (current_data_frame.flags() & DATA_FLAG_COMPRESSED) { - // TODO(mbelshe): Assert that the decompressor is init'ed. - if (!InitializeDecompressor()) - return NULL; - - size_t decompressed_max_size = amount_to_forward * 100; - scoped_ptr<char> decompressed(new char[decompressed_max_size]); - decompressor_->next_in = reinterpret_cast<Bytef*>( - const_cast<char*>(data)); - decompressor_->avail_in = amount_to_forward; - decompressor_->next_out = - reinterpret_cast<Bytef*>(decompressed.get()); - decompressor_->avail_out = decompressed_max_size; - - int rv = inflate(decompressor_.get(), Z_SYNC_FLUSH); - if (rv != Z_OK) { - set_error(FLIP_DECOMPRESS_FAILURE); - goto bottom; - } - size_t decompressed_size = decompressed_max_size - - decompressor_->avail_out; - // 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. - // 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); - } - - bottom: - return original_len - len; -} - void FlipFramer::ExpandControlFrameBuffer(size_t size) { DCHECK(size < kControlFrameBufferMaxSize); if (size < current_frame_capacity_) return; - int alloc_size = size + FlipFrame::size(); + int alloc_size = size + sizeof(FlipFrame); char* new_buffer = new char[alloc_size]; memcpy(new_buffer, current_frame_buffer_, current_frame_len_); current_frame_capacity_ = alloc_size; @@ -390,18 +379,17 @@ void FlipFramer::ExpandControlFrameBuffer(size_t size) { bool FlipFramer::ParseHeaderBlock(const FlipFrame* frame, FlipHeaderBlock* block) { - FlipControlFrame control_frame(frame->data(), false); - uint32 type = control_frame.type(); + uint32 type = reinterpret_cast<const FlipControlFrame*>(frame)->type(); if (type != SYN_STREAM && type != SYN_REPLY) return false; // Find the header data within the control frame. - scoped_ptr<FlipFrame> decompressed_frame(DecompressFrame(frame)); - if (!decompressed_frame.get()) + scoped_array<FlipSynStreamControlFrame> control_frame( + reinterpret_cast<FlipSynStreamControlFrame*>(DecompressFrame(frame))); + if (!control_frame.get()) return false; - FlipSynStreamControlFrame syn_frame(decompressed_frame->data(), false); - const char *header_data = syn_frame.header_block(); - int header_length = syn_frame.header_block_len(); + const char *header_data = control_frame.get()->header_block(); + int header_length = control_frame.get()->header_block_len(); FlipFrameBuilder builder(header_data, header_length); void* iter = NULL; @@ -450,18 +438,21 @@ FlipSynStreamControlFrame* FlipFramer::CreateSynStream( } // Write the length and flags. - size_t length = frame.length() - FlipFrame::size(); + 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)); - scoped_ptr<FlipFrame> syn_frame(frame.take()); - if (compressed) - return reinterpret_cast<FlipSynStreamControlFrame*>( - CompressFrame(syn_frame.get())); - return reinterpret_cast<FlipSynStreamControlFrame*>(syn_frame.release()); + if (compressed) { + FlipSynStreamControlFrame* new_frame = + reinterpret_cast<FlipSynStreamControlFrame*>( + CompressFrame(frame.data())); + return new_frame; + } + + return reinterpret_cast<FlipSynStreamControlFrame*>(frame.take()); } /* static */ @@ -496,18 +487,17 @@ FlipSynReplyControlFrame* FlipFramer::CreateSynReply(FlipStreamId stream_id, } // Write the length - size_t length = frame.length() - FlipFrame::size(); + 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)); - scoped_ptr<FlipFrame> reply_frame(frame.take()); if (compressed) return reinterpret_cast<FlipSynReplyControlFrame*>( - CompressFrame(reply_frame.get())); - return reinterpret_cast<FlipSynReplyControlFrame*>(reply_frame.release()); + CompressFrame(frame.data())); + return reinterpret_cast<FlipSynReplyControlFrame*>(frame.take()); } FlipDataFrame* FlipFramer::CreateDataFrame(FlipStreamId stream_id, @@ -524,10 +514,9 @@ FlipDataFrame* FlipFramer::CreateDataFrame(FlipStreamId stream_id, frame.WriteBytes(&flags_length, sizeof(flags_length)); frame.WriteBytes(data, len); - scoped_ptr<FlipFrame> data_frame(frame.take()); if (flags & DATA_FLAG_COMPRESSED) - return reinterpret_cast<FlipDataFrame*>(CompressFrame(data_frame.get())); - return reinterpret_cast<FlipDataFrame*>(data_frame.release()); + return reinterpret_cast<FlipDataFrame*>(CompressFrame(frame.data())); + return reinterpret_cast<FlipDataFrame*>(frame.take()); } /* static */ @@ -600,7 +589,7 @@ bool FlipFramer::InitializeDecompressor() { bool FlipFramer::GetFrameBoundaries(const FlipFrame* frame, int* payload_length, int* header_length, - const char** payload) const { + const unsigned char** payload) const { if (frame->is_control_frame()) { const FlipControlFrame* control_frame = reinterpret_cast<const FlipControlFrame*>(frame); @@ -611,8 +600,10 @@ bool FlipFramer::GetFrameBoundaries(const FlipFrame* frame, const FlipSynStreamControlFrame *syn_frame = reinterpret_cast<const FlipSynStreamControlFrame*>(frame); *payload_length = syn_frame->header_block_len(); - *header_length = syn_frame->size(); - *payload = frame->data() + *header_length; + *header_length = sizeof(FlipFrame) + syn_frame->length() - + syn_frame->header_block_len(); + *payload = reinterpret_cast<const unsigned char*>(frame) + + *header_length; } break; default: @@ -620,12 +611,13 @@ bool FlipFramer::GetFrameBoundaries(const FlipFrame* frame, return false; // We can't compress this frame! } } else { - *header_length = FlipFrame::size(); + *header_length = sizeof(FlipFrame); *payload_length = frame->length(); - *payload = frame->data() + FlipFrame::size(); + *payload = reinterpret_cast<const unsigned char*>(frame) + + sizeof(FlipFrame); } DCHECK(static_cast<size_t>(*header_length) <= - FlipFrame::size() + *payload_length); + sizeof(FlipFrame) + *payload_length); return true; } @@ -633,7 +625,7 @@ bool FlipFramer::GetFrameBoundaries(const FlipFrame* frame, FlipFrame* FlipFramer::CompressFrame(const FlipFrame* frame) { int payload_length; int header_length; - const char* payload; + const unsigned char* payload; static StatsCounter pre_compress_bytes("flip.PreCompressSize"); static StatsCounter post_compress_bytes("flip.PostCompressSize"); @@ -652,13 +644,13 @@ FlipFrame* FlipFramer::CompressFrame(const FlipFrame* frame) { // Create an output frame. int compressed_max_size = deflateBound(compressor_.get(), payload_length); int new_frame_size = header_length + compressed_max_size; - FlipFrame* new_frame = new FlipFrame(new_frame_size); - memcpy(new_frame->data(), frame->data(), frame->length() + FlipFrame::size()); + FlipFrame* new_frame = + reinterpret_cast<FlipFrame*>(new char[new_frame_size]); + memcpy(new_frame, frame, header_length); - compressor_->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload)); + compressor_->next_in = const_cast<Bytef*>(payload); compressor_->avail_in = payload_length; - compressor_->next_out = reinterpret_cast<Bytef*>(new_frame->data()) + - header_length; + compressor_->next_out = reinterpret_cast<Bytef*>(new_frame) + header_length; compressor_->avail_out = compressed_max_size; // Data packets have a 'compressed flag @@ -670,12 +662,12 @@ FlipFrame* FlipFramer::CompressFrame(const FlipFrame* frame) { int rv = deflate(compressor_.get(), Z_SYNC_FLUSH); if (rv != Z_OK) { // How can we know that it compressed everything? // This shouldn't happen, right? - delete [] new_frame; + free(new_frame); return NULL; } int compressed_size = compressed_max_size - compressor_->avail_out; - new_frame->set_length(header_length + compressed_size - FlipFrame::size()); + new_frame->set_length(header_length + compressed_size - sizeof(FlipFrame)); pre_compress_bytes.Add(payload_length); post_compress_bytes.Add(new_frame->length()); @@ -686,7 +678,7 @@ FlipFrame* FlipFramer::CompressFrame(const FlipFrame* frame) { FlipFrame* FlipFramer::DecompressFrame(const FlipFrame* frame) { int payload_length; int header_length; - const char* payload; + const unsigned char* payload; static StatsCounter pre_decompress_bytes("flip.PreDeCompressSize"); static StatsCounter post_decompress_bytes("flip.PostDeCompressSize"); @@ -713,12 +705,13 @@ FlipFrame* FlipFramer::DecompressFrame(const FlipFrame* frame) { // the input data. int decompressed_max_size = kControlFrameBufferInitialSize; int new_frame_size = header_length + decompressed_max_size; - FlipFrame* new_frame = new FlipFrame(new_frame_size); - memcpy(new_frame->data(), frame->data(), frame->length() + FlipFrame::size()); + FlipFrame* new_frame = + reinterpret_cast<FlipFrame*>(new char[new_frame_size]); + memcpy(new_frame, frame, header_length); - decompressor_->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload)); + decompressor_->next_in = const_cast<Bytef*>(payload); decompressor_->avail_in = payload_length; - decompressor_->next_out = reinterpret_cast<Bytef*>(new_frame->data()) + + decompressor_->next_out = reinterpret_cast<Bytef*>(new_frame) + header_length; decompressor_->avail_out = decompressed_max_size; @@ -733,7 +726,7 @@ FlipFrame* FlipFramer::DecompressFrame(const FlipFrame* frame) { } } if (rv != Z_OK) { // How can we know that it decompressed everything? - delete [] new_frame; + free(new_frame); return NULL; } @@ -744,7 +737,7 @@ FlipFrame* FlipFramer::DecompressFrame(const FlipFrame* frame) { } int decompressed_size = decompressed_max_size - decompressor_->avail_out; - new_frame->set_length(header_length + decompressed_size - FlipFrame::size()); + new_frame->set_length(header_length + decompressed_size - sizeof(FlipFrame)); pre_decompress_bytes.Add(frame->length()); post_decompress_bytes.Add(new_frame->length()); @@ -753,10 +746,10 @@ FlipFrame* FlipFramer::DecompressFrame(const FlipFrame* frame) { } FlipFrame* FlipFramer::DuplicateFrame(const FlipFrame* frame) { - int size = FlipFrame::size() + frame->length(); - FlipFrame* new_frame = new FlipFrame(size); - memcpy(new_frame->data(), frame->data(), size); - return new_frame; + int size = sizeof(FlipFrame) + frame->length(); + char* new_frame = new char[size]; + memcpy(new_frame, frame, size); + return reinterpret_cast<FlipFrame*>(new_frame); } void FlipFramer::set_enable_compression(bool value) { diff --git a/net/flip/flip_framer.h b/net/flip/flip_framer.h index b333176..d3cae28 100644 --- a/net/flip/flip_framer.h +++ b/net/flip/flip_framer.h @@ -30,11 +30,7 @@ namespace flip { class FlipFramer; class FlipFramerTest; - -namespace test { class TestFlipVisitor; -void FramerSetEnableCompressionHelper(FlipFramer* framer, bool compress); -} // namespace test // A datastructure for holding a set of headers from either a // SYN_STREAM or SYN_REPLY frame. @@ -62,6 +58,9 @@ class FlipFramerVisitorInterface { virtual void OnStreamFrameData(flip::FlipStreamId stream_id, const char* data, size_t len) = 0; + + // TODO(fenix): Implement me! + virtual void OnLameDuck() = 0; }; class FlipFramer { @@ -201,11 +200,9 @@ class FlipFramer { protected: FRIEND_TEST(FlipFramerTest, HeaderBlockBarfsOnOutOfOrderHeaders); + friend class flip::TestFlipVisitor; friend class net::FlipNetworkTransactionTest; friend class net::HttpNetworkLayer; // This is temporary for the server. - friend class test::TestFlipVisitor; - friend void test::FramerSetEnableCompressionHelper(FlipFramer* framer, - bool compress); // For ease of testing we can tweak compression on/off. void set_enable_compression(bool value); @@ -215,9 +212,7 @@ class FlipFramer { // Internal breakout from ProcessInput. Returns the number of bytes // consumed from the data. size_t ProcessCommonHeader(const char* data, size_t len); - void ProcessControlFrameHeader(); size_t ProcessControlFramePayload(const char* data, size_t len); - size_t ProcessDataFramePayload(const char* data, size_t len); // Initialize the ZLib state. bool InitializeCompressor(); @@ -235,7 +230,8 @@ class FlipFramer { // Given a frame, breakdown the variable payload length, the static header // header length, and variable payload pointer. bool GetFrameBoundaries(const FlipFrame* frame, int* payload_length, - int* header_length, const char** payload) const; + int* header_length, + const unsigned char** payload) const; FlipState state_; FlipError error_code_; diff --git a/net/flip/flip_framer_test.cc b/net/flip/flip_framer_test.cc index 921e052..bee0432 100644 --- a/net/flip/flip_framer_test.cc +++ b/net/flip/flip_framer_test.cc @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <algorithm> #include <iostream> - #include "base/scoped_ptr.h" + #include "flip_framer.h" // cross-google3 directory naming. #include "flip_protocol.h" #include "flip_frame_builder.h" @@ -13,15 +12,14 @@ namespace flip { -namespace test { - -void FramerSetEnableCompressionHelper(FlipFramer* framer, bool compress) { - framer->set_enable_compression(compress); -} +class FlipFramerTest : public PlatformTest { + public: + virtual void TearDown() {} +}; class TestFlipVisitor : public FlipFramerVisitorInterface { public: - TestFlipVisitor() + explicit TestFlipVisitor() : error_count_(0), syn_frame_count_(0), syn_reply_frame_count_(0), @@ -39,9 +37,10 @@ class TestFlipVisitor : public FlipFramerVisitorInterface { const char* data, size_t len) { if (len == 0) - ++zero_length_data_frame_count_; + zero_length_data_frame_count_++; data_bytes_ += len; +#ifdef TEST_LOGGING std::cerr << "OnStreamFrameData(" << stream_id << ", \""; if (len > 0) { for (size_t i = 0 ; i < len; ++i) { @@ -49,6 +48,7 @@ class TestFlipVisitor : public FlipFramerVisitorInterface { } } std::cerr << "\", " << len << ")\n"; +#endif // TEST_LOGGING } void OnControl(const FlipControlFrame* frame) { @@ -56,12 +56,14 @@ class TestFlipVisitor : public FlipFramerVisitorInterface { bool parsed_headers = false; switch (frame->type()) { case SYN_STREAM: - parsed_headers = framer_.ParseHeaderBlock(frame, &headers); + parsed_headers = framer_.ParseHeaderBlock( + reinterpret_cast<const FlipFrame*>(frame), &headers); DCHECK(parsed_headers); syn_frame_count_++; break; case SYN_REPLY: - parsed_headers = framer_.ParseHeaderBlock(frame, &headers); + parsed_headers = framer_.ParseHeaderBlock( + reinterpret_cast<const FlipFrame*>(frame), &headers); DCHECK(parsed_headers); syn_reply_frame_count_++; break; @@ -72,7 +74,10 @@ class TestFlipVisitor : public FlipFramerVisitorInterface { DCHECK(false); // Error! } if (frame->flags() & CONTROL_FLAG_FIN) - ++fin_flag_count_; + fin_flag_count_++; + } + + void OnLameDuck() { } // Convenience function which runs a framer simulation with particular input. @@ -108,27 +113,75 @@ class TestFlipVisitor : public FlipFramerVisitorInterface { int zero_length_data_frame_count_; // The count of zero-length data frames. }; -} // namespace test +// Test our protocol constants +TEST_F(FlipFramerTest, ProtocolConstants) { + EXPECT_EQ(8u, sizeof(FlipFrame)); + EXPECT_EQ(8u, sizeof(FlipDataFrame)); + EXPECT_EQ(12u, sizeof(FlipControlFrame)); + EXPECT_EQ(16u, sizeof(FlipSynStreamControlFrame)); + EXPECT_EQ(16u, sizeof(FlipSynReplyControlFrame)); + EXPECT_EQ(16u, sizeof(FlipFinStreamControlFrame)); + EXPECT_EQ(1, SYN_STREAM); + EXPECT_EQ(2, SYN_REPLY); + EXPECT_EQ(3, FIN_STREAM); +} -} // namespace flip +// Test some of the protocol helper functions +TEST_F(FlipFramerTest, FrameStructs) { + FlipFrame frame; + memset(&frame, 0, sizeof(frame)); + frame.set_length(12345); + frame.set_flags(10); + EXPECT_EQ(12345u, frame.length()); + EXPECT_EQ(10u, frame.flags()); + EXPECT_EQ(false, frame.is_control_frame()); + + memset(&frame, 0, sizeof(frame)); + frame.set_length(0); + frame.set_flags(10); + EXPECT_EQ(0u, frame.length()); + EXPECT_EQ(10u, frame.flags()); + EXPECT_EQ(false, frame.is_control_frame()); +} -using flip::FlipFrame; -using flip::FlipFrameBuilder; -using flip::FlipFramer; -using flip::FlipHeaderBlock; -using flip::FlipSynStreamControlFrame; -using flip::kControlFlagMask; -using flip::CONTROL_FLAG_NONE; -using flip::SYN_STREAM; -using flip::test::FramerSetEnableCompressionHelper; -using flip::test::TestFlipVisitor; +TEST_F(FlipFramerTest, DataFrameStructs) { + FlipDataFrame data_frame; + memset(&data_frame, 0, sizeof(data_frame)); + data_frame.set_stream_id(12345); + EXPECT_EQ(12345u, data_frame.stream_id()); +} -namespace { +TEST_F(FlipFramerTest, ControlFrameStructs) { + FlipFramer framer; + FlipHeaderBlock headers; -class FlipFramerTest : public PlatformTest { - public: - virtual void TearDown() {} -}; + scoped_array<FlipSynStreamControlFrame> syn_frame( + 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()); + EXPECT_EQ(123u, syn_frame.get()->stream_id()); + EXPECT_EQ(2u, syn_frame.get()->priority()); + EXPECT_EQ(2, syn_frame.get()->header_block_len()); + + scoped_array<FlipSynReplyControlFrame> syn_reply( + 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()); + EXPECT_EQ(123u, syn_reply.get()->stream_id()); + EXPECT_EQ(2, syn_reply.get()->header_block_len()); + + scoped_array<FlipFinStreamControlFrame> fin_frame( + framer.CreateFinStream(123, 444)); + EXPECT_EQ(kFlipProtocolVersion, fin_frame.get()->version()); + EXPECT_EQ(true, fin_frame.get()->is_control_frame()); + EXPECT_EQ(FIN_STREAM, fin_frame.get()->type()); + EXPECT_EQ(123u, fin_frame.get()->stream_id()); + EXPECT_EQ(444u, fin_frame.get()->status()); + fin_frame.get()->set_status(555); + EXPECT_EQ(555u, fin_frame.get()->status()); +} // Test that we can encode and decode a FlipHeaderBlock. TEST_F(FlipFramerTest, HeaderBlock) { @@ -138,12 +191,13 @@ TEST_F(FlipFramerTest, HeaderBlock) { FlipFramer framer; // Encode the header block into a SynStream frame. - scoped_ptr<FlipSynStreamControlFrame> frame( + scoped_array<FlipSynStreamControlFrame> frame( framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, true, &headers)); EXPECT_TRUE(frame.get() != NULL); FlipHeaderBlock new_headers; - framer.ParseHeaderBlock(frame.get(), &new_headers); + FlipFrame* control_frame = reinterpret_cast<FlipFrame*>(frame.get()); + framer.ParseHeaderBlock(control_frame, &new_headers); EXPECT_EQ(headers.size(), new_headers.size()); EXPECT_EQ(headers["alpha"], new_headers["alpha"]); @@ -166,13 +220,13 @@ TEST_F(FlipFramerTest, HeaderBlockBarfsOnOutOfOrderHeaders) { frame.WriteString("alpha"); frame.WriteString("alpha"); // write the length - frame.WriteUInt32ToOffset(4, frame.length() - FlipFrame::size()); + frame.WriteUInt32ToOffset(4, frame.length() - sizeof(FlipFrame)); FlipHeaderBlock new_headers; - scoped_ptr<FlipFrame> control_frame(frame.take()); + const FlipFrame* control_frame = frame.data(); FlipFramer framer; - FramerSetEnableCompressionHelper(&framer, false); - EXPECT_FALSE(framer.ParseHeaderBlock(control_frame.get(), &new_headers)); + framer.set_enable_compression(false); + EXPECT_FALSE(framer.ParseHeaderBlock(control_frame, &new_headers)); } TEST_F(FlipFramerTest, BasicCompression) { @@ -185,45 +239,26 @@ TEST_F(FlipFramerTest, BasicCompression) { headers["content-length"] = "12"; FlipFramer framer; - FramerSetEnableCompressionHelper(&framer, true); - scoped_ptr<FlipSynStreamControlFrame> + scoped_array<FlipSynStreamControlFrame> frame1(framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, true, &headers)); - scoped_ptr<FlipSynStreamControlFrame> + scoped_array<FlipSynStreamControlFrame> frame2(framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, true, &headers)); // Expect the second frame to be more compact than the first. - EXPECT_LE(frame2->length(), frame1->length()); + EXPECT_LE(frame2.get()->length(), frame1.get()->length()); // Decompress the first frame - scoped_ptr<FlipFrame> frame3(framer.DecompressFrame(frame1.get())); + scoped_array<FlipFrame> frame3( + framer.DecompressFrame(reinterpret_cast<FlipFrame*>(frame1.get()))); // Decompress the second frame - scoped_ptr<FlipFrame> frame4(framer.DecompressFrame(frame2.get())); + scoped_array<FlipFrame> frame4( + framer.DecompressFrame(reinterpret_cast<FlipFrame*>(frame2.get()))); // Expect frames 3 & 4 to be the same. EXPECT_EQ(0, - memcmp(frame3->data(), frame4->data(), - FlipFrame::size() + frame3->length())); -} - -TEST_F(FlipFramerTest, DecompressUncompressedFrame) { - FlipHeaderBlock headers; - headers["server"] = "FlipServer 1.0"; - headers["date"] = "Mon 12 Jan 2009 12:12:12 PST"; - headers["status"] = "200"; - headers["version"] = "HTTP/1.1"; - headers["content-type"] = "text/html"; - headers["content-length"] = "12"; - - FlipFramer framer; - FramerSetEnableCompressionHelper(&framer, true); - scoped_ptr<FlipSynStreamControlFrame> - frame1(framer.CreateSynStream(1, 1, CONTROL_FLAG_NONE, false, &headers)); - - // Decompress the frame - scoped_ptr<FlipFrame> frame2(framer.DecompressFrame(frame1.get())); - - EXPECT_EQ(NULL, frame2.get()); + memcmp(frame3.get(), frame4.get(), + sizeof(FlipFrame) + frame3.get()->length())); } TEST_F(FlipFramerTest, Basic) { @@ -351,5 +386,6 @@ TEST_F(FlipFramerTest, FinOnSynReplyFrame) { EXPECT_EQ(1, visitor.zero_length_data_frame_count_); } -} // namespace +} // namespace flip + diff --git a/net/flip/flip_protocol.h b/net/flip/flip_protocol.h index 7c0c659..8a585bc 100644 --- a/net/flip/flip_protocol.h +++ b/net/flip/flip_protocol.h @@ -12,11 +12,11 @@ #else #include <arpa/inet.h> #endif - #include "base/basictypes.h" #include "base/logging.h" #include "flip_bitmasks.h" // cross-google3 directory naming. + // Data Frame Format // +----------------------------------+ // |0| Stream-ID (31bits) | @@ -116,22 +116,29 @@ typedef uint32 FlipStreamId; #define FLIP_PRIORITY_LOWEST 3 #define FLIP_PRIORITY_HIGHEST 0 -// ------------------------------------------------------------------------- -// These structures mirror the protocol structure definitions. - -// For the control data structures, we pack so that sizes match the -// protocol over-the-wire sizes. -#pragma pack(push) -#pragma pack(1) - // A special structure for the 8 bit flags and 24 bit length fields. union FlagsAndLength { - uint8 flags_[4]; // 8 bits - uint32 length_; // 24 bits + uint8 flags_[4]; // 8 bits + uint32 length_; // 24 bits }; -// The basic FLIP Frame. -struct FlipFrameBlock { +// All Flip Frame types derive from the FlipFrame struct. +typedef struct { + uint8 flags() const { return flags_length_.flags_[0]; } + void set_flags(uint8 flags) { flags_length_.flags_[0] = flags; } + + uint32 length() const { return ntohl(flags_length_.length_) & kLengthMask; } + void set_length(uint32 length) { + DCHECK((length & ~kLengthMask) == 0); + length = htonl(length & kLengthMask); + flags_length_.length_ = (flags() << 6) | length; + } + + bool is_control_frame() const { + return (ntohs(control_.version_) & kControlFlagMask) == kControlFlagMask; + } + + protected: union { struct { uint16 version_; @@ -142,229 +149,74 @@ struct FlipFrameBlock { } data_; }; FlagsAndLength flags_length_; -}; - -// A Control Frame. -struct FlipControlFrameBlock : FlipFrameBlock { - FlipStreamId stream_id_; -}; - -// A SYN_STREAM Control Frame. -struct FlipSynStreamControlFrameBlock : FlipControlFrameBlock { - uint8 priority_; - uint8 unused_; -}; - -// A SYN_REPLY Control Frame. -struct FlipSynReplyControlFrameBlock : FlipControlFrameBlock { - uint16 unused_; -}; - -// A FNI_STREAM Control Frame. -struct FlipFinStreamControlFrameBlock : FlipControlFrameBlock { - uint32 status_; -}; - -#pragma pack(pop) - -// ------------------------------------------------------------------------- -// Wrapper classes for various FLIP frames. - -// All Flip Frame types derive from this FlipFrame class. -class FlipFrame { - public: - // Create a FlipFrame for a given sized buffer. - explicit FlipFrame(size_t size) : frame_(NULL), needs_delete_(true) { - DCHECK_GE(size, sizeof(struct FlipFrameBlock)); - char* buffer = new char[size]; - memset(buffer, 0, size); - frame_ = reinterpret_cast<struct FlipFrameBlock*>(buffer); - } - - // Create a FlipFrame using a pre-created buffer. - // If |needs_delete| is true, this class takes ownership of the buffer - // and will delete it on cleanup. The buffer must have been created using - // new char[]. - // If |needs_delete| is false, the caller retains ownership - // of the buffer and will keep the buffer alive longer than |this|. In other - // words, this class does NOT create a copy of the buffer. - FlipFrame(char* data, bool needs_delete) - : frame_(reinterpret_cast<struct FlipFrameBlock*>(data)), - needs_delete_(needs_delete) { - DCHECK(frame_); - } - - virtual ~FlipFrame() { - if (needs_delete_) { - char* buffer = reinterpret_cast<char*>(frame_); - delete [] buffer; - } - frame_ = NULL; - } - - // Provide access to the frame bytes - char* data() const { return reinterpret_cast<char*>(frame_); } - - uint8 flags() const { return frame_->flags_length_.flags_[0]; } - void set_flags(uint8 flags) { frame_->flags_length_.flags_[0] = flags; } - - uint32 length() const { - return ntohl(frame_->flags_length_.length_) & kLengthMask; - } - - void set_length(uint32 length) { - DCHECK_EQ(0u, (length & ~kLengthMask)); - length = htonl(length & kLengthMask); - frame_->flags_length_.length_ = flags() | length; - } - - bool is_control_frame() const { - return (ntohs(frame_->control_.version_) & kControlFlagMask) == - kControlFlagMask; - } - - static size_t size() { return sizeof(struct FlipFrameBlock); } - - protected: - FlipFrameBlock* frame_; - - private: - bool needs_delete_; - DISALLOW_COPY_AND_ASSIGN(FlipFrame); -}; +} FlipFrame; // A Data Frame. -class FlipDataFrame : public FlipFrame { - public: - FlipDataFrame() : FlipFrame(size()) {} - FlipDataFrame(char* data, bool needs_delete) - : FlipFrame(data, needs_delete) {} - virtual ~FlipDataFrame() {} - +typedef struct : public FlipFrame { FlipStreamId stream_id() const { - return ntohl(frame_->data_.stream_id_) & kStreamIdMask; - } - - // Note that setting the stream id sets the control bit to false. - // As stream id should always be set, this means the control bit - // should always be set correctly. - void set_stream_id(FlipStreamId id) { - DCHECK_EQ(0u, (id & ~kStreamIdMask)); - frame_->data_.stream_id_ = htonl(id & kStreamIdMask); + return ntohl(data_.stream_id_) & kStreamIdMask; } - - static size_t size() { return FlipFrame::size(); } - private: - DISALLOW_COPY_AND_ASSIGN(FlipDataFrame); -}; + void set_stream_id(FlipStreamId id) { data_.stream_id_ = htonl(id); } +} FlipDataFrame; // A Control Frame. -class FlipControlFrame : public FlipFrame { - public: - explicit FlipControlFrame(size_t size) : FlipFrame(size) {} - FlipControlFrame(char* data, bool needs_delete) - : FlipFrame(data, needs_delete) {} - virtual ~FlipControlFrame() {} - +typedef struct : public FlipFrame { uint16 version() const { const int kVersionMask = 0x7fff; - return ntohs(block()->control_.version_) & kVersionMask; + return ntohs(control_.version_) & kVersionMask; } FlipControlType type() const { - uint16 type = ntohs(block()->control_.type_); + uint16 type = ntohs(control_.type_); DCHECK(type >= SYN_STREAM && type <= NOOP); return static_cast<FlipControlType>(type); } - FlipStreamId stream_id() const { - return ntohl(block()->stream_id_) & kStreamIdMask; - } - - void set_stream_id(FlipStreamId id) { - block()->stream_id_ = htonl(id & kStreamIdMask); - } - - static size_t size() { return sizeof(FlipControlFrameBlock); } + FlipStreamId stream_id() const { return ntohl(stream_id_) & kStreamIdMask; } private: - struct FlipControlFrameBlock* block() const { - return static_cast<FlipControlFrameBlock*>(frame_); - } - DISALLOW_COPY_AND_ASSIGN(FlipControlFrame); -}; + FlipStreamId stream_id_; +} FlipControlFrame; // A SYN_STREAM frame. -class FlipSynStreamControlFrame : public FlipControlFrame { - public: - FlipSynStreamControlFrame() : FlipControlFrame(size()) {} - FlipSynStreamControlFrame(char* data, bool needs_delete) - : FlipControlFrame(data, needs_delete) {} - virtual ~FlipSynStreamControlFrame() {} - - uint8 priority() const { return (block()->priority_ & kPriorityMask) >> 6; } - +typedef struct FlipSynStreamControlFrame : public FlipControlFrame { + uint8 priority() const { return (priority_ & kPriorityMask) >> 6; } // The number of bytes in the header block beyond the frame header length. - int header_block_len() const { - return length() - (size() - FlipFrame::size()); - } - + int header_block_len() const { return length() - kHeaderBlockOffset; } const char* header_block() const { - return reinterpret_cast<const char*>(block()) + size(); + return reinterpret_cast<const char*>(this) + + sizeof(FlipFrame) + kHeaderBlockOffset; } - - static size_t size() { return sizeof(FlipSynStreamControlFrameBlock); } - private: - struct FlipSynStreamControlFrameBlock* block() const { - return static_cast<FlipSynStreamControlFrameBlock*>(frame_); - } - DISALLOW_COPY_AND_ASSIGN(FlipSynStreamControlFrame); -}; + // Offset from the end of the FlipControlFrame to the FlipHeaderBlock. + static const int kHeaderBlockOffset = 6; + uint8 priority_; + uint8 unused_; + // Variable FlipHeaderBlock here. +} FlipSynStreamControlFrame; // A SYN_REPLY frame. -class FlipSynReplyControlFrame : public FlipControlFrame { - public: - FlipSynReplyControlFrame() : FlipControlFrame(size()) {} - FlipSynReplyControlFrame(char* data, bool needs_delete) - : FlipControlFrame(data, needs_delete) {} - virtual ~FlipSynReplyControlFrame() {} - - int header_block_len() const { - return length() - (size() - FlipFrame::size()); - } - +typedef struct FlipSynReplyControlFrame : public FlipControlFrame { + int header_block_len() const { return length() - kHeaderBlockOffset; } const char* header_block() const { - return reinterpret_cast<const char*>(block()) + size(); + return reinterpret_cast<const char*>(this) + + sizeof(FlipFrame) + kHeaderBlockOffset; } - static size_t size() { return sizeof(FlipSynReplyControlFrameBlock); } - private: - struct FlipSynReplyControlFrameBlock* block() const { - return static_cast<FlipSynReplyControlFrameBlock*>(frame_); - } - DISALLOW_COPY_AND_ASSIGN(FlipSynReplyControlFrame); -}; + // Offset from the end of the FlipControlFrame to the FlipHeaderBlock. + static const int kHeaderBlockOffset = 6; + uint16 unused_; + // Variable FlipHeaderBlock here. +} FlipSynReplyControlFrame; // A FIN_STREAM frame. -class FlipFinStreamControlFrame : public FlipControlFrame { - public: - FlipFinStreamControlFrame() : FlipControlFrame(size()) {} - FlipFinStreamControlFrame(char* data, bool needs_delete) - : FlipControlFrame(data, needs_delete) {} - virtual ~FlipFinStreamControlFrame() {} - - uint32 status() const { return ntohl(block()->status_); } - void set_status(uint32 status) { block()->status_ = htonl(status); } - - static size_t size() { return sizeof(FlipFinStreamControlFrameBlock); } - +typedef struct FlipFinStreamControlFrame : public FlipControlFrame { + uint32 status() const { return ntohl(status_); } + void set_status(int id) { status_ = htonl(id); } private: - struct FlipFinStreamControlFrameBlock* block() const { - return static_cast<FlipFinStreamControlFrameBlock*>(frame_); - } - DISALLOW_COPY_AND_ASSIGN(FlipFinStreamControlFrame); -}; + uint32 status_; +} FlipFinStreamControlFrame; } // namespace flip #endif // NET_FLIP_FLIP_PROTOCOL_H_ + diff --git a/net/flip/flip_protocol_test.cc b/net/flip/flip_protocol_test.cc deleted file mode 100644 index fb78b63..0000000 --- a/net/flip/flip_protocol_test.cc +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flip_protocol.h" - -#include "base/scoped_ptr.h" -#include "flip_bitmasks.h" // shared with server. -#include "flip_framer.h" -#ifdef _WIN32 -#include "testing/platform_test.h" -#else -#include "testing/base/public/gunit.h" -#endif - -using flip::FlipDataFrame; -using flip::FlipFrame; -using flip::FlipControlFrame; -using flip::FlipSynStreamControlFrame; -using flip::FlipSynReplyControlFrame; -using flip::FlipFinStreamControlFrame; -using flip::FlipFramer; -using flip::FlipHeaderBlock; -using flip::FlagsAndLength; -using flip::kLengthMask; -using flip::kStreamIdMask; -using flip::kFlipProtocolVersion; -using flip::SYN_STREAM; -using flip::SYN_REPLY; -using flip::FIN_STREAM; -using flip::CONTROL_FLAG_FIN; -using flip::CONTROL_FLAG_NONE; - -namespace { - -// Test our protocol constants -TEST(FlipProtocolTest, ProtocolConstants) { - EXPECT_EQ(8u, FlipFrame::size()); - EXPECT_EQ(8u, FlipDataFrame::size()); - EXPECT_EQ(12u, FlipControlFrame::size()); - EXPECT_EQ(14u, FlipSynStreamControlFrame::size()); - EXPECT_EQ(14u, FlipSynReplyControlFrame::size()); - EXPECT_EQ(16u, FlipFinStreamControlFrame::size()); - EXPECT_EQ(4u, sizeof(FlagsAndLength)); - EXPECT_EQ(1, SYN_STREAM); - EXPECT_EQ(2, SYN_REPLY); - EXPECT_EQ(3, FIN_STREAM); -} - -// Test some of the protocol helper functions -TEST(FlipProtocolTest, FrameStructs) { - FlipFrame frame(FlipFrame::size()); - frame.set_length(12345); - frame.set_flags(10); - EXPECT_EQ(12345u, frame.length()); - EXPECT_EQ(10u, frame.flags()); - EXPECT_EQ(false, frame.is_control_frame()); - - frame.set_length(0); - frame.set_flags(10); - EXPECT_EQ(0u, frame.length()); - EXPECT_EQ(10u, frame.flags()); - EXPECT_EQ(false, frame.is_control_frame()); -} - -TEST(FlipProtocolTest, DataFrameStructs) { - FlipDataFrame data_frame; - data_frame.set_stream_id(12345); - EXPECT_EQ(12345u, data_frame.stream_id()); -} - -TEST(FlipProtocolTest, ControlFrameStructs) { - FlipFramer framer; - FlipHeaderBlock headers; - - scoped_ptr<FlipSynStreamControlFrame> syn_frame( - framer.CreateSynStream(123, 2, CONTROL_FLAG_FIN, false, &headers)); - EXPECT_EQ(kFlipProtocolVersion, syn_frame->version()); - EXPECT_EQ(true, syn_frame->is_control_frame()); - EXPECT_EQ(SYN_STREAM, syn_frame->type()); - EXPECT_EQ(123u, syn_frame->stream_id()); - EXPECT_EQ(2u, syn_frame->priority()); - EXPECT_EQ(2, syn_frame->header_block_len()); - EXPECT_EQ(1u, syn_frame->flags()); - - scoped_ptr<FlipSynReplyControlFrame> syn_reply( - framer.CreateSynReply(123, CONTROL_FLAG_NONE, false, &headers)); - EXPECT_EQ(kFlipProtocolVersion, syn_reply->version()); - EXPECT_EQ(true, syn_reply->is_control_frame()); - EXPECT_EQ(SYN_REPLY, syn_reply->type()); - EXPECT_EQ(123u, syn_reply->stream_id()); - EXPECT_EQ(2, syn_reply->header_block_len()); - EXPECT_EQ(0, syn_reply->flags()); - - scoped_ptr<FlipFinStreamControlFrame> fin_frame( - framer.CreateFinStream(123, 444)); - EXPECT_EQ(kFlipProtocolVersion, fin_frame->version()); - EXPECT_EQ(true, fin_frame->is_control_frame()); - EXPECT_EQ(FIN_STREAM, fin_frame->type()); - EXPECT_EQ(123u, fin_frame->stream_id()); - EXPECT_EQ(444u, fin_frame->status()); - fin_frame->set_status(555); - EXPECT_EQ(555u, fin_frame->status()); - EXPECT_EQ(0, fin_frame->flags()); -} - -TEST(FlipProtocolTest, TestDataFrame) { - FlipDataFrame frame; - - // Set the stream ID to various values. - frame.set_stream_id(0); - EXPECT_EQ(0, frame.stream_id()); - EXPECT_FALSE(frame.is_control_frame()); - frame.set_stream_id(~0 & kStreamIdMask); - EXPECT_EQ(~0 & kStreamIdMask, frame.stream_id()); - EXPECT_FALSE(frame.is_control_frame()); - - // Set length to various values. Make sure that when you set_length(x), - // length() == x. Also make sure the flags are unaltered. - memset(frame.data(), '1', FlipDataFrame::size()); - int8 flags = frame.flags(); - frame.set_length(0); - EXPECT_EQ(0, frame.length()); - EXPECT_EQ(flags, frame.flags()); - frame.set_length(kLengthMask); - EXPECT_EQ(kLengthMask, frame.length()); - EXPECT_EQ(flags, frame.flags()); - frame.set_length(5); - EXPECT_EQ(5, frame.length()); - EXPECT_EQ(flags, frame.flags()); - - // Set flags to various values. Make sure that when you set_flags(x), - // flags() == x. Also make sure the length is unaltered. - memset(frame.data(), '1', FlipDataFrame::size()); - uint32 length = frame.length(); - frame.set_flags(0); - EXPECT_EQ(0, frame.flags()); - EXPECT_EQ(length, frame.length()); - int8 all_flags = ~0; - frame.set_flags(all_flags); - flags = frame.flags(); - EXPECT_EQ(all_flags, flags); - EXPECT_EQ(length, frame.length()); - frame.set_flags(5); - EXPECT_EQ(5, frame.flags()); - EXPECT_EQ(length, frame.length()); -} - -// Make sure that overflows both die in debug mode, and do not cause problems -// in opt mode. Note: Chrome doesn't die on DCHECK failures, so the -// EXPECT_DEBUG_DEATH doesn't work. -TEST(FlipProtocolDeathTest, TestDataFrame) { - FlipDataFrame frame; - - frame.set_stream_id(0); -#ifndef WIN32 - EXPECT_DEBUG_DEATH(frame.set_stream_id(~0), ""); -#endif - EXPECT_FALSE(frame.is_control_frame()); - - frame.set_flags(0); -#ifndef WIN32 - EXPECT_DEBUG_DEATH(frame.set_length(~0), ""); -#endif - EXPECT_EQ(0, frame.flags()); -} - -TEST(FlipProtocolDeathTest, TestFlipControlFrame) { - FlipControlFrame frame(FlipControlFrame::size()); - memset(frame.data(), '1', FlipControlFrame::size()); - - // Set the stream ID to various values. - frame.set_stream_id(0); - EXPECT_EQ(0, frame.stream_id()); - EXPECT_FALSE(frame.is_control_frame()); - frame.set_stream_id(~0 & kStreamIdMask); - EXPECT_EQ(~0 & kStreamIdMask, frame.stream_id()); - EXPECT_FALSE(frame.is_control_frame()); -} - -} // namespace - diff --git a/net/flip/flip_session.cc b/net/flip/flip_session.cc index 1f594eb..72bd387 100644 --- a/net/flip/flip_session.cc +++ b/net/flip/flip_session.cc @@ -188,12 +188,13 @@ int FlipSession::CreateStream(FlipDelegate* delegate) { flags = flip::CONTROL_FLAG_FIN; // Create a SYN_STREAM packet and add to the output queue. - scoped_ptr<flip::FlipSynStreamControlFrame> syn_frame( - flip_framer_.CreateSynStream(stream_id, priority, flags, false, - &headers)); - int length = flip::FlipFrame::size() + syn_frame->length(); - IOBufferWithSize* buffer = new IOBufferWithSize(length); - memcpy(buffer->data(), syn_frame->data(), length); + flip::FlipSynStreamControlFrame* syn_frame = + flip_framer_.CreateSynStream(stream_id, priority, flags, false, &headers); + int length = sizeof(flip::FlipFrame) + syn_frame->length(); + IOBufferWithSize* buffer = + new IOBufferWithSize(length); + memcpy(buffer->data(), syn_frame, length); + delete[] syn_frame; queue_.push(FlipIOBuffer(buffer, priority, stream)); static StatsCounter flip_requests("flip.requests"); @@ -410,16 +411,17 @@ void FlipSession::WriteSocket() { // We've deferred compression until just before we write it to the socket, // which is now. - flip::FlipFrame uncompressed_frame(next_buffer.buffer()->data(), false); - scoped_ptr<flip::FlipFrame> compressed_frame( - flip_framer_.CompressFrame(&uncompressed_frame)); - size_t size = compressed_frame.get()->length() + flip::FlipFrame::size(); + flip::FlipFrame* uncompressed_frame = + reinterpret_cast<flip::FlipFrame*>(next_buffer.buffer()->data()); + scoped_array<flip::FlipFrame> compressed_frame( + flip_framer_.CompressFrame(uncompressed_frame)); + size_t size = compressed_frame.get()->length() + sizeof(flip::FlipFrame); DCHECK(size > 0); // TODO(mbelshe): We have too much copying of data here. IOBufferWithSize* buffer = new IOBufferWithSize(size); - memcpy(buffer->data(), compressed_frame->data(), size); + memcpy(buffer->data(), compressed_frame.get(), size); // Attempt to send the frame. in_flight_write_ = FlipIOBuffer(buffer, 0, next_buffer.stream()); @@ -643,7 +645,8 @@ void FlipSession::OnControl(const flip::FlipControlFrame* frame) { flip::FlipHeaderBlock headers; uint32 type = frame->type(); if (type == flip::SYN_STREAM || type == flip::SYN_REPLY) { - if (!flip_framer_.ParseHeaderBlock(frame, &headers)) { + if (!flip_framer_.ParseHeaderBlock( + reinterpret_cast<const flip::FlipFrame*>(frame), &headers)) { LOG(WARNING) << "Could not parse Flip Control Frame Header"; return; } @@ -695,4 +698,8 @@ void FlipSession::OnFin(const flip::FlipFinStreamControlFrame* frame) { } } +void FlipSession::OnLameDuck() { + NOTIMPLEMENTED(); +} + } // namespace net diff --git a/net/flip/flip_session.h b/net/flip/flip_session.h index 7c7ad78..a76630d 100644 --- a/net/flip/flip_session.h +++ b/net/flip/flip_session.h @@ -143,6 +143,7 @@ class FlipSession : public base::RefCounted<FlipSession>, const char* data, size_t len); virtual void OnControl(const flip::FlipControlFrame* frame); + virtual void OnLameDuck(); // Control frame handlers. void OnSyn(const flip::FlipSynStreamControlFrame* frame, |