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