1/* 2 * Copyright (C) 2006 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 "ResourceResponse.h" 28 29#import "HTTPParsers.h" 30#import "WebCoreURLResponse.h" 31#import "WebCoreSystemInterface.h" 32#import <Foundation/Foundation.h> 33#import <limits> 34#import <wtf/StdLibExtras.h> 35 36@interface NSURLResponse (WebNSURLResponseDetails) 37- (NSTimeInterval)_calculatedExpiration; 38- (id)_initWithCFURLResponse:(CFURLResponseRef)response; 39- (CFURLResponseRef) _CFURLResponse; 40+ (id)_responseWithCFURLResponse:(CFURLResponseRef)response; 41@end 42 43 44namespace WebCore { 45 46void ResourceResponse::initNSURLResponse() const 47{ 48 // Work around a mistake in the NSURLResponse class - <rdar://problem/6875219>. 49 // The init function takes an NSInteger, even though the accessor returns a long long. 50 // For values that won't fit in an NSInteger, pass -1 instead. 51 NSInteger expectedContentLength; 52 if (m_expectedContentLength < 0 || m_expectedContentLength > std::numeric_limits<NSInteger>::max()) 53 expectedContentLength = -1; 54 else 55 expectedContentLength = static_cast<NSInteger>(m_expectedContentLength); 56 57 // FIXME: This creates a very incomplete NSURLResponse, which does not even have a status code. 58 59 m_nsResponse = adoptNS([[NSURLResponse alloc] initWithURL:m_url MIMEType:m_mimeType expectedContentLength:expectedContentLength textEncodingName:m_textEncodingName]); 60} 61 62#if USE(CFNETWORK) 63 64NSURLResponse *ResourceResponse::nsURLResponse() const 65{ 66 if (!m_nsResponse && !m_cfResponse && !m_isNull) { 67 initNSURLResponse(); 68 m_cfResponse = [m_nsResponse.get() _CFURLResponse]; 69 return m_nsResponse.get(); 70 } 71 72 if (!m_cfResponse) 73 return nil; 74 75 if (!m_nsResponse) 76 m_nsResponse = [NSURLResponse _responseWithCFURLResponse:m_cfResponse.get()]; 77 78 return m_nsResponse.get(); 79} 80 81ResourceResponse::ResourceResponse(NSURLResponse* nsResponse) 82 : m_initLevel(Uninitialized) 83 , m_platformResponseIsUpToDate(true) 84 , m_cfResponse([nsResponse _CFURLResponse]) 85 , m_nsResponse(nsResponse) 86{ 87 m_isNull = !nsResponse; 88} 89 90#else 91 92static NSString* const commonHeaderFields[] = { 93 @"Age", @"Cache-Control", @"Content-Type", @"Date", @"Etag", @"Expires", @"Last-Modified", @"Pragma" 94}; 95 96NSURLResponse *ResourceResponse::nsURLResponse() const 97{ 98 if (!m_nsResponse && !m_isNull) 99 initNSURLResponse(); 100 return m_nsResponse.get(); 101} 102 103void ResourceResponse::platformLazyInit(InitLevel initLevel) 104{ 105 if (m_initLevel >= initLevel) 106 return; 107 108 if (m_isNull || !m_nsResponse) 109 return; 110 111 if (m_initLevel < CommonFieldsOnly && initLevel >= CommonFieldsOnly) { 112 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 113 114 m_httpHeaderFields.clear(); 115 m_url = [m_nsResponse.get() URL]; 116 m_mimeType = [m_nsResponse.get() MIMEType]; 117 m_expectedContentLength = [m_nsResponse.get() expectedContentLength]; 118 m_textEncodingName = [m_nsResponse.get() textEncodingName]; 119 120 // Workaround for <rdar://problem/8757088>, can be removed once that is fixed. 121 unsigned textEncodingNameLength = m_textEncodingName.length(); 122 if (textEncodingNameLength >= 2 && m_textEncodingName[0U] == '"' && m_textEncodingName[textEncodingNameLength - 1] == '"') 123 m_textEncodingName = m_textEncodingName.string().substring(1, textEncodingNameLength - 2); 124 125 if ([m_nsResponse.get() isKindOfClass:[NSHTTPURLResponse class]]) { 126 NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)m_nsResponse.get(); 127 128 m_httpStatusCode = [httpResponse statusCode]; 129 130 NSDictionary *headers = [httpResponse allHeaderFields]; 131 132 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(commonHeaderFields); ++i) { 133 if (NSString* headerValue = [headers objectForKey:commonHeaderFields[i]]) 134 m_httpHeaderFields.set(String(commonHeaderFields[i]), headerValue); 135 } 136 } else 137 m_httpStatusCode = 0; 138 139 [pool drain]; 140 } 141 142 if (m_initLevel < CommonAndUncommonFields && initLevel >= CommonAndUncommonFields) { 143 if ([m_nsResponse.get() isKindOfClass:[NSHTTPURLResponse class]]) { 144 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 145 146 NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)m_nsResponse.get(); 147 148 RetainPtr<NSString> httpStatusLine = adoptNS(wkCopyNSURLResponseStatusLine(m_nsResponse.get())); 149 if (httpStatusLine) 150 m_httpStatusText = extractReasonPhraseFromHTTPStatusLine(httpStatusLine.get()); 151 else 152 m_httpStatusText = "OK"; 153 154 NSDictionary *headers = [httpResponse allHeaderFields]; 155 NSEnumerator *e = [headers keyEnumerator]; 156 while (NSString *name = [e nextObject]) 157 m_httpHeaderFields.set(String(name), [headers objectForKey:name]); 158 159 [pool drain]; 160 } 161 } 162 163 if (m_initLevel < AllFields && initLevel >= AllFields) 164 m_suggestedFilename = [m_nsResponse.get() suggestedFilename]; 165 166 m_initLevel = initLevel; 167} 168 169 170bool ResourceResponse::platformCompare(const ResourceResponse& a, const ResourceResponse& b) 171{ 172 return a.nsURLResponse() == b.nsURLResponse(); 173} 174 175#endif // USE(CFNETWORK) 176 177#if PLATFORM(COCOA) || USE(CFNETWORK) 178 179void ResourceResponse::setCertificateChain(CFArrayRef certificateChain) 180{ 181 ASSERT(!wkCopyNSURLResponseCertificateChain(nsURLResponse())); 182 m_externalCertificateChain = certificateChain; 183} 184 185RetainPtr<CFArrayRef> ResourceResponse::certificateChain() const 186{ 187 if (m_externalCertificateChain) 188 return m_externalCertificateChain; 189 190 return adoptCF(wkCopyNSURLResponseCertificateChain(nsURLResponse())); 191} 192 193#endif // PLATFORM(COCOA) || USE(CFNETWORK) 194 195} // namespace WebCore 196 197