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 #ifndef TALK_BASE_HTTPCLIENT_H__ 29 #define TALK_BASE_HTTPCLIENT_H__ 30 31 #include "talk/base/common.h" 32 #include "talk/base/httpbase.h" 33 #include "talk/base/proxyinfo.h" 34 #include "talk/base/scoped_ptr.h" 35 #include "talk/base/sigslot.h" 36 #include "talk/base/socketaddress.h" 37 #include "talk/base/socketpool.h" 38 39 namespace talk_base { 40 41 ////////////////////////////////////////////////////////////////////// 42 // Client-specific http utilities 43 ////////////////////////////////////////////////////////////////////// 44 45 // Write cache-relevant response headers to output stream. If size is non-null, 46 // it contains the length of the output in bytes. output may be null if only 47 // the length is desired. 48 bool HttpWriteCacheHeaders(const HttpResponseData* response, 49 StreamInterface* output, size_t* size); 50 // Read cached headers from a stream, and them merge them into the response 51 // object using the specified combine operation. 52 bool HttpReadCacheHeaders(StreamInterface* input, 53 HttpResponseData* response, 54 HttpData::HeaderCombine combine); 55 56 ////////////////////////////////////////////////////////////////////// 57 // HttpClient 58 // Implements an HTTP 1.1 client. 59 ////////////////////////////////////////////////////////////////////// 60 61 class DiskCache; 62 class HttpClient; 63 class IPNetPool; 64 65 // What to do: Define STRICT_HTTP_ERROR=1 in your makefile. Use HttpError in 66 // your code (HttpErrorType should only be used for code that is shared 67 // with groups which have not yet migrated). 68 #if STRICT_HTTP_ERROR 69 typedef HttpError HttpErrorType; 70 #else // !STRICT_HTTP_ERROR 71 typedef int HttpErrorType; 72 #endif // !STRICT_HTTP_ERROR 73 74 class HttpClient : private IHttpNotify { 75 public: 76 // If HttpRequestData and HttpResponseData objects are provided, they must 77 // be freed by the caller. Otherwise, an internal object is allocated. 78 HttpClient(const std::string& agent, StreamPool* pool, 79 HttpTransaction* transaction = NULL); 80 virtual ~HttpClient(); 81 set_pool(StreamPool * pool)82 void set_pool(StreamPool* pool) { pool_ = pool; } 83 set_agent(const std::string & agent)84 void set_agent(const std::string& agent) { agent_ = agent; } agent()85 const std::string& agent() const { return agent_; } 86 set_proxy(const ProxyInfo & proxy)87 void set_proxy(const ProxyInfo& proxy) { proxy_ = proxy; } proxy()88 const ProxyInfo& proxy() const { return proxy_; } 89 90 // Request retries occur when the connection closes before the beginning of 91 // an http response is received. In these cases, the http server may have 92 // timed out the keepalive connection before it received our request. Note 93 // that if a request document cannot be rewound, no retry is made. The 94 // default is 1. set_request_retries(size_t retries)95 void set_request_retries(size_t retries) { retries_ = retries; } request_retries()96 size_t request_retries() const { return retries_; } 97 98 enum RedirectAction { REDIRECT_DEFAULT, REDIRECT_ALWAYS, REDIRECT_NEVER }; set_redirect_action(RedirectAction action)99 void set_redirect_action(RedirectAction action) { redirect_action_ = action; } redirect_action()100 RedirectAction redirect_action() const { return redirect_action_; } 101 // Deprecated set_fail_redirect(bool fail_redirect)102 void set_fail_redirect(bool fail_redirect) { 103 redirect_action_ = REDIRECT_NEVER; 104 } fail_redirect()105 bool fail_redirect() const { return (REDIRECT_NEVER == redirect_action_); } 106 107 enum UriForm { URI_DEFAULT, URI_ABSOLUTE, URI_RELATIVE }; set_uri_form(UriForm form)108 void set_uri_form(UriForm form) { uri_form_ = form; } uri_form()109 UriForm uri_form() const { return uri_form_; } 110 set_cache(DiskCache * cache)111 void set_cache(DiskCache* cache) { ASSERT(!IsCacheActive()); cache_ = cache; } cache_enabled()112 bool cache_enabled() const { return (NULL != cache_); } 113 114 // reset clears the server, request, and response structures. It will also 115 // abort an active request. 116 void reset(); 117 118 void set_server(const SocketAddress& address); server()119 const SocketAddress& server() const { return server_; } 120 121 // Note: in order for HttpClient to retry a POST in response to 122 // an authentication challenge, a redirect response, or socket disconnection, 123 // the request document must support 'replaying' by calling Rewind() on it. 124 // In the case where just a subset of a stream should be used as the request 125 // document, the stream may be wrapped with the StreamSegment adapter. transaction()126 HttpTransaction* transaction() { return transaction_; } transaction()127 const HttpTransaction* transaction() const { return transaction_; } request()128 HttpRequestData& request() { return transaction_->request; } request()129 const HttpRequestData& request() const { return transaction_->request; } response()130 HttpResponseData& response() { return transaction_->response; } response()131 const HttpResponseData& response() const { return transaction_->response; } 132 133 // convenience methods 134 void prepare_get(const std::string& url); 135 void prepare_post(const std::string& url, const std::string& content_type, 136 StreamInterface* request_doc); 137 138 // Convert HttpClient to a pull-based I/O model. 139 StreamInterface* GetDocumentStream(); 140 141 // After you finish setting up your request, call start. 142 void start(); 143 144 // Signalled when the header has finished downloading, before the document 145 // content is processed. You may change the response document in response 146 // to this signal. The second parameter indicates whether this is an 147 // intermediate (false) or final (true) header. An intermediate header is 148 // one that generates another request, such as a redirect or authentication 149 // challenge. The third parameter indicates the length of the response 150 // document, or else SIZE_UNKNOWN. Note: Do NOT abort the request in response 151 // to this signal. 152 sigslot::signal3<HttpClient*,bool,size_t> SignalHeaderAvailable; 153 // Signalled when the current request finishes. On success, err is 0. 154 sigslot::signal2<HttpClient*,HttpErrorType> SignalHttpClientComplete; 155 156 protected: 157 void connect(); 158 void release(); 159 160 bool ShouldRedirect(std::string* location) const; 161 162 bool BeginCacheFile(); 163 HttpError WriteCacheHeaders(const std::string& id); 164 void CompleteCacheFile(); 165 166 bool CheckCache(); 167 HttpError ReadCacheHeaders(const std::string& id, bool override); 168 HttpError ReadCacheBody(const std::string& id); 169 170 bool PrepareValidate(); 171 HttpError CompleteValidate(); 172 173 HttpError OnHeaderAvailable(bool ignore_data, bool chunked, size_t data_size); 174 175 // IHttpNotify Interface 176 virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size); 177 virtual void onHttpComplete(HttpMode mode, HttpError err); 178 virtual void onHttpClosed(HttpError err); 179 180 private: 181 enum CacheState { CS_READY, CS_WRITING, CS_READING, CS_VALIDATING }; IsCacheActive()182 bool IsCacheActive() const { return (cache_state_ > CS_READY); } 183 184 std::string agent_; 185 StreamPool* pool_; 186 HttpBase base_; 187 SocketAddress server_; 188 ProxyInfo proxy_; 189 HttpTransaction* transaction_; 190 bool free_transaction_; 191 size_t retries_, attempt_, redirects_; 192 RedirectAction redirect_action_; 193 UriForm uri_form_; 194 scoped_ptr<HttpAuthContext> context_; 195 DiskCache* cache_; 196 CacheState cache_state_; 197 }; 198 199 ////////////////////////////////////////////////////////////////////// 200 // HttpClientDefault - Default implementation of HttpClient 201 ////////////////////////////////////////////////////////////////////// 202 203 class HttpClientDefault : public ReuseSocketPool, public HttpClient { 204 public: 205 HttpClientDefault(SocketFactory* factory, const std::string& agent, 206 HttpTransaction* transaction = NULL); 207 }; 208 209 ////////////////////////////////////////////////////////////////////// 210 211 } // namespace talk_base 212 213 #endif // TALK_BASE_HTTPCLIENT_H__ 214