Home | History | Annotate | Download | only in flip_server
      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