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#ifdef WIN32
31f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#define WIN32_LEAN_AND_MEAN
32f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <windows.h>
33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <winsock2.h>
34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <ws2tcpip.h>
35f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#define SECURITY_WIN32
36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <security.h>
37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
38f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/httpcommon-inl.h"
40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
41f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/base64.h"
42f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/common.h"
43f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/cryptstring.h"
44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/httpcommon.h"
45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/socketaddress.h"
46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/stringdigest.h"
47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/stringencode.h"
48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/stringutils.h"
49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace talk_base {
51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef WIN32
53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochextern const ConstantLabel SECURITY_ERRORS[];
54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//////////////////////////////////////////////////////////////////////
57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Enum - TODO: expose globally later?
58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//////////////////////////////////////////////////////////////////////
59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
60f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool find_string(size_t& index, const std::string& needle,
61f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                 const char* const haystack[], size_t max_index) {
62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (index=0; index<max_index; ++index) {
63f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch	if (_stricmp(needle.c_str(), haystack[index]) == 0) {
64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch	  return true;
65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch	}
66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
67f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return false;
68f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochtemplate<class E>
71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstruct Enum {
72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  static const char** Names;
73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  static size_t Size;
74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
75f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  static inline const char* Name(E val) { return Names[val]; }
76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  static inline bool Parse(E& val, const std::string& name) {
77f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch	size_t index;
78f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch	if (!find_string(index, name, Names, Size))
79f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch	  return false;
80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch	val = static_cast<E>(index);
81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch	return true;
82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  E val;
85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  inline operator E&() { return val; }
87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  inline Enum& operator=(E rhs) { val = rhs; return *this; }
88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  inline const char* name() const { return Name(val); }
90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  inline bool assign(const std::string& name) { return Parse(val, name); }
91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  inline Enum& operator=(const std::string& rhs) { assign(rhs); return *this; }
92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch};
93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#define ENUM(e,n) \
95f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  template<> const char** Enum<e>::Names = n; \
96f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  template<> size_t Enum<e>::Size = sizeof(n)/sizeof(n[0])
97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//////////////////////////////////////////////////////////////////////
99f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// HttpCommon
100f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//////////////////////////////////////////////////////////////////////
101f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
102f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const char* kHttpVersions[HVER_LAST+1] = {
103f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "1.0", "1.1", "Unknown"
104f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch};
105f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochENUM(HttpVersion, kHttpVersions);
106f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const char* kHttpVerbs[HV_LAST+1] = {
108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "GET", "POST", "PUT", "DELETE", "CONNECT", "HEAD"
109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch};
110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochENUM(HttpVerb, kHttpVerbs);
111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstatic const char* kHttpHeaders[HH_LAST+1] = {
113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Age",
114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Cache-Control",
115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Connection",
116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Content-Disposition",
117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Content-Length",
118f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Content-Range",
119f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Content-Type",
120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Cookie",
121f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Date",
122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "ETag",
123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Expires",
124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Host",
125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "If-Modified-Since",
126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "If-None-Match",
127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Keep-Alive",
128f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Last-Modified",
129f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Location",
130f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Proxy-Authenticate",
131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Proxy-Authorization",
132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Proxy-Connection",
133f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Range",
134f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Set-Cookie",
135f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "TE",
136f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Trailers",
137f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Transfer-Encoding",
138f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Upgrade",
139f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "User-Agent",
140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "WWW-Authenticate",
141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch};
142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochENUM(HttpHeader, kHttpHeaders);
143f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
144f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char* ToString(HttpVersion version) {
145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return Enum<HttpVersion>::Name(version);
146f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
147f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
148f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool FromString(HttpVersion& version, const std::string& str) {
149f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return Enum<HttpVersion>::Parse(version, str);
150f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
151f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
152f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char* ToString(HttpVerb verb) {
153f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return Enum<HttpVerb>::Name(verb);
154f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
155f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
156f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool FromString(HttpVerb& verb, const std::string& str) {
157f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return Enum<HttpVerb>::Parse(verb, str);
158f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
159f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
160f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char* ToString(HttpHeader header) {
161f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return Enum<HttpHeader>::Name(header);
162f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
163f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
164f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool FromString(HttpHeader& header, const std::string& str) {
165f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return Enum<HttpHeader>::Parse(header, str);
166f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
167f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
168f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpCodeHasBody(uint32 code) {
169f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return !HttpCodeIsInformational(code)
170f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch         && (code != HC_NO_CONTENT) && (code != HC_NOT_MODIFIED);
171f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
172f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
173f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpCodeIsCacheable(uint32 code) {
174f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  switch (code) {
175f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HC_OK:
176f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HC_NON_AUTHORITATIVE:
177f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HC_PARTIAL_CONTENT:
178f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HC_MULTIPLE_CHOICES:
179f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HC_MOVED_PERMANENTLY:
180f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HC_GONE:
181f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return true;
182f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  default:
183f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
184f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
185f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
186f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
187f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpHeaderIsEndToEnd(HttpHeader header) {
188f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  switch (header) {
189f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HH_CONNECTION:
190f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HH_KEEP_ALIVE:
191f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HH_PROXY_AUTHENTICATE:
192f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HH_PROXY_AUTHORIZATION:
193f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HH_PROXY_CONNECTION:  // Note part of RFC... this is non-standard header
194f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HH_TE:
195f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HH_TRAILERS:
196f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HH_TRANSFER_ENCODING:
197f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HH_UPGRADE:
198f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
199f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  default:
200f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return true;
201f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
202f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
203f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
204f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpHeaderIsCollapsible(HttpHeader header) {
205f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  switch (header) {
206f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HH_SET_COOKIE:
207f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HH_PROXY_AUTHENTICATE:
208f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case HH_WWW_AUTHENTICATE:
209f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
210f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  default:
211f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return true;
212f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
213f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
214f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
215f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpShouldKeepAlive(const HttpData& data) {
216f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::string connection;
217f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if ((data.hasHeader(HH_PROXY_CONNECTION, &connection)
218f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      || data.hasHeader(HH_CONNECTION, &connection))) {
219f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return (_stricmp(connection.c_str(), "Keep-Alive") == 0);
220f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
221f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return (data.version >= HVER_1_1);
222f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
223f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
224f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace {
225f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
226f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochinline bool IsEndOfAttributeName(size_t pos, size_t len, const char * data) {
227f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (pos >= len)
228f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return true;
229f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (isspace(static_cast<unsigned char>(data[pos])))
230f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return true;
231f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // The reason for this complexity is that some attributes may contain trailing
232f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // equal signs (like base64 tokens in Negotiate auth headers)
233f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if ((pos+1 < len) && (data[pos] == '=') &&
234f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      !isspace(static_cast<unsigned char>(data[pos+1])) &&
235f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      (data[pos+1] != '=')) {
236f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return true;
237f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
238f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return false;
239f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
240f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
241f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// TODO: unittest for EscapeAttribute and HttpComposeAttributes.
242f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
243f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstd::string EscapeAttribute(const std::string& attribute) {
244f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const size_t kMaxLength = attribute.length() * 2 + 1;
245f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  char* buffer = STACK_ARRAY(char, kMaxLength);
246f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t len = escape(buffer, kMaxLength, attribute.data(), attribute.length(),
247f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                      "\"", '\\');
248f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return std::string(buffer, len);
249f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
250f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
251f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}  // anonymous namespace
252f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
253f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpComposeAttributes(const HttpAttributeList& attributes, char separator,
254f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                           std::string* composed) {
255f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::stringstream ss;
256f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (size_t i=0; i<attributes.size(); ++i) {
257f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (i > 0) {
258f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ss << separator << " ";
259f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
260f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ss << attributes[i].first;
261f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!attributes[i].second.empty()) {
262f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ss << "=\"" << EscapeAttribute(attributes[i].second) << "\"";
263f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
264f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
265f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  *composed = ss.str();
266f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
267f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
268f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpParseAttributes(const char * data, size_t len,
269f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                         HttpAttributeList& attributes) {
270f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t pos = 0;
271f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  while (true) {
272f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // Skip leading whitespace
273f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    while ((pos < len) && isspace(static_cast<unsigned char>(data[pos]))) {
274f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ++pos;
275f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
276f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
277f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // End of attributes?
278f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (pos >= len)
279f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return;
280f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
281f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // Find end of attribute name
282f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    size_t start = pos;
283f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    while (!IsEndOfAttributeName(pos, len, data)) {
284f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ++pos;
285f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
286f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
287f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    HttpAttribute attribute;
288f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    attribute.first.assign(data + start, data + pos);
289f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
290f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // Attribute has value?
291f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if ((pos < len) && (data[pos] == '=')) {
292f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ++pos; // Skip '='
293f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      // Check if quoted value
294f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if ((pos < len) && (data[pos] == '"')) {
295f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        while (++pos < len) {
296f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          if (data[pos] == '"') {
297f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            ++pos;
298f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            break;
299f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          }
300f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          if ((data[pos] == '\\') && (pos + 1 < len))
301f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            ++pos;
302f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          attribute.second.append(1, data[pos]);
303f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
304f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      } else {
305f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        while ((pos < len) &&
306f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            !isspace(static_cast<unsigned char>(data[pos])) &&
307f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            (data[pos] != ',')) {
308f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          attribute.second.append(1, data[pos++]);
309f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
310f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
311f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
312f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
313f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    attributes.push_back(attribute);
314f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if ((pos < len) && (data[pos] == ',')) ++pos; // Skip ','
315f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
316f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
317f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
318f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpHasAttribute(const HttpAttributeList& attributes,
319f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                      const std::string& name,
320f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                      std::string* value) {
321f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (HttpAttributeList::const_iterator it = attributes.begin();
322f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch       it != attributes.end(); ++it) {
323f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (it->first == name) {
324f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (value) {
325f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        *value = it->second;
326f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
327f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return true;
328f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
329f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
330f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return false;
331f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
332f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
333f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpHasNthAttribute(HttpAttributeList& attributes,
334f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                         size_t index,
335f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                         std::string* name,
336f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                         std::string* value) {
337f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (index >= attributes.size())
338f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
339f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
340f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (name)
341f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    *name = attributes[index].first;
342f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (value)
343f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    *value = attributes[index].second;
344f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
345f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
346f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
347f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpDateToSeconds(const std::string& date, unsigned long* seconds) {
348f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const char* const kTimeZones[] = {
349f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    "UT", "GMT", "EST", "EDT", "CST", "CDT", "MST", "MDT", "PST", "PDT",
350f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    "A", "B", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M",
351f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y"
352f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  };
353f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const int kTimeZoneOffsets[] = {
354f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch     0,  0, -5, -4, -6, -5, -7, -6, -8, -7,
355f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12,
356f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch     1,  2,  3,  4,  5,  6,  7,  8,  9,  10,  11,  12
357f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  };
358f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
359f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(NULL != seconds);
360f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  struct tm tval;
361f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  memset(&tval, 0, sizeof(tval));
362f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  char month[4], zone[6];
363f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  memset(month, 0, sizeof(month));
364f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  memset(zone, 0, sizeof(zone));
365f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
366f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (7 != sscanf(date.c_str(), "%*3s, %d %3s %d %d:%d:%d %5c",
367f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                  &tval.tm_mday, month, &tval.tm_year,
368f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                  &tval.tm_hour, &tval.tm_min, &tval.tm_sec, zone)) {
369f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
370f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
371f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  switch (toupper(month[2])) {
372f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case 'N': tval.tm_mon = (month[1] == 'A') ? 0 : 5; break;
373f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case 'B': tval.tm_mon = 1; break;
374f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case 'R': tval.tm_mon = (month[0] == 'M') ? 2 : 3; break;
375f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case 'Y': tval.tm_mon = 4; break;
376f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case 'L': tval.tm_mon = 6; break;
377f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case 'G': tval.tm_mon = 7; break;
378f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case 'P': tval.tm_mon = 8; break;
379f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case 'T': tval.tm_mon = 9; break;
380f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case 'V': tval.tm_mon = 10; break;
381f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  case 'C': tval.tm_mon = 11; break;
382f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
383f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  tval.tm_year -= 1900;
384f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  unsigned long gmt, non_gmt = mktime(&tval);
385f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if ((zone[0] == '+') || (zone[0] == '-')) {
386f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!isdigit(zone[1]) || !isdigit(zone[2])
387f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        || !isdigit(zone[3]) || !isdigit(zone[4])) {
388f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return false;
389f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
390f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    int hours = (zone[1] - '0') * 10 + (zone[2] - '0');
391f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    int minutes = (zone[3] - '0') * 10 + (zone[4] - '0');
392f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    int offset = (hours * 60 + minutes) * 60;
393f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    gmt = non_gmt + (zone[0] == '+') ? offset : -offset;
394f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
395f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    size_t zindex;
396f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!find_string(zindex, zone, kTimeZones, ARRAY_SIZE(kTimeZones))) {
397f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return false;
398f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
399f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    gmt = non_gmt + kTimeZoneOffsets[zindex] * 60 * 60;
400f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
401f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // TODO: Android should support timezone, see b/2441195
402731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#if defined(OSX) || defined(ANDROID) || defined(BSD)
403f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  tm *tm_for_timezone = localtime((time_t *)&gmt);
404f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  *seconds = gmt + tm_for_timezone->tm_gmtoff;
405f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#else
406f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  *seconds = gmt - timezone;
407f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
408f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
409f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
410f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
411f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstd::string HttpAddress(const SocketAddress& address, bool secure) {
412f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return (address.port() == HttpDefaultPort(secure))
413f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          ? address.hostname() : address.ToString();
414f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
415f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
416f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//////////////////////////////////////////////////////////////////////
417f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// HttpData
418f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//////////////////////////////////////////////////////////////////////
419f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
420f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
421f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpData::clear(bool release_document) {
422f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Clear headers first, since releasing a document may have far-reaching
423f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // effects.
424f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  headers_.clear();
425f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (release_document) {
426f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    document.reset();
427f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
428f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
429f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
430f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
431f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpData::copy(const HttpData& src) {
432f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  headers_ = src.headers_;
433f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
434f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
435f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
436f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpData::changeHeader(const std::string& name, const std::string& value,
437f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                       HeaderCombine combine) {
438f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (combine == HC_AUTO) {
439f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    HttpHeader header;
440f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // Unrecognized headers are collapsible
441f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    combine = !FromString(header, name) || HttpHeaderIsCollapsible(header)
442f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch              ? HC_YES : HC_NO;
443f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else if (combine == HC_REPLACE) {
444f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    headers_.erase(name);
445f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    combine = HC_NO;
446f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
447f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // At this point, combine is one of (YES, NO, NEW)
448f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (combine != HC_NO) {
449f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    HeaderMap::iterator it = headers_.find(name);
450f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (it != headers_.end()) {
451f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (combine == HC_YES) {
452f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        it->second.append(",");
453f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        it->second.append(value);
454f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch	  }
455f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return;
456f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch	}
457f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
458f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  headers_.insert(HeaderMap::value_type(name, value));
459f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
460f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
461f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochsize_t HttpData::clearHeader(const std::string& name) {
462f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return headers_.erase(name);
463f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
464f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
465f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpData::iterator HttpData::clearHeader(iterator header) {
466f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  iterator deprecated = header++;
467f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  headers_.erase(deprecated);
468f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return header;
469f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
470f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
471f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool
472f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpData::hasHeader(const std::string& name, std::string* value) const {
473f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  HeaderMap::const_iterator it = headers_.find(name);
474f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (it == headers_.end()) {
475f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
476f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else if (value) {
477f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    *value = it->second;
478f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
479f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
480f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
481f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
482f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpData::setContent(const std::string& content_type,
483f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                          StreamInterface* document) {
484f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  setHeader(HH_CONTENT_TYPE, content_type);
485f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  setDocumentAndLength(document);
486f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
487f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
488f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid HttpData::setDocumentAndLength(StreamInterface* document) {
489f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // TODO: Consider calling Rewind() here?
490f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(!hasHeader(HH_CONTENT_LENGTH, NULL));
491f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(!hasHeader(HH_TRANSFER_ENCODING, NULL));
492f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(document != NULL);
493f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  this->document.reset(document);
494f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t content_length = 0;
495f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (this->document->GetAvailable(&content_length)) {
496f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    char buffer[32];
497f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    sprintfn(buffer, sizeof(buffer), "%d", content_length);
498f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    setHeader(HH_CONTENT_LENGTH, buffer);
499f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
500f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    setHeader(HH_TRANSFER_ENCODING, "chunked");
501f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
502f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
503f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
504f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//
505f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// HttpRequestData
506f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//
507f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
508f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
509f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpRequestData::clear(bool release_document) {
510f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  verb = HV_GET;
511f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  path.clear();
512f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  HttpData::clear(release_document);
513f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
514f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
515f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
516f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpRequestData::copy(const HttpRequestData& src) {
517f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  verb = src.verb;
518f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  path = src.path;
519f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  HttpData::copy(src);
520f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
521f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
522f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochsize_t
523f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpRequestData::formatLeader(char* buffer, size_t size) const {
524f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  ASSERT(path.find(' ') == std::string::npos);
525f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return sprintfn(buffer, size, "%s %.*s HTTP/%s", ToString(verb), path.size(),
526f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                  path.data(), ToString(version));
527f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
528f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
529f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpError
530f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpRequestData::parseLeader(const char* line, size_t len) {
531f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  UNUSED(len);
532f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  unsigned int vmajor, vminor;
533f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int vend, dstart, dend;
534f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if ((sscanf(line, "%*s%n %n%*s%n HTTP/%u.%u", &vend, &dstart, &dend,
535f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch              &vmajor, &vminor) != 2)
536f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      || (vmajor != 1)) {
537f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return HE_PROTOCOL;
538f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
539f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (vminor == 0) {
540f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    version = HVER_1_0;
541f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else if (vminor == 1) {
542f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    version = HVER_1_1;
543f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
544f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return HE_PROTOCOL;
545f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
546f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::string sverb(line, vend);
547f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!FromString(verb, sverb.c_str())) {
548f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return HE_PROTOCOL; // !?! HC_METHOD_NOT_SUPPORTED?
549f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
550f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  path.assign(line + dstart, line + dend);
551f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return HE_NONE;
552f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
553f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
554f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpRequestData::getAbsoluteUri(std::string* uri) const {
555f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (HV_CONNECT == verb)
556f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
557f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Url<char> url(path);
558f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (url.valid()) {
559f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    uri->assign(path);
560f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return true;
561f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
562f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::string host;
563f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!hasHeader(HH_HOST, &host))
564f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
565f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  url.set_address(host);
566f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  url.set_full_path(path);
567f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  uri->assign(url.url());
568f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return url.valid();
569f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
570f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
571f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochbool HttpRequestData::getRelativeUri(std::string* host,
572f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                     std::string* path) const
573f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch{
574f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (HV_CONNECT == verb)
575f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
576f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Url<char> url(this->path);
577f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (url.valid()) {
578f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    host->assign(url.address());
579f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    path->assign(url.full_path());
580f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return true;
581f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
582f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!hasHeader(HH_HOST, host))
583f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
584f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  path->assign(this->path);
585f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
586f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
587f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
588f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//
589f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// HttpResponseData
590f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//
591f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
592f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
593f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpResponseData::clear(bool release_document) {
594f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  scode = HC_INTERNAL_SERVER_ERROR;
595f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  message.clear();
596f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  HttpData::clear(release_document);
597f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
598f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
599f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
600f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpResponseData::copy(const HttpResponseData& src) {
601f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  scode = src.scode;
602f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  message = src.message;
603f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  HttpData::copy(src);
604f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
605f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
606f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
607f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpResponseData::set_success(uint32 scode) {
608f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  this->scode = scode;
609f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  message.clear();
610f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  setHeader(HH_CONTENT_LENGTH, "0", false);
611f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
612f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
613f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
614f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpResponseData::set_success(const std::string& content_type,
615f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                              StreamInterface* document,
616f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                              uint32 scode) {
617f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  this->scode = scode;
618f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  message.erase(message.begin(), message.end());
619f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  setContent(content_type, document);
620f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
621f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
622f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
623f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpResponseData::set_redirect(const std::string& location, uint32 scode) {
624f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  this->scode = scode;
625f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  message.clear();
626f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  setHeader(HH_LOCATION, location);
627f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  setHeader(HH_CONTENT_LENGTH, "0", false);
628f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
629f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
630f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid
631f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpResponseData::set_error(uint32 scode) {
632f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  this->scode = scode;
633f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  message.clear();
634f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  setHeader(HH_CONTENT_LENGTH, "0", false);
635f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
636f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
637f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochsize_t
638f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpResponseData::formatLeader(char* buffer, size_t size) const {
639f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t len = sprintfn(buffer, size, "HTTP/%s %lu", ToString(version), scode);
640f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (!message.empty()) {
641f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    len += sprintfn(buffer + len, size - len, " %.*s",
642f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                    message.size(), message.data());
643f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
644f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return len;
645f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
646f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
647f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpError
648f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpResponseData::parseLeader(const char* line, size_t len) {
649f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t pos = 0;
650f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  unsigned int vmajor, vminor, temp_scode;
651f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int temp_pos;
652f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (sscanf(line, "HTTP %u%n",
653f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch             &temp_scode, &temp_pos) == 1) {
654f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // This server's response has no version. :( NOTE: This happens for every
655f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // response to requests made from Chrome plugins, regardless of the server's
656f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // behaviour.
657f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    LOG(LS_VERBOSE) << "HTTP version missing from response";
658f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    version = HVER_UNKNOWN;
659f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else if ((sscanf(line, "HTTP/%u.%u %u%n",
660f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                     &vmajor, &vminor, &temp_scode, &temp_pos) == 3)
661f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch             && (vmajor == 1)) {
662f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // This server's response does have a version.
663f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (vminor == 0) {
664f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      version = HVER_1_0;
665f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    } else if (vminor == 1) {
666f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      version = HVER_1_1;
667f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    } else {
668f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return HE_PROTOCOL;
669f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
670f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  } else {
671f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return HE_PROTOCOL;
672f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
673f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  scode = temp_scode;
674f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  pos = static_cast<size_t>(temp_pos);
675f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  while ((pos < len) && isspace(static_cast<unsigned char>(line[pos]))) ++pos;
676f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  message.assign(line + pos, len - pos);
677f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return HE_NONE;
678f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
679f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
680f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//////////////////////////////////////////////////////////////////////
681f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// Http Authentication
682f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//////////////////////////////////////////////////////////////////////
683f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
684f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#define TEST_DIGEST 0
685f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if TEST_DIGEST
686f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/*
687f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char * const DIGEST_CHALLENGE =
688f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Digest realm=\"testrealm@host.com\","
689f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  " qop=\"auth,auth-int\","
690f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  " nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\","
691f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  " opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";
692f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char * const DIGEST_METHOD = "GET";
693f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char * const DIGEST_URI =
694f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "/dir/index.html";;
695f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char * const DIGEST_CNONCE =
696f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "0a4f113b";
697f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char * const DIGEST_RESPONSE =
698f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "6629fae49393a05397450978507c4ef1";
699f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//user_ = "Mufasa";
700f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//pass_ = "Circle Of Life";
701f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch*/
702f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char * const DIGEST_CHALLENGE =
703f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "Digest realm=\"Squid proxy-caching web server\","
704f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  " nonce=\"Nny4QuC5PwiSDixJ\","
705f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  " qop=\"auth\","
706f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  " stale=false";
707f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char * const DIGEST_URI =
708f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "/";
709f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char * const DIGEST_CNONCE =
710f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "6501d58e9a21cee1e7b5fec894ded024";
711f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst char * const DIGEST_RESPONSE =
712f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  "edffcb0829e755838b073a4a42de06bc";
713f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
714f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
715f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstd::string quote(const std::string& str) {
716f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::string result;
717f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  result.push_back('"');
718f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  for (size_t i=0; i<str.size(); ++i) {
719f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if ((str[i] == '"') || (str[i] == '\\'))
720f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      result.push_back('\\');
721f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    result.push_back(str[i]);
722f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
723f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  result.push_back('"');
724f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return result;
725f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
726f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
727f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef WIN32
728f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstruct NegotiateAuthContext : public HttpAuthContext {
729f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  CredHandle cred;
730f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  CtxtHandle ctx;
731f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  size_t steps;
732f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  bool specified_credentials;
733f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
734f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  NegotiateAuthContext(const std::string& auth, CredHandle c1, CtxtHandle c2)
735f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  : HttpAuthContext(auth), cred(c1), ctx(c2), steps(0),
736f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    specified_credentials(false)
737f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  { }
738f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
739f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  virtual ~NegotiateAuthContext() {
740f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    DeleteSecurityContext(&ctx);
741f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    FreeCredentialsHandle(&cred);
742f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
743f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch};
744f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif // WIN32
745f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
746f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochHttpAuthResult HttpAuthenticate(
747f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const char * challenge, size_t len,
748f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const SocketAddress& server,
749f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const std::string& method, const std::string& uri,
750f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  const std::string& username, const CryptString& password,
751f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  HttpAuthContext *& context, std::string& response, std::string& auth_method)
752f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch{
753f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if TEST_DIGEST
754f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  challenge = DIGEST_CHALLENGE;
755f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  len = strlen(challenge);
756f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
757f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
758f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  HttpAttributeList args;
759f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  HttpParseAttributes(challenge, len, args);
760f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  HttpHasNthAttribute(args, 0, &auth_method, NULL);
761f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
762f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (context && (context->auth_method != auth_method))
763f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return HAR_IGNORE;
764f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
765f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // BASIC
766f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (_stricmp(auth_method.c_str(), "basic") == 0) {
767f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (context)
768f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return HAR_CREDENTIALS; // Bad credentials
769f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (username.empty())
770f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return HAR_CREDENTIALS; // Missing credentials
771f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
772f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    context = new HttpAuthContext(auth_method);
773f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
774f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // TODO: convert sensitive to a secure buffer that gets securely deleted
775f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    //std::string decoded = username + ":" + password;
776f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    size_t len = username.size() + password.GetLength() + 2;
777f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    char * sensitive = new char[len];
778f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    size_t pos = strcpyn(sensitive, len, username.data(), username.size());
779f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    pos += strcpyn(sensitive + pos, len - pos, ":");
780f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    password.CopyTo(sensitive + pos, true);
781f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
782f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    response = auth_method;
783f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    response.append(" ");
784f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // TODO: create a sensitive-source version of Base64::encode
785f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    response.append(Base64::Encode(sensitive));
786f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    memset(sensitive, 0, len);
787f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    delete [] sensitive;
788f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return HAR_RESPONSE;
789f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
790f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
791f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // DIGEST
792f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (_stricmp(auth_method.c_str(), "digest") == 0) {
793f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (context)
794f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return HAR_CREDENTIALS; // Bad credentials
795f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (username.empty())
796f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return HAR_CREDENTIALS; // Missing credentials
797f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
798f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    context = new HttpAuthContext(auth_method);
799f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
800f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    std::string cnonce, ncount;
801f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if TEST_DIGEST
802f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    method = DIGEST_METHOD;
803f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    uri    = DIGEST_URI;
804f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    cnonce = DIGEST_CNONCE;
805f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#else
806f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    char buffer[256];
807f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    sprintf(buffer, "%d", static_cast<int>(time(0)));
808f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    cnonce = MD5(buffer);
809f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
810f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ncount = "00000001";
811f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
812f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    std::string realm, nonce, qop, opaque;
813f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    HttpHasAttribute(args, "realm", &realm);
814f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    HttpHasAttribute(args, "nonce", &nonce);
815f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    bool has_qop = HttpHasAttribute(args, "qop", &qop);
816f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    bool has_opaque = HttpHasAttribute(args, "opaque", &opaque);
817f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
818f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // TODO: convert sensitive to be secure buffer
819f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    //std::string A1 = username + ":" + realm + ":" + password;
820f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    size_t len = username.size() + realm.size() + password.GetLength() + 3;
821f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    char * sensitive = new char[len];  // A1
822f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    size_t pos = strcpyn(sensitive, len, username.data(), username.size());
823f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    pos += strcpyn(sensitive + pos, len - pos, ":");
824f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    pos += strcpyn(sensitive + pos, len - pos, realm.c_str());
825f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    pos += strcpyn(sensitive + pos, len - pos, ":");
826f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    password.CopyTo(sensitive + pos, true);
827f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
828f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    std::string A2 = method + ":" + uri;
829f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    std::string middle;
830f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (has_qop) {
831f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      qop = "auth";
832f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      middle = nonce + ":" + ncount + ":" + cnonce + ":" + qop;
833f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    } else {
834f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      middle = nonce;
835f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
836f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    std::string HA1 = MD5(sensitive);
837f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    memset(sensitive, 0, len);
838f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    delete [] sensitive;
839f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    std::string HA2 = MD5(A2);
840f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    std::string dig_response = MD5(HA1 + ":" + middle + ":" + HA2);
841f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
842f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if TEST_DIGEST
8433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT(strcmp(dig_response.c_str(), DIGEST_RESPONSE) == 0);
844f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
845f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
846f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    std::stringstream ss;
847f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ss << auth_method;
848f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ss << " username=" << quote(username);
849f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ss << ", realm=" << quote(realm);
850f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ss << ", nonce=" << quote(nonce);
851f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ss << ", uri=" << quote(uri);
852f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (has_qop) {
853f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ss << ", qop=" << qop;
854f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ss << ", nc="  << ncount;
855f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ss << ", cnonce=" << quote(cnonce);
856f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
857f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ss << ", response=\"" << dig_response << "\"";
858f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (has_opaque) {
859f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ss << ", opaque=" << quote(opaque);
860f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
861f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    response = ss.str();
862f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return HAR_RESPONSE;
863f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
864f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
865f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#ifdef WIN32
866f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if 1
867f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  bool want_negotiate = (_stricmp(auth_method.c_str(), "negotiate") == 0);
868f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  bool want_ntlm = (_stricmp(auth_method.c_str(), "ntlm") == 0);
869f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // SPNEGO & NTLM
870f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (want_negotiate || want_ntlm) {
871f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    const size_t MAX_MESSAGE = 12000, MAX_SPN = 256;
872f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    char out_buf[MAX_MESSAGE], spn[MAX_SPN];
873f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
874f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#if 0 // Requires funky windows versions
875f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    DWORD len = MAX_SPN;
876f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (DsMakeSpn("HTTP", server.IPAsString().c_str(), NULL, server.port(),
877f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                  0, &len, spn) != ERROR_SUCCESS) {
878f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      LOG_F(WARNING) << "(Negotiate) - DsMakeSpn failed";
879f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      return HAR_IGNORE;
880f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
881f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#else
882f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    sprintfn(spn, MAX_SPN, "HTTP/%s", server.ToString().c_str());
883f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
884f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
885f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    SecBuffer out_sec;
886f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    out_sec.pvBuffer   = out_buf;
887f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    out_sec.cbBuffer   = sizeof(out_buf);
888f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    out_sec.BufferType = SECBUFFER_TOKEN;
889f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
890f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    SecBufferDesc out_buf_desc;
891f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    out_buf_desc.ulVersion = 0;
892f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    out_buf_desc.cBuffers  = 1;
893f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    out_buf_desc.pBuffers  = &out_sec;
894f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
895f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    const ULONG NEG_FLAGS_DEFAULT =
896f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      //ISC_REQ_ALLOCATE_MEMORY
897f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ISC_REQ_CONFIDENTIALITY
898f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      //| ISC_REQ_EXTENDED_ERROR
899f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      //| ISC_REQ_INTEGRITY
900f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      | ISC_REQ_REPLAY_DETECT
901f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      | ISC_REQ_SEQUENCE_DETECT
902f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      //| ISC_REQ_STREAM
903f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      //| ISC_REQ_USE_SUPPLIED_CREDS
904f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ;
905f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
906f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ::TimeStamp lifetime;
907f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    SECURITY_STATUS ret = S_OK;
908f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    ULONG ret_flags = 0, flags = NEG_FLAGS_DEFAULT;
909f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
910f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    bool specify_credentials = !username.empty();
911f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    size_t steps = 0;
912f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
913f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    //uint32 now = Time();
914f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
915f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    NegotiateAuthContext * neg = static_cast<NegotiateAuthContext *>(context);
916f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (neg) {
917f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      const size_t max_steps = 10;
918f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (++neg->steps >= max_steps) {
919f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        LOG(WARNING) << "AsyncHttpsProxySocket::Authenticate(Negotiate) too many retries";
920f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        return HAR_ERROR;
921f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
922f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      steps = neg->steps;
923f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
924f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      std::string challenge, decoded_challenge;
925f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (HttpHasNthAttribute(args, 1, &challenge, NULL)
926f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          && Base64::Decode(challenge, Base64::DO_STRICT,
927f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                            &decoded_challenge, NULL)) {
928f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        SecBuffer in_sec;
929f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        in_sec.pvBuffer   = const_cast<char *>(decoded_challenge.data());
930f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        in_sec.cbBuffer   = static_cast<unsigned long>(decoded_challenge.size());
931f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        in_sec.BufferType = SECBUFFER_TOKEN;
932f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
933f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        SecBufferDesc in_buf_desc;
934f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        in_buf_desc.ulVersion = 0;
935f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        in_buf_desc.cBuffers  = 1;
936f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        in_buf_desc.pBuffers  = &in_sec;
937f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
938f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        ret = InitializeSecurityContextA(&neg->cred, &neg->ctx, spn, flags, 0, SECURITY_NATIVE_DREP, &in_buf_desc, 0, &neg->ctx, &out_buf_desc, &ret_flags, &lifetime);
939f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        //LOG(INFO) << "$$$ InitializeSecurityContext @ " << TimeSince(now);
940f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (FAILED(ret)) {
941f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          LOG(LS_ERROR) << "InitializeSecurityContext returned: "
942f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                      << ErrorName(ret, SECURITY_ERRORS);
943f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          return HAR_ERROR;
944f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
945f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      } else if (neg->specified_credentials) {
946f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        // Try again with default credentials
947f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        specify_credentials = false;
948f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        delete context;
949f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        context = neg = 0;
950f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      } else {
951f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        return HAR_CREDENTIALS;
952f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
953f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
954f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
955f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (!neg) {
956f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      unsigned char userbuf[256], passbuf[256], domainbuf[16];
957f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      SEC_WINNT_AUTH_IDENTITY_A auth_id, * pauth_id = 0;
958f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (specify_credentials) {
959f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        memset(&auth_id, 0, sizeof(auth_id));
960f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        size_t len = password.GetLength()+1;
961f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        char * sensitive = new char[len];
962f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        password.CopyTo(sensitive, true);
963f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        std::string::size_type pos = username.find('\\');
964f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        if (pos == std::string::npos) {
965f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          auth_id.UserLength = static_cast<unsigned long>(
966f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            _min(sizeof(userbuf) - 1, username.size()));
967f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          memcpy(userbuf, username.c_str(), auth_id.UserLength);
968f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          userbuf[auth_id.UserLength] = 0;
969f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          auth_id.DomainLength = 0;
970f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          domainbuf[auth_id.DomainLength] = 0;
971f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          auth_id.PasswordLength = static_cast<unsigned long>(
972f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            _min(sizeof(passbuf) - 1, password.GetLength()));
973f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          memcpy(passbuf, sensitive, auth_id.PasswordLength);
974f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          passbuf[auth_id.PasswordLength] = 0;
975f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        } else {
976f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          auth_id.UserLength = static_cast<unsigned long>(
977f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            _min(sizeof(userbuf) - 1, username.size() - pos - 1));
978f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          memcpy(userbuf, username.c_str() + pos + 1, auth_id.UserLength);
979f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          userbuf[auth_id.UserLength] = 0;
980f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          auth_id.DomainLength = static_cast<unsigned long>(
981f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            _min(sizeof(domainbuf) - 1, pos));
982f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          memcpy(domainbuf, username.c_str(), auth_id.DomainLength);
983f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          domainbuf[auth_id.DomainLength] = 0;
984f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          auth_id.PasswordLength = static_cast<unsigned long>(
985f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch            _min(sizeof(passbuf) - 1, password.GetLength()));
986f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          memcpy(passbuf, sensitive, auth_id.PasswordLength);
987f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch          passbuf[auth_id.PasswordLength] = 0;
988f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        }
989f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        memset(sensitive, 0, len);
990f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        delete [] sensitive;
991f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        auth_id.User = userbuf;
992f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        auth_id.Domain = domainbuf;
993f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        auth_id.Password = passbuf;
994f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        auth_id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
995f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        pauth_id = &auth_id;
996f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        LOG(LS_VERBOSE) << "Negotiate protocol: Using specified credentials";
997f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      } else {
998f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        LOG(LS_VERBOSE) << "Negotiate protocol: Using default credentials";
999f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
1000f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
1001f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      CredHandle cred;
1002f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ret = AcquireCredentialsHandleA(0, want_negotiate ? NEGOSSP_NAME_A : NTLMSP_NAME_A, SECPKG_CRED_OUTBOUND, 0, pauth_id, 0, 0, &cred, &lifetime);
1003f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      //LOG(INFO) << "$$$ AcquireCredentialsHandle @ " << TimeSince(now);
1004f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (ret != SEC_E_OK) {
1005f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        LOG(LS_ERROR) << "AcquireCredentialsHandle error: "
1006f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                    << ErrorName(ret, SECURITY_ERRORS);
1007f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        return HAR_IGNORE;
1008f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
1009f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
1010f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      //CSecBufferBundle<5, CSecBufferBase::FreeSSPI> sb_out;
1011f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
1012f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      CtxtHandle ctx;
1013f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ret = InitializeSecurityContextA(&cred, 0, spn, flags, 0, SECURITY_NATIVE_DREP, 0, 0, &ctx, &out_buf_desc, &ret_flags, &lifetime);
1014f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      //LOG(INFO) << "$$$ InitializeSecurityContext @ " << TimeSince(now);
1015f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (FAILED(ret)) {
1016f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        LOG(LS_ERROR) << "InitializeSecurityContext returned: "
1017f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                    << ErrorName(ret, SECURITY_ERRORS);
1018f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        FreeCredentialsHandle(&cred);
1019f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        return HAR_IGNORE;
1020f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
1021f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
10223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      ASSERT(!context);
1023f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      context = neg = new NegotiateAuthContext(auth_method, cred, ctx);
1024f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      neg->specified_credentials = specify_credentials;
1025f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      neg->steps = steps;
1026f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
1027f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
1028f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if ((ret == SEC_I_COMPLETE_NEEDED) || (ret == SEC_I_COMPLETE_AND_CONTINUE)) {
1029f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      ret = CompleteAuthToken(&neg->ctx, &out_buf_desc);
1030f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      //LOG(INFO) << "$$$ CompleteAuthToken @ " << TimeSince(now);
1031f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      LOG(LS_VERBOSE) << "CompleteAuthToken returned: "
1032f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                      << ErrorName(ret, SECURITY_ERRORS);
1033f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      if (FAILED(ret)) {
1034f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch        return HAR_ERROR;
1035f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
1036f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
1037f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
1038f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    //LOG(INFO) << "$$$ NEGOTIATE took " << TimeSince(now) << "ms";
1039f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
1040f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    std::string decoded(out_buf, out_buf + out_sec.cbBuffer);
1041f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    response = auth_method;
1042f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    response.append(" ");
1043f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    response.append(Base64::Encode(decoded));
1044f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return HAR_RESPONSE;
1045f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
1046f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif
1047f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#endif // WIN32
1048f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
1049f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return HAR_IGNORE;
1050f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
1051f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
1052f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch//////////////////////////////////////////////////////////////////////
1053f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
1054f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} // namespace talk_base
1055