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.
5 #ifndef NET_TOOLS_FLIP_SERVER_BALSA_FRAME_H_
6 #define NET_TOOLS_FLIP_SERVER_BALSA_FRAME_H_
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"
22 // For additional debug output, uncomment the following:
23 // #define DEBUGFRAMER 1
27 // BalsaFrame is a 'Model' of a framer (haha).
28 // It exists as a proof of concept headers framer.
31 typedef std::vector
<std::pair
<size_t, size_t> > Lines
;
33 typedef BalsaHeaders::HeaderLineDescription HeaderLineDescription
;
34 typedef BalsaHeaders::HeaderLines HeaderLines
;
35 typedef BalsaHeaders::HeaderTokenList HeaderTokenList
;
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()
40 static const uint32 kValidTerm1
= '\n' << 16 |
43 static const uint32 kValidTerm1Mask
= 0xFF << 16 |
46 static const uint32 kValidTerm2
= '\n' << 8 |
48 static const uint32 kValidTerm2Mask
= 0xFF << 8 |
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_).
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
) {
68 // Clear the headers if they are non-null, even if the new headers are
69 // the same as the old.
74 void set_balsa_visitor(BalsaVisitorInterface
* visitor
) {
76 if (visitor_
== NULL
) {
77 visitor_
= &do_nothing_visitor_
;
81 void set_is_request(bool is_request
) { is_request_
= is_request
; }
83 bool is_request() const {
87 void set_request_was_head(bool request_was_head
) {
88 request_was_head_
= request_was_head
;
91 bool request_was_head() const {
92 return request_was_head_
;
95 void set_max_header_length(size_t max_header_length
) {
96 max_header_length_
= max_header_length
;
99 size_t max_header_length() const {
100 return max_header_length_
;
103 void set_max_request_uri_length(size_t max_request_uri_length
) {
104 max_request_uri_length_
= max_request_uri_length
;
107 size_t max_request_uri_length() const {
108 return max_request_uri_length_
;
112 bool MessageFullyRead() {
113 return parse_state_
== BalsaFrameEnums::MESSAGE_FULLY_READ
;
116 BalsaFrameEnums::ParseState
ParseState() const { return parse_state_
; }
120 return parse_state_
== BalsaFrameEnums::PARSE_ERROR
;
123 BalsaFrameEnums::ErrorCode
ErrorCode() const { return last_error_
; }
125 const BalsaHeaders
* headers() const { return headers_
; }
126 BalsaHeaders
* mutable_headers() { return headers_
; }
128 size_t BytesSafeToSplice() const;
129 void BytesSpliced(size_t bytes_spliced
);
131 size_t ProcessInput(const char* input
, size_t size
);
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
);
139 // The utils object needs access to the ParseTokenList in order to do its
141 friend class BalsaHeadersTokenUtils
;
143 inline void ProcessContentLengthLine(
145 BalsaHeadersEnums::ContentLengthStatus
* status
,
148 inline void ProcessTransferEncodingLine(size_t line_idx
);
150 void ProcessFirstLine(const char* begin
,
153 void CleanUpKeyValueWhitespace(
154 const char* stream_begin
,
155 const char* line_begin
,
157 const char* line_end
,
158 HeaderLineDescription
* current_header_line
);
160 void FindColonsAndParseIntoKeyValue();
162 void ProcessHeaderLines();
164 inline size_t ProcessHeaders(const char* message_start
,
165 size_t message_length
);
167 void AssignParseStateAfterHeadersHaveBeenParsed();
169 inline bool LineFramingFound(char current_char
) {
170 return current_char
== '\n';
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
180 if (current_char
== '\n' || current_char
== '\r') {
182 // This is necessary IFF architecture has > 8 bit char. Alas, I'm
184 term_chars_
|= current_char
& 0xFF;
186 if ((term_chars_
& kValidTerm1Mask
) == kValidTerm1
) {
190 if ((term_chars_
& kValidTerm2Mask
) == kValidTerm2
) {
200 inline bool HeaderFramingMayBeFound() const {
201 return term_chars_
!= 0;
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
,
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
,
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
{}
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_
;
253 BalsaFrameEnums::ParseState parse_state_
;
254 BalsaFrameEnums::ErrorCode last_error_
;
258 BalsaHeaders
* headers_
; // This is not reset to NULL in Reset().
259 DoNothingBalsaVisitor do_nothing_visitor_
;
264 #endif // NET_TOOLS_FLIP_SERVER_BALSA_FRAME_H_