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

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

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

Powered by Google App Engine
This is Rietveld 408576698