1/* 2 * Copyright (C) 2006, 2007, 2008 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 COMPUTER, 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 COMPUTER, 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#import "FormDataStreamMac.h" 30#import "ResourceRequestCFNet.h" 31#import "RuntimeApplicationChecks.h" 32#import "WebCoreSystemInterface.h" 33#import <wtf/text/CString.h> 34 35#import <Foundation/Foundation.h> 36 37 38@interface NSURLRequest (WebNSURLRequestDetails) 39- (NSArray *)contentDispositionEncodingFallbackArray; 40+ (void)setDefaultTimeoutInterval:(NSTimeInterval)seconds; 41- (CFURLRequestRef)_CFURLRequest; 42- (id)_initWithCFURLRequest:(CFURLRequestRef)request; 43@end 44 45@interface NSMutableURLRequest (WebMutableNSURLRequestDetails) 46- (void)setContentDispositionEncodingFallbackArray:(NSArray *)theEncodingFallbackArray; 47@end 48 49namespace WebCore { 50 51NSURLRequest *ResourceRequest::nsURLRequest(HTTPBodyUpdatePolicy bodyPolicy) const 52{ 53 updatePlatformRequest(bodyPolicy); 54 55 return [[m_nsRequest.get() retain] autorelease]; 56} 57 58#if USE(CFNETWORK) 59 60ResourceRequest::ResourceRequest(NSURLRequest *nsRequest) 61 : ResourceRequestBase() 62 , m_cfRequest([nsRequest _CFURLRequest]) 63 , m_nsRequest(nsRequest) 64{ 65} 66 67void ResourceRequest::updateNSURLRequest() 68{ 69 if (m_cfRequest) 70 m_nsRequest = adoptNS([[NSURLRequest alloc] _initWithCFURLRequest:m_cfRequest.get()]); 71} 72 73#else 74 75CFURLRequestRef ResourceRequest::cfURLRequest(HTTPBodyUpdatePolicy bodyPolicy) const 76{ 77 return [nsURLRequest(bodyPolicy) _CFURLRequest]; 78} 79 80void ResourceRequest::doUpdateResourceRequest() 81{ 82 m_url = [m_nsRequest.get() URL]; 83 m_cachePolicy = (ResourceRequestCachePolicy)[m_nsRequest.get() cachePolicy]; 84 m_timeoutInterval = [m_nsRequest.get() timeoutInterval]; 85 m_firstPartyForCookies = [m_nsRequest.get() mainDocumentURL]; 86 87 if (NSString* method = [m_nsRequest.get() HTTPMethod]) 88 m_httpMethod = method; 89 m_allowCookies = [m_nsRequest.get() HTTPShouldHandleCookies]; 90 91#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 92 if (ResourceRequest::httpPipeliningEnabled()) 93 m_priority = toResourceLoadPriority(wkGetHTTPPipeliningPriority([m_nsRequest.get() _CFURLRequest])); 94#endif 95 96 NSDictionary *headers = [m_nsRequest.get() allHTTPHeaderFields]; 97 NSEnumerator *e = [headers keyEnumerator]; 98 NSString *name; 99 m_httpHeaderFields.clear(); 100 while ((name = [e nextObject])) 101 m_httpHeaderFields.set(name, [headers objectForKey:name]); 102 103 m_responseContentDispositionEncodingFallbackArray.clear(); 104 NSArray *encodingFallbacks = [m_nsRequest.get() contentDispositionEncodingFallbackArray]; 105 NSUInteger count = [encodingFallbacks count]; 106 for (NSUInteger i = 0; i < count; ++i) { 107 CFStringEncoding encoding = CFStringConvertNSStringEncodingToEncoding([(NSNumber *)[encodingFallbacks objectAtIndex:i] unsignedLongValue]); 108 if (encoding != kCFStringEncodingInvalidId) 109 m_responseContentDispositionEncodingFallbackArray.append(CFStringConvertEncodingToIANACharSetName(encoding)); 110 } 111 112#if ENABLE(CACHE_PARTITIONING) 113 NSString* cachePartition = [NSURLProtocol propertyForKey:(NSString *)wkCachePartitionKey() inRequest:m_nsRequest.get()]; 114 if (cachePartition) 115 m_cachePartition = cachePartition; 116#endif 117} 118 119void ResourceRequest::doUpdateResourceHTTPBody() 120{ 121 if (NSData* bodyData = [m_nsRequest.get() HTTPBody]) 122 m_httpBody = FormData::create([bodyData bytes], [bodyData length]); 123 else if (NSInputStream* bodyStream = [m_nsRequest.get() HTTPBodyStream]) { 124 FormData* formData = httpBodyFromStream(bodyStream); 125 // There is no FormData object if a client provided a custom data stream. 126 // We shouldn't be looking at http body after client callbacks. 127 ASSERT(formData); 128 if (formData) 129 m_httpBody = formData; 130 } 131} 132 133void ResourceRequest::doUpdatePlatformRequest() 134{ 135 if (isNull()) { 136 m_nsRequest = nil; 137 return; 138 } 139 140 NSMutableURLRequest *nsRequest = [m_nsRequest.get() mutableCopy]; 141 142 if (nsRequest) 143 [nsRequest setURL:url()]; 144 else 145 nsRequest = [[NSMutableURLRequest alloc] initWithURL:url()]; 146 147 148#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 149 if (ResourceRequest::httpPipeliningEnabled()) 150 wkSetHTTPPipeliningPriority([nsRequest _CFURLRequest], toHTTPPipeliningPriority(m_priority)); 151#endif 152 153 [nsRequest setCachePolicy:(NSURLRequestCachePolicy)cachePolicy()]; 154#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 155 wkCFURLRequestAllowAllPostCaching([nsRequest _CFURLRequest]); 156#endif 157 158 double timeoutInterval = ResourceRequestBase::timeoutInterval(); 159 if (timeoutInterval) 160 [nsRequest setTimeoutInterval:timeoutInterval]; 161 // Otherwise, respect NSURLRequest default timeout. 162 163 [nsRequest setMainDocumentURL:firstPartyForCookies()]; 164 if (!httpMethod().isEmpty()) 165 [nsRequest setHTTPMethod:httpMethod()]; 166 [nsRequest setHTTPShouldHandleCookies:allowCookies()]; 167 168 // Cannot just use setAllHTTPHeaderFields here, because it does not remove headers. 169 NSArray *oldHeaderFieldNames = [[nsRequest allHTTPHeaderFields] allKeys]; 170 for (unsigned i = [oldHeaderFieldNames count]; i != 0; --i) 171 [nsRequest setValue:nil forHTTPHeaderField:[oldHeaderFieldNames objectAtIndex:i - 1]]; 172 HTTPHeaderMap::const_iterator end = httpHeaderFields().end(); 173 for (HTTPHeaderMap::const_iterator it = httpHeaderFields().begin(); it != end; ++it) 174 [nsRequest setValue:it->value forHTTPHeaderField:it->key]; 175 176#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 177 // Workaround for <rdar://problem/16848509> 178 if (url().host().contains('%')) 179 [nsRequest setValue:url().host() forHTTPHeaderField:@"Host"]; 180#endif 181 182 NSMutableArray *encodingFallbacks = [NSMutableArray array]; 183 unsigned count = m_responseContentDispositionEncodingFallbackArray.size(); 184 for (unsigned i = 0; i != count; ++i) { 185 RetainPtr<CFStringRef> encodingName = m_responseContentDispositionEncodingFallbackArray[i].createCFString(); 186 unsigned long nsEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName.get())); 187 188 if (nsEncoding != kCFStringEncodingInvalidId) 189 [encodingFallbacks addObject:[NSNumber numberWithUnsignedLong:nsEncoding]]; 190 } 191 [nsRequest setContentDispositionEncodingFallbackArray:encodingFallbacks]; 192 193#if ENABLE(CACHE_PARTITIONING) 194 String partition = cachePartition(); 195 if (!partition.isNull() && !partition.isEmpty()) { 196 NSString *partitionValue = [NSString stringWithUTF8String:partition.utf8().data()]; 197 [NSURLProtocol setProperty:partitionValue forKey:(NSString *)wkCachePartitionKey() inRequest:nsRequest]; 198 } 199#endif 200 201 m_nsRequest = adoptNS(nsRequest); 202} 203 204void ResourceRequest::doUpdatePlatformHTTPBody() 205{ 206 if (isNull()) { 207 ASSERT(!m_nsRequest); 208 return; 209 } 210 211 NSMutableURLRequest *nsRequest = [m_nsRequest.get() mutableCopy]; 212 213 if (nsRequest) 214 [nsRequest setURL:url()]; 215 else 216 nsRequest = [[NSMutableURLRequest alloc] initWithURL:url()]; 217 218 RefPtr<FormData> formData = httpBody(); 219 if (formData && !formData->isEmpty()) 220 WebCore::setHTTPBody(nsRequest, formData); 221 222 if (NSInputStream *bodyStream = [nsRequest HTTPBodyStream]) { 223 // For streams, provide a Content-Length to avoid using chunked encoding, and to get accurate total length in callbacks. 224 NSString *lengthString = [bodyStream propertyForKey:(NSString *)formDataStreamLengthPropertyName()]; 225 if (lengthString) { 226 [nsRequest setValue:lengthString forHTTPHeaderField:@"Content-Length"]; 227 // Since resource request is already marked updated, we need to keep it up to date too. 228 ASSERT(m_resourceRequestUpdated); 229 m_httpHeaderFields.set("Content-Length", lengthString); 230 } 231 } 232 233 m_nsRequest = adoptNS(nsRequest); 234} 235 236void ResourceRequest::updateFromDelegatePreservingOldHTTPBody(const ResourceRequest& delegateProvidedRequest) 237{ 238 RefPtr<FormData> oldHTTPBody = httpBody(); 239 240 *this = delegateProvidedRequest; 241 setHTTPBody(oldHTTPBody.release()); 242} 243 244void ResourceRequest::applyWebArchiveHackForMail() 245{ 246 // Hack because Mail checks for this property to detect data / archive loads 247 [NSURLProtocol setProperty:@"" forKey:@"WebDataRequest" inRequest:(NSMutableURLRequest *)nsURLRequest(DoNotUpdateHTTPBody)]; 248} 249 250void ResourceRequest::setStorageSession(CFURLStorageSessionRef storageSession) 251{ 252 updatePlatformRequest(); 253 m_nsRequest = adoptNS(wkCopyRequestWithStorageSession(storageSession, m_nsRequest.get())); 254} 255 256#endif // USE(CFNETWORK) 257 258static bool initQuickLookResourceCachingQuirks() 259{ 260 if (applicationIsSafari()) 261 return false; 262 263 NSArray* frameworks = [NSBundle allFrameworks]; 264 265 if (!frameworks) 266 return false; 267 268 for (unsigned int i = 0; i < [frameworks count]; i++) { 269 NSBundle* bundle = [frameworks objectAtIndex: i]; 270 const char* bundleID = [[bundle bundleIdentifier] UTF8String]; 271 if (bundleID && !strcasecmp(bundleID, "com.apple.QuickLookUIFramework")) 272 return true; 273 } 274 return false; 275} 276 277bool ResourceRequest::useQuickLookResourceCachingQuirks() 278{ 279 static bool flag = initQuickLookResourceCachingQuirks(); 280 return flag; 281} 282 283} // namespace WebCore 284 285