| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 #ifndef NET_TOOLS_FLIP_SERVER_BALSA_FRAME_H_ | |
| 6 #define NET_TOOLS_FLIP_SERVER_BALSA_FRAME_H_ | |
| 7 | |
| 8 #include <strings.h> | |
| 9 | |
| 10 #include <utility> | |
| 11 #include <vector> | |
| 12 | |
| 13 #include "base/compiler_specific.h" | |
| 14 #include "base/port.h" | |
| 15 #include "net/tools/flip_server/balsa_enums.h" | |
| 16 #include "net/tools/flip_server/balsa_headers.h" | |
| 17 #include "net/tools/flip_server/balsa_visitor_interface.h" | |
| 18 #include "net/tools/flip_server/buffer_interface.h" | |
| 19 #include "net/tools/flip_server/http_message_constants.h" | |
| 20 #include "net/tools/flip_server/simple_buffer.h" | |
| 21 | |
| 22 // For additional debug output, uncomment the following: | |
| 23 // #define DEBUGFRAMER 1 | |
| 24 | |
| 25 namespace net { | |
| 26 | |
| 27 // BalsaFrame is a 'Model' of a framer (haha). | |
| 28 // It exists as a proof of concept headers framer. | |
| 29 class BalsaFrame { | |
| 30 public: | |
| 31 typedef std::vector<std::pair<size_t, size_t> > Lines; | |
| 32 | |
| 33 typedef BalsaHeaders::HeaderLineDescription HeaderLineDescription; | |
| 34 typedef BalsaHeaders::HeaderLines HeaderLines; | |
| 35 typedef BalsaHeaders::HeaderTokenList HeaderTokenList; | |
| 36 | |
| 37 // TODO(fenix): get rid of the 'kValidTerm*' stuff by using the 'since last | |
| 38 // index' strategy. Note that this implies getting rid of the HeaderFramed() | |
| 39 | |
| 40 static const uint32 kValidTerm1 = '\n' << 16 | | |
| 41 '\r' << 8 | | |
| 42 '\n'; | |
| 43 static const uint32 kValidTerm1Mask = 0xFF << 16 | | |
| 44 0xFF << 8 | | |
| 45 0xFF; | |
| 46 static const uint32 kValidTerm2 = '\n' << 8 | | |
| 47 '\n'; | |
| 48 static const uint32 kValidTerm2Mask = 0xFF << 8 | | |
| 49 0xFF; | |
| 50 BalsaFrame(); | |
| 51 ~BalsaFrame(); | |
| 52 | |
| 53 // Reset reinitializes all the member variables of the framer and clears the | |
| 54 // attached header object (but doesn't change the pointer value headers_). | |
| 55 void Reset(); | |
| 56 | |
| 57 const BalsaHeaders* const_balsa_headers() const { return headers_; } | |
| 58 BalsaHeaders* balsa_headers() { return headers_; } | |
| 59 // The method set_balsa_headers clears the headers provided and attaches them | |
| 60 // to the framer. This is a required step before the framer will process any | |
| 61 // input message data. | |
| 62 // To detach the header object from the framer, use set_balsa_headers(NULL). | |
| 63 void set_balsa_headers(BalsaHeaders* headers) { | |
| 64 if (headers_ != headers) { | |
| 65 headers_ = headers; | |
| 66 } | |
| 67 if (headers_) { | |
| 68 // Clear the headers if they are non-null, even if the new headers are | |
| 69 // the same as the old. | |
| 70 headers_->Clear(); | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 void set_balsa_visitor(BalsaVisitorInterface* visitor) { | |
| 75 visitor_ = visitor; | |
| 76 if (visitor_ == NULL) { | |
| 77 visitor_ = &do_nothing_visitor_; | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 void set_is_request(bool is_request) { is_request_ = is_request; } | |
| 82 | |
| 83 bool is_request() const { | |
| 84 return is_request_; | |
| 85 } | |
| 86 | |
| 87 void set_request_was_head(bool request_was_head) { | |
| 88 request_was_head_ = request_was_head; | |
| 89 } | |
| 90 | |
| 91 bool request_was_head() const { | |
| 92 return request_was_head_; | |
| 93 } | |
| 94 | |
| 95 void set_max_header_length(size_t max_header_length) { | |
| 96 max_header_length_ = max_header_length; | |
| 97 } | |
| 98 | |
| 99 size_t max_header_length() const { | |
| 100 return max_header_length_; | |
| 101 } | |
| 102 | |
| 103 void set_max_request_uri_length(size_t max_request_uri_length) { | |
| 104 max_request_uri_length_ = max_request_uri_length; | |
| 105 } | |
| 106 | |
| 107 size_t max_request_uri_length() const { | |
| 108 return max_request_uri_length_; | |
| 109 } | |
| 110 | |
| 111 | |
| 112 bool MessageFullyRead() { | |
| 113 return parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ; | |
| 114 } | |
| 115 | |
| 116 BalsaFrameEnums::ParseState ParseState() const { return parse_state_; } | |
| 117 | |
| 118 | |
| 119 bool Error() { | |
| 120 return parse_state_ == BalsaFrameEnums::PARSE_ERROR; | |
| 121 } | |
| 122 | |
| 123 BalsaFrameEnums::ErrorCode ErrorCode() const { return last_error_; } | |
| 124 | |
| 125 const BalsaHeaders* headers() const { return headers_; } | |
| 126 BalsaHeaders* mutable_headers() { return headers_; } | |
| 127 | |
| 128 size_t BytesSafeToSplice() const; | |
| 129 void BytesSpliced(size_t bytes_spliced); | |
| 130 | |
| 131 size_t ProcessInput(const char* input, size_t size); | |
| 132 | |
| 133 // Parses input and puts the key, value chunk extensions into extensions. | |
| 134 // TODO(phython): Find a better data structure to put the extensions into. | |
| 135 static void ProcessChunkExtensions(const char* input, size_t size, | |
| 136 BalsaHeaders* extensions); | |
| 137 | |
| 138 protected: | |
| 139 // The utils object needs access to the ParseTokenList in order to do its | |
| 140 // job. | |
| 141 friend class BalsaHeadersTokenUtils; | |
| 142 | |
| 143 inline void ProcessContentLengthLine( | |
| 144 size_t line_idx, | |
| 145 BalsaHeadersEnums::ContentLengthStatus* status, | |
| 146 size_t* length); | |
| 147 | |
| 148 inline void ProcessTransferEncodingLine(size_t line_idx); | |
| 149 | |
| 150 void ProcessFirstLine(const char* begin, | |
| 151 const char* end); | |
| 152 | |
| 153 void CleanUpKeyValueWhitespace( | |
| 154 const char* stream_begin, | |
| 155 const char* line_begin, | |
| 156 const char* current, | |
| 157 const char* line_end, | |
| 158 HeaderLineDescription* current_header_line); | |
| 159 | |
| 160 void FindColonsAndParseIntoKeyValue(); | |
| 161 | |
| 162 void ProcessHeaderLines(); | |
| 163 | |
| 164 inline size_t ProcessHeaders(const char* message_start, | |
| 165 size_t message_length); | |
| 166 | |
| 167 void AssignParseStateAfterHeadersHaveBeenParsed(); | |
| 168 | |
| 169 inline bool LineFramingFound(char current_char) { | |
| 170 return current_char == '\n'; | |
| 171 } | |
| 172 | |
| 173 // TODO(fenix): get rid of the following function and its uses (and | |
| 174 // replace with something more efficient) | |
| 175 inline bool HeaderFramingFound(char current_char) { | |
| 176 // Note that the 'if (current_char == '\n' ...)' test exists to ensure that | |
| 177 // the HeaderFramingMayBeFound test works properly. In benchmarking done on | |
| 178 // 2/13/2008, the 'if' actually speeds up performance of the function | |
| 179 // anyway.. | |
| 180 if (current_char == '\n' || current_char == '\r') { | |
| 181 term_chars_ <<= 8; | |
| 182 // This is necessary IFF architecture has > 8 bit char. Alas, I'm | |
| 183 // paranoid. | |
| 184 term_chars_ |= current_char & 0xFF; | |
| 185 | |
| 186 if ((term_chars_ & kValidTerm1Mask) == kValidTerm1) { | |
| 187 term_chars_ = 0; | |
| 188 return true; | |
| 189 } | |
| 190 if ((term_chars_ & kValidTerm2Mask) == kValidTerm2) { | |
| 191 term_chars_ = 0; | |
| 192 return true; | |
| 193 } | |
| 194 } else { | |
| 195 term_chars_ = 0; | |
| 196 } | |
| 197 return false; | |
| 198 } | |
| 199 | |
| 200 inline bool HeaderFramingMayBeFound() const { | |
| 201 return term_chars_ != 0; | |
| 202 } | |
| 203 | |
| 204 private: | |
| 205 class DoNothingBalsaVisitor : public BalsaVisitorInterface { | |
| 206 virtual void ProcessBodyInput(const char *input, size_t size) OVERRIDE {} | |
| 207 virtual void ProcessBodyData(const char *input, size_t size) OVERRIDE {} | |
| 208 virtual void ProcessHeaderInput(const char *input, size_t size) OVERRIDE {} | |
| 209 virtual void ProcessTrailerInput(const char *input, size_t size) OVERRIDE {} | |
| 210 virtual void ProcessHeaders(const BalsaHeaders& headers) OVERRIDE {} | |
| 211 virtual void ProcessRequestFirstLine(const char* line_input, | |
| 212 size_t line_length, | |
| 213 const char* method_input, | |
| 214 size_t method_length, | |
| 215 const char* request_uri_input, | |
| 216 size_t request_uri_length, | |
| 217 const char* version_input, | |
| 218 size_t version_length) OVERRIDE {} | |
| 219 virtual void ProcessResponseFirstLine(const char *line_input, | |
| 220 size_t line_length, | |
| 221 const char *version_input, | |
| 222 size_t version_length, | |
| 223 const char *status_input, | |
| 224 size_t status_length, | |
| 225 const char *reason_input, | |
| 226 size_t reason_length) OVERRIDE {} | |
| 227 virtual void ProcessChunkLength(size_t chunk_length) OVERRIDE {} | |
| 228 virtual void ProcessChunkExtensions(const char *input, | |
| 229 size_t size) OVERRIDE {} | |
| 230 virtual void HeaderDone() OVERRIDE {} | |
| 231 virtual void MessageDone() OVERRIDE {} | |
| 232 virtual void HandleHeaderError(BalsaFrame* framer) OVERRIDE {} | |
| 233 virtual void HandleHeaderWarning(BalsaFrame* framer) OVERRIDE {} | |
| 234 virtual void HandleChunkingError(BalsaFrame* framer) OVERRIDE {} | |
| 235 virtual void HandleBodyError(BalsaFrame* framer) OVERRIDE {} | |
| 236 }; | |
| 237 | |
| 238 bool last_char_was_slash_r_; | |
| 239 bool saw_non_newline_char_; | |
| 240 bool start_was_space_; | |
| 241 bool chunk_length_character_extracted_; | |
| 242 bool is_request_; // This is not reset in Reset() | |
| 243 bool request_was_head_; // This is not reset in Reset() | |
| 244 size_t max_header_length_; // This is not reset in Reset() | |
| 245 size_t max_request_uri_length_; // This is not reset in Reset() | |
| 246 BalsaVisitorInterface* visitor_; | |
| 247 size_t chunk_length_remaining_; | |
| 248 size_t content_length_remaining_; | |
| 249 const char* last_slash_n_loc_; | |
| 250 const char* last_recorded_slash_n_loc_; | |
| 251 size_t last_slash_n_idx_; | |
| 252 uint32 term_chars_; | |
| 253 BalsaFrameEnums::ParseState parse_state_; | |
| 254 BalsaFrameEnums::ErrorCode last_error_; | |
| 255 | |
| 256 Lines lines_; | |
| 257 | |
| 258 BalsaHeaders* headers_; // This is not reset to NULL in Reset(). | |
| 259 DoNothingBalsaVisitor do_nothing_visitor_; | |
| 260 }; | |
| 261 | |
| 262 } // namespace net | |
| 263 | |
| 264 #endif // NET_TOOLS_FLIP_SERVER_BALSA_FRAME_H_ | |
| 265 | |
| OLD | NEW |