| 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 |