1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/quic/quic_spdy_decompressor.h" 6 7 #include <algorithm> 8 9 #include "base/logging.h" 10 11 using base::StringPiece; 12 using std::min; 13 14 namespace net { 15 16 class SpdyFramerVisitor : public SpdyFramerVisitorInterface { 17 public: 18 explicit SpdyFramerVisitor(QuicSpdyDecompressor::Visitor* visitor) 19 : visitor_(visitor), 20 error_(false) { 21 } 22 23 virtual void OnError(SpdyFramer* framer) OVERRIDE { 24 error_ = true; 25 } 26 virtual void OnDataFrameHeader(SpdyStreamId stream_id, 27 size_t length, 28 bool fin) OVERRIDE {} 29 virtual void OnStreamFrameData(SpdyStreamId stream_id, 30 const char* data, 31 size_t len, 32 bool fin) OVERRIDE {} 33 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id, 34 const char* header_data, 35 size_t len) OVERRIDE; 36 virtual void OnSynStream(SpdyStreamId stream_id, 37 SpdyStreamId associated_stream_id, 38 SpdyPriority priority, 39 uint8 credential_slot, 40 bool fin, 41 bool unidirectional) OVERRIDE {} 42 virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {} 43 virtual void OnRstStream(SpdyStreamId stream_id, 44 SpdyRstStreamStatus status) OVERRIDE {} 45 virtual void OnSetting(SpdySettingsIds id, 46 uint8 flags, 47 uint32 value) OVERRIDE {} 48 virtual void OnPing(uint32 unique_id) OVERRIDE {} 49 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id, 50 SpdyGoAwayStatus status) OVERRIDE {} 51 virtual void OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE {} 52 virtual void OnWindowUpdate(SpdyStreamId stream_id, 53 uint32 delta_window_size) OVERRIDE {} 54 virtual bool OnCredentialFrameData(const char* credential_data, 55 size_t len) OVERRIDE { 56 return false; 57 } 58 virtual void OnPushPromise(SpdyStreamId stream_id, 59 SpdyStreamId promised_stream_id) OVERRIDE {} 60 void set_visitor(QuicSpdyDecompressor::Visitor* visitor) { 61 DCHECK(visitor); 62 visitor_ = visitor; 63 } 64 65 private: 66 QuicSpdyDecompressor::Visitor* visitor_; 67 bool error_; 68 }; 69 70 bool SpdyFramerVisitor::OnControlFrameHeaderData(SpdyStreamId stream_id, 71 const char* header_data, 72 size_t len) { 73 DCHECK(visitor_); 74 return visitor_->OnDecompressedData(StringPiece(header_data, len)); 75 } 76 77 QuicSpdyDecompressor::QuicSpdyDecompressor() 78 : spdy_framer_(SPDY3), 79 spdy_visitor_(new SpdyFramerVisitor(NULL)), 80 current_header_id_(1), 81 has_current_compressed_size_(false), 82 current_compressed_size_(0), 83 compressed_bytes_consumed_(0) { 84 spdy_framer_.set_visitor(spdy_visitor_.get()); 85 } 86 87 QuicSpdyDecompressor::~QuicSpdyDecompressor() { 88 } 89 90 size_t QuicSpdyDecompressor::DecompressData(StringPiece data, 91 Visitor* visitor) { 92 spdy_visitor_->set_visitor(visitor); 93 size_t bytes_consumed = 0; 94 95 if (!has_current_compressed_size_) { 96 const size_t kCompressedBufferSizeSize = sizeof(uint32); 97 DCHECK_GT(kCompressedBufferSizeSize, compressed_size_buffer_.length()); 98 size_t missing_size = 99 kCompressedBufferSizeSize - compressed_size_buffer_.length(); 100 if (data.length() < missing_size) { 101 data.AppendToString(&compressed_size_buffer_); 102 return data.length(); 103 } 104 bytes_consumed += missing_size; 105 data.substr(0, missing_size).AppendToString(&compressed_size_buffer_); 106 DCHECK_EQ(kCompressedBufferSizeSize, compressed_size_buffer_.length()); 107 memcpy(¤t_compressed_size_, compressed_size_buffer_.data(), 108 kCompressedBufferSizeSize); 109 compressed_size_buffer_.clear(); 110 has_current_compressed_size_ = true; 111 data = data.substr(missing_size); 112 compressed_bytes_consumed_ = 0; 113 } 114 115 size_t bytes_to_consume = 116 min(current_compressed_size_ - compressed_bytes_consumed_, 117 static_cast<uint32>(data.length())); 118 if (bytes_to_consume > 0) { 119 if (!spdy_framer_.IncrementallyDecompressControlFrameHeaderData( 120 current_header_id_, data.data(), bytes_to_consume)) { 121 visitor->OnDecompressionError(); 122 return bytes_consumed; 123 } 124 compressed_bytes_consumed_ += bytes_to_consume; 125 bytes_consumed += bytes_to_consume; 126 } 127 if (current_compressed_size_ - compressed_bytes_consumed_ == 0) { 128 ResetForNextHeaders(); 129 } 130 return bytes_consumed; 131 } 132 133 void QuicSpdyDecompressor::ResetForNextHeaders() { 134 has_current_compressed_size_ = false; 135 current_compressed_size_ = 0; 136 compressed_bytes_consumed_ = 0; 137 ++current_header_id_; 138 } 139 140 } // namespace net 141