Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1608)

Side by Side Diff: net/tools/flip_server/balsa_headers.cc

Issue 25085002: Break out balsa and epoll_server from net/tools/flip_server. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/tools/flip_server/balsa_headers.h ('k') | net/tools/flip_server/balsa_headers_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/tools/flip_server/balsa_headers.h"
6
7 #include <stdio.h>
8 #include <algorithm>
9 #include <ext/hash_set>
10 #include <string>
11 #include <utility>
12 #include <vector>
13
14 #include "base/logging.h"
15 #include "base/port.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/string_piece.h"
18 #include "net/tools/flip_server/balsa_enums.h"
19 #include "net/tools/flip_server/buffer_interface.h"
20 #include "net/tools/flip_server/simple_buffer.h"
21 #include "third_party/tcmalloc/chromium/src/base/googleinit.h"
22 // #include "util/gtl/iterator_adaptors-inl.h"
23 // #include "util/gtl/map-util.h"
24
25 namespace {
26
27 const char kContentLength[] = "Content-Length";
28 const char kTransferEncoding[] = "Transfer-Encoding";
29 const char kSpaceChar = ' ';
30
31 __gnu_cxx::hash_set<base::StringPiece,
32 net::StringPieceCaseHash,
33 net::StringPieceCaseEqual> g_multivalued_headers;
34
35 void InitMultivaluedHeaders() {
36 g_multivalued_headers.insert("accept");
37 g_multivalued_headers.insert("accept-charset");
38 g_multivalued_headers.insert("accept-encoding");
39 g_multivalued_headers.insert("accept-language");
40 g_multivalued_headers.insert("accept-ranges");
41 g_multivalued_headers.insert("allow");
42 g_multivalued_headers.insert("cache-control");
43 g_multivalued_headers.insert("connection");
44 g_multivalued_headers.insert("content-encoding");
45 g_multivalued_headers.insert("content-language");
46 g_multivalued_headers.insert("expect");
47 g_multivalued_headers.insert("if-match");
48 g_multivalued_headers.insert("if-none-match");
49 g_multivalued_headers.insert("pragma");
50 g_multivalued_headers.insert("proxy-authenticate");
51 g_multivalued_headers.insert("te");
52 g_multivalued_headers.insert("trailer");
53 g_multivalued_headers.insert("transfer-encoding");
54 g_multivalued_headers.insert("upgrade");
55 g_multivalued_headers.insert("vary");
56 g_multivalued_headers.insert("via");
57 g_multivalued_headers.insert("warning");
58 g_multivalued_headers.insert("www-authenticate");
59 // Not mentioned in RFC 2616, but it can have multiple values.
60 g_multivalued_headers.insert("set-cookie");
61 }
62
63 REGISTER_MODULE_INITIALIZER(multivalued_headers, InitMultivaluedHeaders());
64
65 const int kFastToBufferSize = 32; // I think 22 is adequate, but anyway..
66
67 } // namespace
68
69 namespace net {
70
71 const size_t BalsaBuffer::kDefaultBlocksize;
72
73 BalsaHeaders::iterator_base::iterator_base() : headers_(NULL), idx_(0) { }
74
75 BalsaHeaders::iterator_base::iterator_base(const iterator_base& it)
76 : headers_(it.headers_),
77 idx_(it.idx_) {
78 }
79
80 std::ostream& BalsaHeaders::iterator_base::operator<<(std::ostream& os) const {
81 os << "[" << this->headers_ << ", " << this->idx_ << "]";
82 return os;
83 }
84
85 BalsaHeaders::iterator_base::iterator_base(const BalsaHeaders* headers,
86 HeaderLines::size_type index)
87 : headers_(headers),
88 idx_(index) {
89 }
90
91 BalsaBuffer::~BalsaBuffer() {
92 CleanupBlocksStartingFrom(0);
93 }
94
95 // Returns the total amount of memory used by the buffer blocks.
96 size_t BalsaBuffer::GetTotalBufferBlockSize() const {
97 size_t buffer_size = 0;
98 for (Blocks::const_iterator iter = blocks_.begin();
99 iter != blocks_.end();
100 ++iter) {
101 buffer_size += iter->buffer_size;
102 }
103 return buffer_size;
104 }
105
106 void BalsaBuffer::WriteToContiguousBuffer(const base::StringPiece& sp) {
107 if (sp.empty()) {
108 return;
109 }
110 CHECK(can_write_to_contiguous_buffer_);
111 DCHECK_GE(blocks_.size(), 1u);
112 if (blocks_[0].buffer == NULL && sp.size() <= blocksize_) {
113 blocks_[0] = AllocBlock();
114 memcpy(blocks_[0].start_of_unused_bytes(), sp.data(), sp.size());
115 } else if (blocks_[0].bytes_free < sp.size()) {
116 // the first block isn't big enough, resize it.
117 const size_t old_storage_size_used = blocks_[0].bytes_used();
118 const size_t new_storage_size = old_storage_size_used + sp.size();
119 char* new_storage = new char[new_storage_size];
120 char* old_storage = blocks_[0].buffer;
121 if (old_storage_size_used) {
122 memcpy(new_storage, old_storage, old_storage_size_used);
123 }
124 memcpy(new_storage + old_storage_size_used, sp.data(), sp.size());
125 blocks_[0].buffer = new_storage;
126 blocks_[0].bytes_free = sp.size();
127 blocks_[0].buffer_size = new_storage_size;
128 delete[] old_storage;
129 } else {
130 memcpy(blocks_[0].start_of_unused_bytes(), sp.data(), sp.size());
131 }
132 blocks_[0].bytes_free -= sp.size();
133 }
134
135 base::StringPiece BalsaBuffer::Write(const base::StringPiece& sp,
136 Blocks::size_type* block_buffer_idx) {
137 if (sp.empty()) {
138 return sp;
139 }
140 char* storage = Reserve(sp.size(), block_buffer_idx);
141 memcpy(storage, sp.data(), sp.size());
142 return base::StringPiece(storage, sp.size());
143 }
144
145 char* BalsaBuffer::Reserve(size_t size,
146 Blocks::size_type* block_buffer_idx) {
147 // There should always be a 'first_block', even if it
148 // contains nothing.
149 DCHECK_GE(blocks_.size(), 1u);
150 BufferBlock* block = NULL;
151 Blocks::size_type block_idx = can_write_to_contiguous_buffer_ ? 1 : 0;
152 for (; block_idx < blocks_.size(); ++block_idx) {
153 if (blocks_[block_idx].bytes_free >= size) {
154 block = &blocks_[block_idx];
155 break;
156 }
157 }
158 if (block == NULL) {
159 if (blocksize_ < size) {
160 blocks_.push_back(AllocCustomBlock(size));
161 } else {
162 blocks_.push_back(AllocBlock());
163 }
164 block = &blocks_.back();
165 }
166
167 char* storage = block->start_of_unused_bytes();
168 block->bytes_free -= size;
169 if (block_buffer_idx) {
170 *block_buffer_idx = block_idx;
171 }
172 return storage;
173 }
174
175 void BalsaBuffer::Clear() {
176 CHECK(!blocks_.empty());
177 if (blocksize_ == blocks_[0].buffer_size) {
178 CleanupBlocksStartingFrom(1);
179 blocks_[0].bytes_free = blocks_[0].buffer_size;
180 } else {
181 CleanupBlocksStartingFrom(0);
182 blocks_.push_back(AllocBlock());
183 }
184 DCHECK_GE(blocks_.size(), 1u);
185 can_write_to_contiguous_buffer_ = true;
186 }
187
188 void BalsaBuffer::Swap(BalsaBuffer* b) {
189 blocks_.swap(b->blocks_);
190 std::swap(can_write_to_contiguous_buffer_,
191 b->can_write_to_contiguous_buffer_);
192 std::swap(blocksize_, b->blocksize_);
193 }
194
195 void BalsaBuffer::CopyFrom(const BalsaBuffer& b) {
196 CleanupBlocksStartingFrom(0);
197 blocks_.resize(b.blocks_.size());
198 for (Blocks::size_type i = 0; i < blocks_.size(); ++i) {
199 blocks_[i] = CopyBlock(b.blocks_[i]);
200 }
201 blocksize_ = b.blocksize_;
202 can_write_to_contiguous_buffer_ = b.can_write_to_contiguous_buffer_;
203 }
204
205 BalsaBuffer::BalsaBuffer()
206 : blocksize_(kDefaultBlocksize), can_write_to_contiguous_buffer_(true) {
207 blocks_.push_back(AllocBlock());
208 }
209
210 BalsaBuffer::BalsaBuffer(size_t blocksize) :
211 blocksize_(blocksize), can_write_to_contiguous_buffer_(true) {
212 blocks_.push_back(AllocBlock());
213 }
214
215 BalsaBuffer::BufferBlock BalsaBuffer::AllocBlock() {
216 return AllocCustomBlock(blocksize_);
217 }
218
219 BalsaBuffer::BufferBlock BalsaBuffer::AllocCustomBlock(size_t blocksize) {
220 return BufferBlock(new char[blocksize], blocksize, blocksize);
221 }
222
223 BalsaBuffer::BufferBlock BalsaBuffer::CopyBlock(const BufferBlock& b) {
224 BufferBlock block = b;
225 if (b.buffer == NULL) {
226 return block;
227 }
228
229 block.buffer = new char[b.buffer_size];
230 memcpy(block.buffer, b.buffer, b.bytes_used());
231 return block;
232 }
233
234 void BalsaBuffer::CleanupBlocksStartingFrom(Blocks::size_type start_idx) {
235 for (Blocks::size_type i = start_idx; i < blocks_.size(); ++i) {
236 delete[] blocks_[i].buffer;
237 }
238 blocks_.resize(start_idx);
239 }
240
241 BalsaHeaders::const_header_lines_key_iterator::const_header_lines_key_iterator(
242 const const_header_lines_key_iterator& other)
243 : iterator_base(other),
244 key_(other.key_) {
245 }
246
247 BalsaHeaders::const_header_lines_key_iterator::const_header_lines_key_iterator(
248 const BalsaHeaders* headers,
249 HeaderLines::size_type index,
250 const base::StringPiece& key)
251 : iterator_base(headers, index),
252 key_(key) {
253 }
254
255 BalsaHeaders::const_header_lines_key_iterator::const_header_lines_key_iterator(
256 const BalsaHeaders* headers,
257 HeaderLines::size_type index)
258 : iterator_base(headers, index) {
259 }
260
261 BalsaHeaders::BalsaHeaders()
262 : balsa_buffer_(4096),
263 content_length_(0),
264 content_length_status_(BalsaHeadersEnums::NO_CONTENT_LENGTH),
265 parsed_response_code_(0),
266 firstline_buffer_base_idx_(0),
267 whitespace_1_idx_(0),
268 non_whitespace_1_idx_(0),
269 whitespace_2_idx_(0),
270 non_whitespace_2_idx_(0),
271 whitespace_3_idx_(0),
272 non_whitespace_3_idx_(0),
273 whitespace_4_idx_(0),
274 end_of_firstline_idx_(0),
275 transfer_encoding_is_chunked_(false) {
276 }
277
278 BalsaHeaders::~BalsaHeaders() {}
279
280 void BalsaHeaders::Clear() {
281 balsa_buffer_.Clear();
282 transfer_encoding_is_chunked_ = false;
283 content_length_ = 0;
284 content_length_status_ = BalsaHeadersEnums::NO_CONTENT_LENGTH;
285 parsed_response_code_ = 0;
286 firstline_buffer_base_idx_ = 0;
287 whitespace_1_idx_ = 0;
288 non_whitespace_1_idx_ = 0;
289 whitespace_2_idx_ = 0;
290 non_whitespace_2_idx_ = 0;
291 whitespace_3_idx_ = 0;
292 non_whitespace_3_idx_ = 0;
293 whitespace_4_idx_ = 0;
294 end_of_firstline_idx_ = 0;
295 header_lines_.clear();
296 }
297
298 void BalsaHeaders::Swap(BalsaHeaders* other) {
299 // Protect against swapping with self.
300 if (this == other) return;
301
302 balsa_buffer_.Swap(&other->balsa_buffer_);
303
304 bool tmp_bool = transfer_encoding_is_chunked_;
305 transfer_encoding_is_chunked_ = other->transfer_encoding_is_chunked_;
306 other->transfer_encoding_is_chunked_ = tmp_bool;
307
308 size_t tmp_size_t = content_length_;
309 content_length_ = other->content_length_;
310 other->content_length_ = tmp_size_t;
311
312 BalsaHeadersEnums::ContentLengthStatus tmp_status =
313 content_length_status_;
314 content_length_status_ = other->content_length_status_;
315 other->content_length_status_ = tmp_status;
316
317 tmp_size_t = parsed_response_code_;
318 parsed_response_code_ = other->parsed_response_code_;
319 other->parsed_response_code_ = tmp_size_t;
320
321 BalsaBuffer::Blocks::size_type tmp_blk_idx = firstline_buffer_base_idx_;
322 firstline_buffer_base_idx_ = other->firstline_buffer_base_idx_;
323 other->firstline_buffer_base_idx_ = tmp_blk_idx;
324
325 tmp_size_t = whitespace_1_idx_;
326 whitespace_1_idx_ = other->whitespace_1_idx_;
327 other->whitespace_1_idx_ = tmp_size_t;
328
329 tmp_size_t = non_whitespace_1_idx_;
330 non_whitespace_1_idx_ = other->non_whitespace_1_idx_;
331 other->non_whitespace_1_idx_ = tmp_size_t;
332
333 tmp_size_t = whitespace_2_idx_;
334 whitespace_2_idx_ = other->whitespace_2_idx_;
335 other->whitespace_2_idx_ = tmp_size_t;
336
337 tmp_size_t = non_whitespace_2_idx_;
338 non_whitespace_2_idx_ = other->non_whitespace_2_idx_;
339 other->non_whitespace_2_idx_ = tmp_size_t;
340
341 tmp_size_t = whitespace_3_idx_;
342 whitespace_3_idx_ = other->whitespace_3_idx_;
343 other->whitespace_3_idx_ = tmp_size_t;
344
345 tmp_size_t = non_whitespace_3_idx_;
346 non_whitespace_3_idx_ = other->non_whitespace_3_idx_;
347 other->non_whitespace_3_idx_ = tmp_size_t;
348
349 tmp_size_t = whitespace_4_idx_;
350 whitespace_4_idx_ = other->whitespace_4_idx_;
351 other->whitespace_4_idx_ = tmp_size_t;
352
353 tmp_size_t = end_of_firstline_idx_;
354 end_of_firstline_idx_ = other->end_of_firstline_idx_;
355 other->end_of_firstline_idx_ = tmp_size_t;
356
357 swap(header_lines_, other->header_lines_);
358 }
359
360 void BalsaHeaders::CopyFrom(const BalsaHeaders& other) {
361 // Protect against copying with self.
362 if (this == &other) return;
363
364 balsa_buffer_.CopyFrom(other.balsa_buffer_);
365 transfer_encoding_is_chunked_ = other.transfer_encoding_is_chunked_;
366 content_length_ = other.content_length_;
367 content_length_status_ = other.content_length_status_;
368 parsed_response_code_ = other.parsed_response_code_;
369 firstline_buffer_base_idx_ = other.firstline_buffer_base_idx_;
370 whitespace_1_idx_ = other.whitespace_1_idx_;
371 non_whitespace_1_idx_ = other.non_whitespace_1_idx_;
372 whitespace_2_idx_ = other.whitespace_2_idx_;
373 non_whitespace_2_idx_ = other.non_whitespace_2_idx_;
374 whitespace_3_idx_ = other.whitespace_3_idx_;
375 non_whitespace_3_idx_ = other.non_whitespace_3_idx_;
376 whitespace_4_idx_ = other.whitespace_4_idx_;
377 end_of_firstline_idx_ = other.end_of_firstline_idx_;
378 header_lines_ = other.header_lines_;
379 }
380
381 void BalsaHeaders::AddAndMakeDescription(const base::StringPiece& key,
382 const base::StringPiece& value,
383 HeaderLineDescription* d) {
384 CHECK(d != NULL);
385 // + 2 to size for ": "
386 size_t line_size = key.size() + 2 + value.size();
387 BalsaBuffer::Blocks::size_type block_buffer_idx = 0;
388 char* storage = balsa_buffer_.Reserve(line_size, &block_buffer_idx);
389 size_t base_idx = storage - GetPtr(block_buffer_idx);
390
391 char* cur_loc = storage;
392 memcpy(cur_loc, key.data(), key.size());
393 cur_loc += key.size();
394 *cur_loc = ':';
395 ++cur_loc;
396 *cur_loc = ' ';
397 ++cur_loc;
398 memcpy(cur_loc, value.data(), value.size());
399 *d = HeaderLineDescription(base_idx,
400 base_idx + key.size(),
401 base_idx + key.size() + 2,
402 base_idx + key.size() + 2 + value.size(),
403 block_buffer_idx);
404 }
405
406 void BalsaHeaders::AppendOrPrependAndMakeDescription(
407 const base::StringPiece& key,
408 const base::StringPiece& value,
409 bool append,
410 HeaderLineDescription* d) {
411 // Figure out how much space we need to reserve for the new header size.
412 size_t old_value_size = d->last_char_idx - d->value_begin_idx;
413 if (old_value_size == 0) {
414 AddAndMakeDescription(key, value, d);
415 return;
416 }
417 base::StringPiece old_value(GetPtr(d->buffer_base_idx) + d->value_begin_idx,
418 old_value_size);
419
420 BalsaBuffer::Blocks::size_type block_buffer_idx = 0;
421 // + 3 because we potentially need to add ": ", and "," to the line.
422 size_t new_size = key.size() + 3 + old_value_size + value.size();
423 char* storage = balsa_buffer_.Reserve(new_size, &block_buffer_idx);
424 size_t base_idx = storage - GetPtr(block_buffer_idx);
425
426 base::StringPiece first_value = old_value;
427 base::StringPiece second_value = value;
428 if (!append) { // !append == prepend
429 first_value = value;
430 second_value = old_value;
431 }
432 char* cur_loc = storage;
433 memcpy(cur_loc, key.data(), key.size());
434 cur_loc += key.size();
435 *cur_loc = ':';
436 ++cur_loc;
437 *cur_loc = ' ';
438 ++cur_loc;
439 memcpy(cur_loc, first_value.data(), first_value.size());
440 cur_loc += first_value.size();
441 *cur_loc = ',';
442 ++cur_loc;
443 memcpy(cur_loc, second_value.data(), second_value.size());
444
445 *d = HeaderLineDescription(base_idx,
446 base_idx + key.size(),
447 base_idx + key.size() + 2,
448 base_idx + new_size,
449 block_buffer_idx);
450 }
451
452 // Removes all keys value pairs with key 'key' starting at 'start'.
453 void BalsaHeaders::RemoveAllOfHeaderStartingAt(const base::StringPiece& key,
454 HeaderLines::iterator start) {
455 while (start != header_lines_.end()) {
456 start->skip = true;
457 ++start;
458 start = GetHeaderLinesIterator(key, start);
459 }
460 }
461
462 void BalsaHeaders::HackHeader(const base::StringPiece& key,
463 const base::StringPiece& value) {
464 // See TODO in balsa_headers.h
465 const HeaderLines::iterator end = header_lines_.end();
466 const HeaderLines::iterator begin = header_lines_.begin();
467 HeaderLines::iterator i = GetHeaderLinesIteratorNoSkip(key, begin);
468 if (i != end) {
469 // First, remove all of the header lines including this one. We want to
470 // remove before replacing, in case our replacement ends up being appended
471 // at the end (and thus would be removed by this call)
472 RemoveAllOfHeaderStartingAt(key, i);
473 // Now add the replacement, at this location.
474 AddAndMakeDescription(key, value, &(*i));
475 return;
476 }
477 AppendHeader(key, value);
478 }
479
480 void BalsaHeaders::HackAppendToHeader(const base::StringPiece& key,
481 const base::StringPiece& append_value) {
482 // See TODO in balsa_headers.h
483 const HeaderLines::iterator end = header_lines_.end();
484 const HeaderLines::iterator begin = header_lines_.begin();
485
486 HeaderLines::iterator i = GetHeaderLinesIterator(key, begin);
487 if (i == end) {
488 HackHeader(key, append_value);
489 return;
490 }
491
492 AppendOrPrependAndMakeDescription(key, append_value, true, &(*i));
493 }
494
495 void BalsaHeaders::ReplaceOrAppendHeader(const base::StringPiece& key,
496 const base::StringPiece& value) {
497 const HeaderLines::iterator end = header_lines_.end();
498 const HeaderLines::iterator begin = header_lines_.begin();
499 HeaderLines::iterator i = GetHeaderLinesIterator(key, begin);
500 if (i != end) {
501 // First, remove all of the header lines including this one. We want to
502 // remove before replacing, in case our replacement ends up being appended
503 // at the end (and thus would be removed by this call)
504 RemoveAllOfHeaderStartingAt(key, i);
505 // Now, take the first instance and replace it. This will remove the
506 // 'skipped' tag if the replacement is done in-place.
507 AddAndMakeDescription(key, value, &(*i));
508 return;
509 }
510 AppendHeader(key, value);
511 }
512
513 void BalsaHeaders::AppendHeader(const base::StringPiece& key,
514 const base::StringPiece& value) {
515 HeaderLineDescription hld;
516 AddAndMakeDescription(key, value, &hld);
517 header_lines_.push_back(hld);
518 }
519
520 void BalsaHeaders::AppendToHeader(const base::StringPiece& key,
521 const base::StringPiece& value) {
522 AppendOrPrependToHeader(key, value, true);
523 }
524
525 void BalsaHeaders::PrependToHeader(const base::StringPiece& key,
526 const base::StringPiece& value) {
527 AppendOrPrependToHeader(key, value, false);
528 }
529
530 base::StringPiece BalsaHeaders::GetValueFromHeaderLineDescription(
531 const HeaderLineDescription& line) const {
532 DCHECK_GE(line.last_char_idx, line.value_begin_idx);
533 return base::StringPiece(GetPtr(line.buffer_base_idx) + line.value_begin_idx,
534 line.last_char_idx - line.value_begin_idx);
535 }
536
537 const base::StringPiece BalsaHeaders::GetHeader(
538 const base::StringPiece& key) const {
539 DCHECK(!IsMultivaluedHeader(key))
540 << "Header '" << key << "' may consist of multiple lines. Do not "
541 << "use BalsaHeaders::GetHeader() or you may be missing some of its "
542 << "values.";
543 const HeaderLines::const_iterator end = header_lines_.end();
544 const HeaderLines::const_iterator begin = header_lines_.begin();
545 HeaderLines::const_iterator i = GetConstHeaderLinesIterator(key, begin);
546 if (i == end) {
547 return base::StringPiece(NULL, 0);
548 }
549 return GetValueFromHeaderLineDescription(*i);
550 }
551
552 BalsaHeaders::const_header_lines_iterator BalsaHeaders::GetHeaderPosition(
553 const base::StringPiece& key) const {
554 const HeaderLines::const_iterator end = header_lines_.end();
555 const HeaderLines::const_iterator begin = header_lines_.begin();
556 HeaderLines::const_iterator i = GetConstHeaderLinesIterator(key, begin);
557 if (i == end) {
558 return header_lines_end();
559 }
560
561 return const_header_lines_iterator(this, (i - begin));
562 }
563
564 BalsaHeaders::const_header_lines_key_iterator BalsaHeaders::GetIteratorForKey(
565 const base::StringPiece& key) const {
566 HeaderLines::const_iterator i =
567 GetConstHeaderLinesIterator(key, header_lines_.begin());
568 if (i == header_lines_.end()) {
569 return header_lines_key_end();
570 }
571
572 const HeaderLines::const_iterator begin = header_lines_.begin();
573 return const_header_lines_key_iterator(this, (i - begin), key);
574 }
575
576 void BalsaHeaders::AppendOrPrependToHeader(const base::StringPiece& key,
577 const base::StringPiece& value,
578 bool append) {
579 HeaderLines::iterator i = GetHeaderLinesIterator(key, header_lines_.begin());
580 if (i == header_lines_.end()) {
581 // The header did not exist already. Instead of appending to an existing
582 // header simply append the key/value pair to the headers.
583 AppendHeader(key, value);
584 return;
585 }
586 HeaderLineDescription hld = *i;
587
588 AppendOrPrependAndMakeDescription(key, value, append, &hld);
589
590 // Invalidate the old header line and add the new one.
591 i->skip = true;
592 header_lines_.push_back(hld);
593 }
594
595 BalsaHeaders::HeaderLines::const_iterator
596 BalsaHeaders::GetConstHeaderLinesIterator(
597 const base::StringPiece& key,
598 BalsaHeaders::HeaderLines::const_iterator start) const {
599 const HeaderLines::const_iterator end = header_lines_.end();
600 for (HeaderLines::const_iterator i = start; i != end; ++i) {
601 const HeaderLineDescription& line = *i;
602 if (line.skip) {
603 continue;
604 }
605 const size_t key_len = line.key_end_idx - line.first_char_idx;
606
607 if (key_len != key.size()) {
608 continue;
609 }
610 if (strncasecmp(GetPtr(line.buffer_base_idx) + line.first_char_idx,
611 key.data(), key_len) == 0) {
612 DCHECK_GE(line.last_char_idx, line.value_begin_idx);
613 return i;
614 }
615 }
616 return end;
617 }
618
619 BalsaHeaders::HeaderLines::iterator BalsaHeaders::GetHeaderLinesIteratorNoSkip(
620 const base::StringPiece& key,
621 BalsaHeaders::HeaderLines::iterator start) {
622 const HeaderLines::iterator end = header_lines_.end();
623 for (HeaderLines::iterator i = start; i != end; ++i) {
624 const HeaderLineDescription& line = *i;
625 const size_t key_len = line.key_end_idx - line.first_char_idx;
626
627 if (key_len != key.size()) {
628 continue;
629 }
630 if (strncasecmp(GetPtr(line.buffer_base_idx) + line.first_char_idx,
631 key.data(), key_len) == 0) {
632 DCHECK_GE(line.last_char_idx, line.value_begin_idx);
633 return i;
634 }
635 }
636 return end;
637 }
638
639 BalsaHeaders::HeaderLines::iterator BalsaHeaders::GetHeaderLinesIterator(
640 const base::StringPiece& key,
641 BalsaHeaders::HeaderLines::iterator start) {
642 const HeaderLines::iterator end = header_lines_.end();
643 for (HeaderLines::iterator i = start; i != end; ++i) {
644 const HeaderLineDescription& line = *i;
645 if (line.skip) {
646 continue;
647 }
648 const size_t key_len = line.key_end_idx - line.first_char_idx;
649
650 if (key_len != key.size()) {
651 continue;
652 }
653 if (strncasecmp(GetPtr(line.buffer_base_idx) + line.first_char_idx,
654 key.data(), key_len) == 0) {
655 DCHECK_GE(line.last_char_idx, line.value_begin_idx);
656 return i;
657 }
658 }
659 return end;
660 }
661
662 void BalsaHeaders::GetAllOfHeader(
663 const base::StringPiece& key, std::vector<base::StringPiece>* out) const {
664 for (const_header_lines_key_iterator it = GetIteratorForKey(key);
665 it != header_lines_end(); ++it) {
666 out->push_back(it->second);
667 }
668 }
669
670 bool BalsaHeaders::HasNonEmptyHeader(const base::StringPiece& key) const {
671 for (const_header_lines_key_iterator it = GetIteratorForKey(key);
672 it != header_lines_key_end(); ++it) {
673 if (!it->second.empty())
674 return true;
675 }
676 return false;
677 }
678
679 void BalsaHeaders::GetAllOfHeaderAsString(const base::StringPiece& key,
680 std::string* out) const {
681 const_header_lines_iterator it = header_lines_begin();
682 const_header_lines_iterator end = header_lines_end();
683
684 for (; it != end; ++it) {
685 if (key == it->first) {
686 if (!out->empty()) {
687 out->append(",");
688 }
689 out->append(std::string(it->second.data(), it->second.size()));
690 }
691 }
692 }
693
694 // static
695 bool BalsaHeaders::IsMultivaluedHeader(const base::StringPiece& header) {
696 return g_multivalued_headers.find(header) != g_multivalued_headers.end();
697 }
698
699 void BalsaHeaders::RemoveAllOfHeader(const base::StringPiece& key) {
700 HeaderLines::iterator it = GetHeaderLinesIterator(key, header_lines_.begin());
701 RemoveAllOfHeaderStartingAt(key, it);
702 }
703
704 void BalsaHeaders::RemoveAllHeadersWithPrefix(const base::StringPiece& key) {
705 for (HeaderLines::size_type i = 0; i < header_lines_.size(); ++i) {
706 if (header_lines_[i].skip) {
707 continue;
708 }
709 HeaderLineDescription& line = header_lines_[i];
710 const size_t key_len = line.key_end_idx - line.first_char_idx;
711 if (key_len < key.size()) {
712 // If the key given to us is longer than this header, don't consider it.
713 continue;
714 }
715 if (!strncasecmp(GetPtr(line.buffer_base_idx) + line.first_char_idx,
716 key.data(), key.size())) {
717 line.skip = true;
718 }
719 }
720 }
721
722 size_t BalsaHeaders::GetMemoryUsedLowerBound() const {
723 return (sizeof(*this) +
724 balsa_buffer_.GetTotalBufferBlockSize() +
725 header_lines_.capacity() * sizeof(HeaderLineDescription));
726 }
727
728 size_t BalsaHeaders::GetSizeForWriteBuffer() const {
729 // First add the space required for the first line + CRLF
730 size_t write_buf_size = whitespace_4_idx_ - non_whitespace_1_idx_ + 2;
731 // Then add the space needed for each header line to write out + CRLF.
732 const HeaderLines::size_type end = header_lines_.size();
733 for (HeaderLines::size_type i = 0; i < end; ++i) {
734 const HeaderLineDescription& line = header_lines_[i];
735 if (!line.skip) {
736 // Add the key size and ": ".
737 write_buf_size += line.key_end_idx - line.first_char_idx + 2;
738 // Add the value size and the CRLF
739 write_buf_size += line.last_char_idx - line.value_begin_idx + 2;
740 }
741 }
742 // Finally tag on the terminal CRLF.
743 return write_buf_size + 2;
744 }
745
746 void BalsaHeaders::DumpToString(std::string* str) const {
747 const base::StringPiece firstline = first_line();
748 const int buffer_length =
749 OriginalHeaderStreamEnd() - OriginalHeaderStreamBegin();
750 // First check whether the header object is empty.
751 if (firstline.empty() && buffer_length == 0) {
752 str->append("\n<empty header>\n");
753 return;
754 }
755
756 // Then check whether the header is in a partially parsed state. If so, just
757 // dump the raw data.
758 if (balsa_buffer_.can_write_to_contiguous_buffer()) {
759 base::StringAppendF(str, "\n<incomplete header len: %d>\n%.*s\n",
760 buffer_length, buffer_length,
761 OriginalHeaderStreamBegin());
762 return;
763 }
764
765 // If the header is complete, then just dump them with the logical key value
766 // pair.
767 str->reserve(str->size() + GetSizeForWriteBuffer());
768 base::StringAppendF(str, "\n %.*s\n",
769 static_cast<int>(firstline.size()),
770 firstline.data());
771 BalsaHeaders::const_header_lines_iterator i = header_lines_begin();
772 for (; i != header_lines_end(); ++i) {
773 base::StringAppendF(str, " %.*s: %.*s\n",
774 static_cast<int>(i->first.size()), i->first.data(),
775 static_cast<int>(i->second.size()), i->second.data());
776 }
777 }
778
779 void BalsaHeaders::SetFirstLine(const base::StringPiece& line) {
780 base::StringPiece new_line = balsa_buffer_.Write(line,
781 &firstline_buffer_base_idx_);
782 whitespace_1_idx_ = new_line.data() - GetPtr(firstline_buffer_base_idx_);
783 non_whitespace_1_idx_ = whitespace_1_idx_;
784 whitespace_4_idx_ = whitespace_1_idx_ + line.size();
785 whitespace_2_idx_ = whitespace_4_idx_;
786 non_whitespace_2_idx_ = whitespace_4_idx_;
787 whitespace_3_idx_ = whitespace_4_idx_;
788 non_whitespace_3_idx_ = whitespace_4_idx_;
789 end_of_firstline_idx_ = whitespace_4_idx_;
790 }
791
792 void BalsaHeaders::SetContentLength(size_t length) {
793 // If the content-length is already the one we want, don't do anything.
794 if (content_length_status_ == BalsaHeadersEnums::VALID_CONTENT_LENGTH &&
795 content_length_ == length) {
796 return;
797 }
798 const base::StringPiece content_length(kContentLength,
799 sizeof(kContentLength) - 1);
800 // If header state indicates that there is either a content length or
801 // transfer encoding header, remove them before adding the new content
802 // length. There is always the possibility that client can manually add
803 // either header directly and cause content_length_status_ or
804 // transfer_encoding_is_chunked_ to be inconsistent with the actual header.
805 // In the interest of efficiency, however, we will assume that clients will
806 // use the header object correctly and thus we will not scan the all headers
807 // each time this function is called.
808 if (content_length_status_ != BalsaHeadersEnums::NO_CONTENT_LENGTH) {
809 RemoveAllOfHeader(content_length);
810 } else if (transfer_encoding_is_chunked_) {
811 const base::StringPiece transfer_encoding(kTransferEncoding,
812 sizeof(kTransferEncoding) - 1);
813 RemoveAllOfHeader(transfer_encoding);
814 transfer_encoding_is_chunked_ = false;
815 }
816 content_length_status_ = BalsaHeadersEnums::VALID_CONTENT_LENGTH;
817 content_length_ = length;
818 // FastUInt64ToBuffer is supposed to use a maximum of kFastToBufferSize bytes.
819 char buffer[kFastToBufferSize];
820 int len_converted = snprintf(buffer, sizeof(buffer), "%zd", length);
821 CHECK_GT(len_converted, 0);
822 const base::StringPiece length_str(buffer, len_converted);
823 AppendHeader(content_length, length_str);
824 }
825
826 void BalsaHeaders::SetChunkEncoding(bool chunk_encode) {
827 if (transfer_encoding_is_chunked_ == chunk_encode) {
828 return;
829 }
830 if (content_length_status_ != BalsaHeadersEnums::NO_CONTENT_LENGTH &&
831 chunk_encode) {
832 // Want to change to chunk encoding, but have content length. Arguably we
833 // can leave this step out, since transfer-encoding overrides
834 // content-length.
835 const base::StringPiece content_length(kContentLength,
836 sizeof(kContentLength) - 1);
837 RemoveAllOfHeader(content_length);
838 content_length_status_ = BalsaHeadersEnums::NO_CONTENT_LENGTH;
839 content_length_ = 0;
840 }
841 const base::StringPiece transfer_encoding(kTransferEncoding,
842 sizeof(kTransferEncoding) - 1);
843 if (chunk_encode) {
844 const char kChunked[] = "chunked";
845 const base::StringPiece chunked(kChunked, sizeof(kChunked) - 1);
846 AppendHeader(transfer_encoding, chunked);
847 } else {
848 RemoveAllOfHeader(transfer_encoding);
849 }
850 transfer_encoding_is_chunked_ = chunk_encode;
851 }
852
853 // See the comment about this function in the header file for a
854 // warning about its usage.
855 void BalsaHeaders::SetFirstlineFromStringPieces(
856 const base::StringPiece& firstline_a,
857 const base::StringPiece& firstline_b,
858 const base::StringPiece& firstline_c) {
859 size_t line_size = (firstline_a.size() +
860 firstline_b.size() +
861 firstline_c.size() +
862 2);
863 char* storage = balsa_buffer_.Reserve(line_size, &firstline_buffer_base_idx_);
864 char* cur_loc = storage;
865
866 memcpy(cur_loc, firstline_a.data(), firstline_a.size());
867 cur_loc += firstline_a.size();
868
869 *cur_loc = ' ';
870 ++cur_loc;
871
872 memcpy(cur_loc, firstline_b.data(), firstline_b.size());
873 cur_loc += firstline_b.size();
874
875 *cur_loc = ' ';
876 ++cur_loc;
877
878 memcpy(cur_loc, firstline_c.data(), firstline_c.size());
879
880 whitespace_1_idx_ = storage - GetPtr(firstline_buffer_base_idx_);
881 non_whitespace_1_idx_ = whitespace_1_idx_;
882 whitespace_2_idx_ = non_whitespace_1_idx_ + firstline_a.size();
883 non_whitespace_2_idx_ = whitespace_2_idx_ + 1;
884 whitespace_3_idx_ = non_whitespace_2_idx_ + firstline_b.size();
885 non_whitespace_3_idx_ = whitespace_3_idx_ + 1;
886 whitespace_4_idx_ = non_whitespace_3_idx_ + firstline_c.size();
887 end_of_firstline_idx_ = whitespace_4_idx_;
888 }
889
890 void BalsaHeaders::SetRequestMethod(const base::StringPiece& method) {
891 // This is the first of the three parts of the firstline.
892 if (method.size() <= (whitespace_2_idx_ - non_whitespace_1_idx_)) {
893 non_whitespace_1_idx_ = whitespace_2_idx_ - method.size();
894 char* stream_begin = GetPtr(firstline_buffer_base_idx_);
895 memcpy(stream_begin + non_whitespace_1_idx_,
896 method.data(),
897 method.size());
898 } else {
899 // The new method is too large to fit in the space available for the old
900 // one, so we have to reformat the firstline.
901 SetFirstlineFromStringPieces(method, request_uri(), request_version());
902 }
903 }
904
905 void BalsaHeaders::SetResponseVersion(const base::StringPiece& version) {
906 // Note: There is no difference between request_method() and
907 // response_Version(). Thus, a function to set one is equivalent to a
908 // function to set the other. We maintain two functions for this as it is
909 // much more descriptive, and makes code more understandable.
910 SetRequestMethod(version);
911 }
912
913 void BalsaHeaders::SetRequestUri(const base::StringPiece& uri) {
914 SetFirstlineFromStringPieces(request_method(), uri, request_version());
915 }
916
917 void BalsaHeaders::SetResponseCode(const base::StringPiece& code) {
918 // Note: There is no difference between request_uri() and response_code().
919 // Thus, a function to set one is equivalent to a function to set the other.
920 // We maintain two functions for this as it is much more descriptive, and
921 // makes code more understandable.
922 SetRequestUri(code);
923 }
924
925 void BalsaHeaders::SetParsedResponseCodeAndUpdateFirstline(
926 size_t parsed_response_code) {
927 char buffer[kFastToBufferSize];
928 int len_converted = snprintf(buffer, sizeof(buffer),
929 "%zd", parsed_response_code);
930 CHECK_GT(len_converted, 0);
931 SetResponseCode(base::StringPiece(buffer, len_converted));
932 }
933
934 void BalsaHeaders::SetRequestVersion(const base::StringPiece& version) {
935 // This is the last of the three parts of the firstline.
936 // Since whitespace_3_idx and non_whitespace_3_idx may point to the same
937 // place, we ensure below that any available space includes space for a
938 // litteral space (' ') character between the second component and the third
939 // component. If the space between whitespace_3_idx_ and
940 // end_of_firstline_idx_ is >= to version.size() + 1 (for the space), then we
941 // can update the firstline in-place.
942 char* stream_begin = GetPtr(firstline_buffer_base_idx_);
943 if (version.size() + 1 <= end_of_firstline_idx_ - whitespace_3_idx_) {
944 *(stream_begin + whitespace_3_idx_) = kSpaceChar;
945 non_whitespace_3_idx_ = whitespace_3_idx_ + 1;
946 whitespace_4_idx_ = non_whitespace_3_idx_ + version.size();
947 memcpy(stream_begin + non_whitespace_3_idx_,
948 version.data(),
949 version.size());
950 } else {
951 // The new version is to large to fit in the space available for the old
952 // one, so we have to reformat the firstline.
953 SetFirstlineFromStringPieces(request_method(), request_uri(), version);
954 }
955 }
956
957 void BalsaHeaders::SetResponseReasonPhrase(const base::StringPiece& reason) {
958 // Note: There is no difference between request_version() and
959 // response_reason_phrase(). Thus, a function to set one is equivalent to a
960 // function to set the other. We maintain two functions for this as it is
961 // much more descriptive, and makes code more understandable.
962 SetRequestVersion(reason);
963 }
964
965 } // namespace net
OLDNEW
« no previous file with comments | « net/tools/flip_server/balsa_headers.h ('k') | net/tools/flip_server/balsa_headers_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698