root/trunk/whisperlib/net/http/http_request.cc

Revision 7, 43.3 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Catalin Popescu
31
32 #include "net/http/http_request.h"
33 #include "common/base/errno.h"
34
35 DEFINE_bool(http_log_detail_errors,
36             true,
37             "Log internal http errors");
38 namespace http {
39
40 ////////////////////////////////////////////////////////////////////////////////
41
42 Request::Request(bool strict_headers,
43                  common::ByteOrder client_byte_order, int32 client_block_size,
44                  common::ByteOrder server_byte_order, int32 server_block_size)
45   : client_data_(client_byte_order, client_block_size),
46     client_header_(strict_headers),
47     server_data_(server_byte_order, server_block_size),
48     server_header_(strict_headers),
49     url_(NULL),
50     in_chunk_encoding_(false),
51     deflate_zwrapper_(NULL),
52     gzip_state_begin_(true),
53     gzip_zwrapper_(NULL),
54     server_use_gzip_encoding_(true),
55     compress_option_(COMPRESS_NONE) {
56 }
57
58 Request::~Request() {
59   delete gzip_zwrapper_;
60   delete deflate_zwrapper_;
61   delete url_;
62 }
63
64 URL* Request::InitializeUrlFromClientRequest(const URL* absolute_root) {
65   if ( url_ != NULL ) {
66     delete url_;
67     url_ = NULL;
68   }
69   if ( client_header_.parse_error() < http::Header::READ_NO_REQUEST_URI ) {
70     url_ = new URL(absolute_root->Resolve(client_header_.uri()));
71   }
72   return url_;
73 }
74
75 void Request::AppendClientRequest(io::MemoryStream* out, int64 max_chunk_size) {
76   CHECK(!in_chunk_encoding_);
77   CHECK_EQ(client_header_.first_line_type(), http::Header::REQUEST_LINE)
78     << " Make sure you prepared your request properly !";
79   DCHECK_NE(client_header_.method(), METHOD_UNKNOWN);
80   DCHECK_NE(client_header_.http_version(), VERSION_UNKNOWN);
81
82   const bool zippable_content = client_header_.IsZippableContentType();
83   if ( client_header_.IsGzipContentEncoding() && zippable_content ) {
84     CHECK_GE(client_header_.http_version(), VERSION_1_0);
85     delete gzip_zwrapper_;
86     gzip_state_begin_ = true;
87     gzip_zwrapper_ = new io::ZlibGzipEncodeWrapper();
88     client_header_.SetContentEncoding("gzip");
89     compress_option_ = COMPRESS_GZIP;
90   } else if ( client_header_.IsDeflateAcceptableEncoding() &&
91               zippable_content ) {
92     CHECK_GE(client_header_.http_version(), VERSION_1_0);
93     delete deflate_zwrapper_;
94     deflate_zwrapper_ = new io::ZlibDeflateWrapper();
95     client_header_.SetContentEncoding("deflate");
96     compress_option_ = COMPRESS_DEFLATE;
97   } else {
98     client_header_.SetContentEncoding(NULL);
99     compress_option_ = COMPRESS_NONE;
100   }
101
102   if ( server_use_gzip_encoding_ ) {
103     // We can accept gzip, and deflate but not much else..
104     client_header_.AddField(kHeaderAcceptEncoding, "gzip, deflate", true);
105   } else {
106     client_header_.ClearField(kHeaderAcceptEncoding);
107   }
108
109   if ( client_header_.IsChunkedTransfer() ) {
110     in_chunk_encoding_ = true;
111     CHECK_GE(client_header_.http_version(), VERSION_1_1);
112     client_header_.AppendToStream(out);
113     while ( !client_data_.IsEmpty() ) {
114       AppendClientChunk(out, max_chunk_size);
115     }
116   } else {
117     // We do not know anything else - clear the transfer encoding
118     client_header_.SetChunkedTransfer(false);
119     // Append the body (compressed if necessary) to a temp
120     io::MemoryStream ms;
121     io::MemoryStream* source = &ms;
122     switch ( compress_option_ ) {
123     case COMPRESS_GZIP:
124       gzip_zwrapper_->Encode(&client_data_, out);
125       break;
126     case COMPRESS_DEFLATE:
127       deflate_zwrapper_->Deflate(&client_data_, out);
128       break;
129     case COMPRESS_NONE:
130       source = &client_data_;
131       break;   // no temp compression
132     }
133     // Set the content length from the data size
134     if ( !client_data_.IsEmpty() ||
135          client_header_.method() == METHOD_POST ||
136          client_header_.method() == METHOD_PUT ) {
137       client_header_.AddField(
138           kHeaderContentLength,
139           strutil::IntToString(client_data_.Size()),
140           true);  // replace !
141     }
142     // Append the header data and the body
143     client_header_.AppendToStream(out);
144     out->MarkerSet();
145     out->MarkerRestore();
146     out->AppendStream(source);
147   }
148 }
149
150 void Request::AppendServerReply(io::MemoryStream* out,
151                                 bool streaming,
152                                 bool do_chunks,
153                                 int64 max_chunk_size) {
154   CHECK(!in_chunk_encoding_);
155   CHECK_EQ(server_header_.first_line_type(), http::Header::STATUS_LINE)
156     << " Make sure you prepared your request properly !";
157   DCHECK_NE(server_header_.status_code(), UNKNOWN);
158   if ( server_header_.http_version() == VERSION_UNKNOWN ) {
159     server_header_.set_http_version(VERSION_1_1);
160   }
161
162   if ( server_header_.http_version() > client_header_.http_version() ) {
163     LOG_WARNING << " Downgrading server verion: "
164                 << GetHttpVersionName(client_header_.http_version());
165     server_header_.set_http_version(VERSION_1_0);
166   }
167   const bool zippable_content = server_header_.IsZippableContentType();
168   if ( server_use_gzip_encoding_ && zippable_content ) {
169     if ( client_header_.IsGzipAcceptableEncoding() ) {
170       delete gzip_zwrapper_;
171       gzip_zwrapper_ = new io::ZlibGzipEncodeWrapper();
172       server_header_.SetContentEncoding("gzip");
173       compress_option_ = COMPRESS_GZIP;
174     } else if ( client_header_.IsDeflateAcceptableEncoding() ) {
175       delete deflate_zwrapper_;
176       deflate_zwrapper_ = new io::ZlibDeflateWrapper();
177       server_header_.SetContentEncoding("deflate");
178       compress_option_ = COMPRESS_DEFLATE;
179     } else {
180       server_header_.SetContentEncoding(NULL);
181     }
182   } else {
183     server_header_.SetContentEncoding(NULL);
184     compress_option_ = COMPRESS_NONE;
185   }
186
187   if ( streaming ) {
188     if (do_chunks && client_header_.http_version() >= VERSION_1_1) {
189       server_header_.SetChunkedTransfer(true);
190       CHECK_GT(client_header_.http_version(), VERSION_1_0);
191     } else {
192       server_header_.SetChunkedTransfer(false);
193     }
194     server_header_.AppendToStream(out);
195     if ( !NoServerBodyTransmitted() ) {
196       in_chunk_encoding_ = true;
197       while ( !server_data_.IsEmpty() ) {
198         // Let them close the chunks by themselves
199         AppendServerChunk(out, do_chunks, max_chunk_size);
200       }
201     }
202   } else {
203     server_header_.SetChunkedTransfer(false);
204     const HttpReturnCode code = server_header_.status_code();
205     io::MemoryStream ms;
206     io::MemoryStream* source = &ms;
207     // Append the body (compressed if necessary) to a temp
208     switch ( compress_option_ ) {
209     case COMPRESS_GZIP:
210       gzip_zwrapper_->Encode(&server_data_, &ms);
211       break;
212     case COMPRESS_DEFLATE:
213       deflate_zwrapper_->Deflate(&server_data_, &ms);
214       break;
215     case COMPRESS_NONE:
216       source = &server_data_;
217       break;
218     }
219     // Set the content length from the compressed stuff.
220     if ( !( (code >= 100 && code < 200) ||
221             code == NO_CONTENT || code == NOT_MODIFIED) ) {
222       server_header_.AddField(kHeaderContentLength,
223                               strutil::IntToString(source->Size()),
224                               true);  // replace !
225     }
226     // Append the header data and the body
227     server_header_.AppendToStream(out);
228     out->AppendStream(source);
229   }
230 }
231
232 namespace {
233 static void BufferAppendChunk(io::MemoryStream* in,
234                               io::MemoryStream* out,
235                               bool add_decorations,
236                               int32 max_size) {
237   int32 size = min(max_size, in->Size());
238   if ( add_decorations ) {
239     string first_line = strutil::StringPrintf("0%x\r\n",
240                                               static_cast<int>(size));
241     out->Write(first_line);
242   }
243   out->AppendStream(in, size);
244   if ( add_decorations ) {
245     out->Write("\r\n");
246   }
247 }
248 }
249
250 bool Request::AppendClientChunk(io::MemoryStream* out,
251                                 int64 max_chunk_size) {
252   return AppendChunkHelper(
253     &client_header_, &client_data_, out,
254     client_header_.http_version() >= VERSION_1_1, max_chunk_size);
255 }
256 bool Request::AppendServerChunk(io::MemoryStream* out,
257                                 bool do_chunks,
258                                 int64 max_chunk_size) {
259   CHECK(!NoServerBodyTransmitted())
260     << " Code:" << server_header_.status_code()
261     << " Method:" << client_header_.method();
262   return AppendChunkHelper(&server_header_, &server_data_, out,
263       do_chunks && (client_header_.http_version() >= VERSION_1_1),
264                            max_chunk_size);
265 }
266
267 bool Request::AppendChunkHelper(const http::Header* src_header,
268                                 io::MemoryStream* src_data,
269                                 io::MemoryStream* out,
270                                 bool add_decorations,
271                                 int64 max_chunk_size) {
272   const bool is_empty = src_data->IsEmpty();
273   if ( compress_option_ != COMPRESS_NONE ) {
274     io::MemoryStream tmp;
275     if ( compress_option_ == COMPRESS_GZIP ) {
276       if ( gzip_state_begin_ ) {
277         gzip_zwrapper_->BeginEncoding(&tmp);
278         gzip_state_begin_ = false;
279       }
280       gzip_zwrapper_->ContinueEncoding(src_data, &tmp);
281       if ( is_empty ) {
282         gzip_zwrapper_->EndEncoding(&tmp);
283       }
284     } else {
285       int32 size = src_data->Size();
286       if ( !is_empty ) size++;   // basically do not flush the state ..
287       deflate_zwrapper_->DeflateSize(src_data, &tmp, &size);
288       CHECK(size == 1 || (size == 0 && is_empty))
289         << "Strange zlib behaviour. Left size: " << size;
290     }
291     if ( tmp.IsEmpty() ) {
292       if ( is_empty ) {
293         // Turns out that the flush resulted in an empty body..
294         in_chunk_encoding_ = false;
295         if ( add_decorations ) {
296           out->Write("0\r\n\r\n");
297         }
298         return true;
299       } else {
300         // The zlib did not produce anything this call - just skip it for
301         // the next time ...
302         return false;
303       }
304     } else {
305       max_chunk_size = (max_chunk_size <= 0) ? kMaxInt32 : max_chunk_size;
306       while (!tmp.IsEmpty()) {
307         BufferAppendChunk(&tmp, out, add_decorations, max_chunk_size);
308       }
309       if ( is_empty ) {
310         // If it was a flush, put the end of stream out..
311         in_chunk_encoding_ = false;
312         if ( add_decorations ) {
313           out->Write("0\r\n\r\n");
314         }
315         return true;
316       }
317     }
318   } else {
319     // The last chunk (empty) => append empty trailed
320     if ( is_empty ) {
321       in_chunk_encoding_ = false;
322       if ( add_decorations ) {
323         out->Write("0\r\n\r\n");
324       }
325       return true;
326     } else {
327       max_chunk_size = (max_chunk_size <= 0) ? kMaxInt32 : max_chunk_size;
328       while (!src_data->IsEmpty()) {
329         BufferAppendChunk(src_data, out, add_decorations, max_chunk_size);
330       }
331       return false;
332     }
333   }
334   return false;
335 }
336
337 ////////////////////////////////////////////////////////////////////////////////
338
339 #define LOG_HTTP LOG_INFO_IF(dlog_level_) << name() << ": "
340 #define LOG_HTTP_ERR LOG_ERROR_IF(FLAGS_http_log_detail_errors)  \
341   << name() << ": "
342
343 RequestParser::RequestParser(
344   const char* name,
345   int32 max_header_size,
346   int64 max_body_size,
347   int64 max_chunk_size,
348   int64 max_num_chunks,
349   bool accept_wrong_method,
350   bool accept_wrong_version,
351   bool accept_no_content_length,
352   http::Header::ParseError worst_accepted_header_error)
353   : max_header_size_(max_header_size),
354     max_body_size_(max_body_size),
355     max_chunk_size_(max_chunk_size),
356     max_num_chunks_(max_num_chunks),
357     accept_wrong_method_(accept_wrong_method),
358     accept_wrong_version_(accept_wrong_version),
359     accept_no_content_length_(accept_no_content_length),
360     worst_accepted_header_error_(worst_accepted_header_error),
361     name_(name),
362     dlog_level_(false),
363     inflate_zwrapper_(NULL),
364     gzip_zwrapper_(NULL) {
365   Clear();
366 }
367
368 RequestParser::~RequestParser() {
369   Clear();
370 }
371
372 const char* RequestParser::ParseStateName(ParseState state) {
373   switch ( state ) {
374     CONSIDER(STATE_INITIALIZED);
375     CONSIDER(STATE_HEADER_READING);
376     CONSIDER(STATE_END_OF_HEADER);
377     CONSIDER(STATE_END_OF_HEADER_FINAL);
378     CONSIDER(STATE_BODY_READING);
379     CONSIDER(STATE_BODY_END);
380     CONSIDER(STATE_CHUNK_HEAD_READING);
381     CONSIDER(STATE_CHUNK_READING);
382     CONSIDER(STATE_END_OF_CHUNK);
383     CONSIDER(STATE_LAST_CHUNK_READ);
384     CONSIDER(STATE_END_OF_TRAIL_HEADER);
385     CONSIDER(ERROR_HEADER_BAD);
386     CONSIDER(ERROR_HEADER_BAD_CONTENT_LEN);
387     CONSIDER(ERROR_HEADER_TOO_LONG);
388     CONSIDER(ERROR_HEADER_LINE);
389     CONSIDER(ERROR_CONTENT_TOO_LONG);
390     CONSIDER(ERROR_TRANSFER_ENCODING_UNKNOWN);
391     CONSIDER(ERROR_CONTENT_ENCODING_UNKNOWN);
392     CONSIDER(ERROR_CONTENT_GZIP_TOO_LONG);
393     CONSIDER(ERROR_CONTENT_GZIP_ERROR);
394     CONSIDER(ERROR_CONTENT_GZIP_UNFINISHED);
395     CONSIDER(ERROR_CHUNK_HEADER_TOO_LONG);
396     CONSIDER(ERROR_CHUNK_TOO_LONG);
397     CONSIDER(ERROR_CHUNK_TOO_MANY);
398     CONSIDER(ERROR_CHUNK_TRAIL_HEADER);
399     CONSIDER(ERROR_CHUNK_BAD_CHUNK_LENGTH);
400     CONSIDER(ERROR_CHUNK_BAD_CHUNK_TERMINATION);
401     CONSIDER(ERROR_CHUNK_BIGGER_THEN_DECLARED);
402     CONSIDER(ERROR_CHUNK_UNFINISHED_GZIP_CONTENT);
403     CONSIDER(ERROR_CHUNK_CONTINUED_FINISHED_GZIP_CONTENT);
404     CONSIDER(ERROR_CHUNK_CONTENT_GZIP_TOO_LONG);
405     CONSIDER(ERROR_CHUNK_CONTENT_GZIP_ERROR);
406     CONSIDER(ERROR_CHUNK_TRAILER_TOO_LONG);
407     // Not real states:
408     // CONSIDER(FIRST_FINAL_STATE);
409     // CONSIDER(FIRST_ERROR_STATE);
410   default:
411     return "INVALD_STATE";
412   }
413   return "INVALID_STATE";  // keep g++ happy
414 }
415
416 string RequestParser::ReadStateName(int32 read_state) {
417   vector<string> states;
418   if ( read_state & HEADER_READ ) {
419     states.push_back("HEADER_READ");
420   }
421   if ( read_state & BODY_READING ) {
422     states.push_back("BODY_READING");
423   }
424   if ( read_state & CHUNKED_BODY_READING ) {
425     states.push_back("CHUNKED_BODY_READING");
426   }
427   if ( read_state & CHUNKED_TRAILER_READING ) {
428     states.push_back("CHUNKED_TRAILER_READING");
429   }
430   if ( read_state & BODY_FINISHED ) {
431     states.push_back("BODY_FINISHED");
432   }
433   if ( read_state & CHUNKS_FINISHED ) {
434     states.push_back("CHUNKS_FINISHED");
435   }
436   if ( read_state & REQUEST_FINISHED ) {
437     states.push_back("REQUEST_FINISHED");
438   }
439   if ( states.empty() ) return "NONE";
440   return strutil::JoinStrings(states, " | ");
441 }
442
443 // Call this before starting to parse a new request - and you better do it !
444 void RequestParser::Clear() {
445   LOG_HTTP << " Clear parse state.";
446   parse_state_ = STATE_INITIALIZED;
447   body_size_to_read_ = 0LL;
448   chunk_size_to_read_ = 0LL;
449   num_chunks_read_ = 0;
450   next_chunk_expectation_ = EXPECT_CHUNK_NONE;
451   partial_data_.Clear();
452   trail_header_.Clear();
453   delete inflate_zwrapper_;
454   inflate_zwrapper_ = NULL;
455   delete gzip_zwrapper_;
456   gzip_zwrapper_ = NULL;
457 }
458
459 //////////////////////////////////////////////////////////////////////
460 //
461 // ParseClientRequest
462 //
463 int32 RequestParser::ParseClientRequest(io::MemoryStream* in, Request* req) {
464   CHECK(!InFinalState());
465   if ( parse_state_ == STATE_INITIALIZED ) {
466     // CONTINUE - Initial state
467     req->client_data()->Clear();
468     req->client_header()->Clear();
469     set_parse_state(STATE_HEADER_READING);
470   }
471
472   //////////////////////////////////////////////////////////////////////
473   //
474   // Header reading for client
475   //
476   if ( parse_state_ == STATE_HEADER_READING ) {
477     if ( !req->client_header()->ParseHttpRequest(in) ) {
478       if ( in->Size() + req->client_header()->bytes_parsed() >
479            max_header_size_ ) {
480         // ERROR - header too big
481         LOG_HTTP_ERR << " Header too long. Got at least: "
482                      << in->Size() + req->client_header()->bytes_parsed()
483                      << " max: " << max_header_size_;
484         set_parse_state(ERROR_HEADER_TOO_LONG);
485         return REQUEST_FINISHED;
486       }
487       // Clear any error w/ the first line
488       req->server_header()->set_first_line_type(Header::REQUEST_LINE);
489       // CONTINUE - with header parsing next call
490       return 0;
491     } else if ( req->client_header()->bytes_parsed() > max_header_size_ ) {
492       // ERROR - header too big
493       LOG_HTTP_ERR << " Header too long. Parsed: "
494                    << in->Size() + req->client_header()->bytes_parsed()
495                    << " max: " << max_header_size_;
496       set_parse_state(ERROR_HEADER_TOO_LONG);
497       return REQUEST_FINISHED;
498     }
499     // Header parsed at this point (w/ errors or not..)
500     if ( (req->client_header()->http_version() == VERSION_UNKNOWN &&
501           !accept_wrong_version_) ||
502          (req->client_header()->method() == METHOD_UNKNOWN &&
503           !accept_wrong_method_) ) {
504       // ERROR - Invalid data in the first line (and unaccepted)
505       LOG_HTTP_ERR << " Invalid Header line. Method: "
506                    << req->client_header()->method()
507                    << " Version: " << req->client_header()->http_version();
508       set_parse_state(ERROR_HEADER_LINE);
509       return HEADER_READ | REQUEST_FINISHED;
510     }
511     if ( req->client_header()->parse_error() > worst_accepted_header_error_ ) {
512       // ERROR - unacceptale error in header parsing
513       LOG_HTTP_ERR << " Bad Header Found: "
514                    << req->client_header()->ParseErrorName();
515       set_parse_state(ERROR_HEADER_BAD);
516       return HEADER_READ | REQUEST_FINISHED;
517     }
518     // CONTINUE - header parsed good enough
519     set_parse_state(STATE_END_OF_HEADER);
520     // Give guys a chance to check things after the header was parsed..
521     return HEADER_READ | CONTINUE;
522   }
523   // CONTINUE - w/ the parsing of the message payload
524   return ParsePayloadInternal(in, req->client_header(), req->client_data());
525 }
526
527
528 //////////////////////////////////////////////////////////////////////
529 //
530 // ParseServerReply
531 //
532 int32 RequestParser::ParseServerReply(io::MemoryStream* in, Request* req) {
533   CHECK(!InFinalState());
534   if ( parse_state_ == STATE_INITIALIZED ) {
535     // CONTINUE - Initial state
536     req->server_data()->Clear();
537     req->server_header()->Clear();
538     set_parse_state(STATE_HEADER_READING);
539   }
540   //////////////////////////////////////////////////////////////////////
541   //
542   // Header reading for server
543   //
544   if ( parse_state_ == STATE_HEADER_READING ) {
545     if ( !req->server_header()->ParseHttpReply(in) ) {
546       if ( in->Size() + req->server_header()->bytes_parsed() >
547            max_header_size_ ) {
548         // ERROR - header too big
549         LOG_HTTP_ERR << " Header too long. Got at least: "
550                      << in->Size() + req->server_header()->bytes_parsed()
551                      << " on max: " << max_header_size_;
552         set_parse_state(ERROR_HEADER_TOO_LONG);
553         return REQUEST_FINISHED;
554       }
555       // Clear any error w/ the first line
556       req->server_header()->set_first_line_type(Header::STATUS_LINE);
557       // CONTINUE - with header parsing next call
558       return 0;
559     } else if ( req->server_header()->bytes_parsed() > max_header_size_ ) {
560       // ERROR - header too big
561       LOG_HTTP_ERR << " Header too long. Parsed: "
562                    << req->server_header()->bytes_parsed()
563                    << " on max: " << max_header_size_;
564       set_parse_state(ERROR_HEADER_TOO_LONG);
565       return REQUEST_FINISHED;
566     }
567     if ( req->server_header()->parse_error() > worst_accepted_header_error_ ) {
568       // ERROR - unacceptable error in the header
569       LOG_HTTP_ERR << " Error in headers found: "
570                    << req->client_header()->ParseErrorName();
571       set_parse_state(ERROR_HEADER_BAD);
572       return HEADER_READ | REQUEST_FINISHED;
573     }
574     if ( req->NoServerBodyTransmitted() ) {
575       // FINAL - We don't have a body in these cases !
576       set_parse_state(STATE_END_OF_HEADER_FINAL);
577       return HEADER_READ | REQUEST_FINISHED;
578     }
579     // TODO(cpopescu):  "multipart/byteranges"
580
581     // CONTINUE - header parsed is good enough
582     set_parse_state(STATE_END_OF_HEADER);
583
584     // Give guys a chance to check things after the header was parsed..
585     return HEADER_READ | CONTINUE;
586   }
587   // CONTINUE - w/ the parsing of the message payload
588   return ParsePayloadInternal(in, req->server_header(), req->server_data());
589 }
590
591 //////////////////////////////////////////////////////////////////////
592 //
593 // ParsePayloadInternal - parses the message payload (body)
594 //
595 int32 RequestParser::ParsePayloadInternal(io::MemoryStream* in,
596                                           http::Header* header,
597                                           io::MemoryStream* out) {
598   CHECK_GE(parse_state_, STATE_END_OF_HEADER);
599
600   //////////////////////////////////////////////////////////////////////
601   //
602   // Detrmine the trasmission mode for the body
603   //
604   if ( parse_state_ == STATE_END_OF_HEADER ) {
605     if ( !IsKnownContentEncoding(header) ) {
606       // ERROR - we don't know this content encoding (identity & gzip accepted)
607       LOG_HTTP_ERR << " Unknown content encoding in header: "
608                    << header->ToString();
609       set_parse_state(ERROR_CONTENT_ENCODING_UNKNOWN);
610       return HEADER_READ | REQUEST_FINISHED;
611     }
612     if ( !IsKnownTransferEncoding(header) ) {
613       // ERROR - we don't know this transfer encoding
614       // (identity & chunk accepted)
615       LOG_HTTP_ERR << " Unknown transfer encoding in header: "
616                    << header->ToString();
617       set_parse_state(ERROR_TRANSFER_ENCODING_UNKNOWN);
618       return HEADER_READ | REQUEST_FINISHED;
619     }
620     if ( !header->IsChunkedTransfer() ) {
621       // Identity transder encoding => expect Content Lenght (in this state)
622       string content_length_str;
623       if ( !header->FindField(kHeaderContentLength, &content_length_str) ) {
624         body_size_to_read_ = header->DefaultBodyLen();
625         if ( !accept_no_content_length_ && body_size_to_read_ > 0 ) {
626           // ERROR - There is no content length header
627           set_parse_state(STATE_END_OF_HEADER_FINAL);
628           return HEADER_READ | REQUEST_FINISHED;
629         }
630         if (max_body_size_ >= 0) {
631           if ( body_size_to_read_ > max_body_size_ ) {
632             body_size_to_read_ = max_body_size_;
633           }
634         }
635         // CONTINUE -> read as much as we consider it makes sense..
636         set_parse_state(STATE_BODY_READING);
637       } else {
638         errno = 0;  // essential as strtol would not set a 0 errno
639         const int32 content_length = strtol(content_length_str.c_str(),
640                                             NULL, 10);
641         if ( errno || content_length < 0 ) {
642           LOG_HTTP << " Content-Length found: [" << content_length_str << "].";
643           // ERROR - Badly specified content length
644           LOG_HTTP_ERR << " Bad Content Length in header: ["
645                        << content_length_str << "]";
646           set_parse_state(ERROR_HEADER_BAD_CONTENT_LEN);
647           return HEADER_READ | REQUEST_FINISHED;
648         }
649         // CONTINUE -> expect identity encoded transfer w/ a content length
650         body_size_to_read_ = static_cast<int64>(content_length);
651         set_parse_state(STATE_BODY_READING);
652       }
653     } else {
654       // CONTINUE -> expect chunked encoding transfer
655       set_parse_state(STATE_CHUNK_HEAD_READING);
656     }
657   }
658
659   if ( parse_state_ == STATE_BODY_READING ) {
660     // CONTINUE - Body reading - regular - Content-Length specified
661     const int32 result = ParseBodyInternal(in, header, out);
662     return result;
663   }
664   // We better be in a chunks reading state :)
665   CHECK_GE(parse_state_, STATE_CHUNK_HEAD_READING)
666     << " In error state - this is a bug: " << ParseStateName();
667   return ParseChunksInternal(in, header, out);
668 }
669
670 //////////////////////////////////////////////////////////////////////
671 //
672 // ParseBodyInternal - parses the body for non chunked transfers
673 //
674 int32 RequestParser::ParseBodyInternal(io::MemoryStream* in,
675                                        http::Header* header,
676                                        io::MemoryStream* out) {
677   CHECK_EQ(parse_state_, STATE_BODY_READING);
678   if (max_body_size_ >= 0) {
679     if ( body_size_to_read_ > max_body_size_ ) {
680       // ERROR - body too big ..
681       LOG_HTTP_ERR << " Content too long. Got " << body_size_to_read_
682                    << "  on a max of: " << max_body_size_;
683       set_parse_state(ERROR_CONTENT_TOO_LONG);
684       return HEADER_READ | REQUEST_FINISHED;
685     }
686   }
687   // copy the payload from in to our internal buffer.
688   const int64 to_read = min(body_size_to_read_,
689                             static_cast<int64>(in->Size()));
690   partial_data_.AppendStreamNonDestructive(in, to_read);
691   in->Skip(to_read);
692   body_size_to_read_ -= to_read;
693   bool is_gzipped = header->IsGzipContentEncoding();
694   bool is_deflated = header->IsDeflateContentEncoding();
695   if ( inflate_zwrapper_ != NULL && is_gzipped ) {
696     // One converted gzip to deflate (declared deflate but is gzip..
697     is_deflated = true;
698     is_gzipped = false;
699   }
700
701   LOG_HTTP << " Reading body data:" << to_read
702            << " left:" << body_size_to_read_
703            << " partial_data_.Size()=" << partial_data_.Size()
704            << " is_gzipped: " << is_gzipped;
705
706   if ( is_gzipped ) {
707     ///////////////////////////////////////////////////////////////////
708     //
709     // GZIP - content encoding
710     //
711     CHECK(!is_deflated);
712
713     bool maybe_try_deflate = gzip_zwrapper_ == NULL;
714     if ( gzip_zwrapper_ == NULL ) {
715       gzip_zwrapper_ = new io::ZlibGzipDecodeWrapper();
716     }
717     int32 consumed_size = 0;
718     do {
719       partial_data_.MarkerSet();
720       io::MemoryStream tmp;
721       const int32 initial_size = partial_data_.Size();
722       const int zerr = gzip_zwrapper_->Decode(&partial_data_, &tmp);
723       consumed_size = initial_size - partial_data_.Size();
724       // TODO(cosming) TODO: this is a test, remove
725       DLOG_DEBUG << "GZip Decoder zerr="
726                  << zerr << " consumed_size=" << consumed_size
727                  << " remaining=" << partial_data_.Size();
728       if ( zerr == Z_STREAM_END ) {
729         partial_data_.MarkerClear();
730         out->AppendStream(&tmp);
731         if ( body_size_to_read_ == 0 && partial_data_.IsEmpty() ) {
732           // FINAL - state w/ body decompressed ok
733           set_parse_state(STATE_BODY_END);
734           return HEADER_READ | BODY_FINISHED | REQUEST_FINISHED;
735         }
736         // CONTINUE
737       } else if ( zerr != Z_OK ) {
738         if ( !maybe_try_deflate ) {
739           LOG_HTTP << " ZLib error found in gzip encoding: " << zerr;
740           partial_data_.MarkerClear();
741           // ERROR - error data in compressed body
742           LOG_HTTP_ERR << " Error in gzipped content: " << zerr;
743           return HEADER_READ | BODY_READING | REQUEST_FINISHED;
744         }
745         LOG_HTTP << " ZLib error found in gzip encoding - trying deflate.";
746         partial_data_.MarkerRestore();
747         is_deflated = true;
748         // CONTINUE  w/ deflate
749       } else {
750         partial_data_.MarkerClear();
751         out->AppendStream(&tmp);
752         if ( body_size_to_read_ == 0 ) {
753           // ERROR - no more data left in body, but zip did not finish
754           LOG_HTTP_ERR << " Error in gzipped content: Unfinished gzip";
755           set_parse_state(ERROR_CONTENT_GZIP_UNFINISHED);
756           return HEADER_READ | BODY_FINISHED | REQUEST_FINISHED;
757         }
758       }
759     } while ( !is_deflated && consumed_size > 0 && !partial_data_.IsEmpty() );
760   }
761   if ( is_deflated ) {
762     ///////////////////////////////////////////////////////////////////
763     //
764     // DEFLATE - content encoding
765     //
766     if ( inflate_zwrapper_ == NULL ) {
767       inflate_zwrapper_ = new io::ZlibInflateWrapper();
768     }
769     const int zerr = inflate_zwrapper_->InflateSize(&partial_data_, out);
770     if ( zerr == Z_STREAM_END ) {
771       if ( body_size_to_read_ > 0 ) {
772         LOG_HTTP_ERR << " ZLib EOS when left in body: " << body_size_to_read_;
773         // ERROR - End of gzipped data, but body continues
774         set_parse_state(ERROR_CONTENT_GZIP_TOO_LONG);
775         return HEADER_READ | BODY_READING | REQUEST_FINISHED;
776       }
777       // FINAL - state w/ body decompressed ok
778       set_parse_state(STATE_BODY_END);
779       return HEADER_READ | BODY_FINISHED | REQUEST_FINISHED;
780     }
781     if ( zerr != Z_OK ) {
782       LOG_HTTP_ERR << " ZLib error found: " << zerr;
783       // ERROR - error data in compressed body
784       set_parse_state(ERROR_CONTENT_GZIP_ERROR);
785       return HEADER_READ | BODY_READING | REQUEST_FINISHED;
786     }
787   } else if ( !is_gzipped ) {
788     ///////////////////////////////////////////////////////////////////
789     //
790     // IDENTITY - content encoding
791     //
792     out->AppendStream(&partial_data_);
793     if ( body_size_to_read_ == 0 ) {
794       // FINAL - state w/ body set OK
795       set_parse_state(STATE_BODY_END);
796       return HEADER_READ | BODY_FINISHED | REQUEST_FINISHED;
797     }
798   }
799   // CONTINUE - with the compressed body
800   DCHECK_EQ(parse_state_, STATE_BODY_READING);
801   return HEADER_READ | BODY_READING;
802 }
803
804
805 //////////////////////////////////////////////////////////////////////
806 //
807 // ParseChunksInternal - parses the body for chunked transfers
808 //
809
810 // A small cut-and-paste from the protocol RFC:
811 //
812 //  Chunked-Body   = *chunk
813 //                   last-chunk
814 //                   trailer
815 //                   CRLF
816 //
817 //  chunk          = chunk-size [ chunk-extension ] CRLF
818 //                   chunk-data CRLF
819 //  chunk-size     = 1*HEX
820 //  last-chunk     = 1*("0") [ chunk-extension ] CRLF
821 //
822 //  chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
823 //  chunk-ext-name = token
824 //  chunk-ext-val  = token | quoted-string
825 //  chunk-data     = chunk-size(OCTET)
826 //  trailer        = *(entity-header CRLF)
827 //
828 int32 RequestParser::ParseChunksInternal(io::MemoryStream* in,
829                                          http::Header* header,
830                                          io::MemoryStream* out) {
831   do {
832     //////////////////////////////////////////////////////////////////////
833     //
834     // STATE_CHUNK_HEAD_READING ----------> Read the chunk header
835     //
836     if ( parse_state_ == STATE_CHUNK_HEAD_READING ) {
837       string line;
838       if ( !in->ReadCRLFLine(&line) ) {
839         if ( in->Size() > max_chunk_size_ ) {
840           // ERROR - got too much in the first chunk line
841           LOG_HTTP_ERR << " Chumk header too long. Have at least: "
842                        << in->Size() << "  on a max of: " << max_chunk_size_;
843           set_parse_state(ERROR_CHUNK_HEADER_TOO_LONG);
844           return HEADER_READ | CHUNKED_BODY_READING | REQUEST_FINISHED;
845         }
846         // CONTINUE - waiting for more data in the first chunk line
847         return HEADER_READ | CHUNKED_BODY_READING;
848       }
849       // Got one more chunk header !! - Cut the last CRLF
850       DCHECK_GE(line.size(), 2);  // at least CRLF
851       line.resize(line.size() - 2);
852       // We ignore the chunk extension (if any)
853       errno = 0;  // essential as strtol would not set a 0 errno
854       const int32 chunk_length = strtol(line.c_str(), NULL, 16);
855       if ( errno || chunk_length < 0 ) {
856         LOG_HTTP_ERR << " Invalid chunk len specification : " << line;
857         // ERROR - Badly specified chunk lenght
858         set_parse_state(ERROR_CHUNK_BAD_CHUNK_LENGTH);
859         return HEADER_READ | CHUNKED_BODY_READING | REQUEST_FINISHED;
860       }
861       if ( chunk_length == 0 ) {
862         if ( next_chunk_expectation_ == EXPECT_CHUNK_NON_EMPTY ) {
863           // ERROR - wanted a non empty chunk - got an empty one ..
864           LOG_HTTP_ERR << " Unfinished gzip content. When expecting chunk "
865                        << " got end of stream";
866           set_parse_state(ERROR_CHUNK_UNFINISHED_GZIP_CONTENT);
867           return HEADER_READ | CHUNKED_BODY_READING | REQUEST_FINISHED;
868         }
869         next_chunk_expectation_ = EXPECT_CHUNK_NONE;
870         // Last chunk signaled !!
871         set_parse_state(STATE_LAST_CHUNK_READ);
872         continue;
873       } else {
874         LOG_HTTP << " Got a chunk size of: " << chunk_length
875                  << " original hex: " << line;
876         if ( next_chunk_expectation_ == EXPECT_CHUNK_EMPTY ) {
877           // ERROR - wanted an end of body (empty chunk) - got some content
878           LOG_HTTP_ERR << " Long gzip content. When expecting no chunk "
879                        << " got extra data.";
880           set_parse_state(ERROR_CHUNK_CONTINUED_FINISHED_GZIP_CONTENT);
881           return HEADER_READ | CHUNKED_BODY_READING | REQUEST_FINISHED;
882         }
883         if ( chunk_length > max_chunk_size_ ) {
884           // ERROR - Chunk too long signaled
885           LOG_HTTP_ERR << " Chunk to long obtained: " << chunk_length
886                        << "  when max is: " << max_chunk_size_;
887           set_parse_state(ERROR_CHUNK_TOO_LONG);
888           return HEADER_READ | CHUNKED_BODY_READING | REQUEST_FINISHED;
889         }
890         next_chunk_expectation_ = EXPECT_CHUNK_NONE;
891         num_chunks_read_++;
892         if ( max_num_chunks_ >= 0 && num_chunks_read_ > max_num_chunks_ ) {
893           // ERROR - Too many chunks transmitted
894           LOG_HTTP_ERR << " Too many chunks in request. Got: "
895                        << num_chunks_read_
896                        << "  when max is: " << max_num_chunks_;
897           set_parse_state(ERROR_CHUNK_TOO_MANY);
898           return HEADER_READ | CHUNKED_BODY_READING | REQUEST_FINISHED;
899         }
900         // CONTINUE - reading the chunk data !
901         chunk_size_to_read_ = chunk_length;
902         set_parse_state(STATE_CHUNK_READING);
903       }
904     } else if ( parse_state_ == STATE_END_OF_CHUNK ) {
905       //////////////////////////////////////////////////////////////////////
906       //
907       //  STATE_END_OF_CHUNK -----------> Read the \r\n chunk termiantion
908       //
909       string line;
910       if ( !in->ReadCRLFLine(&line) ) {
911         if ( in->Size() > strlen("\r\n") ) {
912           LOG_HTTP_ERR << " Got at the end of chunks invalid leftover data: "
913                        << in->Size();
914           set_parse_state(ERROR_CHUNK_BAD_CHUNK_TERMINATION);
915           return HEADER_READ | CHUNKED_BODY_READING | REQUEST_FINISHED;
916         }
917         // CONTINUE - waiting for more data in the chunk termination
918         return HEADER_READ | CHUNKED_BODY_READING;
919       }
920       // Got one more chunk header !! - Cut the last CRLF
921       DCHECK_GE(line.size(), 2);  // at least CRLF
922       line.resize(line.size() - 2);
923       if ( !line.empty() ) {
924         LOG_HTTP_ERR
925             << " Got a non empty line at end of chunk: "
926             << strutil::PrintableDataBuffer(
927                 reinterpret_cast<const uint8*>(line.data()), line.size());
928         // ERROR: got some chars before chunk termination..
929         set_parse_state(ERROR_CHUNK_BIGGER_THEN_DECLARED);
930         return HEADER_READ | CHUNKED_BODY_READING | REQUEST_FINISHED;
931       }
932       // CONTINUE - read the next chunck header
933       set_parse_state(STATE_CHUNK_HEAD_READING);
934     } else if ( parse_state_ == STATE_CHUNK_READING ) {
935       //////////////////////////////////////////////////////////////////////
936       //
937       //  STATE_CHUNK_READING -----------> Pull Chunk content
938       //
939       if ( in->IsEmpty() ) {
940         return HEADER_READ | CHUNKED_BODY_READING;
941       }
942       const int64 to_read = min(chunk_size_to_read_,
943                                 static_cast<int64>(in->Size()));
944       partial_data_.AppendStreamNonDestructive(in, to_read);
945       in->Skip(to_read);
946
947       bool is_gzipped = header->IsGzipContentEncoding();
948       bool is_deflated = header->IsDeflateContentEncoding();
949       if ( is_gzipped && inflate_zwrapper_ != NULL ) {
950         // one gzip converted to deflate (normally bad server)
951         is_deflated = true;
952         is_gzipped = false;
953       }
954
955       chunk_size_to_read_ -= to_read;
956       LOG_HTTP << " Reading chunk data: " << to_read
957                << " left: " << chunk_size_to_read_
958                << " is_gzipped: " << is_gzipped
959                << " is_deflate: " << is_deflated;
960
961       if ( chunk_size_to_read_ == 0 ) {
962         set_parse_state(STATE_END_OF_CHUNK);
963       }
964       if ( is_gzipped ) {
965         ///////////////////////////////////////////////////////////////////
966         //
967         // GZIP - content encoding
968         //
969         //
970         // TODO(cpopescu): protect from chunks too long after
971         //                 decompression !!!
972         //
973         CHECK(!is_deflated);
974         if ( partial_data_.Size() <
975              io::ZlibGzipDecodeWrapper::kMinGzipDataSize ) {
976           if ( in->Size() > io::ZlibGzipDecodeWrapper::kMinGzipDataSize )
977             continue;
978           return HEADER_READ | BODY_READING;
979         }
980         bool maybe_try_deflate = gzip_zwrapper_ == NULL;
981         if ( gzip_zwrapper_ == NULL ) {
982           gzip_zwrapper_ = new io::ZlibGzipDecodeWrapper();
983         }
984         int32 consumed_size = 0;
985         do {
986           partial_data_.MarkerSet();
987           io::MemoryStream tmp;
988           const int32 initial_size = partial_data_.Size();
989           const int zerr = gzip_zwrapper_->Decode(&partial_data_, &tmp);
990           consumed_size = initial_size - partial_data_.Size();
991           if ( zerr == Z_STREAM_END ) {
992             partial_data_.MarkerClear();
993             out->AppendStream(&tmp);
994             // CONTINUE if ( partial_data_.IsEmpty() ) {
995             // We have more data to process..
996           }  else if ( zerr != Z_OK ) {
997             if ( !maybe_try_deflate ) {
998               LOG_HTTP_ERR << " ZLib error found in gzip encoding: " << zerr;
999               partial_data_.MarkerClear();
1000               // ERROR - error data in compressed body
1001               set_parse_state(ERROR_CHUNK_CONTENT_GZIP_ERROR);
1002               return HEADER_READ | CHUNKED_BODY_READING | REQUEST_FINISHED;
1003             }
1004             LOG_HTTP << " ZLib error found in gzip encoding - trying deflate.";
1005             partial_data_.MarkerRestore();
1006             is_deflated = true;
1007           } else {
1008             partial_data_.MarkerClear();
1009             out->AppendStream(&tmp);
1010             if ( chunk_size_to_read_ == 0 ) {
1011               // CONTINUE - no more data left in the chunk,
1012               //            but zip did not finish -  we expect to continue !!
1013               next_chunk_expectation_ = EXPECT_CHUNK_NON_EMPTY;
1014             }
1015           }
1016         } while ( !is_deflated && consumed_size > 0 &&
1017                   !partial_data_.IsEmpty() );
1018       }
1019       if ( is_deflated ) {
1020         ///////////////////////////////////////////////////////////////////
1021         //
1022         // DEFLATE - content encoding
1023         //
1024         if ( inflate_zwrapper_ == NULL ) {
1025           inflate_zwrapper_ = new io::ZlibInflateWrapper();
1026         }
1027         const int zerr = inflate_zwrapper_->InflateSize(&partial_data_, out);
1028         if ( zerr == Z_STREAM_END ) {
1029           if ( chunk_size_to_read_ > 0 ) {
1030             LOG_HTTP_ERR << " ZLib EOS when left in chunk: "
1031                          << chunk_size_to_read_;
1032             // ERROR - End of gzipped data, but chunk continues
1033             set_parse_state(ERROR_CHUNK_CONTENT_GZIP_TOO_LONG);
1034             return HEADER_READ | CHUNKED_BODY_READING | REQUEST_FINISHED;
1035           }
1036           // FINAL - state w/ body decompressed ok - but we also expect
1037           //         no chunks to follow
1038           next_chunk_expectation_ = EXPECT_CHUNK_EMPTY;
1039         } else if ( zerr != Z_OK ) {
1040           // ERROR - error data in compressed body
1041           LOG_HTTP_ERR << " ZLib error found: " << zerr;
1042           set_parse_state(ERROR_CHUNK_CONTENT_GZIP_ERROR);
1043           return HEADER_READ | CHUNKED_BODY_READING | REQUEST_FINISHED;
1044         } else if ( chunk_size_to_read_ == 0 ) {
1045           // CONTINUE - no more data left in the chunk, but zip did not finish
1046           //         - we expect to continue !!
1047           next_chunk_expectation_ = EXPECT_CHUNK_NON_EMPTY;
1048         }
1049       } else if ( !is_gzipped ) {
1050         ///////////////////////////////////////////////////////////////////
1051         //
1052         // IDENTITY - content encoding
1053         //
1054         out->AppendStream(&partial_data_);
1055       }
1056     } else if ( parse_state_ == STATE_LAST_CHUNK_READ ) {
1057       //////////////////////////////////////////////////////////////////////
1058       //
1059       //  STATE_LAST_CHUNK_READ -----------> Parse the trail header
1060       //
1061       return ParseTrailHeader(in, header, out);
1062     } else {
1063       LOG_FATAL << " Got in a wrong state - this is a bug: "
1064                 << ParseStateName();
1065     }
1066   } while (true);  // should exit w/ a return in the code above..
1067   return 0;  // keep g++ happy
1068 }
1069
1070 //////////////////////////////////////////////////////////////////////
1071 //
1072 // ParseTrailHeader - helper for parsing the trailer of a chunked
1073 //                    transmission
1074 //
1075 int32 RequestParser::ParseTrailHeader(io::MemoryStream* in,
1076                                       http::Header* header,
1077                                       io::MemoryStream* out) {
1078   CHECK_EQ(parse_state_, STATE_LAST_CHUNK_READ);
1079   if ( !trail_header_.ReadHeaderFields(in) ) {
1080     if ( trail_header_.bytes_parsed() + in->Size() > max_header_size_ ) {
1081       // ERROR : trail header too long.
1082       LOG_HTTP_ERR << " Chunk trailer has header too long. Got at least: "
1083                    << trail_header_.bytes_parsed() + in->Size()
1084                    << " on a max of: " << max_header_size_;
1085       set_parse_state(ERROR_CHUNK_TRAILER_TOO_LONG);
1086       return HEADER_READ | CHUNKED_TRAILER_READING | REQUEST_FINISHED;
1087     }
1088     return HEADER_READ | CHUNKED_TRAILER_READING;
1089   }
1090   // CONTINUE - got the trailing header
1091   if ( trail_header_.parse_error() > worst_accepted_header_error_ ) {
1092     // ERROR - unacceptale error in trailed header parsing
1093     LOG_HTTP_ERR << " Error in trail headers found: "
1094                  << trail_header_.ParseErrorName();
1095     set_parse_state(ERROR_CHUNK_TRAIL_HEADER);
1096     return HEADER_READ | CHUNKED_TRAILER_READING | REQUEST_FINISHED;
1097   }
1098   // Copy all trailing header in the provided header
1099   //
1100   // TODO(cpopescu): it is correct this way ??
1101   //
1102   header->CopyHeaderFields(trail_header_, false);
1103   set_parse_state(STATE_END_OF_TRAIL_HEADER);
1104   return HEADER_READ | CHUNKS_FINISHED | REQUEST_FINISHED;
1105 }
1106
1107 //////////////////////////////////////////////////////////////////////
1108
1109
1110 static const char kGzip[] = "gzip";
1111 static const char kDeflate[] = "deflate";
1112 static const char kIdentity[] = "identity";
1113 static const char kChunked[] = "chunked";
1114
1115 bool RequestParser::IsKnownContentEncoding(const http::Header* header) {
1116   int len;
1117   const char* s = header->FindField(kHeaderContentEncoding, &len);
1118   if ( !s ) return true;
1119   string s_trim = strutil::StrTrim(string(s, len));
1120   if ( s_trim.empty() ||
1121        strutil::StrCasePrefix(s_trim.c_str(), kGzip) ||
1122        strutil::StrCasePrefix(s_trim.c_str(), kDeflate) ||
1123        strutil::StrCasePrefix(s_trim.c_str(), kIdentity) ) {
1124     return true;
1125   }
1126   LOG_WARNING << " Unknown Content Encoding found: [" << s_trim << "].";
1127   return false;
1128 }
1129
1130 bool RequestParser::IsKnownTransferEncoding(const http::Header* header) {
1131   int len;
1132   const char* s = header->FindField(kHeaderTransferEncoding, &len);
1133   if ( !s ) return true;
1134   string s_trim = strutil::StrTrim(string(s, len));
1135   if ( s_trim.empty() ||
1136        strutil::StrCasePrefix(s_trim.c_str(), kChunked) ||
1137        strutil::StrCasePrefix(s_trim.c_str(), kIdentity) ) {
1138     return true;
1139   }
1140   LOG_WARNING << " Unknown Transfer Encoding found: [" << s_trim << "].";
1141   return false;
1142 }
1143 }
Note: See TracBrowser for help on using the browser.