15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Derived from:
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   mozilla/netwerk/protocol/http/src/nsHttpChunkedDecoder.cpp
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The license block is:
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* ***** BEGIN LICENSE BLOCK *****
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Version: MPL 1.1/GPL 2.0/LGPL 2.1
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The contents of this file are subject to the Mozilla Public License Version
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1.1 (the "License"); you may not use this file except in compliance with
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the License. You may obtain a copy of the License at
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * http://www.mozilla.org/MPL/
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Software distributed under the License is distributed on an "AS IS" basis,
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * for the specific language governing rights and limitations under the
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * License.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The Original Code is Mozilla.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * The Initial Developer of the Original Code is
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Netscape Communications.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Portions created by the Initial Developer are Copyright (C) 2001
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the Initial Developer. All Rights Reserved.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Contributor(s):
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   Darin Fisher <darin@netscape.com> (original author)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Alternatively, the contents of this file may be used under the terms of
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * either the GNU General Public License Version 2 or later (the "GPL"), or
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * in which case the provisions of the GPL or the LGPL are applicable instead
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * of those above. If you wish to allow use of your version of this file only
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * under the terms of either the GPL or the LGPL, and not to allow others to
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * use your version of this file under the terms of the MPL, indicate your
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * decision by deleting the provisions above and replace them with the notice
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * and other provisions required by the GPL or the LGPL. If you do not delete
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the provisions above, a recipient may use your version of this file under
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the terms of any one of the MPL, the GPL or the LGPL.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ***** END LICENSE BLOCK ***** */
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_chunked_decoder.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <algorithm>
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h"
527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h"
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Absurdly long size to avoid imposing a constraint on chunked encoding
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// extensions.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t HttpChunkedDecoder::kMaxLineBufLen = 16384;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpChunkedDecoder::HttpChunkedDecoder()
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : chunk_remaining_(0),
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chunk_terminator_remaining_(false),
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reached_last_chunk_(false),
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reached_eof_(false),
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bytes_after_eof_(0) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpChunkedDecoder::FilterBuf(char* buf, int buf_len) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = 0;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (buf_len) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (chunk_remaining_) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int num = std::min(chunk_remaining_, buf_len);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf_len -= num;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chunk_remaining_ -= num;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result += num;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf += num;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // After each chunk's data there should be a CRLF
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!chunk_remaining_)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        chunk_terminator_remaining_ = true;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (reached_eof_) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bytes_after_eof_ += buf_len;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;  // Done!
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int bytes_consumed = ScanForChunkRemaining(buf, buf_len);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bytes_consumed < 0)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return bytes_consumed; // Error
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buf_len -= bytes_consumed;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (buf_len)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      memmove(buf, buf + bytes_consumed, buf_len);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpChunkedDecoder::ScanForChunkRemaining(const char* buf, int buf_len) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(0, chunk_remaining_);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(buf_len, 0);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bytes_consumed = 0;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t index_of_lf = base::StringPiece(buf, buf_len).find('\n');
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index_of_lf != base::StringPiece::npos) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buf_len = static_cast<int>(index_of_lf);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (buf_len && buf[buf_len - 1] == '\r')  // Eliminate a preceding CR.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf_len--;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bytes_consumed = static_cast<int>(index_of_lf) + 1;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make buf point to the full line buffer to parse.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!line_buf_.empty()) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      line_buf_.append(buf, buf_len);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf = line_buf_.data();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf_len = static_cast<int>(line_buf_.size());
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (reached_last_chunk_) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (buf_len)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DVLOG(1) << "ignoring http trailer";
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reached_eof_ = true;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (chunk_terminator_remaining_) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (buf_len) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DLOG(ERROR) << "chunk data not terminated properly";
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return ERR_INVALID_CHUNKED_ENCODING;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chunk_terminator_remaining_ = false;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (buf_len) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Ignore any chunk-extensions.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_t index_of_semicolon = base::StringPiece(buf, buf_len).find(';');
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (index_of_semicolon != base::StringPiece::npos)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        buf_len = static_cast<int>(index_of_semicolon);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!ParseChunkSize(buf, buf_len, &chunk_remaining_)) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DLOG(ERROR) << "Failed parsing HEX from: " <<
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            std::string(buf, buf_len);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return ERR_INVALID_CHUNKED_ENCODING;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (chunk_remaining_ == 0)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reached_last_chunk_ = true;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(ERROR) << "missing chunk-size";
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_INVALID_CHUNKED_ENCODING;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    line_buf_.clear();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Save the partial line; wait for more data.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bytes_consumed = buf_len;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ignore a trailing CR
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (buf[buf_len - 1] == '\r')
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buf_len--;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (line_buf_.length() + buf_len > kMaxLineBufLen) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(ERROR) << "Chunked line length too long";
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_INVALID_CHUNKED_ENCODING;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    line_buf_.append(buf, buf_len);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bytes_consumed;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// While the HTTP 1.1 specification defines chunk-size as 1*HEX
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// some sites rely on more lenient parsing.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://www.yahoo.com/, for example, pads chunk-size with trailing spaces
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (0x20) to be 7 characters long, such as "819b   ".
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A comparison of browsers running on WindowsXP shows that
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// they will parse the following inputs (egrep syntax):
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Let \X be the character class for a hex digit: [0-9a-fA-F]
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   RFC 2616: ^\X+$
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//        IE7: ^\X+[^\X]*$
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Safari 3.1: ^[\t\r ]*\X+[\t ]*$
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  Firefox 3: ^[\t\f\v\r ]*[+]?(0x)?\X+[^\X]*$
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Opera 9.51: ^[\t\f\v ]*[+]?(0x)?\X+[^\X]*$
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Our strategy is to be as strict as possible, while not breaking
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// known sites.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         Us: ^\X+[ ]*$
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpChunkedDecoder::ParseChunkSize(const char* start, int len, int* out) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(len, 0);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Strip trailing spaces
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (len && start[len - 1] == ' ')
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    len--;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Be more restrictive than HexStringToInt;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // don't allow inputs with leading "-", "+", "0x", "0X"
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StringPiece chunk_size(start, len);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (chunk_size.find_first_not_of("0123456789abcdefABCDEF")
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      != base::StringPiece::npos) {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int parsed_number;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = base::HexStringToInt(chunk_size, &parsed_number);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ok && parsed_number >= 0) {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *out = parsed_number;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
217