OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/spdy/spdy_framer.h" | 5 #include "net/spdy/spdy_framer.h" |
6 | 6 |
7 #include "base/lazy_instance.h" | 7 #include "base/lazy_instance.h" |
8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
9 #include "base/metrics/stats_counters.h" | 9 #include "base/metrics/stats_counters.h" |
10 #include "base/third_party/valgrind/memcheck.h" | 10 #include "base/third_party/valgrind/memcheck.h" |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 size_t len) { | 151 size_t len) { |
152 return true; | 152 return true; |
153 } | 153 } |
154 | 154 |
155 SpdyFramer::SpdyFramer(SpdyMajorVersion version) | 155 SpdyFramer::SpdyFramer(SpdyMajorVersion version) |
156 : current_frame_buffer_(new char[kControlFrameBufferSize]), | 156 : current_frame_buffer_(new char[kControlFrameBufferSize]), |
157 enable_compression_(true), | 157 enable_compression_(true), |
158 visitor_(NULL), | 158 visitor_(NULL), |
159 debug_visitor_(NULL), | 159 debug_visitor_(NULL), |
160 display_protocol_("SPDY"), | 160 display_protocol_("SPDY"), |
161 spdy_version_(version), | 161 protocol_version_(version), |
162 syn_frame_processed_(false), | 162 syn_frame_processed_(false), |
163 probable_http_response_(false), | 163 probable_http_response_(false), |
164 expect_continuation_(0), | 164 expect_continuation_(0), |
165 end_stream_when_done_(false) { | 165 end_stream_when_done_(false) { |
166 DCHECK_GE(spdy_version_, SPDY_MIN_VERSION); | 166 DCHECK_GE(protocol_version_, SPDY_MIN_VERSION); |
167 DCHECK_LE(spdy_version_, SPDY_MAX_VERSION); | 167 DCHECK_LE(protocol_version_, SPDY_MAX_VERSION); |
168 DCHECK_LE(kMaxControlFrameSize, | 168 DCHECK_LE(kMaxControlFrameSize, |
169 SpdyConstants::GetFrameMaximumSize(spdy_version_) + | 169 SpdyConstants::GetFrameMaximumSize(protocol_version_) + |
170 SpdyConstants::GetControlFrameHeaderSize(spdy_version_)); | 170 SpdyConstants::GetControlFrameHeaderSize(protocol_version_)); |
171 Reset(); | 171 Reset(); |
172 } | 172 } |
173 | 173 |
174 SpdyFramer::~SpdyFramer() { | 174 SpdyFramer::~SpdyFramer() { |
175 if (header_compressor_.get()) { | 175 if (header_compressor_.get()) { |
176 deflateEnd(header_compressor_.get()); | 176 deflateEnd(header_compressor_.get()); |
177 } | 177 } |
178 if (header_decompressor_.get()) { | 178 if (header_decompressor_.get()) { |
179 inflateEnd(header_decompressor_.get()); | 179 inflateEnd(header_decompressor_.get()); |
180 } | 180 } |
(...skipping 872 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1053 break; | 1053 break; |
1054 } | 1054 } |
1055 | 1055 |
1056 if (state_ == SPDY_ERROR) { | 1056 if (state_ == SPDY_ERROR) { |
1057 return; | 1057 return; |
1058 } | 1058 } |
1059 | 1059 |
1060 if (current_frame_length_ > | 1060 if (current_frame_length_ > |
1061 SpdyConstants::GetFrameMaximumSize(protocol_version()) + | 1061 SpdyConstants::GetFrameMaximumSize(protocol_version()) + |
1062 SpdyConstants::GetControlFrameHeaderSize(protocol_version())) { | 1062 SpdyConstants::GetControlFrameHeaderSize(protocol_version())) { |
1063 DLOG(WARNING) << "Received control frame with way too big of a payload: " | 1063 DLOG(WARNING) << "Received control frame of type " << current_frame_type_ |
| 1064 << " with way too big of a payload: " |
1064 << current_frame_length_; | 1065 << current_frame_length_; |
1065 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); | 1066 set_error(SPDY_CONTROL_PAYLOAD_TOO_LARGE); |
1066 return; | 1067 return; |
1067 } | 1068 } |
1068 | 1069 |
1069 if (current_frame_type_ == GOAWAY) { | 1070 if (current_frame_type_ == GOAWAY) { |
1070 CHANGE_STATE(SPDY_GOAWAY_FRAME_PAYLOAD); | 1071 CHANGE_STATE(SPDY_GOAWAY_FRAME_PAYLOAD); |
1071 return; | 1072 return; |
1072 } | 1073 } |
1073 | 1074 |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1274 } | 1275 } |
1275 WriteZ(base::StringPiece(buf, length), clas, out); | 1276 WriteZ(base::StringPiece(buf, length), clas, out); |
1276 } | 1277 } |
1277 | 1278 |
1278 // WriteHeaderBlockToZ serialises |headers| to the deflate context |z| in a | 1279 // WriteHeaderBlockToZ serialises |headers| to the deflate context |z| in a |
1279 // manner that resists the length of the compressed data from compromising | 1280 // manner that resists the length of the compressed data from compromising |
1280 // cookie data. | 1281 // cookie data. |
1281 void SpdyFramer::WriteHeaderBlockToZ(const SpdyHeaderBlock* headers, | 1282 void SpdyFramer::WriteHeaderBlockToZ(const SpdyHeaderBlock* headers, |
1282 z_stream* z) const { | 1283 z_stream* z) const { |
1283 unsigned length_length = 4; | 1284 unsigned length_length = 4; |
1284 if (spdy_version_ < 3) | 1285 if (protocol_version() < 3) |
1285 length_length = 2; | 1286 length_length = 2; |
1286 | 1287 |
1287 WriteLengthZ(headers->size(), length_length, kZStandardData, z); | 1288 WriteLengthZ(headers->size(), length_length, kZStandardData, z); |
1288 | 1289 |
1289 std::map<std::string, std::string>::const_iterator it; | 1290 std::map<std::string, std::string>::const_iterator it; |
1290 for (it = headers->begin(); it != headers->end(); ++it) { | 1291 for (it = headers->begin(); it != headers->end(); ++it) { |
1291 WriteLengthZ(it->first.size(), length_length, kZStandardData, z); | 1292 WriteLengthZ(it->first.size(), length_length, kZStandardData, z); |
1292 WriteZ(it->first, kZStandardData, z); | 1293 WriteZ(it->first, kZStandardData, z); |
1293 | 1294 |
1294 if (it->first == "cookie") { | 1295 if (it->first == "cookie") { |
(...skipping 1674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2969 DCHECK_GT(size, kMaxControlFrameSize); | 2970 DCHECK_GT(size, kMaxControlFrameSize); |
2970 size_t overflow = size - kMaxControlFrameSize; | 2971 size_t overflow = size - kMaxControlFrameSize; |
2971 return overflow / (kMaxControlFrameSize - GetContinuationMinimumSize()) + 1; | 2972 return overflow / (kMaxControlFrameSize - GetContinuationMinimumSize()) + 1; |
2972 } | 2973 } |
2973 | 2974 |
2974 void SpdyFramer::WritePayloadWithContinuation(SpdyFrameBuilder* builder, | 2975 void SpdyFramer::WritePayloadWithContinuation(SpdyFrameBuilder* builder, |
2975 const string& hpack_encoding, | 2976 const string& hpack_encoding, |
2976 SpdyStreamId stream_id, | 2977 SpdyStreamId stream_id, |
2977 SpdyFrameType type, | 2978 SpdyFrameType type, |
2978 int padding_payload_len) { | 2979 int padding_payload_len) { |
2979 uint8 end_flag = 0; | 2980 uint8 end_flag = 0; |
2980 uint8 flags = 0; | 2981 uint8 flags = 0; |
2981 if (type == HEADERS) { | 2982 if (type == HEADERS) { |
2982 end_flag = HEADERS_FLAG_END_HEADERS; | 2983 end_flag = HEADERS_FLAG_END_HEADERS; |
2983 } else if (type == PUSH_PROMISE) { | 2984 } else if (type == PUSH_PROMISE) { |
2984 end_flag = PUSH_PROMISE_FLAG_END_PUSH_PROMISE; | 2985 end_flag = PUSH_PROMISE_FLAG_END_PUSH_PROMISE; |
2985 } else { | 2986 } else { |
2986 DLOG(FATAL) << "CONTINUATION frames cannot be used with frame type " | 2987 DLOG(FATAL) << "CONTINUATION frames cannot be used with frame type " |
2987 << FrameTypeToString(type); | 2988 << FrameTypeToString(type); |
| 2989 } |
| 2990 |
| 2991 // Write all the padding payload and as much of the data payload as possible |
| 2992 // into the initial frame. |
| 2993 size_t bytes_remaining = 0; |
| 2994 bytes_remaining = |
| 2995 hpack_encoding.size() - |
| 2996 std::min(hpack_encoding.size(), |
| 2997 kMaxControlFrameSize - builder->length() - padding_payload_len); |
| 2998 builder->WriteBytes(&hpack_encoding[0], |
| 2999 hpack_encoding.size() - bytes_remaining); |
| 3000 if (padding_payload_len > 0) { |
| 3001 string padding = string(padding_payload_len, 0); |
| 3002 builder->WriteBytes(padding.data(), padding.length()); |
| 3003 } |
| 3004 if (bytes_remaining > 0) { |
| 3005 builder->OverwriteLength( |
| 3006 *this, kMaxControlFrameSize - GetControlFrameHeaderSize()); |
| 3007 } |
| 3008 |
| 3009 // Tack on CONTINUATION frames for the overflow. |
| 3010 while (bytes_remaining > 0) { |
| 3011 size_t bytes_to_write = std::min( |
| 3012 bytes_remaining, kMaxControlFrameSize - GetContinuationMinimumSize()); |
| 3013 // Write CONTINUATION frame prefix. |
| 3014 if (bytes_remaining == bytes_to_write) { |
| 3015 flags |= end_flag; |
2988 } | 3016 } |
2989 | 3017 builder->BeginNewFrame(*this, CONTINUATION, flags, stream_id); |
2990 // Write all the padding payload and as much of the data payload as possible | 3018 // Write payload fragment. |
2991 // into the initial frame. | 3019 builder->WriteBytes( |
2992 size_t bytes_remaining = 0; | 3020 &hpack_encoding[hpack_encoding.size() - bytes_remaining], |
2993 bytes_remaining = hpack_encoding.size() - | 3021 bytes_to_write); |
2994 std::min(hpack_encoding.size(), | 3022 bytes_remaining -= bytes_to_write; |
2995 kMaxControlFrameSize - builder->length() - | 3023 } |
2996 padding_payload_len); | |
2997 builder->WriteBytes(&hpack_encoding[0], | |
2998 hpack_encoding.size() - bytes_remaining); | |
2999 if (padding_payload_len > 0) { | |
3000 string padding = string(padding_payload_len, 0); | |
3001 builder->WriteBytes(padding.data(), padding.length()); | |
3002 } | |
3003 if (bytes_remaining > 0) { | |
3004 builder->OverwriteLength(*this, | |
3005 kMaxControlFrameSize - GetControlFrameHeaderSize()); | |
3006 } | |
3007 | |
3008 // Tack on CONTINUATION frames for the overflow. | |
3009 while (bytes_remaining > 0) { | |
3010 size_t bytes_to_write = std::min(bytes_remaining, | |
3011 kMaxControlFrameSize - | |
3012 GetContinuationMinimumSize()); | |
3013 // Write CONTINUATION frame prefix. | |
3014 if (bytes_remaining == bytes_to_write) { | |
3015 flags |= end_flag; | |
3016 } | |
3017 builder->BeginNewFrame(*this, | |
3018 CONTINUATION, | |
3019 flags, | |
3020 stream_id); | |
3021 // Write payload fragment. | |
3022 builder->WriteBytes(&hpack_encoding[hpack_encoding.size() - | |
3023 bytes_remaining], | |
3024 bytes_to_write); | |
3025 bytes_remaining -= bytes_to_write; | |
3026 } | |
3027 } | 3024 } |
3028 | 3025 |
3029 // The following compression setting are based on Brian Olson's analysis. See | 3026 // The following compression setting are based on Brian Olson's analysis. See |
3030 // https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac79
2 | 3027 // https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac79
2 |
3031 // for more details. | 3028 // for more details. |
3032 #if defined(USE_SYSTEM_ZLIB) | 3029 #if defined(USE_SYSTEM_ZLIB) |
3033 // System zlib is not expected to have workaround for http://crbug.com/139744, | 3030 // System zlib is not expected to have workaround for http://crbug.com/139744, |
3034 // so disable compression in that case. | 3031 // so disable compression in that case. |
3035 // TODO(phajdan.jr): Remove the special case when it's no longer necessary. | 3032 // TODO(phajdan.jr): Remove the special case when it's no longer necessary. |
3036 static const int kCompressorLevel = 0; | 3033 static const int kCompressorLevel = 0; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3080 int success = inflateInit(header_decompressor_.get()); | 3077 int success = inflateInit(header_decompressor_.get()); |
3081 if (success != Z_OK) { | 3078 if (success != Z_OK) { |
3082 LOG(WARNING) << "inflateInit failure: " << success; | 3079 LOG(WARNING) << "inflateInit failure: " << success; |
3083 header_decompressor_.reset(NULL); | 3080 header_decompressor_.reset(NULL); |
3084 return NULL; | 3081 return NULL; |
3085 } | 3082 } |
3086 return header_decompressor_.get(); | 3083 return header_decompressor_.get(); |
3087 } | 3084 } |
3088 | 3085 |
3089 HpackEncoder* SpdyFramer::GetHpackEncoder() { | 3086 HpackEncoder* SpdyFramer::GetHpackEncoder() { |
3090 DCHECK_LT(SPDY3, spdy_version_); | 3087 DCHECK_LT(SPDY3, protocol_version()); |
3091 if (hpack_encoder_.get() == NULL) { | 3088 if (hpack_encoder_.get() == nullptr) { |
3092 hpack_encoder_.reset(new HpackEncoder(ObtainHpackHuffmanTable())); | 3089 hpack_encoder_.reset(new HpackEncoder(ObtainHpackHuffmanTable())); |
3093 } | 3090 } |
3094 return hpack_encoder_.get(); | 3091 return hpack_encoder_.get(); |
3095 } | 3092 } |
3096 | 3093 |
3097 HpackDecoder* SpdyFramer::GetHpackDecoder() { | 3094 HpackDecoder* SpdyFramer::GetHpackDecoder() { |
3098 DCHECK_LT(SPDY3, spdy_version_); | 3095 DCHECK_LT(SPDY3, protocol_version()); |
3099 if (hpack_decoder_.get() == NULL) { | 3096 if (hpack_decoder_.get() == nullptr) { |
3100 hpack_decoder_.reset(new HpackDecoder(ObtainHpackHuffmanTable())); | 3097 hpack_decoder_.reset(new HpackDecoder(ObtainHpackHuffmanTable())); |
3101 } | 3098 } |
3102 return hpack_decoder_.get(); | 3099 return hpack_decoder_.get(); |
3103 } | 3100 } |
3104 | 3101 |
3105 uint8 SpdyFramer::MapPriorityToWeight(SpdyPriority priority) { | 3102 uint8 SpdyFramer::MapPriorityToWeight(SpdyPriority priority) { |
3106 const float kSteps = 255.9f / 7.f; | 3103 const float kSteps = 255.9f / 7.f; |
3107 return static_cast<uint8>(kSteps * (7.f - priority)); | 3104 return static_cast<uint8>(kSteps * (7.f - priority)); |
3108 } | 3105 } |
3109 | 3106 |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3291 builder->Seek(compressed_size); | 3288 builder->Seek(compressed_size); |
3292 builder->RewriteLength(*this); | 3289 builder->RewriteLength(*this); |
3293 | 3290 |
3294 pre_compress_bytes.Add(uncompressed_len); | 3291 pre_compress_bytes.Add(uncompressed_len); |
3295 post_compress_bytes.Add(compressed_size); | 3292 post_compress_bytes.Add(compressed_size); |
3296 | 3293 |
3297 compressed_frames.Increment(); | 3294 compressed_frames.Increment(); |
3298 } | 3295 } |
3299 | 3296 |
3300 } // namespace net | 3297 } // namespace net |
OLD | NEW |