14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/tools/balsa/balsa_headers_token_utils.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/tools/balsa/string_piece_utils.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void BalsaHeadersTokenUtils::TokenizeHeaderLine(
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BalsaHeaders& headers,
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BalsaHeaders::HeaderLineDescription& header_line,
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BalsaHeaders::HeaderTokenList* tokens) {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(tokens);
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find where this line is stored
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* stream_begin = headers.GetPtr(header_line.buffer_base_idx);
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Determine the boundaries of the value
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* value_begin = stream_begin + header_line.value_begin_idx;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* line_end = stream_begin + header_line.last_char_idx;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tokenize
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ParseTokenList(value_begin, line_end, tokens);
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BalsaHeadersTokenUtils::RemoveLastTokenFromHeaderValue(
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::StringPiece& key, BalsaHeaders* headers) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BalsaHeaders::HeaderLines::iterator it =
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      headers->GetHeaderLinesIterator(key, headers->header_lines_.begin());
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == headers->header_lines_.end()) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Attempting to remove last token from a non-existent "
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << "header \"" << key << "\"";
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the last line with that key.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BalsaHeaders::HeaderLines::iterator header_line;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header_line = it;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    it = headers->GetHeaderLinesIterator(key, it + 1);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (it != headers->header_lines_.end());
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tokenize just that line.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BalsaHeaders::HeaderTokenList tokens;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TokenizeHeaderLine(*headers, *header_line, &tokens);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tokens.empty()) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Attempting to remove a token from an empty header value "
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << "for header \"" << key << "\"";
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header_line->skip = true;  // remove the whole line
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (tokens.size() == 1) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header_line->skip = true;  // remove the whole line
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Shrink the line size and leave the extra data in the buffer.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::StringPiece& new_last_token = tokens[tokens.size() - 2];
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* last_char_address =
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_last_token.data() + new_last_token.size() - 1;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* stream_begin = headers->GetPtr(header_line->buffer_base_idx);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header_line->last_char_idx = last_char_address - stream_begin + 1;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BalsaHeadersTokenUtils::CheckHeaderForLastToken(
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BalsaHeaders& headers,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::StringPiece& key,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::StringPiece& token) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BalsaHeaders::const_header_lines_key_iterator it =
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      headers.GetIteratorForKey(key);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == headers.header_lines_key_end())
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the last line
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BalsaHeaders::const_header_lines_key_iterator header_line = it;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header_line = it;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++it;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (it != headers.header_lines_key_end());
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tokenize just that line
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BalsaHeaders::HeaderTokenList tokens;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ParseTokenList(header_line->second.begin(), header_line->second.end(),
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 &tokens);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !tokens.empty() &&
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StringPieceUtils::StartsWithIgnoreCase(tokens.back(), token);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BalsaHeadersTokenUtils::TokenizeHeaderValue(
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BalsaHeaders& headers,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::StringPiece& key,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BalsaHeaders::HeaderTokenList* tokens) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(tokens);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tokens->clear();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We may have more then 1 line with the same header key. Tokenize them all
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and stick all the tokens into the same list.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (BalsaHeaders::const_header_lines_key_iterator header_line =
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           headers.GetIteratorForKey(key);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       header_line != headers.header_lines_key_end(); ++header_line) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ParseTokenList(header_line->second.begin(), header_line->second.end(),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   tokens);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BalsaHeadersTokenUtils::ParseTokenList(
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* start,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* end,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BalsaHeaders::HeaderTokenList* tokens) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (start == end) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (true) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // search for first nonwhitespace, non separator char.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (*start == ',' || *start <= ' ') {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++start;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (start == end) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // found. marked.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* nws = start;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // search for next whitspace or separator char.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (*start != ',' && *start > ' ') {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++start;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (start == end) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (nws != start) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          tokens->push_back(base::StringPiece(nws, start - nws));
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tokens->push_back(base::StringPiece(nws, start - nws));
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
143