1/* 2 * Copyright (C) 2008, 2009 Julien Chaffraix <julien.chaffraix@gmail.com> 3 * Copyright (C) 2011, 2012 Research In Motion Limited. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28#include "ParsedCookie.h" 29 30#include "CookieManager.h" 31#include "KURL.h" 32#include "Logging.h" 33#include <curl/curl.h> 34#include <wtf/CurrentTime.h> 35#include <wtf/text/CString.h> 36#include <wtf/text/StringBuilder.h> 37 38namespace WebCore { 39 40ParsedCookie::ParsedCookie(double currentTime) 41 : m_expiry(-1) 42 , m_creationTime(currentTime) 43 , m_lastAccessed(currentTime) 44 , m_isSecure(false) 45 , m_isHttpOnly(false) 46 , m_isSession(true) 47 , m_isForceExpired(false) 48 , m_domainIsIPAddress(false) 49{ 50} 51 52ParsedCookie::ParsedCookie(const String& name, const String& value, const String& domain, const String& protocol, const String& path, double expiry, double lastAccessed, double creationTime, bool isSecure, bool isHttpOnly) 53 : m_name(name) 54 , m_value(value) 55 , m_domain(domain) 56 , m_protocol(protocol) 57 , m_path(path) 58 , m_expiry(expiry) 59 , m_creationTime(creationTime) 60 , m_lastAccessed(lastAccessed) 61 , m_isSecure(isSecure) 62 , m_isHttpOnly(isHttpOnly) 63 , m_isSession(false) 64 , m_isForceExpired(false) 65 , m_domainIsIPAddress(false) 66{ 67} 68 69void ParsedCookie::setExpiry(const String& expiry) 70{ 71 // If a cookie has both the Max-Age and the Expires attribute, 72 // the Max-Age attribute has precedence and controls the expiration date of the cookie. 73 if (m_expiry != -1 || expiry.isEmpty()) 74 return; 75 76 m_isSession = false; 77 78 m_expiry = static_cast<double>(curl_getdate(expiry.utf8().data(), 0)); 79 80 if (m_expiry == -1) { 81 LOG_ERROR("Could not parse date"); 82 // In this case, consider that the cookie is session only 83 m_isSession = true; 84 } 85} 86 87void ParsedCookie::setMaxAge(const String& maxAge) 88{ 89 // According to the HTTP Cookie specification (RFC6265, http://tools.ietf.org/html/rfc6265), 90 // the first character can be a DIGIT or a "-", and the reminder 91 // of the value can only contain DIGIT characters. 92 if (maxAge.isEmpty() || (maxAge[0] != '-' && !isASCIIDigit(maxAge[0]))) { 93 LOG_ERROR("Could not parse Max-Age : %s, first character can only be '-' or ascii digit.", maxAge.ascii().data()); 94 return; 95 } 96 97 bool ok; 98 int value = maxAge.toIntStrict(&ok); 99 100 if (!ok) { 101 LOG_ERROR("Could not parse Max-Age : %s", maxAge.ascii().data()); 102 return; 103 } 104 m_expiry = value; 105 m_isSession = false; 106 107 // If maxAge value is not positive, let expiry-time be the earliest representable time. 108 if (m_expiry > 0) 109 m_expiry += currentTime(); 110 else 111 m_expiry = 0; 112} 113 114bool ParsedCookie::hasExpired() const 115{ 116 // Session cookies do not expire, they will just not be saved to the backing store. 117 return !m_isSession && (m_isForceExpired || m_expiry < currentTime()); 118} 119 120bool ParsedCookie::isUnderSizeLimit() const 121{ 122 return m_value.length() <= CookieManager::maxCookieLength() && m_name.length() <= CookieManager::maxCookieLength(); 123} 124 125String ParsedCookie::toString() const 126{ 127 StringBuilder builder; 128 builder.append(name()); 129 builder.append(" = "); 130 builder.append(value()); 131 builder.append("; Domain = "); 132 builder.append(domain()); 133 builder.append("; Path = "); 134 builder.append(path()); 135 builder.append("; Protocol = "); 136 builder.append(protocol()); 137 return builder.toString(); 138} 139 140String ParsedCookie::toNameValuePair() const 141{ 142 static const String equal("="); 143 144 size_t cookieLength = m_name.length() + m_value.length() + 2; 145 Vector<UChar> result; 146 result.reserveInitialCapacity(cookieLength); 147 append(result, m_name); 148 append(result, equal); 149 append(result, m_value); 150 151 return String::adopt(result); 152} 153 154void ParsedCookie::appendWebCoreCookie(Vector<Cookie>& cookieVector) const 155{ 156 cookieVector.append(Cookie(String(m_name), String(m_value), String(m_domain), 157 // We multiply m_expiry by 1000 to convert from seconds to milliseconds. 158 // This value is passed to Web Inspector and used in the JavaScript Date constructor. 159 String(m_path), (m_expiry * 1000), m_isHttpOnly, m_isSecure, m_isSession)); 160} 161} // namespace WebCore 162