Drop ResourceLoadPriorityUnresolved resource load priority and use Optional<> instead
[WebKit-https.git] / Source / WebCore / platform / network / cocoa / ResourceRequestCocoa.mm
1 /*
2  * Copyright (C) 2014 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 "ResourceRequest.h"
28
29 #if PLATFORM(COCOA)
30
31 #import "FormDataStreamMac.h"
32 #import "HTTPHeaderNames.h"
33 #import "ResourceRequestCFNet.h"
34 #import "RuntimeApplicationChecks.h"
35 #import "WebCoreSystemInterface.h"
36
37 #import <Foundation/Foundation.h>
38 #import <wtf/text/CString.h>
39
40 @interface NSURLRequest (WebNSURLRequestDetails)
41 - (NSArray *)contentDispositionEncodingFallbackArray;
42 + (void)setDefaultTimeoutInterval:(NSTimeInterval)seconds;
43 - (CFURLRequestRef)_CFURLRequest;
44 - (id)_initWithCFURLRequest:(CFURLRequestRef)request;
45 @end
46
47 @interface NSMutableURLRequest (WebMutableNSURLRequestDetails)
48 - (void)setContentDispositionEncodingFallbackArray:(NSArray *)theEncodingFallbackArray;
49 @end
50
51 namespace WebCore {
52
53 NSURLRequest *ResourceRequest::nsURLRequest(HTTPBodyUpdatePolicy bodyPolicy) const
54 {
55     updatePlatformRequest(bodyPolicy);
56 #if USE(CFNETWORK)
57     if (!m_nsRequest)
58         const_cast<ResourceRequest*>(this)->updateNSURLRequest();
59 #endif
60     return [[m_nsRequest.get() retain] autorelease];
61 }
62
63 #if !USE(CFNETWORK)
64
65 CFURLRequestRef ResourceRequest::cfURLRequest(HTTPBodyUpdatePolicy bodyPolicy) const
66 {
67     return [nsURLRequest(bodyPolicy) _CFURLRequest];
68 }
69
70 void ResourceRequest::doUpdateResourceRequest()
71 {
72     m_url = [m_nsRequest.get() URL];
73     m_cachePolicy = (ResourceRequestCachePolicy)[m_nsRequest.get() cachePolicy];
74     m_timeoutInterval = [m_nsRequest.get() timeoutInterval];
75     m_firstPartyForCookies = [m_nsRequest.get() mainDocumentURL];
76
77     if (NSString* method = [m_nsRequest.get() HTTPMethod])
78         m_httpMethod = method;
79     m_allowCookies = [m_nsRequest.get() HTTPShouldHandleCookies];
80
81     if (resourcePrioritiesEnabled())
82         m_priority = toResourceLoadPriority(wkGetHTTPRequestPriority([m_nsRequest.get() _CFURLRequest]));
83
84     m_httpHeaderFields.clear();
85     [[m_nsRequest allHTTPHeaderFields] enumerateKeysAndObjectsUsingBlock: ^(NSString *name, NSString *value, BOOL *) {
86         m_httpHeaderFields.set(name, value);
87     }];
88
89     m_responseContentDispositionEncodingFallbackArray.clear();
90     NSArray *encodingFallbacks = [m_nsRequest.get() contentDispositionEncodingFallbackArray];
91     m_responseContentDispositionEncodingFallbackArray.reserveCapacity([encodingFallbacks count]);
92     for (NSNumber *encodingFallback in [m_nsRequest contentDispositionEncodingFallbackArray]) {
93         CFStringEncoding encoding = CFStringConvertNSStringEncodingToEncoding([encodingFallback unsignedLongValue]);
94         if (encoding != kCFStringEncodingInvalidId)
95             m_responseContentDispositionEncodingFallbackArray.uncheckedAppend(CFStringConvertEncodingToIANACharSetName(encoding));
96     }
97
98 #if ENABLE(CACHE_PARTITIONING)
99     if (m_nsRequest) {
100         NSString* cachePartition = [NSURLProtocol propertyForKey:(NSString *)wkCachePartitionKey() inRequest:m_nsRequest.get()];
101         if (cachePartition)
102             m_cachePartition = cachePartition;
103     }
104 #endif
105 }
106
107 void ResourceRequest::doUpdateResourceHTTPBody()
108 {
109     if (NSData* bodyData = [m_nsRequest.get() HTTPBody])
110         m_httpBody = FormData::create([bodyData bytes], [bodyData length]);
111     else if (NSInputStream* bodyStream = [m_nsRequest.get() HTTPBodyStream]) {
112         FormData* formData = httpBodyFromStream(bodyStream);
113         // There is no FormData object if a client provided a custom data stream.
114         // We shouldn't be looking at http body after client callbacks.
115         ASSERT(formData);
116         if (formData)
117             m_httpBody = formData;
118     }
119 }
120
121 inline NSMutableURLRequest *ResourceRequest::ensureMutableNSURLRequest()
122 {
123     if (m_nsRequest) {
124         if (![m_nsRequest.get() isKindOfClass:[NSMutableURLRequest class]])
125             m_nsRequest = adoptNS([m_nsRequest.get() mutableCopy]);
126         [(NSMutableURLRequest *)m_nsRequest.get() setURL:url()];
127     } else
128         m_nsRequest = adoptNS([[NSMutableURLRequest alloc] initWithURL:url()]);
129     return (NSMutableURLRequest *)m_nsRequest.get();
130 }
131
132 void ResourceRequest::doUpdatePlatformRequest()
133 {
134     if (isNull()) {
135         m_nsRequest = nil;
136         return;
137     }
138
139     NSMutableURLRequest *nsRequest = ensureMutableNSURLRequest();
140
141     if (ResourceRequest::httpPipeliningEnabled())
142         wkHTTPRequestEnablePipelining([nsRequest _CFURLRequest]);
143
144     if (ResourceRequest::resourcePrioritiesEnabled())
145         wkSetHTTPRequestPriority([nsRequest _CFURLRequest], toPlatformRequestPriority(priority()));
146
147     [nsRequest setCachePolicy:(NSURLRequestCachePolicy)cachePolicy()];
148     wkCFURLRequestAllowAllPostCaching([nsRequest _CFURLRequest]);
149
150     double timeoutInterval = ResourceRequestBase::timeoutInterval();
151     if (timeoutInterval)
152         [nsRequest setTimeoutInterval:timeoutInterval];
153     // Otherwise, respect NSURLRequest default timeout.
154
155     [nsRequest setMainDocumentURL:firstPartyForCookies()];
156     if (!httpMethod().isEmpty())
157         [nsRequest setHTTPMethod:httpMethod()];
158     [nsRequest setHTTPShouldHandleCookies:allowCookies()];
159
160     // Cannot just use setAllHTTPHeaderFields here, because it does not remove headers.
161     for (NSString *oldHeaderName in [nsRequest allHTTPHeaderFields])
162         [nsRequest setValue:nil forHTTPHeaderField:oldHeaderName];
163     for (const auto& header : httpHeaderFields())
164         [nsRequest setValue:header.value forHTTPHeaderField:header.key];
165
166     NSMutableArray *encodingFallbacks = [NSMutableArray array];
167     for (const auto& encodingName : m_responseContentDispositionEncodingFallbackArray) {
168         CFStringEncoding nsEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName.createCFString().get()));
169         if (nsEncoding != kCFStringEncodingInvalidId)
170             [encodingFallbacks addObject:[NSNumber numberWithUnsignedLong:nsEncoding]];
171     }
172     [nsRequest setContentDispositionEncodingFallbackArray:encodingFallbacks];
173
174 #if ENABLE(CACHE_PARTITIONING)
175     String partition = cachePartition();
176     if (!partition.isNull() && !partition.isEmpty()) {
177         NSString *partitionValue = [NSString stringWithUTF8String:partition.utf8().data()];
178         [NSURLProtocol setProperty:partitionValue forKey:(NSString *)wkCachePartitionKey() inRequest:nsRequest];
179     }
180 #endif
181 }
182
183 void ResourceRequest::doUpdatePlatformHTTPBody()
184 {
185     if (isNull()) {
186         ASSERT(!m_nsRequest);
187         return;
188     }
189
190     NSMutableURLRequest *nsRequest = ensureMutableNSURLRequest();
191
192     RefPtr<FormData> formData = httpBody();
193     if (formData && !formData->isEmpty())
194         WebCore::setHTTPBody(nsRequest, formData);
195
196     if (NSInputStream *bodyStream = [nsRequest HTTPBodyStream]) {
197         // For streams, provide a Content-Length to avoid using chunked encoding, and to get accurate total length in callbacks.
198         NSString *lengthString = [bodyStream propertyForKey:(NSString *)formDataStreamLengthPropertyName()];
199         if (lengthString) {
200             [nsRequest setValue:lengthString forHTTPHeaderField:@"Content-Length"];
201             // Since resource request is already marked updated, we need to keep it up to date too.
202             ASSERT(m_resourceRequestUpdated);
203             m_httpHeaderFields.set(HTTPHeaderName::ContentLength, lengthString);
204         }
205     }
206 }
207
208 void ResourceRequest::updateFromDelegatePreservingOldProperties(const ResourceRequest& delegateProvidedRequest)
209 {
210     ResourceLoadPriority oldPriority = priority();
211     RefPtr<FormData> oldHTTPBody = httpBody();
212     bool isHiddenFromInspector = hiddenFromInspector();
213
214     *this = delegateProvidedRequest;
215
216     setPriority(oldPriority);
217     setHTTPBody(oldHTTPBody.release());
218     setHiddenFromInspector(isHiddenFromInspector);
219 }
220
221 #if !PLATFORM(IOS)
222 void ResourceRequest::applyWebArchiveHackForMail()
223 {
224     // Hack because Mail checks for this property to detect data / archive loads
225     [NSURLProtocol setProperty:@"" forKey:@"WebDataRequest" inRequest:(NSMutableURLRequest *)nsURLRequest(DoNotUpdateHTTPBody)];
226 }
227 #endif
228
229 void ResourceRequest::setStorageSession(CFURLStorageSessionRef storageSession)
230 {
231     updatePlatformRequest();
232     m_nsRequest = adoptNS(wkCopyRequestWithStorageSession(storageSession, m_nsRequest.get()));
233 }
234
235 #endif // USE(CFNETWORK)
236
237 } // namespace WebCore
238
239 #endif // PLATFORM(COCOA)
240