4f99f06dd126ea7eb50bc28c2c4a32e32420c518
[WebKit-https.git] / Source / WebCore / platform / network / cocoa / CookieCocoa.mm
1 /*
2  * Copyright (C) 2015 Apple, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "Cookie.h"
28
29 namespace WebCore {
30
31 static Vector<uint16_t> portVectorFromList(NSArray<NSNumber *> *portList)
32 {
33     Vector<uint16_t> ports;
34     ports.reserveInitialCapacity(portList.count);
35
36     for (NSNumber *port : portList)
37         ports.uncheckedAppend(port.unsignedShortValue);
38
39     return ports;
40 }
41
42 static NSString *portStringFromVector(const Vector<uint16_t>& ports)
43 {
44     if (ports.isEmpty())
45         return nil;
46
47     auto *string = [NSMutableString stringWithCapacity:ports.size() * 5];
48
49     for (size_t i = 0; i < ports.size() - 1; ++i)
50         [string appendFormat:@"%" PRIu16 ", ", ports[i]];
51
52     [string appendFormat:@"%" PRIu16, ports.last()];
53
54     return string;
55 }
56
57 Cookie::Cookie(NSHTTPCookie *cookie)
58     : Cookie(cookie.name, cookie.value, cookie.domain, cookie.path, [cookie.expiresDate timeIntervalSince1970] * 1000.0,
59     cookie.HTTPOnly, cookie.secure, cookie.sessionOnly, cookie.comment, cookie.commentURL, portVectorFromList(cookie.portList))
60 {
61 }
62
63 Cookie::operator NSHTTPCookie *() const
64 {
65     if (isNull())
66         return nil;
67
68     // FIXME: existing APIs do not provide a way to set httpOnly without parsing headers from scratch.
69
70     NSMutableDictionary *properties = [NSMutableDictionary dictionaryWithCapacity:11];
71
72     if (!comment.isNull())
73         [properties setObject:(NSString *)comment forKey:NSHTTPCookieComment];
74
75     if (!commentURL.isNull())
76         [properties setObject:(NSURL *)commentURL forKey:NSHTTPCookieCommentURL];
77
78     if (!domain.isNull())
79         [properties setObject:(NSString *)domain forKey:NSHTTPCookieDomain];
80
81     if (!name.isNull())
82         [properties setObject:(NSString *)name forKey:NSHTTPCookieName];
83
84     if (!path.isNull())
85         [properties setObject:(NSString *)path forKey:NSHTTPCookiePath];
86
87     if (!value.isNull())
88         [properties setObject:(NSString *)value forKey:NSHTTPCookieValue];
89
90     NSDate *expirationDate = [NSDate dateWithTimeIntervalSince1970:expires / 1000.0];
91     auto maxAge = [expirationDate timeIntervalSinceNow];
92     if (maxAge > 0)
93         [properties setObject:[NSString stringWithFormat:@"%f", maxAge] forKey:NSHTTPCookieMaximumAge];
94
95     auto* portString = portStringFromVector(ports);
96     if (portString)
97         [properties setObject:portString forKey:NSHTTPCookiePort];
98
99     if (secure)
100         [properties setObject:@YES forKey:NSHTTPCookieSecure];
101
102     if (session)
103         [properties setObject:@YES forKey:NSHTTPCookieDiscard];
104
105     [properties setObject:@"1" forKey:NSHTTPCookieVersion];
106
107     return [NSHTTPCookie cookieWithProperties:properties];
108 }
109     
110 bool Cookie::operator==(const Cookie& other) const
111 {
112     ASSERT(!name.isHashTableDeletedValue());
113     bool thisNull = isNull();
114     bool otherNull = other.isNull();
115     if (thisNull || otherNull)
116         return thisNull == otherNull;
117     
118     NSHTTPCookie *nsCookie(*this);
119     return [nsCookie isEqual:other];
120 }
121     
122 unsigned Cookie::hash() const
123 {
124     ASSERT(!name.isHashTableDeletedValue());
125     ASSERT(!isNull());
126     NSHTTPCookie *nsCookie(*this);
127     return nsCookie.hash;
128 }
129
130 } // namespace WebCore