1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/* 2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * libjingle 3f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Copyright 2004--2005, Google Inc. 4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Redistribution and use in source and binary forms, with or without 6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * modification, are permitted provided that the following conditions are met: 7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 1. Redistributions of source code must retain the above copyright notice, 9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * this list of conditions and the following disclaimer. 10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 2. Redistributions in binary form must reproduce the above copyright notice, 11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * this list of conditions and the following disclaimer in the documentation 12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * and/or other materials provided with the distribution. 13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 3. The name of the author may not be used to endorse or promote products 14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * derived from this software without specific prior written permission. 15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch */ 27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 28f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <time.h> 29f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 30f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/httpcommon-inl.h" 31f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 32f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/asyncsocket.h" 33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/common.h" 34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/diskcache.h" 35f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/httpclient.h" 36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/logging.h" 37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/pathutils.h" 38f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/socketstream.h" 39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/stringencode.h" 40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/stringutils.h" 41f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/thread.h" 42f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 43f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace talk_base { 44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch////////////////////////////////////////////////////////////////////// 46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Helpers 47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch////////////////////////////////////////////////////////////////////// 48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace { 50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst size_t kCacheHeader = 0; 52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst size_t kCacheBody = 1; 53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Convert decimal string to integer 55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpStringToInt(const std::string& str, unsigned long* val) { 56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(NULL != val); 57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch char* eos = NULL; 58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *val = strtoul(str.c_str(), &eos, 10); 59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return (*eos == '\0'); 60f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 61f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpShouldCache(const HttpTransaction& t) { 63f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool verb_allows_cache = (t.request.verb == HV_GET) 64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch || (t.request.verb == HV_HEAD); 65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool is_range_response = t.response.hasHeader(HH_CONTENT_RANGE, NULL); 66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool has_expires = t.response.hasHeader(HH_EXPIRES, NULL); 67f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool request_allows_cache = 68f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch has_expires || (std::string::npos != t.request.path.find('?')); 69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool response_allows_cache = 70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch has_expires || HttpCodeIsCacheable(t.response.scode); 71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool may_cache = verb_allows_cache 73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && request_allows_cache 74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && response_allows_cache 75f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && !is_range_response; 76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 77f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string value; 78f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (t.response.hasHeader(HH_CACHE_CONTROL, &value)) { 79f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpAttributeList directives; 80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpParseAttributes(value.data(), value.size(), directives); 81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Response Directives Summary: 82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // public - always cacheable 83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // private - do not cache in a shared cache 84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // no-cache - may cache, but must revalidate whether fresh or stale 85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // no-store - sensitive information, do not cache or store in any way 86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // max-age - supplants Expires for staleness 87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // s-maxage - use as max-age for shared caches, ignore otherwise 88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // must-revalidate - may cache, but must revalidate after stale 89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // proxy-revalidate - shared cache must revalidate 90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HttpHasAttribute(directives, "no-store", NULL)) { 91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch may_cache = false; 92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (HttpHasAttribute(directives, "public", NULL)) { 93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch may_cache = true; 94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 95f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 96f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return may_cache; 97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 99f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochenum HttpCacheState { 100f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HCS_FRESH, // In cache, may use 101f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HCS_STALE, // In cache, must revalidate 102f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HCS_NONE // Not in cache 103f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}; 104f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 105f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpCacheState HttpGetCacheState(const HttpTransaction& t) { 106f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Temporaries 107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string s_temp; 108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long i_temp; 109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Current time 111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long now = time(0); 112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpAttributeList cache_control; 114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (t.response.hasHeader(HH_CACHE_CONTROL, &s_temp)) { 115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpParseAttributes(s_temp.data(), s_temp.size(), cache_control); 116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 118f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Compute age of cache document 119f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long date; 120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!t.response.hasHeader(HH_DATE, &s_temp) 121f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch || !HttpDateToSeconds(s_temp, &date)) 122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HCS_NONE; 123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: Timestamp when cache request sent and response received? 125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long request_time = date; 126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long response_time = date; 127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 128f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long apparent_age = 0; 129f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (response_time > date) { 130f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch apparent_age = response_time - date; 131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 133f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long corrected_received_age = apparent_age; 134f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (t.response.hasHeader(HH_AGE, &s_temp) 135f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && HttpStringToInt(s_temp, &i_temp)) { 136f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch corrected_received_age = stdmax(apparent_age, i_temp); 137f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 138f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 139f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long response_delay = response_time - request_time; 140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long corrected_initial_age = corrected_received_age + response_delay; 141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long resident_time = now - response_time; 142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long current_age = corrected_initial_age + resident_time; 143f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 144f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Compute lifetime of document 145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long lifetime; 146f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HttpHasAttribute(cache_control, "max-age", &s_temp)) { 147f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch lifetime = atoi(s_temp.c_str()); 148f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (t.response.hasHeader(HH_EXPIRES, &s_temp) 149f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && HttpDateToSeconds(s_temp, &i_temp)) { 150f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch lifetime = i_temp - date; 151f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (t.response.hasHeader(HH_LAST_MODIFIED, &s_temp) 152f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && HttpDateToSeconds(s_temp, &i_temp)) { 153f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: Issue warning 113 if age > 24 hours 154f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch lifetime = (now - i_temp) / 10; 155f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 156f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HCS_STALE; 157f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 158f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 159f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return (lifetime > current_age) ? HCS_FRESH : HCS_STALE; 160f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 161f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 162f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochenum HttpValidatorStrength { 163f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HVS_NONE, 164f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HVS_WEAK, 165f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HVS_STRONG 166f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}; 167f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 168f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpValidatorStrength 169f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpRequestValidatorLevel(const HttpRequestData& request) { 170f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HV_GET != request.verb) 171f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HVS_STRONG; 172f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return request.hasHeader(HH_RANGE, NULL) ? HVS_STRONG : HVS_WEAK; 173f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 174f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 175f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpValidatorStrength 176f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpResponseValidatorLevel(const HttpResponseData& response) { 177f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string value; 178f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (response.hasHeader(HH_ETAG, &value)) { 179f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool is_weak = (strnicmp(value.c_str(), "W/", 2) == 0); 180f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return is_weak ? HVS_WEAK : HVS_STRONG; 181f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 182f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (response.hasHeader(HH_LAST_MODIFIED, &value)) { 183f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch unsigned long last_modified, date; 184f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HttpDateToSeconds(value, &last_modified) 185f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && response.hasHeader(HH_DATE, &value) 186f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && HttpDateToSeconds(value, &date) 187f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && (last_modified + 60 < date)) { 188f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HVS_STRONG; 189f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 190f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HVS_WEAK; 191f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 192f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HVS_NONE; 193f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 194f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 195f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstd::string GetCacheID(const HttpRequestData& request) { 196f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string id, url; 197f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch id.append(ToString(request.verb)); 198f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch id.append("_"); 199f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request.getAbsoluteUri(&url); 200f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch id.append(url); 201f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return id; 202f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 203f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 204f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} // anonymous namespace 205f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 206f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch////////////////////////////////////////////////////////////////////// 207f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Public Helpers 208f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch////////////////////////////////////////////////////////////////////// 209f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 210f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpWriteCacheHeaders(const HttpResponseData* response, 211f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StreamInterface* output, size_t* size) { 212f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t length = 0; 213f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Write all unknown and end-to-end headers to a cache file 214f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (HttpData::const_iterator it = response->begin(); 215f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch it != response->end(); ++it) { 216f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpHeader header; 217f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (FromString(header, it->first) && !HttpHeaderIsEndToEnd(header)) 218f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch continue; 219f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch length += it->first.length() + 2 + it->second.length() + 2; 220f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!output) 221f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch continue; 222f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string formatted_header(it->first); 223f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch formatted_header.append(": "); 224f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch formatted_header.append(it->second); 225f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch formatted_header.append("\r\n"); 226f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StreamResult result = output->WriteAll(formatted_header.data(), 227f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch formatted_header.length(), 228f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch NULL, NULL); 229f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (SR_SUCCESS != result) { 230f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 231f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 232f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 233f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (output && (SR_SUCCESS != output->WriteAll("\r\n", 2, NULL, NULL))) { 234f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 235f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 236f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch length += 2; 237f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (size) 238f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *size = length; 239f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return true; 240f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 241f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 242f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpReadCacheHeaders(StreamInterface* input, HttpResponseData* response, 243f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpData::HeaderCombine combine) { 244f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch while (true) { 245f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string formatted_header; 246f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StreamResult result = input->ReadLine(&formatted_header); 247f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((SR_EOS == result) || (1 == formatted_header.size())) { 248f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 249f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 250f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (SR_SUCCESS != result) { 251f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 252f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 253f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t end_of_name = formatted_header.find(':'); 254f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (std::string::npos == end_of_name) { 255f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_F(LS_WARNING) << "Malformed cache header"; 256f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch continue; 257f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 258f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t start_of_value = end_of_name + 1; 259f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t end_of_value = formatted_header.length(); 260f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch while ((start_of_value < end_of_value) 261f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && isspace(formatted_header[start_of_value])) 262f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ++start_of_value; 263f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch while ((start_of_value < end_of_value) 264f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && isspace(formatted_header[end_of_value-1])) 265f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch --end_of_value; 266f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t value_length = end_of_value - start_of_value; 267f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 268f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string name(formatted_header.substr(0, end_of_name)); 269f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string value(formatted_header.substr(start_of_value, value_length)); 270f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch response->changeHeader(name, value, combine); 271f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 272f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return true; 273f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 274f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 275f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch////////////////////////////////////////////////////////////////////// 276f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// HttpClient 277f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch////////////////////////////////////////////////////////////////////// 278f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 279f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst size_t kDefaultRetries = 1; 280f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst size_t kMaxRedirects = 5; 281f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 282f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpClient::HttpClient(const std::string& agent, StreamPool* pool, 283f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpTransaction* transaction) 284f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch : agent_(agent), pool_(pool), 285f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch transaction_(transaction), free_transaction_(false), 286f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch retries_(kDefaultRetries), attempt_(0), redirects_(0), 287f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch redirect_action_(REDIRECT_DEFAULT), 288f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch uri_form_(URI_DEFAULT), cache_(NULL), cache_state_(CS_READY) { 289f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch base_.notify(this); 290f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (NULL == transaction_) { 291f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch free_transaction_ = true; 292f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch transaction_ = new HttpTransaction; 293f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 294f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 295f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 296f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpClient::~HttpClient() { 297f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch base_.notify(NULL); 298f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch base_.abort(HE_SHUTDOWN); 299f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch release(); 300f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (free_transaction_) 301f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch delete transaction_; 302f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 303f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 304f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpClient::reset() { 305f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch server_.Clear(); 306f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().clear(true); 307f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch response().clear(true); 308f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch context_.reset(); 309f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch redirects_ = 0; 310f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch base_.abort(HE_OPERATION_CANCELLED); 311f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 312f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 313f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpClient::set_server(const SocketAddress& address) { 314f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch server_ = address; 315f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Setting 'Host' here allows it to be overridden before starting the request, 316f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // if necessary. 317f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().setHeader(HH_HOST, HttpAddress(server_, false), true); 318f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 319f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 320f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochStreamInterface* HttpClient::GetDocumentStream() { 321f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return base_.GetDocumentStream(); 322f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 323f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 324f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpClient::start() { 325f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (base_.mode() != HM_NONE) { 326f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // call reset() to abort an in-progress request 327f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(false); 328f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 329f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 330f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 331f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(!IsCacheActive()); 332f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 333f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (request().hasHeader(HH_TRANSFER_ENCODING, NULL)) { 334f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Exact size must be known on the client. Instead of using chunked 335f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // encoding, wrap data with auto-caching file or memory stream. 336f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(false); 337f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 338f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 339f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 340f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch attempt_ = 0; 341f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 342f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If no content has been specified, using length of 0. 343f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().setHeader(HH_CONTENT_LENGTH, "0", false); 344f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 345f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!agent_.empty()) { 346f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().setHeader(HH_USER_AGENT, agent_, false); 347f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 348f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 349f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch UriForm uri_form = uri_form_; 350f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (PROXY_HTTPS == proxy_.type) { 351f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Proxies require absolute form 352f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch uri_form = URI_ABSOLUTE; 353f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().version = HVER_1_0; 354f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().setHeader(HH_PROXY_CONNECTION, "Keep-Alive", false); 355f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 356f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().setHeader(HH_CONNECTION, "Keep-Alive", false); 357f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 358f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 359f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (URI_ABSOLUTE == uri_form) { 360f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Convert to absolute uri form 361f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string url; 362f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (request().getAbsoluteUri(&url)) { 363f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().path = url; 364f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 365f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_WARNING) << "Couldn't obtain absolute uri"; 366f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 367f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (URI_RELATIVE == uri_form) { 368f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Convert to relative uri form 369f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string host, path; 370f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (request().getRelativeUri(&host, &path)) { 371f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().setHeader(HH_HOST, host); 372f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().path = path; 373f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 374f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_WARNING) << "Couldn't obtain relative uri"; 375f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 376f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 377f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 378f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((NULL != cache_) && CheckCache()) { 379f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 380f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 381f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 382f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch connect(); 383f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 384f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 385f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpClient::connect() { 386f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int stream_err; 387f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StreamInterface* stream = pool_->RequestConnectedStream(server_, &stream_err); 388f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (stream == NULL) { 389f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(0 != stream_err); 390f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_ERROR) << "RequestConnectedStream error: " << stream_err; 391f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch onHttpComplete(HM_CONNECT, HE_CONNECT_FAILED); 392f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 393f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch base_.attach(stream); 394f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (stream->GetState() == SS_OPEN) { 395f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch base_.send(&transaction_->request); 396f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 397f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 398f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 399f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 400f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpClient::prepare_get(const std::string& url) { 401f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch reset(); 402f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Url<char> purl(url); 403f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch set_server(SocketAddress(purl.host(), purl.port())); 404f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().verb = HV_GET; 405f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().path = purl.full_path(); 406f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 407f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 408f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpClient::prepare_post(const std::string& url, 409f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const std::string& content_type, 410f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StreamInterface* request_doc) { 411f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch reset(); 412f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Url<char> purl(url); 413f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch set_server(SocketAddress(purl.host(), purl.port())); 414f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().verb = HV_POST; 415f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().path = purl.full_path(); 416f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().setContent(content_type, request_doc); 417f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 418f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 419f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpClient::release() { 420f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (StreamInterface* stream = base_.detach()) { 421f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch pool_->ReturnConnectedStream(stream); 422f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 423f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 424f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 425f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpClient::ShouldRedirect(std::string* location) const { 426f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: Unittest redirection. 427f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((REDIRECT_NEVER == redirect_action_) 428f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch || !HttpCodeIsRedirection(response().scode) 429f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch || !response().hasHeader(HH_LOCATION, location) 430f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch || (redirects_ >= kMaxRedirects)) 431f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 432f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return (REDIRECT_ALWAYS == redirect_action_) 433f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch || (HC_SEE_OTHER == response().scode) 434f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch || (HV_HEAD == request().verb) 435f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch || (HV_GET == request().verb); 436f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 437f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 438f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpClient::BeginCacheFile() { 439f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(NULL != cache_); 440f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(CS_READY == cache_state_); 441f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 442f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string id = GetCacheID(request()); 443f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CacheLock lock(cache_, id, true); 444f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!lock.IsLocked()) { 445f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_F(LS_WARNING) << "Couldn't lock cache"; 446f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 447f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 448f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 449f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HE_NONE != WriteCacheHeaders(id)) { 450f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 451f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 452f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 453f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch scoped_ptr<StreamInterface> stream(cache_->WriteResource(id, kCacheBody)); 454f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!stream.get()) { 455f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_F(LS_ERROR) << "Couldn't open body cache"; 456f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 457f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 458f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch lock.Commit(); 459f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 460f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Let's secretly replace the response document with Folgers Crystals, 461f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // er, StreamTap, so that we can mirror the data to our cache. 462f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StreamInterface* output = response().document.release(); 463f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!output) { 464f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch output = new NullStream; 465f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 466f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StreamTap* tap = new StreamTap(output, stream.release()); 467f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch response().document.reset(tap); 468f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return true; 469f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 470f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 471f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpError HttpClient::WriteCacheHeaders(const std::string& id) { 472f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch scoped_ptr<StreamInterface> stream(cache_->WriteResource(id, kCacheHeader)); 473f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!stream.get()) { 474f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_F(LS_ERROR) << "Couldn't open header cache"; 475f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HE_CACHE; 476f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 477f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 478f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!HttpWriteCacheHeaders(&transaction_->response, stream.get(), NULL)) { 479f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_F(LS_ERROR) << "Couldn't write header cache"; 480f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HE_CACHE; 481f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 482f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 483f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HE_NONE; 484f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 485f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 486f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpClient::CompleteCacheFile() { 487f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Restore previous response document 488f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StreamTap* tap = static_cast<StreamTap*>(response().document.release()); 489f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch response().document.reset(tap->Detach()); 490f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 491f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int error; 492f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StreamResult result = tap->GetTapResult(&error); 493f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 494f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Delete the tap and cache stream (which completes cache unlock) 495f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch delete tap; 496f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 497f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (SR_SUCCESS != result) { 498f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_ERROR) << "Cache file error: " << error; 499f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch cache_->DeleteResource(GetCacheID(request())); 500f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 501f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 502f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 503f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpClient::CheckCache() { 504f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(NULL != cache_); 505f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(CS_READY == cache_state_); 506f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 507f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string id = GetCacheID(request()); 508f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!cache_->HasResource(id)) { 509f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // No cache file available 510f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 511f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 512f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 513f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpError error = ReadCacheHeaders(id, true); 514f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 515f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HE_NONE == error) { 516f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch switch (HttpGetCacheState(*transaction_)) { 517f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case HCS_FRESH: 518f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Cache content is good, read from cache 519f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 520f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case HCS_STALE: 521f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Cache content may be acceptable. Issue a validation request. 522f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (PrepareValidate()) { 523f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 524f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 525f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Couldn't validate, fall through. 526f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case HCS_NONE: 527f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Cache content is not useable. Issue a regular request. 528f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch response().clear(false); 529f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 530f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 531f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 532f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 533f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HE_NONE == error) { 534f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch error = ReadCacheBody(id); 535f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch cache_state_ = CS_READY; 536f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 537f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 538f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HE_CACHE == error) { 539f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_F(LS_WARNING) << "Cache failure, continuing with normal request"; 540f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch response().clear(false); 541f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 542f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 543f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 544f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SignalHttpClientComplete(this, error); 545f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return true; 546f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 547f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 548f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpError HttpClient::ReadCacheHeaders(const std::string& id, bool override) { 549f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch scoped_ptr<StreamInterface> stream(cache_->ReadResource(id, kCacheHeader)); 550f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!stream.get()) { 551f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HE_CACHE; 552f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 553f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 554f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpData::HeaderCombine combine = 555f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch override ? HttpData::HC_REPLACE : HttpData::HC_AUTO; 556f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 557f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!HttpReadCacheHeaders(stream.get(), &transaction_->response, combine)) { 558f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_F(LS_ERROR) << "Error reading cache headers"; 559f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HE_CACHE; 560f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 561f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 562f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch response().scode = HC_OK; 563f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HE_NONE; 564f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 565f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 566f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpError HttpClient::ReadCacheBody(const std::string& id) { 567f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch cache_state_ = CS_READING; 568f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 569f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpError error = HE_NONE; 570f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 571f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t data_size; 572f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch scoped_ptr<StreamInterface> stream(cache_->ReadResource(id, kCacheBody)); 573f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!stream.get() || !stream->GetAvailable(&data_size)) { 574f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_F(LS_ERROR) << "Unavailable cache body"; 575f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch error = HE_CACHE; 576f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 577f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch error = OnHeaderAvailable(false, false, data_size); 578f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 579f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 580f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((HE_NONE == error) 581f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && (HV_HEAD != request().verb) 582f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && (NULL != response().document.get())) { 583f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch char buffer[1024 * 64]; 584f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch StreamResult result = Flow(stream.get(), buffer, ARRAY_SIZE(buffer), 585f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch response().document.get()); 586f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (SR_SUCCESS != result) { 587f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch error = HE_STREAM; 588f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 589f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 590f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 591f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return error; 592f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 593f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 594f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpClient::PrepareValidate() { 595f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(CS_READY == cache_state_); 596f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // At this point, request() contains the pending request, and response() 597f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // contains the cached response headers. Reformat the request to validate 598f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // the cached content. 599f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpValidatorStrength vs_required = HttpRequestValidatorLevel(request()); 600f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpValidatorStrength vs_available = HttpResponseValidatorLevel(response()); 601f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (vs_available < vs_required) { 602f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return false; 603f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 604f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string value; 605f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (response().hasHeader(HH_ETAG, &value)) { 606f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().addHeader(HH_IF_NONE_MATCH, value); 607f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 608f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (response().hasHeader(HH_LAST_MODIFIED, &value)) { 609f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().addHeader(HH_IF_MODIFIED_SINCE, value); 610f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 611f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch response().clear(false); 612f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch cache_state_ = CS_VALIDATING; 613f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return true; 614f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 615f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 616f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpError HttpClient::CompleteValidate() { 617f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(CS_VALIDATING == cache_state_); 618f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 619f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string id = GetCacheID(request()); 620f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 621f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Merge cached headers with new headers 622f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpError error = ReadCacheHeaders(id, false); 623f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HE_NONE != error) { 624f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Rewrite merged headers to cache 625f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CacheLock lock(cache_, id); 626f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch error = WriteCacheHeaders(id); 627f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 628f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HE_NONE != error) { 629f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch error = ReadCacheBody(id); 630f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 631f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return error; 632f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 633f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 634f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpError HttpClient::OnHeaderAvailable(bool ignore_data, bool chunked, 635f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t data_size) { 636f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If we are ignoring the data, this is an intermediate header. 637f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: don't signal intermediate headers. Instead, do all header-dependent 638f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // processing now, and either set up the next request, or fail outright. 639f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: by default, only write response documents with a success code. 640f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SignalHeaderAvailable(this, !ignore_data, ignore_data ? 0 : data_size); 641f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!ignore_data && !chunked && (data_size != SIZE_UNKNOWN) 642f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && response().document.get()) { 643f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Attempt to pre-allocate space for the downloaded data. 644f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!response().document->ReserveSize(data_size)) { 645f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HE_OVERFLOW; 646f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 647f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 648f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HE_NONE; 649f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 650f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 651f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// 652f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// HttpBase Implementation 653f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// 654f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 655f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpError HttpClient::onHttpHeaderComplete(bool chunked, size_t& data_size) { 656f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (CS_VALIDATING == cache_state_) { 657f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HC_NOT_MODIFIED == response().scode) { 658f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return CompleteValidate(); 659f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 660f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Should we remove conditional headers from request? 661f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch cache_state_ = CS_READY; 662f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch cache_->DeleteResource(GetCacheID(request())); 663f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Continue processing response as normal 664f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 665f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 666f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(!IsCacheActive()); 667f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((request().verb == HV_HEAD) || !HttpCodeHasBody(response().scode)) { 668f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // HEAD requests and certain response codes contain no body 669f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch data_size = 0; 670f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 671f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (ShouldRedirect(NULL) 672f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch || ((HC_PROXY_AUTHENTICATION_REQUIRED == response().scode) 673f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && (PROXY_HTTPS == proxy_.type))) { 674f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // We're going to issue another request, so ignore the incoming data. 675f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch base_.set_ignore_data(true); 676f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 677f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 678f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpError error = OnHeaderAvailable(base_.ignore_data(), chunked, data_size); 679f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (HE_NONE != error) { 680f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return error; 681f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 682f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 683f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((NULL != cache_) 684f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && !base_.ignore_data() 685f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && HttpShouldCache(*transaction_)) { 686f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (BeginCacheFile()) { 687f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch cache_state_ = CS_WRITING; 688f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 689f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 690f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return HE_NONE; 691f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 692f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 693f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpClient::onHttpComplete(HttpMode mode, HttpError err) { 694f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (((HE_DISCONNECTED == err) || (HE_CONNECT_FAILED == err) 695f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch || (HE_SOCKET_ERROR == err)) 696f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && (HC_INTERNAL_SERVER_ERROR == response().scode) 697f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && (attempt_ < retries_)) { 698f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If the response code has not changed from the default, then we haven't 699f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // received anything meaningful from the server, so we are eligible for a 700f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // retry. 701f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ++attempt_; 702f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (request().document.get() && !request().document->Rewind()) { 703f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Unable to replay the request document. 704f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch err = HE_STREAM; 705f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 706f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch release(); 707f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch connect(); 708f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 709f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 710f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (err != HE_NONE) { 711f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // fall through 712f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (mode == HM_CONNECT) { 713f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch base_.send(&transaction_->request); 714f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 715f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if ((mode == HM_SEND) || HttpCodeIsInformational(response().scode)) { 716f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If you're interested in informational headers, catch 717f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // SignalHeaderAvailable. 718f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch base_.recv(&transaction_->response); 719f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 720f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 721f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!HttpShouldKeepAlive(response())) { 722f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_VERBOSE) << "HttpClient: closing socket"; 723f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch base_.stream()->Close(); 724f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 725f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string location; 726f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (ShouldRedirect(&location)) { 727f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Url<char> purl(location); 728f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch set_server(SocketAddress(purl.host(), purl.port())); 729f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().path = purl.full_path(); 730f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (response().scode == HC_SEE_OTHER) { 731f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().verb = HV_GET; 732f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().clearHeader(HH_CONTENT_TYPE); 733f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().clearHeader(HH_CONTENT_LENGTH); 734f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().document.reset(); 735f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (request().document.get() && !request().document->Rewind()) { 736f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Unable to replay the request document. 737f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(REDIRECT_ALWAYS == redirect_action_); 738f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch err = HE_STREAM; 739f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 740f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (err == HE_NONE) { 741f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ++redirects_; 742f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch context_.reset(); 743f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch response().clear(false); 744f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch release(); 745f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch start(); 746f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 747f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 748f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if ((HC_PROXY_AUTHENTICATION_REQUIRED == response().scode) 749f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && (PROXY_HTTPS == proxy_.type)) { 750f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch std::string authorization, auth_method; 751f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpData::const_iterator begin = response().begin(HH_PROXY_AUTHENTICATE); 752f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpData::const_iterator end = response().end(HH_PROXY_AUTHENTICATE); 753f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (HttpData::const_iterator it = begin; it != end; ++it) { 754f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpAuthContext *context = context_.get(); 755f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpAuthResult res = HttpAuthenticate( 756f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch it->second.data(), it->second.size(), 757f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch proxy_.address, 758f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ToString(request().verb), request().path, 759f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch proxy_.username, proxy_.password, 760f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch context, authorization, auth_method); 761f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch context_.reset(context); 762f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (res == HAR_RESPONSE) { 763f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch request().setHeader(HH_PROXY_AUTHORIZATION, authorization); 764f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (request().document.get() && !request().document->Rewind()) { 765f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch err = HE_STREAM; 766f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 767f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Explicitly do not reset the HttpAuthContext 768f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch response().clear(false); 769f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: Reuse socket when authenticating? 770f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch release(); 771f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch start(); 772f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 773f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 774f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (res == HAR_IGNORE) { 775f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(INFO) << "Ignoring Proxy-Authenticate: " << auth_method; 776f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch continue; 777f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 778f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 779f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 780f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 781f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 782f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 783f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (CS_WRITING == cache_state_) { 784f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CompleteCacheFile(); 785f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch cache_state_ = CS_READY; 786f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (CS_READING == cache_state_) { 787f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch cache_state_ = CS_READY; 788f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 789f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch release(); 790f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SignalHttpClientComplete(this, err); 791f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 792f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 793f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpClient::onHttpClosed(HttpError err) { 794f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // This shouldn't occur, since we return the stream to the pool upon command 795f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // completion. 796f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(false); 797f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 798f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 799f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch////////////////////////////////////////////////////////////////////// 800f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// HttpClientDefault 801f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch////////////////////////////////////////////////////////////////////// 802f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 803f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpClientDefault::HttpClientDefault(SocketFactory* factory, 804f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const std::string& agent, 805f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpTransaction* transaction) 806f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch : ReuseSocketPool(factory ? factory : Thread::Current()->socketserver()), 807f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch HttpClient(agent, NULL, transaction) { 808f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch set_pool(this); 809f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 810f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 811f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch////////////////////////////////////////////////////////////////////// 812f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 813f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} // namespace talk_base 814