Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 // TODO(rtenhove) clean up frame buffer size calculations so that we aren't | 5 // TODO(rtenhove) clean up frame buffer size calculations so that we aren't |
| 6 // constantly adding and subtracting header sizes; this is ugly and error- | 6 // constantly adding and subtracting header sizes; this is ugly and error- |
| 7 // prone. | 7 // prone. |
| 8 | 8 |
| 9 #include "net/spdy/spdy_framer.h" | 9 #include "net/spdy/spdy_framer.h" |
| 10 | 10 |
| 11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/metrics/stats_counters.h" | 12 #include "base/metrics/stats_counters.h" |
| 13 #include "base/third_party/valgrind/memcheck.h" | 13 #include "base/third_party/valgrind/memcheck.h" |
| 14 #include "net/spdy/spdy_frame_builder.h" | 14 #include "net/spdy/spdy_frame_builder.h" |
| 15 #include "net/spdy/spdy_bitmasks.h" | 15 #include "net/spdy/spdy_bitmasks.h" |
| 16 | 16 |
| 17 #if defined(USE_SYSTEM_ZLIB) | 17 #if defined(USE_SYSTEM_ZLIB) |
| 18 #include <zlib.h> | 18 #include <zlib.h> |
| 19 #else | 19 #else |
| 20 #include "third_party/zlib/zlib.h" | 20 #include "third_party/zlib/zlib.h" |
| 21 #endif | 21 #endif |
| 22 | 22 |
| 23 namespace net { | |
| 24 | |
|
Mike Belshe
2011/04/06 18:32:53
delete lines 22-25.
| |
| 25 } // namespace net | |
| 26 | |
| 23 namespace { | 27 namespace { |
| 24 | 28 |
| 25 // The following compression setting are based on Brian Olson's analysis. See | 29 // The following compression setting are based on Brian Olson's analysis. See |
| 26 // https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac79 2 | 30 // https://groups.google.com/group/spdy-dev/browse_thread/thread/dfaf498542fac79 2 |
| 27 // for more details. | 31 // for more details. |
| 28 const int kCompressorLevel = 9; | 32 const int kCompressorLevel = 9; |
| 29 const int kCompressorWindowSizeInBits = 11; | 33 const int kCompressorWindowSizeInBits = 11; |
| 30 const int kCompressorMemLevel = 1; | 34 const int kCompressorMemLevel = 1; |
| 31 | 35 |
| 32 uLong dictionary_id = 0; | 36 // TODO(jtl): Need to decide how to handle this. The array dimension must be as |
| 37 // large as the maximum SCTP stream ID we will ever use. | |
| 38 uLong dictionary_ids[100] = {0}; | |
| 33 | 39 |
| 34 } // namespace | 40 } // namespace |
| 35 | 41 |
| 36 namespace spdy { | 42 namespace spdy { |
| 37 | 43 |
| 38 // This is just a hacked dictionary to use for shrinking HTTP-like headers. | 44 // This is just a hacked dictionary to use for shrinking HTTP-like headers. |
| 39 // TODO(mbelshe): Use a scientific methodology for computing the dictionary. | 45 // TODO(mbelshe): Use a scientific methodology for computing the dictionary. |
| 40 const char SpdyFramer::kDictionary[] = | 46 const char SpdyFramer::kDictionary[] = |
| 41 "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-" | 47 "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-" |
| 42 "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi" | 48 "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 86 remaining_payload_(0), | 92 remaining_payload_(0), |
| 87 remaining_control_payload_(0), | 93 remaining_control_payload_(0), |
| 88 current_frame_buffer_(NULL), | 94 current_frame_buffer_(NULL), |
| 89 current_frame_len_(0), | 95 current_frame_len_(0), |
| 90 current_frame_capacity_(0), | 96 current_frame_capacity_(0), |
| 91 enable_compression_(compression_default_), | 97 enable_compression_(compression_default_), |
| 92 visitor_(NULL) { | 98 visitor_(NULL) { |
| 93 } | 99 } |
| 94 | 100 |
| 95 SpdyFramer::~SpdyFramer() { | 101 SpdyFramer::~SpdyFramer() { |
| 96 if (header_compressor_.get()) { | 102 CleanupHeaderCompressorsAndDecompressors(); |
| 97 deflateEnd(header_compressor_.get()); | |
| 98 } | |
| 99 if (header_decompressor_.get()) { | |
| 100 inflateEnd(header_decompressor_.get()); | |
| 101 } | |
| 102 CleanupStreamCompressorsAndDecompressors(); | 103 CleanupStreamCompressorsAndDecompressors(); |
| 103 delete [] current_frame_buffer_; | 104 delete [] current_frame_buffer_; |
| 104 } | 105 } |
| 105 | 106 |
| 106 size_t SpdyFramer::ProcessInput(const char* data, size_t len) { | 107 size_t SpdyFramer::ProcessInput(const char* data, size_t len) { |
| 107 DCHECK(visitor_); | 108 DCHECK(visitor_); |
| 108 DCHECK(data); | 109 DCHECK(data); |
| 109 | 110 |
| 110 size_t original_len = len; | 111 size_t original_len = len; |
| 111 while (len != 0) { | 112 while (len != 0) { |
| (...skipping 681 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 793 current_data_frame.flags() & DATA_FLAG_FIN) { | 794 current_data_frame.flags() & DATA_FLAG_FIN) { |
| 794 visitor_->OnStreamFrameData(current_data_frame.stream_id(), NULL, 0); | 795 visitor_->OnStreamFrameData(current_data_frame.stream_id(), NULL, 0); |
| 795 CleanupDecompressorForStream(current_data_frame.stream_id()); | 796 CleanupDecompressorForStream(current_data_frame.stream_id()); |
| 796 } | 797 } |
| 797 } else { | 798 } else { |
| 798 CHANGE_STATE(SPDY_AUTO_RESET); | 799 CHANGE_STATE(SPDY_AUTO_RESET); |
| 799 } | 800 } |
| 800 return original_len - len; | 801 return original_len - len; |
| 801 } | 802 } |
| 802 | 803 |
| 803 z_stream* SpdyFramer::GetHeaderCompressor() { | 804 uint16 SpdyFramer::GetDictionaryIndex(const SpdyControlFrame& control_frame) { |
| 804 if (header_compressor_.get()) | 805 uint32 stream_id = 0; |
| 805 return header_compressor_.get(); // Already initialized. | 806 // TODO(jtl): Need to reconcile this with IsCompressible() which only returns |
| 807 // true for SYN_STREAM and SYN_REPLY control frames. | |
| 808 switch (control_frame.type()) { | |
| 809 case SYN_STREAM: | |
| 810 stream_id = reinterpret_cast<const SpdySynStreamControlFrame&> | |
| 811 (control_frame).stream_id(); | |
| 812 break; | |
| 813 case SYN_REPLY: | |
| 814 stream_id = reinterpret_cast<const SpdySynReplyControlFrame&> | |
| 815 (control_frame).stream_id(); | |
| 816 break; | |
| 817 case RST_STREAM: | |
| 818 stream_id = reinterpret_cast<const SpdyRstStreamControlFrame&> | |
| 819 (control_frame).stream_id(); | |
| 820 break; | |
| 821 case HEADERS: | |
| 822 stream_id = reinterpret_cast<const SpdyHeadersControlFrame&> | |
| 823 (control_frame).stream_id(); | |
| 824 break; | |
| 825 case WINDOW_UPDATE: | |
| 826 stream_id = reinterpret_cast<const SpdyWindowUpdateControlFrame&> | |
| 827 (control_frame).stream_id(); | |
| 828 break; | |
| 829 default: | |
| 830 break; | |
| 831 } | |
| 806 | 832 |
| 807 header_compressor_.reset(new z_stream); | 833 return stream_id ? MapSpdyToSctp(stream_id) : 0; |
| 808 memset(header_compressor_.get(), 0, sizeof(z_stream)); | 834 } |
| 809 | 835 |
| 810 int success = deflateInit2(header_compressor_.get(), | 836 z_stream* SpdyFramer::GetHeaderCompressor(int index) { |
| 837 CompressorMap::iterator it = header_compressors_.find(index); | |
| 838 if (it != header_compressors_.end()) | |
| 839 return it->second; // Already initialized. | |
| 840 | |
| 841 scoped_ptr<z_stream> compressor(new z_stream); | |
| 842 memset(compressor.get(), 0, sizeof(z_stream)); | |
| 843 | |
| 844 int success = deflateInit2(compressor.get(), | |
| 811 kCompressorLevel, | 845 kCompressorLevel, |
| 812 Z_DEFLATED, | 846 Z_DEFLATED, |
| 813 kCompressorWindowSizeInBits, | 847 kCompressorWindowSizeInBits, |
| 814 kCompressorMemLevel, | 848 kCompressorMemLevel, |
| 815 Z_DEFAULT_STRATEGY); | 849 Z_DEFAULT_STRATEGY); |
| 816 if (success == Z_OK) | 850 if (success == Z_OK) |
| 817 success = deflateSetDictionary(header_compressor_.get(), | 851 success = deflateSetDictionary(compressor.get(), |
| 818 reinterpret_cast<const Bytef*>(kDictionary), | 852 reinterpret_cast<const Bytef*>(kDictionary), |
| 819 kDictionarySize); | 853 kDictionarySize); |
| 820 if (success != Z_OK) { | 854 if (success != Z_OK) { |
| 821 LOG(WARNING) << "deflateSetDictionary failure: " << success; | 855 LOG(WARNING) << "deflateSetDictionary failure: " << success; |
| 822 header_compressor_.reset(NULL); | 856 compressor.reset(NULL); |
| 823 return NULL; | 857 return NULL; |
| 824 } | 858 } |
| 825 return header_compressor_.get(); | 859 return header_compressors_[index] = compressor.release(); |
| 826 } | 860 } |
| 827 | 861 |
| 828 z_stream* SpdyFramer::GetHeaderDecompressor() { | 862 z_stream* SpdyFramer::GetHeaderDecompressor(int index) { |
| 829 if (header_decompressor_.get()) | 863 CompressorMap::iterator it = header_decompressors_.find(index); |
| 830 return header_decompressor_.get(); // Already initialized. | 864 if (it != header_decompressors_.end()) |
| 865 return it->second; // Already initialized. | |
| 831 | 866 |
| 832 header_decompressor_.reset(new z_stream); | 867 scoped_ptr<z_stream> decompressor(new z_stream); |
| 833 memset(header_decompressor_.get(), 0, sizeof(z_stream)); | 868 memset(decompressor.get(), 0, sizeof(z_stream)); |
| 834 | 869 |
| 835 // Compute the id of our dictionary so that we know we're using the | 870 // Compute the id of our dictionary so that we know we're using the |
| 836 // right one when asked for it. | 871 // right one when asked for it. |
| 837 if (dictionary_id == 0) { | 872 if (dictionary_ids[index] == 0) { |
| 838 dictionary_id = adler32(0L, Z_NULL, 0); | 873 dictionary_ids[index] = adler32(0L, Z_NULL, 0); |
| 839 dictionary_id = adler32(dictionary_id, | 874 dictionary_ids[index] = adler32(dictionary_ids[index], |
| 840 reinterpret_cast<const Bytef*>(kDictionary), | 875 reinterpret_cast<const Bytef*>(kDictionary), |
| 841 kDictionarySize); | 876 kDictionarySize); |
| 842 } | 877 } |
| 843 | 878 |
| 844 int success = inflateInit(header_decompressor_.get()); | 879 int success = inflateInit(decompressor.get()); |
| 845 if (success != Z_OK) { | 880 if (success != Z_OK) { |
| 846 LOG(WARNING) << "inflateInit failure: " << success; | 881 LOG(WARNING) << "inflateInit failure: " << success; |
| 847 header_decompressor_.reset(NULL); | |
| 848 return NULL; | 882 return NULL; |
| 849 } | 883 } |
| 850 return header_decompressor_.get(); | 884 return header_decompressors_[index] = decompressor.release(); |
| 851 } | 885 } |
| 852 | 886 |
| 853 z_stream* SpdyFramer::GetStreamCompressor(SpdyStreamId stream_id) { | 887 z_stream* SpdyFramer::GetStreamCompressor(SpdyStreamId stream_id) { |
| 854 CompressorMap::iterator it = stream_compressors_.find(stream_id); | 888 CompressorMap::iterator it = stream_compressors_.find(stream_id); |
| 855 if (it != stream_compressors_.end()) | 889 if (it != stream_compressors_.end()) |
| 856 return it->second; // Already initialized. | 890 return it->second; // Already initialized. |
| 857 | 891 |
| 858 scoped_ptr<z_stream> compressor(new z_stream); | 892 scoped_ptr<z_stream> compressor(new z_stream); |
| 859 memset(compressor.get(), 0, sizeof(z_stream)); | 893 memset(compressor.get(), 0, sizeof(z_stream)); |
| 860 | 894 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 882 int success = inflateInit(decompressor.get()); | 916 int success = inflateInit(decompressor.get()); |
| 883 if (success != Z_OK) { | 917 if (success != Z_OK) { |
| 884 LOG(WARNING) << "inflateInit failure: " << success; | 918 LOG(WARNING) << "inflateInit failure: " << success; |
| 885 return NULL; | 919 return NULL; |
| 886 } | 920 } |
| 887 return stream_decompressors_[stream_id] = decompressor.release(); | 921 return stream_decompressors_[stream_id] = decompressor.release(); |
| 888 } | 922 } |
| 889 | 923 |
| 890 SpdyControlFrame* SpdyFramer::CompressControlFrame( | 924 SpdyControlFrame* SpdyFramer::CompressControlFrame( |
| 891 const SpdyControlFrame& frame) { | 925 const SpdyControlFrame& frame) { |
| 892 z_stream* compressor = GetHeaderCompressor(); | 926 uint16 dictionary_index = 0; |
| 927 if (using_sctp() && !using_sctp_control_stream()) | |
| 928 dictionary_index = GetDictionaryIndex(frame); | |
| 929 z_stream* compressor = GetHeaderCompressor(dictionary_index); | |
| 930 | |
| 893 if (!compressor) | 931 if (!compressor) |
| 894 return NULL; | 932 return NULL; |
| 895 return reinterpret_cast<SpdyControlFrame*>( | 933 return reinterpret_cast<SpdyControlFrame*>( |
| 896 CompressFrameWithZStream(frame, compressor)); | 934 CompressFrameWithZStream(frame, compressor)); |
| 897 } | 935 } |
| 898 | 936 |
| 899 SpdyDataFrame* SpdyFramer::CompressDataFrame(const SpdyDataFrame& frame) { | 937 SpdyDataFrame* SpdyFramer::CompressDataFrame(const SpdyDataFrame& frame) { |
| 900 z_stream* compressor = GetStreamCompressor(frame.stream_id()); | 938 z_stream* compressor = GetStreamCompressor(frame.stream_id()); |
| 901 if (!compressor) | 939 if (!compressor) |
| 902 return NULL; | 940 return NULL; |
| 903 return reinterpret_cast<SpdyDataFrame*>( | 941 return reinterpret_cast<SpdyDataFrame*>( |
| 904 CompressFrameWithZStream(frame, compressor)); | 942 CompressFrameWithZStream(frame, compressor)); |
| 905 } | 943 } |
| 906 | 944 |
| 907 SpdyControlFrame* SpdyFramer::DecompressControlFrame( | 945 SpdyControlFrame* SpdyFramer::DecompressControlFrame( |
| 908 const SpdyControlFrame& frame) { | 946 const SpdyControlFrame& frame) { |
| 909 z_stream* decompressor = GetHeaderDecompressor(); | 947 uint16 dictionary_index = 0; |
| 948 if (using_sctp() && !using_sctp_control_stream()) | |
| 949 dictionary_index = GetDictionaryIndex(frame); | |
| 950 z_stream* decompressor = GetHeaderDecompressor(dictionary_index); | |
| 951 | |
| 910 if (!decompressor) | 952 if (!decompressor) |
| 911 return NULL; | 953 return NULL; |
| 912 return reinterpret_cast<SpdyControlFrame*>( | 954 return reinterpret_cast<SpdyControlFrame*>( |
| 913 DecompressFrameWithZStream(frame, decompressor)); | 955 DecompressFrameWithZStream(frame, decompressor)); |
| 914 } | 956 } |
| 915 | 957 |
| 916 SpdyDataFrame* SpdyFramer::DecompressDataFrame(const SpdyDataFrame& frame) { | 958 SpdyDataFrame* SpdyFramer::DecompressDataFrame(const SpdyDataFrame& frame) { |
| 917 z_stream* decompressor = GetStreamDecompressor(frame.stream_id()); | 959 z_stream* decompressor = GetStreamDecompressor(frame.stream_id()); |
| 918 if (!decompressor) | 960 if (!decompressor) |
| 919 return NULL; | 961 return NULL; |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1019 | 1061 |
| 1020 decompressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload)); | 1062 decompressor->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(payload)); |
| 1021 decompressor->avail_in = payload_length; | 1063 decompressor->avail_in = payload_length; |
| 1022 decompressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) + | 1064 decompressor->next_out = reinterpret_cast<Bytef*>(new_frame->data()) + |
| 1023 header_length; | 1065 header_length; |
| 1024 decompressor->avail_out = decompressed_max_size; | 1066 decompressor->avail_out = decompressed_max_size; |
| 1025 | 1067 |
| 1026 int rv = inflate(decompressor, Z_SYNC_FLUSH); | 1068 int rv = inflate(decompressor, Z_SYNC_FLUSH); |
| 1027 if (rv == Z_NEED_DICT) { | 1069 if (rv == Z_NEED_DICT) { |
| 1028 // Need to try again with the right dictionary. | 1070 // Need to try again with the right dictionary. |
| 1029 if (decompressor->adler == dictionary_id) { | 1071 uint16 dictionary_index = 0; |
| 1072 if (using_sctp() && !using_sctp_control_stream() && | |
| 1073 frame.is_control_frame()) { | |
| 1074 dictionary_index = GetDictionaryIndex( | |
| 1075 reinterpret_cast<const SpdyControlFrame&>(frame)); | |
| 1076 } | |
| 1077 if (decompressor->adler == dictionary_ids[dictionary_index]) { | |
| 1030 rv = inflateSetDictionary(decompressor, (const Bytef*)kDictionary, | 1078 rv = inflateSetDictionary(decompressor, (const Bytef*)kDictionary, |
| 1031 kDictionarySize); | 1079 kDictionarySize); |
| 1032 if (rv == Z_OK) | 1080 if (rv == Z_OK) |
| 1033 rv = inflate(decompressor, Z_SYNC_FLUSH); | 1081 rv = inflate(decompressor, Z_SYNC_FLUSH); |
| 1034 } | 1082 } |
| 1035 } | 1083 } |
| 1036 if (rv != Z_OK) { // How can we know that it decompressed everything? | 1084 if (rv != Z_OK) { // How can we know that it decompressed everything? |
| 1037 LOG(WARNING) << "inflate failure: " << rv; | 1085 LOG(WARNING) << "inflate failure: " << rv; |
| 1038 return NULL; | 1086 return NULL; |
| 1039 } | 1087 } |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1096 it = stream_decompressors_.begin(); | 1144 it = stream_decompressors_.begin(); |
| 1097 while (it != stream_decompressors_.end()) { | 1145 while (it != stream_decompressors_.end()) { |
| 1098 z_stream* decompressor = it->second; | 1146 z_stream* decompressor = it->second; |
| 1099 inflateEnd(decompressor); | 1147 inflateEnd(decompressor); |
| 1100 delete decompressor; | 1148 delete decompressor; |
| 1101 ++it; | 1149 ++it; |
| 1102 } | 1150 } |
| 1103 stream_decompressors_.clear(); | 1151 stream_decompressors_.clear(); |
| 1104 } | 1152 } |
| 1105 | 1153 |
| 1154 void SpdyFramer::CleanupHeaderCompressorsAndDecompressors() { | |
| 1155 CompressorMap::iterator it; | |
| 1156 | |
| 1157 it = header_compressors_.begin(); | |
| 1158 while (it != header_compressors_.end()) { | |
| 1159 z_stream* compressor = it->second; | |
| 1160 deflateEnd(compressor); | |
| 1161 delete compressor; | |
| 1162 ++it; | |
| 1163 } | |
| 1164 header_compressors_.clear(); | |
| 1165 | |
| 1166 it = header_decompressors_.begin(); | |
| 1167 while (it != header_decompressors_.end()) { | |
| 1168 z_stream* decompressor = it->second; | |
| 1169 inflateEnd(decompressor); | |
| 1170 delete decompressor; | |
| 1171 ++it; | |
| 1172 } | |
| 1173 header_decompressors_.clear(); | |
| 1174 } | |
| 1175 | |
| 1106 size_t SpdyFramer::BytesSafeToRead() const { | 1176 size_t SpdyFramer::BytesSafeToRead() const { |
| 1107 switch (state_) { | 1177 switch (state_) { |
| 1108 case SPDY_ERROR: | 1178 case SPDY_ERROR: |
| 1109 case SPDY_DONE: | 1179 case SPDY_DONE: |
| 1110 case SPDY_AUTO_RESET: | 1180 case SPDY_AUTO_RESET: |
| 1111 case SPDY_RESET: | 1181 case SPDY_RESET: |
| 1112 return 0; | 1182 return 0; |
| 1113 case SPDY_READING_COMMON_HEADER: | 1183 case SPDY_READING_COMMON_HEADER: |
| 1114 DCHECK_LT(current_frame_len_, SpdyFrame::size()); | 1184 DCHECK_LT(current_frame_len_, SpdyFrame::size()); |
| 1115 return SpdyFrame::size() - current_frame_len_; | 1185 return SpdyFrame::size() - current_frame_len_; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1189 } else { | 1259 } else { |
| 1190 frame_size = SpdyFrame::size(); | 1260 frame_size = SpdyFrame::size(); |
| 1191 *header_length = frame_size; | 1261 *header_length = frame_size; |
| 1192 *payload_length = frame.length(); | 1262 *payload_length = frame.length(); |
| 1193 *payload = frame.data() + SpdyFrame::size(); | 1263 *payload = frame.data() + SpdyFrame::size(); |
| 1194 } | 1264 } |
| 1195 return true; | 1265 return true; |
| 1196 } | 1266 } |
| 1197 | 1267 |
| 1198 } // namespace spdy | 1268 } // namespace spdy |
| OLD | NEW |