#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"
namespace net {
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;
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();
void Reset();
const BalsaHeaders* const_balsa_headers() const { return headers_; }
BalsaHeaders* balsa_headers() { return headers_; }
void set_balsa_headers(BalsaHeaders* headers) {
if (headers_ != headers) {
headers_ = headers;
}
if (headers_) {
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);
static void ProcessChunkExtensions(const char* input, size_t size,
BalsaHeaders* extensions);
protected:
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';
}
inline bool HeaderFramingFound(char current_char) {
if (current_char == '\n' || current_char == '\r') {
term_chars_ <<= 8;
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_;
bool request_was_head_;
size_t max_header_length_;
size_t max_request_uri_length_;
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_;
DoNothingBalsaVisitor do_nothing_visitor_;
};
}
#endif