1/* 2 * Copyright (C) 2006, 2007 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#include "config.h" 27#include "ResourceResponse.h" 28 29#if USE(CFNETWORK) 30 31#include "HTTPParsers.h" 32#include "MIMETypeRegistry.h" 33#include <CFNetwork/CFURLResponsePriv.h> 34#include <wtf/RetainPtr.h> 35 36// We would like a better value for a maximum time_t, 37// but there is no way to do that in C with any certainty. 38// INT_MAX should work well enough for our purposes. 39#define MAX_TIME_T ((time_t)INT_MAX) 40 41namespace WebCore { 42 43static CFStringRef const commonHeaderFields[] = { 44 CFSTR("Age"), CFSTR("Cache-Control"), CFSTR("Content-Type"), CFSTR("Date"), CFSTR("Etag"), CFSTR("Expires"), CFSTR("Last-Modified"), CFSTR("Pragma") 45}; 46static const int numCommonHeaderFields = sizeof(commonHeaderFields) / sizeof(CFStringRef); 47 48CFURLResponseRef ResourceResponse::cfURLResponse() const 49{ 50 if (!m_cfResponse && !m_isNull) { 51 RetainPtr<CFURLRef> url = m_url.createCFURL(); 52 53 // FIXME: This creates a very incomplete CFURLResponse, which does not even have a status code. 54 55 m_cfResponse = adoptCF(CFURLResponseCreate(0, url.get(), m_mimeType.string().createCFString().get(), m_expectedContentLength, m_textEncodingName.string().createCFString().get(), kCFURLCacheStorageAllowed)); 56 } 57 58 return m_cfResponse.get(); 59} 60 61void ResourceResponse::platformLazyInit(InitLevel initLevel) 62{ 63 if (m_initLevel > initLevel) 64 return; 65 66 if (m_isNull || !m_cfResponse.get()) 67 return; 68 69 if (m_initLevel < CommonFieldsOnly && initLevel >= CommonFieldsOnly) { 70 m_url = CFURLResponseGetURL(m_cfResponse.get()); 71 m_mimeType = CFURLResponseGetMIMEType(m_cfResponse.get()); 72 m_expectedContentLength = CFURLResponseGetExpectedContentLength(m_cfResponse.get()); 73 m_textEncodingName = CFURLResponseGetTextEncodingName(m_cfResponse.get()); 74 75 // Workaround for <rdar://problem/8757088>, can be removed once that is fixed. 76 unsigned textEncodingNameLength = m_textEncodingName.length(); 77 if (textEncodingNameLength >= 2 && m_textEncodingName[0U] == '"' && m_textEncodingName[textEncodingNameLength - 1] == '"') 78 m_textEncodingName = m_textEncodingName.string().substring(1, textEncodingNameLength - 2); 79 80 CFHTTPMessageRef httpResponse = CFURLResponseGetHTTPResponse(m_cfResponse.get()); 81 if (httpResponse) { 82 m_httpStatusCode = CFHTTPMessageGetResponseStatusCode(httpResponse); 83 84 RetainPtr<CFDictionaryRef> headers = adoptCF(CFHTTPMessageCopyAllHeaderFields(httpResponse)); 85 86 for (int i = 0; i < numCommonHeaderFields; i++) { 87 CFStringRef value; 88 if (CFDictionaryGetValueIfPresent(headers.get(), commonHeaderFields[i], (const void **)&value)) 89 m_httpHeaderFields.set(commonHeaderFields[i], value); 90 } 91 } else 92 m_httpStatusCode = 0; 93 } 94 95 if (m_initLevel < CommonAndUncommonFields && initLevel >= CommonAndUncommonFields) { 96 CFHTTPMessageRef httpResponse = CFURLResponseGetHTTPResponse(m_cfResponse.get()); 97 if (httpResponse) { 98 RetainPtr<CFStringRef> statusLine = adoptCF(CFHTTPMessageCopyResponseStatusLine(httpResponse)); 99 m_httpStatusText = extractReasonPhraseFromHTTPStatusLine(statusLine.get()); 100 101 RetainPtr<CFDictionaryRef> headers = adoptCF(CFHTTPMessageCopyAllHeaderFields(httpResponse)); 102 CFIndex headerCount = CFDictionaryGetCount(headers.get()); 103 Vector<const void*, 128> keys(headerCount); 104 Vector<const void*, 128> values(headerCount); 105 CFDictionaryGetKeysAndValues(headers.get(), keys.data(), values.data()); 106 for (int i = 0; i < headerCount; ++i) 107 m_httpHeaderFields.set((CFStringRef)keys[i], (CFStringRef)values[i]); 108 } 109 } 110 111 if (m_initLevel < AllFields && initLevel >= AllFields) { 112 RetainPtr<CFStringRef> suggestedFilename = adoptCF(CFURLResponseCopySuggestedFilename(m_cfResponse.get())); 113 m_suggestedFilename = suggestedFilename.get(); 114 } 115 116 m_initLevel = initLevel; 117} 118 119bool ResourceResponse::platformCompare(const ResourceResponse& a, const ResourceResponse& b) 120{ 121 // CFEqual crashes if you pass it 0 so do an early check before calling it. 122 if (!a.cfURLResponse() || !b.cfURLResponse()) 123 return a.cfURLResponse() == b.cfURLResponse(); 124 return CFEqual(a.cfURLResponse(), b.cfURLResponse()); 125} 126 127 128} // namespace WebCore 129 130#endif // USE(CFNETWORK) 131