• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_token_utils.h"
6 #include "net/tools/balsa/string_piece_utils.h"
7 
8 namespace net {
9 
TokenizeHeaderLine(const BalsaHeaders & headers,const BalsaHeaders::HeaderLineDescription & header_line,BalsaHeaders::HeaderTokenList * tokens)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 
RemoveLastTokenFromHeaderValue(const base::StringPiece & key,BalsaHeaders * headers)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 
CheckHeaderForLastToken(const BalsaHeaders & headers,const base::StringPiece & key,const base::StringPiece & token)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 
TokenizeHeaderValue(const BalsaHeaders & headers,const base::StringPiece & key,BalsaHeaders::HeaderTokenList * tokens)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 
ParseTokenList(const char * start,const char * end,BalsaHeaders::HeaderTokenList * tokens)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