|  | /* | 
|  | *  Copyright 2004 The WebRTC Project Authors. All rights reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #ifndef RTC_BASE_HTTPBASE_H_ | 
|  | #define RTC_BASE_HTTPBASE_H_ | 
|  |  | 
|  | #include "rtc_base/httpcommon.h" | 
|  |  | 
|  | namespace rtc { | 
|  |  | 
|  | class StreamInterface; | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | // HttpParser - Parses an HTTP stream provided via Process and end_of_input, and | 
|  | // generates events for: | 
|  | //  Structural Elements: Leader, Headers, Document Data | 
|  | //  Events: End of Headers, End of Document, Errors | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | class HttpParser { | 
|  | public: | 
|  | enum ProcessResult { PR_CONTINUE, PR_BLOCK, PR_COMPLETE }; | 
|  | HttpParser(); | 
|  | virtual ~HttpParser(); | 
|  |  | 
|  | void reset(); | 
|  | ProcessResult Process(const char* buffer, size_t len, size_t* processed, | 
|  | HttpError* error); | 
|  | bool is_valid_end_of_input() const; | 
|  | void complete(HttpError err); | 
|  |  | 
|  | size_t GetDataRemaining() const { return data_size_; } | 
|  |  | 
|  | protected: | 
|  | ProcessResult ProcessLine(const char* line, size_t len, HttpError* error); | 
|  |  | 
|  | // HttpParser Interface | 
|  | virtual ProcessResult ProcessLeader(const char* line, size_t len, | 
|  | HttpError* error) = 0; | 
|  | virtual ProcessResult ProcessHeader(const char* name, size_t nlen, | 
|  | const char* value, size_t vlen, | 
|  | HttpError* error) = 0; | 
|  | virtual ProcessResult ProcessHeaderComplete(bool chunked, size_t& data_size, | 
|  | HttpError* error) = 0; | 
|  | virtual ProcessResult ProcessData(const char* data, size_t len, size_t& read, | 
|  | HttpError* error) = 0; | 
|  | virtual void OnComplete(HttpError err) = 0; | 
|  |  | 
|  | private: | 
|  | enum State { | 
|  | ST_LEADER, ST_HEADERS, | 
|  | ST_CHUNKSIZE, ST_CHUNKTERM, ST_TRAILERS, | 
|  | ST_DATA, ST_COMPLETE | 
|  | } state_; | 
|  | bool chunked_; | 
|  | size_t data_size_; | 
|  | }; | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | // IHttpNotify | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | enum HttpMode { HM_NONE, HM_CONNECT, HM_RECV, HM_SEND }; | 
|  |  | 
|  | class IHttpNotify { | 
|  | public: | 
|  | virtual ~IHttpNotify() {} | 
|  | virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size) = 0; | 
|  | virtual void onHttpComplete(HttpMode mode, HttpError err) = 0; | 
|  | virtual void onHttpClosed(HttpError err) = 0; | 
|  | }; | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  | // HttpBase - Provides a state machine for implementing HTTP-based components. | 
|  | // Attach HttpBase to a StreamInterface which represents a bidirectional HTTP | 
|  | // stream, and then call send() or recv() to initiate sending or receiving one | 
|  | // side of an HTTP transaction.  By default, HttpBase operates as an I/O pump, | 
|  | // moving data from the HTTP stream to the HttpData object and vice versa. | 
|  | // However, it can also operate in stream mode, in which case the user of the | 
|  | // stream interface drives I/O via calls to Read(). | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | class HttpBase | 
|  | : private HttpParser, | 
|  | public sigslot::has_slots<> | 
|  | { | 
|  | public: | 
|  | HttpBase(); | 
|  | ~HttpBase() override; | 
|  |  | 
|  | void notify(IHttpNotify* notify) { notify_ = notify; } | 
|  | bool attach(StreamInterface* stream); | 
|  | StreamInterface* stream() { return http_stream_; } | 
|  | StreamInterface* detach(); | 
|  | bool isConnected() const; | 
|  |  | 
|  | void send(HttpData* data); | 
|  | void recv(HttpData* data); | 
|  | void abort(HttpError err); | 
|  |  | 
|  | HttpMode mode() const { return mode_; } | 
|  |  | 
|  | void set_ignore_data(bool ignore) { ignore_data_ = ignore; } | 
|  | bool ignore_data() const { return ignore_data_; } | 
|  |  | 
|  | // Obtaining this stream puts HttpBase into stream mode until the stream | 
|  | // is closed.  HttpBase can only expose one open stream interface at a time. | 
|  | // Further calls will return null. | 
|  | StreamInterface* GetDocumentStream(); | 
|  |  | 
|  | protected: | 
|  | // Do cleanup when the http stream closes (error may be 0 for a clean | 
|  | // shutdown), and return the error code to signal. | 
|  | HttpError HandleStreamClose(int error); | 
|  |  | 
|  | // DoReceiveLoop acts as a data pump, pulling data from the http stream, | 
|  | // pushing it through the HttpParser, and then populating the HttpData object | 
|  | // based on the callbacks from the parser.  One of the most interesting | 
|  | // callbacks is ProcessData, which provides the actual http document body. | 
|  | // This data is then written to the HttpData::document.  As a result, data | 
|  | // flows from the network to the document, with some incidental protocol | 
|  | // parsing in between. | 
|  | // Ideally, we would pass in the document* to DoReceiveLoop, to more easily | 
|  | // support GetDocumentStream().  However, since the HttpParser is callback | 
|  | // driven, we are forced to store the pointer somewhere until the callback | 
|  | // is triggered. | 
|  | // Returns true if the received document has finished, and | 
|  | // HttpParser::complete should be called. | 
|  | bool DoReceiveLoop(HttpError* err); | 
|  |  | 
|  | void read_and_process_data(); | 
|  | void flush_data(); | 
|  | bool queue_headers(); | 
|  | void do_complete(HttpError err = HE_NONE); | 
|  |  | 
|  | void OnHttpStreamEvent(StreamInterface* stream, int events, int error); | 
|  | void OnDocumentEvent(StreamInterface* stream, int events, int error); | 
|  |  | 
|  | // HttpParser Interface | 
|  | ProcessResult ProcessLeader(const char* line, | 
|  | size_t len, | 
|  | HttpError* error) override; | 
|  | ProcessResult ProcessHeader(const char* name, | 
|  | size_t nlen, | 
|  | const char* value, | 
|  | size_t vlen, | 
|  | HttpError* error) override; | 
|  | ProcessResult ProcessHeaderComplete(bool chunked, | 
|  | size_t& data_size, | 
|  | HttpError* error) override; | 
|  | ProcessResult ProcessData(const char* data, | 
|  | size_t len, | 
|  | size_t& read, | 
|  | HttpError* error) override; | 
|  | void OnComplete(HttpError err) override; | 
|  |  | 
|  | private: | 
|  | class DocumentStream; | 
|  | friend class DocumentStream; | 
|  |  | 
|  | enum { kBufferSize = 32 * 1024 }; | 
|  |  | 
|  | HttpMode mode_; | 
|  | HttpData* data_; | 
|  | IHttpNotify* notify_; | 
|  | StreamInterface* http_stream_; | 
|  | DocumentStream* doc_stream_; | 
|  | char buffer_[kBufferSize]; | 
|  | size_t len_; | 
|  |  | 
|  | bool ignore_data_, chunk_data_; | 
|  | HttpData::const_iterator header_; | 
|  | }; | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | } // namespace rtc | 
|  |  | 
|  | #endif // RTC_BASE_HTTPBASE_H_ |