/* * Copyright (C) 2015 Apple, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "Cookie.h" namespace WebCore { static Vector<uint16_t> portVectorFromList(NSArray<NSNumber *> *portList) { Vector<uint16_t> ports; ports.reserveInitialCapacity(portList.count); for (NSNumber *port : portList) ports.uncheckedAppend(port.unsignedShortValue); return ports; } static NSString *portStringFromVector(const Vector<uint16_t>& ports) { if (ports.isEmpty()) return nil; auto *string = [NSMutableString stringWithCapacity:ports.size() * 5]; for (size_t i = 0; i < ports.size() - 1; ++i) [string appendFormat:@"%" PRIu16 ", ", ports[i]]; [string appendFormat:@"%" PRIu16, ports.last()]; return string; } static double cookieCreated(NSHTTPCookie *cookie) { id value = cookie.properties[@"Created"]; auto toCanonicalFormat = [](double referenceFormat) { return 1000.0 * (referenceFormat + NSTimeIntervalSince1970); }; if ([value isKindOfClass:[NSNumber class]]) return toCanonicalFormat(((NSNumber *)value).doubleValue); if ([value isKindOfClass:[NSString class]]) return toCanonicalFormat(((NSString *)value).doubleValue); return 0.0; } Cookie::Cookie(NSHTTPCookie *cookie) : Cookie(cookie.name, cookie.value, cookie.domain, cookie.path, cookieCreated(cookie), [cookie.expiresDate timeIntervalSince1970] * 1000.0, cookie.HTTPOnly, cookie.secure, cookie.sessionOnly, cookie.comment, cookie.commentURL, portVectorFromList(cookie.portList)) { } Cookie::operator NSHTTPCookie *() const { if (isNull()) return nil; // FIXME: existing APIs do not provide a way to set httpOnly without parsing headers from scratch. NSMutableDictionary *properties = [NSMutableDictionary dictionaryWithCapacity:11]; if (!comment.isNull()) [properties setObject:(NSString *)comment forKey:NSHTTPCookieComment]; if (!commentURL.isNull()) [properties setObject:(NSURL *)commentURL forKey:NSHTTPCookieCommentURL]; if (!domain.isNull()) [properties setObject:(NSString *)domain forKey:NSHTTPCookieDomain]; if (!name.isNull()) [properties setObject:(NSString *)name forKey:NSHTTPCookieName]; if (!path.isNull()) [properties setObject:(NSString *)path forKey:NSHTTPCookiePath]; if (!value.isNull()) [properties setObject:(NSString *)value forKey:NSHTTPCookieValue]; NSDate *expirationDate = [NSDate dateWithTimeIntervalSince1970:expires / 1000.0]; auto maxAge = [expirationDate timeIntervalSinceNow]; if (maxAge > 0) [properties setObject:[NSString stringWithFormat:@"%f", maxAge] forKey:NSHTTPCookieMaximumAge]; auto* portString = portStringFromVector(ports); if (portString) [properties setObject:portString forKey:NSHTTPCookiePort]; if (secure) [properties setObject:@YES forKey:NSHTTPCookieSecure]; if (session) [properties setObject:@YES forKey:NSHTTPCookieDiscard]; [properties setObject:@"1" forKey:NSHTTPCookieVersion]; return [NSHTTPCookie cookieWithProperties:properties]; } bool Cookie::operator==(const Cookie& other) const { ASSERT(!name.isHashTableDeletedValue()); bool thisNull = isNull(); bool otherNull = other.isNull(); if (thisNull || otherNull) return thisNull == otherNull; NSHTTPCookie *nsCookie(*this); return [nsCookie isEqual:other]; } unsigned Cookie::hash() const { ASSERT(!name.isHashTableDeletedValue()); ASSERT(!isNull()); NSHTTPCookie *nsCookie(*this); return nsCookie.hash; } } // namespace WebCore