1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/tools/flip_server/balsa_headers.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <algorithm>
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <ext/hash_set>
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <string>
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <utility>
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <vector>
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/port.h"
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_piece.h"
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h"
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/tools/flip_server/balsa_enums.h"
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/tools/flip_server/buffer_interface.h"
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/tools/flip_server/simple_buffer.h"
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "third_party/tcmalloc/chromium/src/base/googleinit.h"
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// #include "util/gtl/iterator_adaptors-inl.h"
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// #include "util/gtl/map-util.h"
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst char kContentLength[] = "Content-Length";
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst char kTransferEncoding[] = "Transfer-Encoding";
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst char kSpaceChar = ' ';
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott__gnu_cxx::hash_set<base::StringPiece,
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    net::StringPieceCaseHash,
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    net::StringPieceCaseEqual> g_multivalued_headers;
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid InitMultivaluedHeaders() {
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("accept");
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("accept-charset");
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("accept-encoding");
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("accept-language");
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("accept-ranges");
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("allow");
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("cache-control");
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("connection");
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("content-encoding");
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("content-language");
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("expect");
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("if-match");
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("if-none-match");
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("pragma");
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("proxy-authenticate");
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("te");
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("trailer");
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("transfer-encoding");
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("upgrade");
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("vary");
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("via");
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("warning");
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("www-authenticate");
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Not mentioned in RFC 2616, but it can have multiple values.
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  g_multivalued_headers.insert("set-cookie");
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottREGISTER_MODULE_INITIALIZER(multivalued_headers, InitMultivaluedHeaders());
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst int kFastToBufferSize = 32;  // I think 22 is adequate, but anyway..
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst size_t BalsaBuffer::kDefaultBlocksize;
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
72731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstd::ostream& BalsaHeaders::iterator_base::operator<<(std::ostream& os) const {
73731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick   os << "[" << this->headers_ << ", " << this->idx_ << "]";
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   return os;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenBalsaBuffer::~BalsaBuffer() {
7872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  CleanupBlocksStartingFrom(0);
7972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
8072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
8172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Returns the total amount of memory used by the buffer blocks.
8272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsensize_t BalsaBuffer::GetTotalBufferBlockSize() const {
8372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  size_t buffer_size = 0;
8472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (Blocks::const_iterator iter = blocks_.begin();
8572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen       iter != blocks_.end();
8672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen       ++iter) {
8772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    buffer_size += iter->buffer_size;
8872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
8972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return buffer_size;
9072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
9172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
9272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BalsaBuffer::WriteToContiguousBuffer(const base::StringPiece& sp) {
9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (sp.empty()) {
9472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return;
9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
9672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  CHECK(can_write_to_contiguous_buffer_);
9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK_GE(blocks_.size(), 1u);
9872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (blocks_[0].buffer == NULL && sp.size() <= blocksize_) {
9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    blocks_[0] = AllocBlock();
10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    memcpy(blocks_[0].start_of_unused_bytes(), sp.data(), sp.size());
10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else if (blocks_[0].bytes_free < sp.size()) {
10272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // the first block isn't big enough, resize it.
10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const size_t old_storage_size_used = blocks_[0].bytes_used();
10472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const size_t new_storage_size = old_storage_size_used + sp.size();
10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    char* new_storage = new char[new_storage_size];
10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    char* old_storage = blocks_[0].buffer;
10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (old_storage_size_used) {
10872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      memcpy(new_storage, old_storage, old_storage_size_used);
10972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
11072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    memcpy(new_storage + old_storage_size_used, sp.data(), sp.size());
11172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    blocks_[0].buffer = new_storage;
11272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    blocks_[0].bytes_free = sp.size();
11372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    blocks_[0].buffer_size = new_storage_size;
11472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    delete[] old_storage;
11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
11672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    memcpy(blocks_[0].start_of_unused_bytes(), sp.data(), sp.size());
11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  blocks_[0].bytes_free -= sp.size();
11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
12072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
12172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbase::StringPiece BalsaBuffer::Write(const base::StringPiece& sp,
12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                     Blocks::size_type* block_buffer_idx) {
12372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (sp.empty()) {
12472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return sp;
12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
12672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  char* storage = Reserve(sp.size(), block_buffer_idx);
12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  memcpy(storage, sp.data(), sp.size());
12872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return base::StringPiece(storage, sp.size());
12972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
13072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
13172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenchar* BalsaBuffer::Reserve(size_t size,
13272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                           Blocks::size_type* block_buffer_idx) {
13372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // There should always be a 'first_block', even if it
13472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // contains nothing.
13572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK_GE(blocks_.size(), 1u);
13672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  BufferBlock* block = NULL;
13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  Blocks::size_type block_idx = can_write_to_contiguous_buffer_ ? 1 : 0;
13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (; block_idx < blocks_.size(); ++block_idx) {
13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (blocks_[block_idx].bytes_free >= size) {
14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      block = &blocks_[block_idx];
14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      break;
14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
14372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
14472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (block == NULL) {
14572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (blocksize_ < size) {
14672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      blocks_.push_back(AllocCustomBlock(size));
14772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else {
14872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      blocks_.push_back(AllocBlock());
14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
15072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    block = &blocks_.back();
15172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
15272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  char* storage = block->start_of_unused_bytes();
15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  block->bytes_free -= size;
15572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (block_buffer_idx) {
15672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    *block_buffer_idx = block_idx;
15772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
15872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return storage;
15972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
16072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
16172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BalsaBuffer::Clear() {
16272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  CHECK(!blocks_.empty());
16372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (blocksize_ == blocks_[0].buffer_size) {
16472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    CleanupBlocksStartingFrom(1);
16572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    blocks_[0].bytes_free = blocks_[0].buffer_size;
16672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
16772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    CleanupBlocksStartingFrom(0);
16872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    blocks_.push_back(AllocBlock());
16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
17072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK_GE(blocks_.size(), 1u);
17172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  can_write_to_contiguous_buffer_ = true;
17272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
17372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
17472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BalsaBuffer::Swap(BalsaBuffer* b) {
17572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  blocks_.swap(b->blocks_);
17672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::swap(can_write_to_contiguous_buffer_,
17772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            b->can_write_to_contiguous_buffer_);
17872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::swap(blocksize_, b->blocksize_);
17972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
18072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
18172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BalsaBuffer::CopyFrom(const BalsaBuffer& b) {
18272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  CleanupBlocksStartingFrom(0);
18372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  blocks_.resize(b.blocks_.size());
18472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (Blocks::size_type i = 0; i < blocks_.size(); ++i) {
18572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    blocks_[i] = CopyBlock(b.blocks_[i]);
18672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
18772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  blocksize_ = b.blocksize_;
18872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  can_write_to_contiguous_buffer_ = b.can_write_to_contiguous_buffer_;
18972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
19072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
19172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenBalsaBuffer::BalsaBuffer()
19272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    : blocksize_(kDefaultBlocksize), can_write_to_contiguous_buffer_(true) {
19372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  blocks_.push_back(AllocBlock());
19472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
19572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
19672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenBalsaBuffer::BalsaBuffer(size_t blocksize) :
19772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    blocksize_(blocksize), can_write_to_contiguous_buffer_(true) {
19872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  blocks_.push_back(AllocBlock());
19972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
20072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
20172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenBalsaBuffer::BufferBlock BalsaBuffer::AllocBlock() {
20272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return AllocCustomBlock(blocksize_);
20372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
20472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
20572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenBalsaBuffer::BufferBlock BalsaBuffer::AllocCustomBlock(size_t blocksize) {
20672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return BufferBlock(new char[blocksize], blocksize, blocksize);
20772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
20872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
20972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenBalsaBuffer::BufferBlock BalsaBuffer::CopyBlock(const BufferBlock& b) {
21072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  BufferBlock block = b;
21172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (b.buffer == NULL) {
21272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return block;
21372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
21472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
21572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  block.buffer = new char[b.buffer_size];
21672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  memcpy(block.buffer, b.buffer, b.bytes_used());
21772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return block;
21872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
21972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
22072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BalsaBuffer::CleanupBlocksStartingFrom(Blocks::size_type start_idx) {
22172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (Blocks::size_type i = start_idx; i < blocks_.size(); ++i) {
22272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    delete[] blocks_[i].buffer;
22372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
22472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  blocks_.resize(start_idx);
22572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
22772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenBalsaHeaders::BalsaHeaders()
22872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    : balsa_buffer_(4096),
22972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      content_length_(0),
23072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      content_length_status_(BalsaHeadersEnums::NO_CONTENT_LENGTH),
23172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      parsed_response_code_(0),
23272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      firstline_buffer_base_idx_(0),
23372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      whitespace_1_idx_(0),
23472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      non_whitespace_1_idx_(0),
23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      whitespace_2_idx_(0),
23672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      non_whitespace_2_idx_(0),
23772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      whitespace_3_idx_(0),
23872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      non_whitespace_3_idx_(0),
23972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      whitespace_4_idx_(0),
24072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      end_of_firstline_idx_(0),
24172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      transfer_encoding_is_chunked_(false) {
24272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
24372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
24472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenBalsaHeaders::~BalsaHeaders() {}
24572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::Clear() {
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  balsa_buffer_.Clear();
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  transfer_encoding_is_chunked_ = false;
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  content_length_ = 0;
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  content_length_status_ = BalsaHeadersEnums::NO_CONTENT_LENGTH;
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  parsed_response_code_ = 0;
252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  firstline_buffer_base_idx_ = 0;
253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_1_idx_ = 0;
254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_1_idx_ = 0;
255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_2_idx_ = 0;
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_2_idx_ = 0;
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_3_idx_ = 0;
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_3_idx_ = 0;
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_4_idx_ = 0;
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  end_of_firstline_idx_ = 0;
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  header_lines_.clear();
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::Swap(BalsaHeaders* other) {
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Protect against swapping with self.
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (this == other) return;
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  balsa_buffer_.Swap(&other->balsa_buffer_);
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool tmp_bool = transfer_encoding_is_chunked_;
271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  transfer_encoding_is_chunked_ = other->transfer_encoding_is_chunked_;
272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->transfer_encoding_is_chunked_ = tmp_bool;
273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  size_t tmp_size_t = content_length_;
275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  content_length_ = other->content_length_;
276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->content_length_ = tmp_size_t;
277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BalsaHeadersEnums::ContentLengthStatus tmp_status =
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      content_length_status_;
280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  content_length_status_ = other->content_length_status_;
281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->content_length_status_ = tmp_status;
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tmp_size_t = parsed_response_code_;
284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  parsed_response_code_ = other->parsed_response_code_;
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->parsed_response_code_ = tmp_size_t;
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BalsaBuffer::Blocks::size_type tmp_blk_idx = firstline_buffer_base_idx_;
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  firstline_buffer_base_idx_ = other->firstline_buffer_base_idx_;
289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->firstline_buffer_base_idx_ = tmp_blk_idx;
290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tmp_size_t = whitespace_1_idx_;
292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_1_idx_ = other->whitespace_1_idx_;
293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->whitespace_1_idx_ = tmp_size_t;
294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tmp_size_t = non_whitespace_1_idx_;
296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_1_idx_ = other->non_whitespace_1_idx_;
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->non_whitespace_1_idx_ = tmp_size_t;
298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tmp_size_t = whitespace_2_idx_;
300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_2_idx_ = other->whitespace_2_idx_;
301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->whitespace_2_idx_ = tmp_size_t;
302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tmp_size_t = non_whitespace_2_idx_;
304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_2_idx_ = other->non_whitespace_2_idx_;
305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->non_whitespace_2_idx_ = tmp_size_t;
306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tmp_size_t = whitespace_3_idx_;
308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_3_idx_ = other->whitespace_3_idx_;
309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->whitespace_3_idx_ = tmp_size_t;
310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tmp_size_t = non_whitespace_3_idx_;
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_3_idx_ = other->non_whitespace_3_idx_;
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->non_whitespace_3_idx_ = tmp_size_t;
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tmp_size_t = whitespace_4_idx_;
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_4_idx_ = other->whitespace_4_idx_;
317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->whitespace_4_idx_ = tmp_size_t;
318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tmp_size_t = end_of_firstline_idx_;
320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  end_of_firstline_idx_ = other->end_of_firstline_idx_;
321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  other->end_of_firstline_idx_ = tmp_size_t;
322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  swap(header_lines_, other->header_lines_);
324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
326c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::CopyFrom(const BalsaHeaders& other) {
327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Protect against copying with self.
328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (this == &other) return;
329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  balsa_buffer_.CopyFrom(other.balsa_buffer_);
331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  transfer_encoding_is_chunked_ = other.transfer_encoding_is_chunked_;
332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  content_length_ = other.content_length_;
333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  content_length_status_ = other.content_length_status_;
334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  parsed_response_code_ = other.parsed_response_code_;
335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  firstline_buffer_base_idx_ = other.firstline_buffer_base_idx_;
336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_1_idx_ = other.whitespace_1_idx_;
337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_1_idx_ = other.non_whitespace_1_idx_;
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_2_idx_ = other.whitespace_2_idx_;
339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_2_idx_ = other.non_whitespace_2_idx_;
340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_3_idx_ = other.whitespace_3_idx_;
341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_3_idx_ = other.non_whitespace_3_idx_;
342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_4_idx_ = other.whitespace_4_idx_;
343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  end_of_firstline_idx_ = other.end_of_firstline_idx_;
344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  header_lines_ = other.header_lines_;
345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::AddAndMakeDescription(const base::StringPiece& key,
348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                         const base::StringPiece& value,
349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                         HeaderLineDescription* d) {
350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CHECK(d != NULL);
351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // + 2 to size for ": "
352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  size_t line_size = key.size() + 2 + value.size();
353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BalsaBuffer::Blocks::size_type block_buffer_idx = 0;
354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  char* storage = balsa_buffer_.Reserve(line_size, &block_buffer_idx);
355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  size_t base_idx = storage - GetPtr(block_buffer_idx);
356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
357c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  char* cur_loc = storage;
358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(cur_loc, key.data(), key.size());
359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_loc += key.size();
360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *cur_loc = ':';
361c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ++cur_loc;
362c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *cur_loc = ' ';
363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ++cur_loc;
364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(cur_loc, value.data(), value.size());
365c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *d = HeaderLineDescription(base_idx,
366c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             base_idx + key.size(),
367c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             base_idx + key.size() + 2,
368c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             base_idx + key.size() + 2 + value.size(),
369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             block_buffer_idx);
370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::AppendOrPrependAndMakeDescription(
373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece& key,
374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece& value,
375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    bool append,
376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    HeaderLineDescription* d) {
377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Figure out how much space we need to reserve for the new header size.
378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  size_t old_value_size = d->last_char_idx - d->value_begin_idx;
379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (old_value_size == 0) {
380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    AddAndMakeDescription(key, value, d);
381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::StringPiece old_value(GetPtr(d->buffer_base_idx) + d->value_begin_idx,
384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                        old_value_size);
385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BalsaBuffer::Blocks::size_type block_buffer_idx = 0;
387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // + 3 because we potentially need to add ": ", and "," to the line.
388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  size_t new_size = key.size() + 3 + old_value_size + value.size();
389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  char* storage = balsa_buffer_.Reserve(new_size, &block_buffer_idx);
390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  size_t base_idx = storage - GetPtr(block_buffer_idx);
391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::StringPiece first_value = old_value;
393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::StringPiece second_value = value;
394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!append) {  // !append == prepend
395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    first_value = value;
396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    second_value = old_value;
397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  char* cur_loc = storage;
399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(cur_loc, key.data(), key.size());
400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_loc += key.size();
401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *cur_loc = ':';
402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ++cur_loc;
403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *cur_loc = ' ';
404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ++cur_loc;
405c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(cur_loc, first_value.data(), first_value.size());
406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_loc += first_value.size();
407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *cur_loc = ',';
408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ++cur_loc;
409c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(cur_loc, second_value.data(), second_value.size());
410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
411c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *d = HeaderLineDescription(base_idx,
412c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             base_idx + key.size(),
413c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             base_idx + key.size() + 2,
414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             base_idx + new_size,
415c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                             block_buffer_idx);
416c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
418c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Removes all keys value pairs with key 'key' starting at 'start'.
419c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::RemoveAllOfHeaderStartingAt(const base::StringPiece& key,
420c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                               HeaderLines::iterator start) {
421c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (start != header_lines_.end()) {
422c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    start->skip = true;
423c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    ++start;
424c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    start = GetHeaderLinesIterator(key, start);
425c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
426c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
427c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
428c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::HackHeader(const base::StringPiece& key,
429c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                              const base::StringPiece& value) {
430c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // See TODO in balsa_headers.h
431c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::iterator end = header_lines_.end();
432c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::iterator begin = header_lines_.begin();
433c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HeaderLines::iterator i = GetHeaderLinesIteratorNoSkip(key, begin);
434c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (i != end) {
435c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // First, remove all of the header lines including this one.  We want to
436c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // remove before replacing, in case our replacement ends up being appended
437c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // at the end (and thus would be removed by this call)
438c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    RemoveAllOfHeaderStartingAt(key, i);
439c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Now add the replacement, at this location.
440c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    AddAndMakeDescription(key, value, &(*i));
441c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
442c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
443c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AppendHeader(key, value);
444c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
445c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
446c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::HackAppendToHeader(const base::StringPiece& key,
447c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                      const base::StringPiece& append_value) {
448c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // See TODO in balsa_headers.h
449c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::iterator end = header_lines_.end();
450c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::iterator begin = header_lines_.begin();
451c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
452c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HeaderLines::iterator i = GetHeaderLinesIterator(key, begin);
453c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (i == end) {
454c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    HackHeader(key, append_value);
455c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
456c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
457c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
458c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AppendOrPrependAndMakeDescription(key, append_value, true, &(*i));
459c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
460c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
461c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::ReplaceOrAppendHeader(const base::StringPiece& key,
462c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                         const base::StringPiece& value) {
463c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::iterator end = header_lines_.end();
464c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::iterator begin = header_lines_.begin();
465c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HeaderLines::iterator i = GetHeaderLinesIterator(key, begin);
466c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (i != end) {
467c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // First, remove all of the header lines including this one.  We want to
468c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // remove before replacing, in case our replacement ends up being appended
469c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // at the end (and thus would be removed by this call)
470c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    RemoveAllOfHeaderStartingAt(key, i);
471c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Now, take the first instance and replace it.  This will remove the
472c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // 'skipped' tag if the replacement is done in-place.
473c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    AddAndMakeDescription(key, value, &(*i));
474c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
475c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
476c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AppendHeader(key, value);
477c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
478c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
479c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::AppendHeader(const base::StringPiece& key,
480c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                const base::StringPiece& value) {
481c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HeaderLineDescription hld;
482c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AddAndMakeDescription(key, value, &hld);
483c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  header_lines_.push_back(hld);
484c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
485c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
486c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::AppendToHeader(const base::StringPiece& key,
487c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                  const base::StringPiece& value) {
488c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AppendOrPrependToHeader(key, value, true);
489c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
490c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
491c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::PrependToHeader(const base::StringPiece& key,
492c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                   const base::StringPiece& value) {
493c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AppendOrPrependToHeader(key, value, false);
494c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
495c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
496c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbase::StringPiece BalsaHeaders::GetValueFromHeaderLineDescription(
497c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const HeaderLineDescription& line) const {
498c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_GE(line.last_char_idx, line.value_begin_idx);
499c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return base::StringPiece(GetPtr(line.buffer_base_idx) + line.value_begin_idx,
500c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                     line.last_char_idx - line.value_begin_idx);
501c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
502c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
503c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottconst base::StringPiece BalsaHeaders::GetHeader(
504c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece& key) const {
505c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!IsMultivaluedHeader(key))
506c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      << "Header '" << key << "' may consist of multiple lines. Do not "
507c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      << "use BalsaHeaders::GetHeader() or you may be missing some of its "
508c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      << "values.";
509c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::const_iterator end = header_lines_.end();
510c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::const_iterator begin = header_lines_.begin();
511c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HeaderLines::const_iterator i = GetConstHeaderLinesIterator(key, begin);
512c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (i == end) {
513c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return base::StringPiece(NULL, 0);
514c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
515c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return GetValueFromHeaderLineDescription(*i);
516c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
517c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
518c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottBalsaHeaders::const_header_lines_iterator BalsaHeaders::GetHeaderPosition(
519c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece& key) const {
520c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::const_iterator end = header_lines_.end();
521c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::const_iterator begin = header_lines_.begin();
522c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HeaderLines::const_iterator i = GetConstHeaderLinesIterator(key, begin);
523c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (i == end) {
524c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return header_lines_end();
525c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
526c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
527c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return const_header_lines_iterator(this, (i - begin));
528c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
529c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
530c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottBalsaHeaders::const_header_lines_key_iterator BalsaHeaders::GetIteratorForKey(
531c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece& key) const {
532c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HeaderLines::const_iterator i =
533c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      GetConstHeaderLinesIterator(key, header_lines_.begin());
534c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (i == header_lines_.end()) {
535c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return header_lines_key_end();
536c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
537c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
538c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::const_iterator begin = header_lines_.begin();
539c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return const_header_lines_key_iterator(this, (i - begin), key);
540c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
541c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
542c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::AppendOrPrependToHeader(const base::StringPiece& key,
543c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                           const base::StringPiece& value,
544c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                           bool append) {
545c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HeaderLines::iterator i = GetHeaderLinesIterator(key, header_lines_.begin());
546c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (i == header_lines_.end()) {
547c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // The header did not exist already.  Instead of appending to an existing
548c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // header simply append the key/value pair to the headers.
549c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    AppendHeader(key, value);
550c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
551c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
552c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HeaderLineDescription hld = *i;
553c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
554c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AppendOrPrependAndMakeDescription(key, value, append, &hld);
555c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
556c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Invalidate the old header line and add the new one.
557c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  i->skip = true;
558c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  header_lines_.push_back(hld);
559c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
560c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
561c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottBalsaHeaders::HeaderLines::const_iterator
562c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottBalsaHeaders::GetConstHeaderLinesIterator(
563c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece& key,
564c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    BalsaHeaders::HeaderLines::const_iterator start) const {
565c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::const_iterator end = header_lines_.end();
566c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (HeaderLines::const_iterator i = start; i != end; ++i) {
567c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const HeaderLineDescription& line = *i;
568c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (line.skip) {
569c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      continue;
570c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
571c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const size_t key_len = line.key_end_idx - line.first_char_idx;
572c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
573c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (key_len != key.size()) {
574c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      continue;
575c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
576c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (strncasecmp(GetPtr(line.buffer_base_idx) + line.first_char_idx,
577c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    key.data(), key_len) == 0) {
578c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      DCHECK_GE(line.last_char_idx, line.value_begin_idx);
579c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return i;
580c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
581c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
582c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return end;
583c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
584c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
585c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottBalsaHeaders::HeaderLines::iterator BalsaHeaders::GetHeaderLinesIteratorNoSkip(
586c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece& key,
587c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    BalsaHeaders::HeaderLines::iterator start) {
588c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::iterator end = header_lines_.end();
589c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (HeaderLines::iterator i = start; i != end; ++i) {
590c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const HeaderLineDescription& line = *i;
591c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const size_t key_len = line.key_end_idx - line.first_char_idx;
592c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
593c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (key_len != key.size()) {
594c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      continue;
595c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
596c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (strncasecmp(GetPtr(line.buffer_base_idx) + line.first_char_idx,
597c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    key.data(), key_len) == 0) {
598c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      DCHECK_GE(line.last_char_idx, line.value_begin_idx);
599c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return i;
600c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
601c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
602c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return end;
603c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
604c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
605c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottBalsaHeaders::HeaderLines::iterator BalsaHeaders::GetHeaderLinesIterator(
606c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece& key,
607c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    BalsaHeaders::HeaderLines::iterator start) {
608c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::iterator end = header_lines_.end();
609c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (HeaderLines::iterator i = start; i != end; ++i) {
610c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const HeaderLineDescription& line = *i;
611c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (line.skip) {
612c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      continue;
613c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
614c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const size_t key_len = line.key_end_idx - line.first_char_idx;
615c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
616c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (key_len != key.size()) {
617c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      continue;
618c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
619c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (strncasecmp(GetPtr(line.buffer_base_idx) + line.first_char_idx,
620c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                    key.data(), key_len) == 0) {
621c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      DCHECK_GE(line.last_char_idx, line.value_begin_idx);
622c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return i;
623c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
624c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
625c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return end;
626c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
627c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
628c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::GetAllOfHeader(
629c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece& key, std::vector<base::StringPiece>* out) const {
630c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (const_header_lines_key_iterator it = GetIteratorForKey(key);
631c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott       it != header_lines_end(); ++it) {
632c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    out->push_back(it->second);
633c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
634c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
635c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
636c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool BalsaHeaders::HasNonEmptyHeader(const base::StringPiece& key) const {
637c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (const_header_lines_key_iterator it = GetIteratorForKey(key);
638c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott       it != header_lines_key_end(); ++it) {
639c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!it->second.empty())
640c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return true;
641c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
642c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return false;
643c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
644c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
645c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::GetAllOfHeaderAsString(const base::StringPiece& key,
646c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                          std::string* out) const {
647c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const_header_lines_iterator it = header_lines_begin();
648c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const_header_lines_iterator end = header_lines_end();
649c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
650c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (; it != end; ++it) {
651c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (key == it->first) {
652c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (!out->empty()) {
653c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        out->append(",");
654c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
655c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      out->append(std::string(it->second.data(), it->second.size()));
656c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
657c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
658c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
659c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
660c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static
661c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool BalsaHeaders::IsMultivaluedHeader(const base::StringPiece& header) {
662c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return g_multivalued_headers.find(header) != g_multivalued_headers.end();
663c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
664c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
665c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::RemoveAllOfHeader(const base::StringPiece& key) {
666c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  HeaderLines::iterator it = GetHeaderLinesIterator(key, header_lines_.begin());
667c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  RemoveAllOfHeaderStartingAt(key, it);
668c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
669c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
670c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::RemoveAllHeadersWithPrefix(const base::StringPiece& key) {
671c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (HeaderLines::size_type i = 0; i < header_lines_.size(); ++i) {
672c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (header_lines_[i].skip) {
673c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      continue;
674c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
675c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    HeaderLineDescription& line = header_lines_[i];
676c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const size_t key_len = line.key_end_idx - line.first_char_idx;
677c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (key_len < key.size()) {
678c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // If the key given to us is longer than this header, don't consider it.
679c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      continue;
680c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
681c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!strncasecmp(GetPtr(line.buffer_base_idx) + line.first_char_idx,
682c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                     key.data(), key.size())) {
683c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      line.skip = true;
684c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
685c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
686c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
687c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
688c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottsize_t BalsaHeaders::GetMemoryUsedLowerBound() const {
689c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return (sizeof(*this) +
690c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          balsa_buffer_.GetTotalBufferBlockSize() +
691c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          header_lines_.capacity() * sizeof(HeaderLineDescription));
692c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
693c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
694c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottsize_t BalsaHeaders::GetSizeForWriteBuffer() const {
695c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // First add the space required for the first line + CRLF
696c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  size_t write_buf_size = whitespace_4_idx_ - non_whitespace_1_idx_ + 2;
697c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Then add the space needed for each header line to write out + CRLF.
698c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const HeaderLines::size_type end = header_lines_.size();
699c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (HeaderLines::size_type i = 0; i < end; ++i) {
700c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const HeaderLineDescription& line = header_lines_[i];
701c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!line.skip) {
702c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Add the key size and ": ".
703c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      write_buf_size += line.key_end_idx - line.first_char_idx + 2;
704c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Add the value size and the CRLF
705c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      write_buf_size += line.last_char_idx - line.value_begin_idx + 2;
706c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
707c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
708c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Finally tag on the terminal CRLF.
709c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return write_buf_size + 2;
710c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
711c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
712c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::DumpToString(std::string* str) const {
713c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const base::StringPiece firstline = first_line();
714c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const int buffer_length =
715c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      OriginalHeaderStreamEnd() - OriginalHeaderStreamBegin();
716c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // First check whether the header object is empty.
717c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (firstline.empty() && buffer_length == 0) {
718c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    str->append("\n<empty header>\n");
719c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
720c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
721c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
722c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Then check whether the header is in a partially parsed state. If so, just
723c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // dump the raw data.
724c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (balsa_buffer_.can_write_to_contiguous_buffer()) {
7254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    base::StringAppendF(str, "\n<incomplete header len: %d>\n%.*s\n",
7264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                        buffer_length, buffer_length,
7274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                        OriginalHeaderStreamBegin());
728c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
729c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
730c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
731c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If the header is complete, then just dump them with the logical key value
732c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // pair.
733c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  str->reserve(str->size() + GetSizeForWriteBuffer());
7344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  base::StringAppendF(str, "\n %.*s\n",
7354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                      static_cast<int>(firstline.size()),
7364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                      firstline.data());
737c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  BalsaHeaders::const_header_lines_iterator i = header_lines_begin();
738c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (; i != header_lines_end(); ++i) {
7394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    base::StringAppendF(str, " %.*s: %.*s\n",
7404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                        static_cast<int>(i->first.size()), i->first.data(),
7414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                        static_cast<int>(i->second.size()), i->second.data());
742c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
743c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
744c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
745c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::SetFirstLine(const base::StringPiece& line) {
746c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::StringPiece new_line = balsa_buffer_.Write(line,
747c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                                   &firstline_buffer_base_idx_);
748c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_1_idx_ = new_line.data() - GetPtr(firstline_buffer_base_idx_);
749c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_1_idx_ = whitespace_1_idx_;
750c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_4_idx_ = whitespace_1_idx_ + line.size();
751c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_2_idx_ = whitespace_4_idx_;
752c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_2_idx_ = whitespace_4_idx_;
753c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_3_idx_ = whitespace_4_idx_;
754c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_3_idx_ = whitespace_4_idx_;
755c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  end_of_firstline_idx_ = whitespace_4_idx_;
756c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
757c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
758c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::SetContentLength(size_t length) {
759c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If the content-length is already the one we want, don't do anything.
760c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (content_length_status_ == BalsaHeadersEnums::VALID_CONTENT_LENGTH &&
761c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      content_length_ == length) {
762c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
763c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
764c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const base::StringPiece content_length(kContentLength,
765c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                         sizeof(kContentLength) - 1);
766c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If header state indicates that there is either a content length or
767c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // transfer encoding header, remove them before adding the new content
768c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // length. There is always the possibility that client can manually add
769c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // either header directly and cause content_length_status_ or
770c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // transfer_encoding_is_chunked_ to be inconsistent with the actual header.
771c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // In the interest of efficiency, however, we will assume that clients will
772c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // use the header object correctly and thus we will not scan the all headers
773c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // each time this function is called.
774c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (content_length_status_ != BalsaHeadersEnums::NO_CONTENT_LENGTH) {
775c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    RemoveAllOfHeader(content_length);
776c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else if (transfer_encoding_is_chunked_) {
777c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece transfer_encoding(kTransferEncoding,
778c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                        sizeof(kTransferEncoding) - 1);
779c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    RemoveAllOfHeader(transfer_encoding);
780c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    transfer_encoding_is_chunked_ = false;
781c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
782c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  content_length_status_ = BalsaHeadersEnums::VALID_CONTENT_LENGTH;
783c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  content_length_ = length;
784c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // FastUInt64ToBuffer is supposed to use a maximum of kFastToBufferSize bytes.
785c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  char buffer[kFastToBufferSize];
786201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  int len_converted = snprintf(buffer, sizeof(buffer), "%zd", length);
787c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CHECK_GT(len_converted, 0);
788c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const base::StringPiece length_str(buffer, len_converted);
789c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AppendHeader(content_length, length_str);
790c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
791c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
792c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::SetChunkEncoding(bool chunk_encode) {
793c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (transfer_encoding_is_chunked_ == chunk_encode) {
794c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
795c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
796c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (content_length_status_ != BalsaHeadersEnums::NO_CONTENT_LENGTH &&
797c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      chunk_encode) {
798c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Want to change to chunk encoding, but have content length. Arguably we
799c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // can leave this step out, since transfer-encoding overrides
800c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // content-length.
801c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece content_length(kContentLength,
802c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                     sizeof(kContentLength) - 1);
803c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    RemoveAllOfHeader(content_length);
804c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    content_length_status_ = BalsaHeadersEnums::NO_CONTENT_LENGTH;
805c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    content_length_ = 0;
806c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
807c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const base::StringPiece transfer_encoding(kTransferEncoding,
808c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                      sizeof(kTransferEncoding) - 1);
809c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (chunk_encode) {
810c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const char kChunked[] = "chunked";
811c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece chunked(kChunked, sizeof(kChunked) - 1);
812c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    AppendHeader(transfer_encoding, chunked);
813c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
814c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    RemoveAllOfHeader(transfer_encoding);
815c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
816c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  transfer_encoding_is_chunked_ = chunk_encode;
817c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
818c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
819c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// See the comment about this function in the header file for a
820c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// warning about its usage.
821c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::SetFirstlineFromStringPieces(
822c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece& firstline_a,
823c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece& firstline_b,
824c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const base::StringPiece& firstline_c) {
825c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  size_t line_size = (firstline_a.size() +
826c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      firstline_b.size() +
827c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      firstline_c.size() +
828c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                      2);
829c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  char* storage = balsa_buffer_.Reserve(line_size, &firstline_buffer_base_idx_);
830c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  char* cur_loc = storage;
831c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
832c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(cur_loc, firstline_a.data(), firstline_a.size());
833c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_loc += firstline_a.size();
834c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
835c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *cur_loc = ' ';
836c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ++cur_loc;
837c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
838c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(cur_loc, firstline_b.data(), firstline_b.size());
839c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cur_loc += firstline_b.size();
840c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
841c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  *cur_loc = ' ';
842c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ++cur_loc;
843c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
844c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(cur_loc, firstline_c.data(), firstline_c.size());
845c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
846c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_1_idx_ = storage - GetPtr(firstline_buffer_base_idx_);
847c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_1_idx_ = whitespace_1_idx_;
848c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_2_idx_ = non_whitespace_1_idx_ + firstline_a.size();
849c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_2_idx_ = whitespace_2_idx_ + 1;
850c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_3_idx_ = non_whitespace_2_idx_ + firstline_b.size();
851c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  non_whitespace_3_idx_ = whitespace_3_idx_ + 1;
852c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  whitespace_4_idx_ = non_whitespace_3_idx_ + firstline_c.size();
853c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  end_of_firstline_idx_ = whitespace_4_idx_;
854c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
855c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
856c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::SetRequestMethod(const base::StringPiece& method) {
857c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // This is the first of the three parts of the firstline.
858c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (method.size() <= (whitespace_2_idx_ - non_whitespace_1_idx_)) {
859c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    non_whitespace_1_idx_ = whitespace_2_idx_ - method.size();
860c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    char* stream_begin = GetPtr(firstline_buffer_base_idx_);
861c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memcpy(stream_begin + non_whitespace_1_idx_,
862c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott           method.data(),
863c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott           method.size());
864c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
865c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // The new method is too large to fit in the space available for the old
866c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // one, so we have to reformat the firstline.
867c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    SetFirstlineFromStringPieces(method, request_uri(), request_version());
868c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
869c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
870c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
871c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::SetResponseVersion(const base::StringPiece& version) {
872c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Note: There is no difference between request_method() and
873c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // response_Version(). Thus, a function to set one is equivalent to a
874c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // function to set the other. We maintain two functions for this as it is
875c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // much more descriptive, and makes code more understandable.
876c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SetRequestMethod(version);
877c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
878c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
879c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::SetRequestUri(const base::StringPiece& uri) {
880c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SetFirstlineFromStringPieces(request_method(), uri, request_version());
881c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
882c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
883c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::SetResponseCode(const base::StringPiece& code) {
884c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Note: There is no difference between request_uri() and response_code().
885c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Thus, a function to set one is equivalent to a function to set the other.
886c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We maintain two functions for this as it is much more descriptive, and
887c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // makes code more understandable.
888c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SetRequestUri(code);
889c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
890c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
891c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::SetParsedResponseCodeAndUpdateFirstline(
892c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    size_t parsed_response_code) {
893c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  char buffer[kFastToBufferSize];
894c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int len_converted = snprintf(buffer, sizeof(buffer),
895201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                               "%zd", parsed_response_code);
896c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CHECK_GT(len_converted, 0);
897c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SetResponseCode(base::StringPiece(buffer, len_converted));
898c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
899c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
900c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::SetRequestVersion(const base::StringPiece& version) {
901c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // This is the last of the three parts of the firstline.
902c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Since whitespace_3_idx and non_whitespace_3_idx may point to the same
903c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // place, we ensure below that any available space includes space for a
904c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // litteral space (' ') character between the second component and the third
905c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // component. If the space between whitespace_3_idx_ and
906c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // end_of_firstline_idx_ is >= to version.size() + 1 (for the space), then we
907c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // can update the firstline in-place.
908c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  char* stream_begin = GetPtr(firstline_buffer_base_idx_);
909c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (version.size() + 1 <= end_of_firstline_idx_ - whitespace_3_idx_) {
910c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    *(stream_begin + whitespace_3_idx_) = kSpaceChar;
911c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    non_whitespace_3_idx_ = whitespace_3_idx_ + 1;
912c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    whitespace_4_idx_ = non_whitespace_3_idx_ + version.size();
913c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memcpy(stream_begin + non_whitespace_3_idx_,
914c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott           version.data(),
915c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott           version.size());
916c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
917c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // The new version is to large to fit in the space available for the old
918c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // one, so we have to reformat the firstline.
919c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    SetFirstlineFromStringPieces(request_method(), request_uri(), version);
920c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
921c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
922c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
923c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid BalsaHeaders::SetResponseReasonPhrase(const base::StringPiece& reason) {
924c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Note: There is no difference between request_version() and
925c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // response_reason_phrase(). Thus, a function to set one is equivalent to a
926c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // function to set the other. We maintain two functions for this as it is
927c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // much more descriptive, and makes code more understandable.
928c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SetRequestVersion(reason);
929c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
930c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
931c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
932