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 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: 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 119 void notify(IHttpNotify* notify) { notify_ = notify; } 120 bool attach(StreamInterface* 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 129 HttpMode mode() const { return mode_; } 130 131 void set_ignore_data(bool ignore) { ignore_data_ = ignore; } 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