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