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