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 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 remaining_data_length_ = 0; | 159 remaining_data_length_ = 0; |
160 remaining_control_header_ = 0; | 160 remaining_control_header_ = 0; |
161 current_frame_buffer_length_ = 0; | 161 current_frame_buffer_length_ = 0; |
162 current_frame_type_ = DATA; | 162 current_frame_type_ = DATA; |
163 current_frame_flags_ = 0; | 163 current_frame_flags_ = 0; |
164 current_frame_length_ = 0; | 164 current_frame_length_ = 0; |
165 current_frame_stream_id_ = kInvalidStream; | 165 current_frame_stream_id_ = kInvalidStream; |
166 settings_scratch_.Reset(); | 166 settings_scratch_.Reset(); |
167 altsvc_scratch_.Reset(); | 167 altsvc_scratch_.Reset(); |
168 remaining_padding_payload_length_ = 0; | 168 remaining_padding_payload_length_ = 0; |
169 remaining_padding_length_fields_ = 0; | |
170 } | 169 } |
171 | 170 |
172 size_t SpdyFramer::GetDataFrameMinimumSize() const { | 171 size_t SpdyFramer::GetDataFrameMinimumSize() const { |
173 return SpdyConstants::GetDataFrameMinimumSize(); | 172 return SpdyConstants::GetDataFrameMinimumSize(); |
174 } | 173 } |
175 | 174 |
176 // Size, in bytes, of the control frame header. | 175 // Size, in bytes, of the control frame header. |
177 size_t SpdyFramer::GetControlFrameHeaderSize() const { | 176 size_t SpdyFramer::GetControlFrameHeaderSize() const { |
178 return SpdyConstants::GetControlFrameHeaderSize(protocol_version()); | 177 return SpdyConstants::GetControlFrameHeaderSize(protocol_version()); |
179 } | 178 } |
(...skipping 594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 // if we're here, then we have the common header all received. | 773 // if we're here, then we have the common header all received. |
775 if (!is_control_frame) { | 774 if (!is_control_frame) { |
776 if (protocol_version() > SPDY3) { | 775 if (protocol_version() > SPDY3) { |
777 // Catch bogus tests sending oversized DATA frames. | 776 // Catch bogus tests sending oversized DATA frames. |
778 DCHECK_GE(GetFrameMaximumSize(), current_frame_length_) | 777 DCHECK_GE(GetFrameMaximumSize(), current_frame_length_) |
779 << "DATA frame too large for SPDY >= 4."; | 778 << "DATA frame too large for SPDY >= 4."; |
780 } | 779 } |
781 | 780 |
782 uint8 valid_data_flags = 0; | 781 uint8 valid_data_flags = 0; |
783 if (protocol_version() > SPDY3) { | 782 if (protocol_version() > SPDY3) { |
784 valid_data_flags = DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT | | 783 valid_data_flags = |
785 DATA_FLAG_PAD_LOW | DATA_FLAG_PAD_HIGH; | 784 DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT | DATA_FLAG_PADDED; |
786 } else { | 785 } else { |
787 valid_data_flags = DATA_FLAG_FIN; | 786 valid_data_flags = DATA_FLAG_FIN; |
788 } | 787 } |
789 | 788 |
790 if (current_frame_flags_ & ~valid_data_flags) { | 789 if (current_frame_flags_ & ~valid_data_flags) { |
791 set_error(SPDY_INVALID_DATA_FRAME_FLAGS); | 790 set_error(SPDY_INVALID_DATA_FRAME_FLAGS); |
792 } else { | 791 } else { |
793 visitor_->OnDataFrameHeader(current_frame_stream_id_, | 792 visitor_->OnDataFrameHeader(current_frame_stream_id_, |
794 remaining_data_length_, | 793 remaining_data_length_, |
795 current_frame_flags_ & DATA_FLAG_FIN); | 794 current_frame_flags_ & DATA_FLAG_FIN); |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
930 } | 929 } |
931 if (current_frame_length_ < min_size) { | 930 if (current_frame_length_ < min_size) { |
932 set_error(SPDY_INVALID_CONTROL_FRAME); | 931 set_error(SPDY_INVALID_CONTROL_FRAME); |
933 } else if (protocol_version() <= SPDY3 && | 932 } else if (protocol_version() <= SPDY3 && |
934 current_frame_flags_ & ~CONTROL_FLAG_FIN) { | 933 current_frame_flags_ & ~CONTROL_FLAG_FIN) { |
935 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | 934 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); |
936 } else if (protocol_version() > SPDY3 && | 935 } else if (protocol_version() > SPDY3 && |
937 current_frame_flags_ & | 936 current_frame_flags_ & |
938 ~(CONTROL_FLAG_FIN | HEADERS_FLAG_PRIORITY | | 937 ~(CONTROL_FLAG_FIN | HEADERS_FLAG_PRIORITY | |
939 HEADERS_FLAG_END_HEADERS | HEADERS_FLAG_END_SEGMENT | | 938 HEADERS_FLAG_END_HEADERS | HEADERS_FLAG_END_SEGMENT | |
940 HEADERS_FLAG_PAD_LOW | HEADERS_FLAG_PAD_HIGH)) { | 939 HEADERS_FLAG_PADDED)) { |
941 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | 940 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); |
942 } | 941 } |
943 } | 942 } |
944 break; | 943 break; |
945 case WINDOW_UPDATE: | 944 case WINDOW_UPDATE: |
946 if (current_frame_length_ != GetWindowUpdateSize()) { | 945 if (current_frame_length_ != GetWindowUpdateSize()) { |
947 set_error(SPDY_INVALID_CONTROL_FRAME); | 946 set_error(SPDY_INVALID_CONTROL_FRAME); |
948 } else if (current_frame_flags_ != 0) { | 947 } else if (current_frame_flags_ != 0) { |
949 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | 948 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); |
950 } | 949 } |
951 break; | 950 break; |
952 case BLOCKED: | 951 case BLOCKED: |
953 if (current_frame_length_ != GetBlockedSize() || | 952 if (current_frame_length_ != GetBlockedSize() || |
954 protocol_version() <= SPDY3) { | 953 protocol_version() <= SPDY3) { |
955 // TODO(mlavan): BLOCKED frames are no longer part of SPDY4. | 954 // TODO(mlavan): BLOCKED frames are no longer part of SPDY4. |
956 set_error(SPDY_INVALID_CONTROL_FRAME); | 955 set_error(SPDY_INVALID_CONTROL_FRAME); |
957 } else if (current_frame_flags_ != 0) { | 956 } else if (current_frame_flags_ != 0) { |
958 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | 957 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); |
959 } | 958 } |
960 break; | 959 break; |
961 case PUSH_PROMISE: | 960 case PUSH_PROMISE: |
962 if (current_frame_length_ < GetPushPromiseMinimumSize()) { | 961 if (current_frame_length_ < GetPushPromiseMinimumSize()) { |
963 set_error(SPDY_INVALID_CONTROL_FRAME); | 962 set_error(SPDY_INVALID_CONTROL_FRAME); |
964 } else if (protocol_version() <= SPDY3 && current_frame_flags_ != 0) { | 963 } else if (protocol_version() <= SPDY3 && current_frame_flags_ != 0) { |
965 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | 964 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); |
966 } else if (protocol_version() > SPDY3 && | 965 } else if (protocol_version() > SPDY3 && |
967 current_frame_flags_ & | 966 current_frame_flags_ & |
968 ~(PUSH_PROMISE_FLAG_END_PUSH_PROMISE | | 967 ~(PUSH_PROMISE_FLAG_END_PUSH_PROMISE | |
969 HEADERS_FLAG_PAD_LOW | HEADERS_FLAG_PAD_HIGH)) { | 968 HEADERS_FLAG_PADDED)) { |
970 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | 969 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); |
971 } | 970 } |
972 break; | 971 break; |
973 case CONTINUATION: | 972 case CONTINUATION: |
974 if (current_frame_length_ < GetContinuationMinimumSize() || | 973 if (current_frame_length_ < GetContinuationMinimumSize() || |
975 protocol_version() <= SPDY3) { | 974 protocol_version() <= SPDY3) { |
976 set_error(SPDY_INVALID_CONTROL_FRAME); | 975 set_error(SPDY_INVALID_CONTROL_FRAME); |
977 } else if (current_frame_flags_ & ~HEADERS_FLAG_END_HEADERS) { | 976 } else if (current_frame_flags_ & ~HEADERS_FLAG_END_HEADERS) { |
978 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); | 977 set_error(SPDY_INVALID_CONTROL_FRAME_FLAGS); |
979 } | 978 } |
(...skipping 1090 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2070 StringPiece(altsvc_scratch_.host.get(), | 2069 StringPiece(altsvc_scratch_.host.get(), |
2071 altsvc_scratch_.host_len), | 2070 altsvc_scratch_.host_len), |
2072 StringPiece(altsvc_scratch_.origin.get(), | 2071 StringPiece(altsvc_scratch_.origin.get(), |
2073 altsvc_scratch_.origin_len)); | 2072 altsvc_scratch_.origin_len)); |
2074 CHANGE_STATE(SPDY_AUTO_RESET); | 2073 CHANGE_STATE(SPDY_AUTO_RESET); |
2075 } | 2074 } |
2076 | 2075 |
2077 return processed_bytes; | 2076 return processed_bytes; |
2078 } | 2077 } |
2079 | 2078 |
| 2079 // TODO(raullenchai): ProcessFramePaddingLength should be able to deal with |
| 2080 // HEADERS_FLAG_PADDED and PUSH_PROMISE_FLAG_PADDED as well (see b/15777051). |
2080 size_t SpdyFramer::ProcessFramePaddingLength(const char* data, size_t len) { | 2081 size_t SpdyFramer::ProcessFramePaddingLength(const char* data, size_t len) { |
2081 DCHECK_EQ(SPDY_READ_PADDING_LENGTH, state_); | 2082 DCHECK_EQ(SPDY_READ_PADDING_LENGTH, state_); |
| 2083 DCHECK_EQ(remaining_padding_payload_length_, 0u); |
2082 | 2084 |
2083 size_t original_len = len; | 2085 size_t original_len = len; |
2084 if (remaining_padding_length_fields_ == 0) { | 2086 if (current_frame_flags_ & DATA_FLAG_PADDED) { |
2085 DCHECK_EQ(remaining_padding_payload_length_, 0u); | 2087 if (len != 0) { |
2086 bool pad_low = false; | 2088 if (remaining_data_length_ < 1) { |
2087 bool pad_high = false; | 2089 set_error(SPDY_INVALID_DATA_FRAME_FLAGS); |
2088 if (current_frame_flags_ & DATA_FLAG_PAD_LOW) { | 2090 return 0; |
2089 pad_low = true; | 2091 } |
2090 ++remaining_padding_length_fields_; | 2092 |
2091 } | 2093 remaining_padding_payload_length_ = *reinterpret_cast<const uint8*>(data); |
2092 if (current_frame_flags_ & DATA_FLAG_PAD_HIGH) { | 2094 ++data; |
2093 pad_high = true; | 2095 --len; |
2094 ++remaining_padding_length_fields_; | 2096 --remaining_data_length_; |
2095 } | 2097 } else { |
2096 if ((pad_high && !pad_low) || | 2098 // We don't have the data available for parsing the pad length field. Keep |
2097 remaining_data_length_ < remaining_padding_length_fields_) { | 2099 // waiting. |
2098 set_error(SPDY_INVALID_DATA_FRAME_FLAGS); | |
2099 return 0; | 2100 return 0; |
2100 } | 2101 } |
2101 } | 2102 } |
2102 | 2103 |
2103 // Parse the padding length. | 2104 if (remaining_padding_payload_length_ > remaining_data_length_) { |
2104 while (len != 0 && remaining_padding_length_fields_ != 0) { | 2105 set_error(SPDY_INVALID_DATA_FRAME_FLAGS); |
2105 remaining_padding_payload_length_ = | 2106 return 0; |
2106 (remaining_padding_payload_length_ << 8) + | |
2107 *reinterpret_cast<const uint8*>(data); | |
2108 ++data; | |
2109 --len; | |
2110 --remaining_padding_length_fields_; | |
2111 --remaining_data_length_; | |
2112 } | 2107 } |
2113 | 2108 if (current_frame_type_ == DATA) { |
2114 if (remaining_padding_length_fields_ == 0) { | 2109 CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME); |
2115 if (remaining_padding_payload_length_ > remaining_data_length_) { | 2110 } else { |
2116 set_error(SPDY_INVALID_DATA_FRAME_FLAGS); | 2111 DCHECK(current_frame_type_ == HEADERS || |
2117 return 0; | 2112 current_frame_type_ == PUSH_PROMISE || |
2118 } | 2113 current_frame_type_ == SYN_STREAM || |
2119 if (current_frame_type_ == DATA) { | 2114 current_frame_type_ == SYN_REPLY) |
2120 CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME); | 2115 << current_frame_type_; |
2121 } else { | 2116 CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK); |
2122 DCHECK(current_frame_type_ == HEADERS || | |
2123 current_frame_type_ == PUSH_PROMISE || | |
2124 current_frame_type_ == SYN_STREAM || | |
2125 current_frame_type_ == SYN_REPLY) | |
2126 << current_frame_type_; | |
2127 CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK); | |
2128 } | |
2129 } | 2117 } |
2130 return original_len - len; | 2118 return original_len - len; |
2131 } | 2119 } |
2132 | 2120 |
2133 size_t SpdyFramer::ProcessFramePadding(const char* data, size_t len) { | 2121 size_t SpdyFramer::ProcessFramePadding(const char* data, size_t len) { |
2134 DCHECK_EQ(SPDY_CONSUME_PADDING, state_); | 2122 DCHECK_EQ(SPDY_CONSUME_PADDING, state_); |
2135 | 2123 |
2136 size_t original_len = len; | 2124 size_t original_len = len; |
2137 if (remaining_padding_payload_length_ > 0) { | 2125 if (remaining_padding_payload_length_ > 0) { |
2138 DCHECK_EQ(remaining_padding_payload_length_, remaining_data_length_); | 2126 DCHECK_EQ(remaining_padding_payload_length_, remaining_data_length_); |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2260 | 2248 |
2261 SpdySerializedFrame* SpdyFramer::SerializeData( | 2249 SpdySerializedFrame* SpdyFramer::SerializeData( |
2262 const SpdyDataIR& data_ir) const { | 2250 const SpdyDataIR& data_ir) const { |
2263 uint8 flags = DATA_FLAG_NONE; | 2251 uint8 flags = DATA_FLAG_NONE; |
2264 if (data_ir.fin()) { | 2252 if (data_ir.fin()) { |
2265 flags = DATA_FLAG_FIN; | 2253 flags = DATA_FLAG_FIN; |
2266 } | 2254 } |
2267 | 2255 |
2268 if (protocol_version() > SPDY3) { | 2256 if (protocol_version() > SPDY3) { |
2269 int num_padding_fields = 0; | 2257 int num_padding_fields = 0; |
2270 if (data_ir.pad_low()) { | 2258 if (data_ir.padded()) { |
2271 flags |= DATA_FLAG_PAD_LOW; | 2259 flags |= DATA_FLAG_PADDED; |
2272 ++num_padding_fields; | |
2273 } | |
2274 if (data_ir.pad_high()) { | |
2275 flags |= DATA_FLAG_PAD_HIGH; | |
2276 ++num_padding_fields; | 2260 ++num_padding_fields; |
2277 } | 2261 } |
2278 | 2262 |
2279 const size_t size_with_padding = num_padding_fields + | 2263 const size_t size_with_padding = num_padding_fields + |
2280 data_ir.data().length() + data_ir.padding_payload_len() + | 2264 data_ir.data().length() + data_ir.padding_payload_len() + |
2281 GetDataFrameMinimumSize(); | 2265 GetDataFrameMinimumSize(); |
2282 SpdyFrameBuilder builder(size_with_padding, protocol_version()); | 2266 SpdyFrameBuilder builder(size_with_padding, protocol_version()); |
2283 builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags); | 2267 builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags); |
2284 if (data_ir.pad_high()) { | 2268 if (data_ir.padded()) { |
2285 builder.WriteUInt8(data_ir.padding_payload_len() >> 8); | |
2286 } | |
2287 if (data_ir.pad_low()) { | |
2288 builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); | 2269 builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); |
2289 } | 2270 } |
2290 builder.WriteBytes(data_ir.data().data(), data_ir.data().length()); | 2271 builder.WriteBytes(data_ir.data().data(), data_ir.data().length()); |
2291 if (data_ir.padding_payload_len() > 0) { | 2272 if (data_ir.padding_payload_len() > 0) { |
2292 string padding = string(data_ir.padding_payload_len(), '0'); | 2273 string padding = string(data_ir.padding_payload_len(), '0'); |
2293 builder.WriteBytes(padding.data(), padding.length()); | 2274 builder.WriteBytes(padding.data(), padding.length()); |
2294 } | 2275 } |
2295 DCHECK_EQ(size_with_padding, builder.length()); | 2276 DCHECK_EQ(size_with_padding, builder.length()); |
2296 return builder.take(); | 2277 return builder.take(); |
2297 } else { | 2278 } else { |
2298 const size_t size = GetDataFrameMinimumSize() + data_ir.data().length(); | 2279 const size_t size = GetDataFrameMinimumSize() + data_ir.data().length(); |
2299 SpdyFrameBuilder builder(size, protocol_version()); | 2280 SpdyFrameBuilder builder(size, protocol_version()); |
2300 builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags); | 2281 builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags); |
2301 builder.WriteBytes(data_ir.data().data(), data_ir.data().length()); | 2282 builder.WriteBytes(data_ir.data().data(), data_ir.data().length()); |
2302 DCHECK_EQ(size, builder.length()); | 2283 DCHECK_EQ(size, builder.length()); |
2303 return builder.take(); | 2284 return builder.take(); |
2304 } | 2285 } |
2305 } | 2286 } |
2306 | 2287 |
2307 SpdySerializedFrame* SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField( | 2288 SpdySerializedFrame* SpdyFramer::SerializeDataFrameHeaderWithPaddingLengthField( |
2308 const SpdyDataIR& data_ir) const { | 2289 const SpdyDataIR& data_ir) const { |
2309 uint8 flags = DATA_FLAG_NONE; | 2290 uint8 flags = DATA_FLAG_NONE; |
2310 if (data_ir.fin()) { | 2291 if (data_ir.fin()) { |
2311 flags = DATA_FLAG_FIN; | 2292 flags = DATA_FLAG_FIN; |
2312 } | 2293 } |
2313 | 2294 |
2314 size_t frame_size = GetDataFrameMinimumSize(); | 2295 size_t frame_size = GetDataFrameMinimumSize(); |
2315 size_t num_padding_fields = 0; | 2296 size_t num_padding_fields = 0; |
2316 if (protocol_version() > SPDY3) { | 2297 if (protocol_version() > SPDY3) { |
2317 if (data_ir.pad_low()) { | 2298 if (data_ir.padded()) { |
2318 flags |= DATA_FLAG_PAD_LOW; | 2299 flags |= DATA_FLAG_PADDED; |
2319 ++num_padding_fields; | |
2320 } | |
2321 if (data_ir.pad_high()) { | |
2322 flags |= DATA_FLAG_PAD_HIGH; | |
2323 ++num_padding_fields; | 2300 ++num_padding_fields; |
2324 } | 2301 } |
2325 frame_size += num_padding_fields; | 2302 frame_size += num_padding_fields; |
2326 } | 2303 } |
2327 | 2304 |
2328 SpdyFrameBuilder builder(frame_size, protocol_version()); | 2305 SpdyFrameBuilder builder(frame_size, protocol_version()); |
2329 builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags); | 2306 builder.WriteDataFrameHeader(*this, data_ir.stream_id(), flags); |
2330 if (protocol_version() > SPDY3) { | 2307 if (protocol_version() > SPDY3) { |
2331 if (data_ir.pad_high()) { | 2308 if (data_ir.padded()) { |
2332 builder.WriteUInt8(data_ir.padding_payload_len() >> 8); | |
2333 } | |
2334 if (data_ir.pad_low()) { | |
2335 builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); | 2309 builder.WriteUInt8(data_ir.padding_payload_len() & 0xff); |
2336 } | 2310 } |
2337 builder.OverwriteLength(*this, num_padding_fields + | 2311 builder.OverwriteLength(*this, num_padding_fields + |
2338 data_ir.data().length() + data_ir.padding_payload_len()); | 2312 data_ir.data().length() + data_ir.padding_payload_len()); |
2339 } else { | 2313 } else { |
2340 builder.OverwriteLength(*this, data_ir.data().length()); | 2314 builder.OverwriteLength(*this, data_ir.data().length()); |
2341 } | 2315 } |
2342 DCHECK_EQ(frame_size, builder.length()); | 2316 DCHECK_EQ(frame_size, builder.length()); |
2343 return builder.take(); | 2317 return builder.take(); |
2344 } | 2318 } |
(...skipping 878 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3223 builder->Seek(compressed_size); | 3197 builder->Seek(compressed_size); |
3224 builder->RewriteLength(*this); | 3198 builder->RewriteLength(*this); |
3225 | 3199 |
3226 pre_compress_bytes.Add(uncompressed_len); | 3200 pre_compress_bytes.Add(uncompressed_len); |
3227 post_compress_bytes.Add(compressed_size); | 3201 post_compress_bytes.Add(compressed_size); |
3228 | 3202 |
3229 compressed_frames.Increment(); | 3203 compressed_frames.Increment(); |
3230 } | 3204 } |
3231 | 3205 |
3232 } // namespace net | 3206 } // namespace net |
OLD | NEW |