| /* |
| * 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 = ceil([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; |
| |
| return name == other.name |
| && value == other.value |
| && domain == other.domain |
| && path == other.path |
| && created == other.created |
| && expires == other.expires |
| && httpOnly == other.httpOnly |
| && secure == other.secure |
| && session == other.session |
| && comment == other.comment |
| && commentURL == other.commentURL |
| && ports == other.ports; |
| } |
| |
| unsigned Cookie::hash() const |
| { |
| ASSERT(!name.isHashTableDeletedValue()); |
| ASSERT(!isNull()); |
| NSHTTPCookie *nsCookie(*this); |
| return nsCookie.hash; |
| } |
| |
| } // namespace WebCore |