1 // Copyright (c) 2009 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_token_utils.h" 6 #include "net/tools/flip_server/string_piece_utils.h" 7 8 namespace net { 9 10 inline void BalsaHeadersTokenUtils::TokenizeHeaderLine( 11 const BalsaHeaders& headers, 12 const BalsaHeaders::HeaderLineDescription& header_line, 13 BalsaHeaders::HeaderTokenList* tokens) { 14 CHECK(tokens); 15 16 // Find where this line is stored 17 const char* stream_begin = headers.GetPtr(header_line.buffer_base_idx); 18 19 // Determine the boundaries of the value 20 const char* value_begin = stream_begin + header_line.value_begin_idx; 21 const char* line_end = stream_begin + header_line.last_char_idx; 22 23 // Tokenize 24 ParseTokenList(value_begin, line_end, tokens); 25 } 26 27 void BalsaHeadersTokenUtils::RemoveLastTokenFromHeaderValue( 28 const base::StringPiece& key, BalsaHeaders* headers) { 29 BalsaHeaders::HeaderLines::iterator it = 30 headers->GetHeaderLinesIterator(key, headers->header_lines_.begin()); 31 if (it == headers->header_lines_.end()) { 32 DLOG(WARNING) << "Attempting to remove last token from a non-existent " 33 << "header \"" << key << "\""; 34 return; 35 } 36 37 // Find the last line with that key. 38 BalsaHeaders::HeaderLines::iterator header_line; 39 do { 40 header_line = it; 41 it = headers->GetHeaderLinesIterator(key, it + 1); 42 } 43 while (it != headers->header_lines_.end()); 44 45 // Tokenize just that line. 46 BalsaHeaders::HeaderTokenList tokens; 47 TokenizeHeaderLine(*headers, *header_line, &tokens); 48 49 if (tokens.empty()) { 50 DLOG(WARNING) << "Attempting to remove a token from an empty header value " 51 << "for header \"" << key << "\""; 52 header_line->skip = true; // remove the whole line 53 } else if (tokens.size() == 1) { 54 header_line->skip = true; // remove the whole line 55 } else { 56 // Shrink the line size and leave the extra data in the buffer. 57 const base::StringPiece& new_last_token = tokens[tokens.size() - 2]; 58 const char* last_char_address = 59 new_last_token.data() + new_last_token.size() - 1; 60 const char* stream_begin = headers->GetPtr(header_line->buffer_base_idx); 61 62 header_line->last_char_idx = last_char_address - stream_begin + 1; 63 } 64 } 65 66 bool BalsaHeadersTokenUtils::CheckHeaderForLastToken( 67 const BalsaHeaders& headers, 68 const base::StringPiece& key, 69 const base::StringPiece& token) { 70 BalsaHeaders::const_header_lines_key_iterator it = 71 headers.GetIteratorForKey(key); 72 if (it == headers.header_lines_key_end()) 73 return false; 74 75 // Find the last line 76 BalsaHeaders::const_header_lines_key_iterator header_line = it; 77 do { 78 header_line = it; 79 ++it; 80 } 81 while (it != headers.header_lines_key_end()); 82 83 // Tokenize just that line 84 BalsaHeaders::HeaderTokenList tokens; 85 ParseTokenList(header_line->second.begin(), header_line->second.end(), 86 &tokens); 87 88 return !tokens.empty() && 89 StringPieceUtils::StartsWithIgnoreCase(tokens.back(), token); 90 } 91 92 void BalsaHeadersTokenUtils::TokenizeHeaderValue( 93 const BalsaHeaders& headers, 94 const base::StringPiece& key, 95 BalsaHeaders::HeaderTokenList* tokens) { 96 CHECK(tokens); 97 tokens->clear(); 98 99 // We may have more then 1 line with the same header key. Tokenize them all 100 // and stick all the tokens into the same list. 101 for (BalsaHeaders::const_header_lines_key_iterator header_line = 102 headers.GetIteratorForKey(key); 103 header_line != headers.header_lines_key_end(); ++header_line) { 104 ParseTokenList(header_line->second.begin(), header_line->second.end(), 105 tokens); 106 } 107 } 108 109 void BalsaHeadersTokenUtils::ParseTokenList( 110 const char* start, 111 const char* end, 112 BalsaHeaders::HeaderTokenList* tokens) { 113 if (start == end) { 114 return; 115 } 116 while (true) { 117 // search for first nonwhitespace, non separator char. 118 while (*start == ',' || *start <= ' ') { 119 ++start; 120 if (start == end) { 121 return; 122 } 123 } 124 // found. marked. 125 const char* nws = start; 126 127 // search for next whitspace or separator char. 128 while (*start != ',' && *start > ' ') { 129 ++start; 130 if (start == end) { 131 if (nws != start) { 132 tokens->push_back(base::StringPiece(nws, start - nws)); 133 } 134 return; 135 } 136 } 137 tokens->push_back(base::StringPiece(nws, start - nws)); 138 } 139 } 140 141 } // namespace net 142 143