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