diff options
Diffstat (limited to 'chromium/net/tools/balsa/balsa_frame.h')
-rw-r--r-- | chromium/net/tools/balsa/balsa_frame.h | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/chromium/net/tools/balsa/balsa_frame.h b/chromium/net/tools/balsa/balsa_frame.h new file mode 100644 index 00000000000..8e1240c86e9 --- /dev/null +++ b/chromium/net/tools/balsa/balsa_frame.h @@ -0,0 +1,265 @@ +// Copyright 2013 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. + +#ifndef NET_TOOLS_BALSA_BALSA_FRAME_H_ +#define NET_TOOLS_BALSA_BALSA_FRAME_H_ + +#include <strings.h> + +#include <utility> +#include <vector> + +#include "base/compiler_specific.h" +#include "base/port.h" +#include "net/tools/balsa/balsa_enums.h" +#include "net/tools/balsa/balsa_headers.h" +#include "net/tools/balsa/balsa_visitor_interface.h" +#include "net/tools/balsa/buffer_interface.h" +#include "net/tools/balsa/http_message_constants.h" +#include "net/tools/balsa/simple_buffer.h" + +// For additional debug output, uncomment the following: +// #define DEBUGFRAMER 1 + +namespace net { + +// BalsaFrame is a 'Model' of a framer (haha). +// It exists as a proof of concept headers framer. +class BalsaFrame { + public: + typedef std::vector<std::pair<size_t, size_t> > Lines; + + typedef BalsaHeaders::HeaderLineDescription HeaderLineDescription; + typedef BalsaHeaders::HeaderLines HeaderLines; + typedef BalsaHeaders::HeaderTokenList HeaderTokenList; + + // TODO(fenix): get rid of the 'kValidTerm*' stuff by using the 'since last + // index' strategy. Note that this implies getting rid of the HeaderFramed() + + static const uint32 kValidTerm1 = '\n' << 16 | + '\r' << 8 | + '\n'; + static const uint32 kValidTerm1Mask = 0xFF << 16 | + 0xFF << 8 | + 0xFF; + static const uint32 kValidTerm2 = '\n' << 8 | + '\n'; + static const uint32 kValidTerm2Mask = 0xFF << 8 | + 0xFF; + BalsaFrame(); + ~BalsaFrame(); + + // Reset reinitializes all the member variables of the framer and clears the + // attached header object (but doesn't change the pointer value headers_). + void Reset(); + + const BalsaHeaders* const_balsa_headers() const { return headers_; } + BalsaHeaders* balsa_headers() { return headers_; } + // The method set_balsa_headers clears the headers provided and attaches them + // to the framer. This is a required step before the framer will process any + // input message data. + // To detach the header object from the framer, use set_balsa_headers(NULL). + void set_balsa_headers(BalsaHeaders* headers) { + if (headers_ != headers) { + headers_ = headers; + } + if (headers_) { + // Clear the headers if they are non-null, even if the new headers are + // the same as the old. + headers_->Clear(); + } + } + + void set_balsa_visitor(BalsaVisitorInterface* visitor) { + visitor_ = visitor; + if (visitor_ == NULL) { + visitor_ = &do_nothing_visitor_; + } + } + + void set_is_request(bool is_request) { is_request_ = is_request; } + + bool is_request() const { + return is_request_; + } + + void set_request_was_head(bool request_was_head) { + request_was_head_ = request_was_head; + } + + bool request_was_head() const { + return request_was_head_; + } + + void set_max_header_length(size_t max_header_length) { + max_header_length_ = max_header_length; + } + + size_t max_header_length() const { + return max_header_length_; + } + + void set_max_request_uri_length(size_t max_request_uri_length) { + max_request_uri_length_ = max_request_uri_length; + } + + size_t max_request_uri_length() const { + return max_request_uri_length_; + } + + + bool MessageFullyRead() { + return parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ; + } + + BalsaFrameEnums::ParseState ParseState() const { return parse_state_; } + + + bool Error() { + return parse_state_ == BalsaFrameEnums::PARSE_ERROR; + } + + BalsaFrameEnums::ErrorCode ErrorCode() const { return last_error_; } + + const BalsaHeaders* headers() const { return headers_; } + BalsaHeaders* mutable_headers() { return headers_; } + + size_t BytesSafeToSplice() const; + void BytesSpliced(size_t bytes_spliced); + + size_t ProcessInput(const char* input, size_t size); + + // Parses input and puts the key, value chunk extensions into extensions. + // TODO(phython): Find a better data structure to put the extensions into. + static void ProcessChunkExtensions(const char* input, size_t size, + BalsaHeaders* extensions); + + protected: + // The utils object needs access to the ParseTokenList in order to do its + // job. + friend class BalsaHeadersTokenUtils; + + inline void ProcessContentLengthLine( + size_t line_idx, + BalsaHeadersEnums::ContentLengthStatus* status, + size_t* length); + + inline void ProcessTransferEncodingLine(size_t line_idx); + + void ProcessFirstLine(const char* begin, + const char* end); + + void CleanUpKeyValueWhitespace( + const char* stream_begin, + const char* line_begin, + const char* current, + const char* line_end, + HeaderLineDescription* current_header_line); + + void FindColonsAndParseIntoKeyValue(); + + void ProcessHeaderLines(); + + inline size_t ProcessHeaders(const char* message_start, + size_t message_length); + + void AssignParseStateAfterHeadersHaveBeenParsed(); + + inline bool LineFramingFound(char current_char) { + return current_char == '\n'; + } + + // TODO(fenix): get rid of the following function and its uses (and + // replace with something more efficient) + inline bool HeaderFramingFound(char current_char) { + // Note that the 'if (current_char == '\n' ...)' test exists to ensure that + // the HeaderFramingMayBeFound test works properly. In benchmarking done on + // 2/13/2008, the 'if' actually speeds up performance of the function + // anyway.. + if (current_char == '\n' || current_char == '\r') { + term_chars_ <<= 8; + // This is necessary IFF architecture has > 8 bit char. Alas, I'm + // paranoid. + term_chars_ |= current_char & 0xFF; + + if ((term_chars_ & kValidTerm1Mask) == kValidTerm1) { + term_chars_ = 0; + return true; + } + if ((term_chars_ & kValidTerm2Mask) == kValidTerm2) { + term_chars_ = 0; + return true; + } + } else { + term_chars_ = 0; + } + return false; + } + + inline bool HeaderFramingMayBeFound() const { + return term_chars_ != 0; + } + + private: + class DoNothingBalsaVisitor : public BalsaVisitorInterface { + virtual void ProcessBodyInput(const char *input, size_t size) OVERRIDE {} + virtual void ProcessBodyData(const char *input, size_t size) OVERRIDE {} + virtual void ProcessHeaderInput(const char *input, size_t size) OVERRIDE {} + virtual void ProcessTrailerInput(const char *input, size_t size) OVERRIDE {} + virtual void ProcessHeaders(const BalsaHeaders& headers) OVERRIDE {} + virtual void ProcessRequestFirstLine(const char* line_input, + size_t line_length, + const char* method_input, + size_t method_length, + const char* request_uri_input, + size_t request_uri_length, + const char* version_input, + size_t version_length) OVERRIDE {} + virtual void ProcessResponseFirstLine(const char *line_input, + size_t line_length, + const char *version_input, + size_t version_length, + const char *status_input, + size_t status_length, + const char *reason_input, + size_t reason_length) OVERRIDE {} + virtual void ProcessChunkLength(size_t chunk_length) OVERRIDE {} + virtual void ProcessChunkExtensions(const char *input, + size_t size) OVERRIDE {} + virtual void HeaderDone() OVERRIDE {} + virtual void MessageDone() OVERRIDE {} + virtual void HandleHeaderError(BalsaFrame* framer) OVERRIDE {} + virtual void HandleHeaderWarning(BalsaFrame* framer) OVERRIDE {} + virtual void HandleChunkingError(BalsaFrame* framer) OVERRIDE {} + virtual void HandleBodyError(BalsaFrame* framer) OVERRIDE {} + }; + + bool last_char_was_slash_r_; + bool saw_non_newline_char_; + bool start_was_space_; + bool chunk_length_character_extracted_; + bool is_request_; // This is not reset in Reset() + bool request_was_head_; // This is not reset in Reset() + size_t max_header_length_; // This is not reset in Reset() + size_t max_request_uri_length_; // This is not reset in Reset() + BalsaVisitorInterface* visitor_; + size_t chunk_length_remaining_; + size_t content_length_remaining_; + const char* last_slash_n_loc_; + const char* last_recorded_slash_n_loc_; + size_t last_slash_n_idx_; + uint32 term_chars_; + BalsaFrameEnums::ParseState parse_state_; + BalsaFrameEnums::ErrorCode last_error_; + + Lines lines_; + + BalsaHeaders* headers_; // This is not reset to NULL in Reset(). + DoNothingBalsaVisitor do_nothing_visitor_; +}; + +} // namespace net + +#endif // NET_TOOLS_BALSA_BALSA_FRAME_H_ + |