// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/tools/flip_server/balsa_headers_token_utils.h" #include "net/tools/flip_server/string_piece_utils.h" namespace net { inline void BalsaHeadersTokenUtils::TokenizeHeaderLine( const BalsaHeaders& headers, const BalsaHeaders::HeaderLineDescription& header_line, BalsaHeaders::HeaderTokenList* tokens) { CHECK(tokens); // Find where this line is stored const char* stream_begin = headers.GetPtr(header_line.buffer_base_idx); // Determine the boundaries of the value const char* value_begin = stream_begin + header_line.value_begin_idx; const char* line_end = stream_begin + header_line.last_char_idx; // Tokenize ParseTokenList(value_begin, line_end, tokens); } void BalsaHeadersTokenUtils::RemoveLastTokenFromHeaderValue( const base::StringPiece& key, BalsaHeaders* headers) { BalsaHeaders::HeaderLines::iterator it = headers->GetHeaderLinesIterator(key, headers->header_lines_.begin()); if (it == headers->header_lines_.end()) { DLOG(WARNING) << "Attempting to remove last token from a non-existent " << "header \"" << key << "\""; return; } // Find the last line with that key. BalsaHeaders::HeaderLines::iterator header_line; do { header_line = it; it = headers->GetHeaderLinesIterator(key, it + 1); } while (it != headers->header_lines_.end()); // Tokenize just that line. BalsaHeaders::HeaderTokenList tokens; TokenizeHeaderLine(*headers, *header_line, &tokens); if (tokens.empty()) { DLOG(WARNING) << "Attempting to remove a token from an empty header value " << "for header \"" << key << "\""; header_line->skip = true; // remove the whole line } else if (tokens.size() == 1) { header_line->skip = true; // remove the whole line } else { // Shrink the line size and leave the extra data in the buffer. const base::StringPiece& new_last_token = tokens[tokens.size() - 2]; const char* last_char_address = new_last_token.data() + new_last_token.size() - 1; const char* stream_begin = headers->GetPtr(header_line->buffer_base_idx); header_line->last_char_idx = last_char_address - stream_begin + 1; } } bool BalsaHeadersTokenUtils::CheckHeaderForLastToken( const BalsaHeaders& headers, const base::StringPiece& key, const base::StringPiece& token) { BalsaHeaders::const_header_lines_key_iterator it = headers.GetIteratorForKey(key); if (it == headers.header_lines_key_end()) return false; // Find the last line BalsaHeaders::const_header_lines_key_iterator header_line = it; do { header_line = it; ++it; } while (it != headers.header_lines_key_end()); // Tokenize just that line BalsaHeaders::HeaderTokenList tokens; ParseTokenList(header_line->second.begin(), header_line->second.end(), &tokens); return !tokens.empty() && StringPieceUtils::StartsWithIgnoreCase(tokens.back(), token); } void BalsaHeadersTokenUtils::TokenizeHeaderValue( const BalsaHeaders& headers, const base::StringPiece& key, BalsaHeaders::HeaderTokenList* tokens) { CHECK(tokens); tokens->clear(); // We may have more then 1 line with the same header key. Tokenize them all // and stick all the tokens into the same list. for (BalsaHeaders::const_header_lines_key_iterator header_line = headers.GetIteratorForKey(key); header_line != headers.header_lines_key_end(); ++header_line) { ParseTokenList(header_line->second.begin(), header_line->second.end(), tokens); } } void BalsaHeadersTokenUtils::ParseTokenList( const char* start, const char* end, BalsaHeaders::HeaderTokenList* tokens) { if (start == end) { return; } while (true) { // search for first nonwhitespace, non separator char. while (*start == ',' || *start <= ' ') { ++start; if (start == end) { return; } } // found. marked. const char* nws = start; // search for next whitspace or separator char. while (*start != ',' && *start > ' ') { ++start; if (start == end) { if (nws != start) { tokens->push_back(base::StringPiece(nws, start - nws)); } return; } } tokens->push_back(base::StringPiece(nws, start - nws)); } } } // namespace net