- add sources.
[platform/framework/web/crosswalk.git] / src / net / tools / balsa / balsa_frame.h
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 #ifndef NET_TOOLS_BALSA_BALSA_FRAME_H_
6 #define NET_TOOLS_BALSA_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/balsa/balsa_enums.h"
16 #include "net/tools/balsa/balsa_headers.h"
17 #include "net/tools/balsa/balsa_visitor_interface.h"
18 #include "net/tools/balsa/buffer_interface.h"
19 #include "net/tools/balsa/http_message_constants.h"
20 #include "net/tools/balsa/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_BALSA_BALSA_FRAME_H_
265