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 // Derived from: | 5 // Derived from: |
6 // mozilla/netwerk/protocol/http/src/nsHttpChunkedDecoder.cpp | 6 // mozilla/netwerk/protocol/http/src/nsHttpChunkedDecoder.cpp |
7 // The license block is: | 7 // The license block is: |
8 /* ***** BEGIN LICENSE BLOCK ***** | 8 /* ***** BEGIN LICENSE BLOCK ***** |
9 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | 9 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
10 * | 10 * |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 : chunk_remaining_(0), | 62 : chunk_remaining_(0), |
63 chunk_terminator_remaining_(false), | 63 chunk_terminator_remaining_(false), |
64 reached_last_chunk_(false), | 64 reached_last_chunk_(false), |
65 reached_eof_(false), | 65 reached_eof_(false), |
66 bytes_after_eof_(0) { | 66 bytes_after_eof_(0) { |
67 } | 67 } |
68 | 68 |
69 int HttpChunkedDecoder::FilterBuf(char* buf, int buf_len) { | 69 int HttpChunkedDecoder::FilterBuf(char* buf, int buf_len) { |
70 int result = 0; | 70 int result = 0; |
71 | 71 |
72 while (buf_len > 0) { | 72 while (buf_len) { |
73 if (chunk_remaining_ > 0) { | 73 if (chunk_remaining_) { |
74 // Since |chunk_remaining_| is positive and |buf_len| an int, the minimum | 74 int num = std::min(chunk_remaining_, buf_len); |
75 // of the two must be an int. | |
76 int num = static_cast<int>( | |
77 std::min(chunk_remaining_, static_cast<int64_t>(buf_len))); | |
78 | 75 |
79 buf_len -= num; | 76 buf_len -= num; |
80 chunk_remaining_ -= num; | 77 chunk_remaining_ -= num; |
81 | 78 |
82 result += num; | 79 result += num; |
83 buf += num; | 80 buf += num; |
84 | 81 |
85 // After each chunk's data there should be a CRLF. | 82 // After each chunk's data there should be a CRLF |
86 if (chunk_remaining_ == 0) | 83 if (!chunk_remaining_) |
87 chunk_terminator_remaining_ = true; | 84 chunk_terminator_remaining_ = true; |
88 continue; | 85 continue; |
89 } else if (reached_eof_) { | 86 } else if (reached_eof_) { |
90 bytes_after_eof_ += buf_len; | 87 bytes_after_eof_ += buf_len; |
91 break; // Done! | 88 break; // Done! |
92 } | 89 } |
93 | 90 |
94 int bytes_consumed = ScanForChunkRemaining(buf, buf_len); | 91 int bytes_consumed = ScanForChunkRemaining(buf, buf_len); |
95 if (bytes_consumed < 0) | 92 if (bytes_consumed < 0) |
96 return bytes_consumed; // Error | 93 return bytes_consumed; // Error |
97 | 94 |
98 buf_len -= bytes_consumed; | 95 buf_len -= bytes_consumed; |
99 if (buf_len > 0) | 96 if (buf_len) |
100 memmove(buf, buf + bytes_consumed, buf_len); | 97 memmove(buf, buf + bytes_consumed, buf_len); |
101 } | 98 } |
102 | 99 |
103 return result; | 100 return result; |
104 } | 101 } |
105 | 102 |
106 int HttpChunkedDecoder::ScanForChunkRemaining(const char* buf, int buf_len) { | 103 int HttpChunkedDecoder::ScanForChunkRemaining(const char* buf, int buf_len) { |
107 DCHECK_EQ(0, chunk_remaining_); | 104 DCHECK_EQ(0, chunk_remaining_); |
108 DCHECK_GT(buf_len, 0); | 105 DCHECK_GT(buf_len, 0); |
109 | 106 |
110 int bytes_consumed = 0; | 107 int bytes_consumed = 0; |
111 | 108 |
112 size_t index_of_lf = base::StringPiece(buf, buf_len).find('\n'); | 109 size_t index_of_lf = base::StringPiece(buf, buf_len).find('\n'); |
113 if (index_of_lf != base::StringPiece::npos) { | 110 if (index_of_lf != base::StringPiece::npos) { |
114 buf_len = static_cast<int>(index_of_lf); | 111 buf_len = static_cast<int>(index_of_lf); |
115 if (buf_len && buf[buf_len - 1] == '\r') // Eliminate a preceding CR. | 112 if (buf_len && buf[buf_len - 1] == '\r') // Eliminate a preceding CR. |
116 buf_len--; | 113 buf_len--; |
117 bytes_consumed = static_cast<int>(index_of_lf) + 1; | 114 bytes_consumed = static_cast<int>(index_of_lf) + 1; |
118 | 115 |
119 // Make buf point to the full line buffer to parse. | 116 // Make buf point to the full line buffer to parse. |
120 if (!line_buf_.empty()) { | 117 if (!line_buf_.empty()) { |
121 line_buf_.append(buf, buf_len); | 118 line_buf_.append(buf, buf_len); |
122 buf = line_buf_.data(); | 119 buf = line_buf_.data(); |
123 buf_len = static_cast<int>(line_buf_.size()); | 120 buf_len = static_cast<int>(line_buf_.size()); |
124 } | 121 } |
125 | 122 |
126 if (reached_last_chunk_) { | 123 if (reached_last_chunk_) { |
127 if (buf_len > 0) | 124 if (buf_len) |
128 DVLOG(1) << "ignoring http trailer"; | 125 DVLOG(1) << "ignoring http trailer"; |
129 else | 126 else |
130 reached_eof_ = true; | 127 reached_eof_ = true; |
131 } else if (chunk_terminator_remaining_) { | 128 } else if (chunk_terminator_remaining_) { |
132 if (buf_len > 0) { | 129 if (buf_len) { |
133 DLOG(ERROR) << "chunk data not terminated properly"; | 130 DLOG(ERROR) << "chunk data not terminated properly"; |
134 return ERR_INVALID_CHUNKED_ENCODING; | 131 return ERR_INVALID_CHUNKED_ENCODING; |
135 } | 132 } |
136 chunk_terminator_remaining_ = false; | 133 chunk_terminator_remaining_ = false; |
137 } else if (buf_len > 0) { | 134 } else if (buf_len) { |
138 // Ignore any chunk-extensions. | 135 // Ignore any chunk-extensions. |
139 size_t index_of_semicolon = base::StringPiece(buf, buf_len).find(';'); | 136 size_t index_of_semicolon = base::StringPiece(buf, buf_len).find(';'); |
140 if (index_of_semicolon != base::StringPiece::npos) | 137 if (index_of_semicolon != base::StringPiece::npos) |
141 buf_len = static_cast<int>(index_of_semicolon); | 138 buf_len = static_cast<int>(index_of_semicolon); |
142 | 139 |
143 if (!ParseChunkSize(buf, buf_len, &chunk_remaining_)) { | 140 if (!ParseChunkSize(buf, buf_len, &chunk_remaining_)) { |
144 DLOG(ERROR) << "Failed parsing HEX from: " << | 141 DLOG(ERROR) << "Failed parsing HEX from: " << |
145 std::string(buf, buf_len); | 142 std::string(buf, buf_len); |
146 return ERR_INVALID_CHUNKED_ENCODING; | 143 return ERR_INVALID_CHUNKED_ENCODING; |
147 } | 144 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 // RFC 7230: ^\X+$ | 182 // RFC 7230: ^\X+$ |
186 // IE7: ^\X+[^\X]*$ | 183 // IE7: ^\X+[^\X]*$ |
187 // Safari 3.1: ^[\t\r ]*\X+[\t ]*$ | 184 // Safari 3.1: ^[\t\r ]*\X+[\t ]*$ |
188 // Firefox 3: ^[\t\f\v\r ]*[+]?(0x)?\X+[^\X]*$ | 185 // Firefox 3: ^[\t\f\v\r ]*[+]?(0x)?\X+[^\X]*$ |
189 // Opera 9.51: ^[\t\f\v ]*[+]?(0x)?\X+[^\X]*$ | 186 // Opera 9.51: ^[\t\f\v ]*[+]?(0x)?\X+[^\X]*$ |
190 // | 187 // |
191 // Our strategy is to be as strict as possible, while not breaking | 188 // Our strategy is to be as strict as possible, while not breaking |
192 // known sites. | 189 // known sites. |
193 // | 190 // |
194 // Us: ^\X+[ ]*$ | 191 // Us: ^\X+[ ]*$ |
195 bool HttpChunkedDecoder::ParseChunkSize(const char* start, | 192 bool HttpChunkedDecoder::ParseChunkSize(const char* start, int len, int* out) { |
196 int len, | |
197 int64_t* out) { | |
198 DCHECK_GE(len, 0); | 193 DCHECK_GE(len, 0); |
199 | 194 |
200 // Strip trailing spaces | 195 // Strip trailing spaces |
201 while (len > 0 && start[len - 1] == ' ') | 196 while (len && start[len - 1] == ' ') |
202 len--; | 197 len--; |
203 | 198 |
204 // Be more restrictive than HexStringToInt64; | 199 // Be more restrictive than HexStringToInt; |
205 // don't allow inputs with leading "-", "+", "0x", "0X" | 200 // don't allow inputs with leading "-", "+", "0x", "0X" |
206 base::StringPiece chunk_size(start, len); | 201 base::StringPiece chunk_size(start, len); |
207 if (chunk_size.find_first_not_of("0123456789abcdefABCDEF") | 202 if (chunk_size.find_first_not_of("0123456789abcdefABCDEF") |
208 != base::StringPiece::npos) { | 203 != base::StringPiece::npos) { |
209 return false; | 204 return false; |
210 } | 205 } |
211 | 206 |
212 int64_t parsed_number; | 207 int parsed_number; |
213 bool ok = base::HexStringToInt64(chunk_size, &parsed_number); | 208 bool ok = base::HexStringToInt(chunk_size, &parsed_number); |
214 if (ok && parsed_number >= 0) { | 209 if (ok && parsed_number >= 0) { |
215 *out = parsed_number; | 210 *out = parsed_number; |
216 return true; | 211 return true; |
217 } | 212 } |
218 return false; | 213 return false; |
219 } | 214 } |
220 | 215 |
221 } // namespace net | 216 } // namespace net |
OLD | NEW |