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