• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2004--2005, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 // Copyright 2005 Google Inc.  All Rights Reserved.
29 //
30 
31 
32 #ifndef TALK_BASE_HTTPBASE_H__
33 #define TALK_BASE_HTTPBASE_H__
34 
35 #include "talk/base/httpcommon.h"
36 
37 namespace talk_base {
38 
39 class StreamInterface;
40 
41 ///////////////////////////////////////////////////////////////////////////////
42 // HttpParser - Parses an HTTP stream provided via Process and end_of_input, and
43 // generates events for:
44 //  Structural Elements: Leader, Headers, Document Data
45 //  Events: End of Headers, End of Document, Errors
46 ///////////////////////////////////////////////////////////////////////////////
47 
48 class HttpParser {
49 public:
50   enum ProcessResult { PR_CONTINUE, PR_BLOCK, PR_COMPLETE };
51   HttpParser();
52   virtual ~HttpParser();
53 
54   void reset();
55   ProcessResult Process(const char* buffer, size_t len, size_t* processed,
56                         HttpError* error);
57   bool is_valid_end_of_input() const;
58   void complete(HttpError err);
59 
GetDataRemaining()60   size_t GetDataRemaining() const { return data_size_; }
61 
62 protected:
63   ProcessResult ProcessLine(const char* line, size_t len, HttpError* error);
64 
65   // HttpParser Interface
66   virtual ProcessResult ProcessLeader(const char* line, size_t len,
67                                       HttpError* error) = 0;
68   virtual ProcessResult ProcessHeader(const char* name, size_t nlen,
69                                       const char* value, size_t vlen,
70                                       HttpError* error) = 0;
71   virtual ProcessResult ProcessHeaderComplete(bool chunked, size_t& data_size,
72                                               HttpError* error) = 0;
73   virtual ProcessResult ProcessData(const char* data, size_t len, size_t& read,
74                                     HttpError* error) = 0;
75   virtual void OnComplete(HttpError err) = 0;
76 
77 private:
78   enum State {
79     ST_LEADER, ST_HEADERS,
80     ST_CHUNKSIZE, ST_CHUNKTERM, ST_TRAILERS,
81     ST_DATA, ST_COMPLETE
82   } state_;
83   bool chunked_;
84   size_t data_size_;
85 };
86 
87 ///////////////////////////////////////////////////////////////////////////////
88 // IHttpNotify
89 ///////////////////////////////////////////////////////////////////////////////
90 
91 enum HttpMode { HM_NONE, HM_CONNECT, HM_RECV, HM_SEND };
92 
93 class IHttpNotify {
94 public:
~IHttpNotify()95   virtual ~IHttpNotify() {}
96   virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size) = 0;
97   virtual void onHttpComplete(HttpMode mode, HttpError err) = 0;
98   virtual void onHttpClosed(HttpError err) = 0;
99 };
100 
101 ///////////////////////////////////////////////////////////////////////////////
102 // HttpBase - Provides a state machine for implementing HTTP-based components.
103 // Attach HttpBase to a StreamInterface which represents a bidirectional HTTP
104 // stream, and then call send() or recv() to initiate sending or receiving one
105 // side of an HTTP transaction.  By default, HttpBase operates as an I/O pump,
106 // moving data from the HTTP stream to the HttpData object and vice versa.
107 // However, it can also operate in stream mode, in which case the user of the
108 // stream interface drives I/O via calls to Read().
109 ///////////////////////////////////////////////////////////////////////////////
110 
111 class HttpBase
112 : private HttpParser,
113   public sigslot::has_slots<>
114 {
115 public:
116   HttpBase();
117   virtual ~HttpBase();
118 
notify(IHttpNotify * notify)119   void notify(IHttpNotify* notify) { notify_ = notify; }
120   bool attach(StreamInterface* stream);
stream()121   StreamInterface* stream() { return http_stream_; }
122   StreamInterface* detach();
123   bool isConnected() const;
124 
125   void send(HttpData* data);
126   void recv(HttpData* data);
127   void abort(HttpError err);
128 
mode()129   HttpMode mode() const { return mode_; }
130 
set_ignore_data(bool ignore)131   void set_ignore_data(bool ignore) { ignore_data_ = ignore; }
ignore_data()132   bool ignore_data() const { return ignore_data_; }
133 
134   // Obtaining this stream puts HttpBase into stream mode until the stream
135   // is closed.  HttpBase can only expose one open stream interface at a time.
136   // Further calls will return NULL.
137   StreamInterface* GetDocumentStream();
138 
139 protected:
140   // Do cleanup when the http stream closes (error may be 0 for a clean
141   // shutdown), and return the error code to signal.
142   HttpError HandleStreamClose(int error);
143 
144   // DoReceiveLoop acts as a data pump, pulling data from the http stream,
145   // pushing it through the HttpParser, and then populating the HttpData object
146   // based on the callbacks from the parser.  One of the most interesting
147   // callbacks is ProcessData, which provides the actual http document body.
148   // This data is then written to the HttpData::document.  As a result, data
149   // flows from the network to the document, with some incidental protocol
150   // parsing in between.
151   // Ideally, we would pass in the document* to DoReceiveLoop, to more easily
152   // support GetDocumentStream().  However, since the HttpParser is callback
153   // driven, we are forced to store the pointer somewhere until the callback
154   // is triggered.
155   // Returns true if the received document has finished, and
156   // HttpParser::complete should be called.
157   bool DoReceiveLoop(HttpError* err);
158 
159   void read_and_process_data();
160   void flush_data();
161   bool queue_headers();
162   void do_complete(HttpError err = HE_NONE);
163 
164   void OnHttpStreamEvent(StreamInterface* stream, int events, int error);
165   void OnDocumentEvent(StreamInterface* stream, int events, int error);
166 
167   // HttpParser Interface
168   virtual ProcessResult ProcessLeader(const char* line, size_t len,
169                                       HttpError* error);
170   virtual ProcessResult ProcessHeader(const char* name, size_t nlen,
171                                       const char* value, size_t vlen,
172                                       HttpError* error);
173   virtual ProcessResult ProcessHeaderComplete(bool chunked, size_t& data_size,
174                                               HttpError* error);
175   virtual ProcessResult ProcessData(const char* data, size_t len, size_t& read,
176                                     HttpError* error);
177   virtual void OnComplete(HttpError err);
178 
179 private:
180   class DocumentStream;
181   friend class DocumentStream;
182 
183   enum { kBufferSize = 32 * 1024 };
184 
185   HttpMode mode_;
186   HttpData* data_;
187   IHttpNotify* notify_;
188   StreamInterface* http_stream_;
189   DocumentStream* doc_stream_;
190   char buffer_[kBufferSize];
191   size_t len_;
192 
193   bool ignore_data_, chunk_data_;
194   HttpData::const_iterator header_;
195 };
196 
197 ///////////////////////////////////////////////////////////////////////////////
198 
199 } // namespace talk_base
200 
201 #endif // TALK_BASE_HTTPBASE_H__
202