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 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 #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 using namespace std; 37 38 // We would like a better value for a maximum time_t, 39 // but there is no way to do that in C with any certainty. 40 // INT_MAX should work well enough for our purposes. 41 #define MAX_TIME_T ((time_t)INT_MAX) 42 43 namespace WebCore { 44 45 static CFStringRef const commonHeaderFields[] = { 46 CFSTR("Age"), CFSTR("Cache-Control"), CFSTR("Date"), CFSTR("Etag"), CFSTR("Expires"), CFSTR("Last-Modified"), CFSTR("Pragma") 47 }; 48 static const int numCommonHeaderFields = sizeof(commonHeaderFields) / sizeof(CFStringRef); 49 50 CFURLResponseRef ResourceResponse::cfURLResponse() const 51 { 52 if (!m_cfResponse && !m_isNull) { 53 RetainPtr<CFURLRef> url(AdoptCF, m_url.createCFURL()); 54 RetainPtr<CFStringRef> mimeType(AdoptCF, m_mimeType.createCFString()); 55 RetainPtr<CFStringRef> textEncodingName(AdoptCF, m_textEncodingName.createCFString()); 56 m_cfResponse.adoptCF(CFURLResponseCreate(0, url.get(), mimeType.get(), m_expectedContentLength, textEncodingName.get(), kCFURLCacheStorageAllowed)); 57 } 58 59 return m_cfResponse.get(); 60 } 61 62 static inline bool filenameHasSaneExtension(const String& filename) 63 { 64 int dot = filename.find('.'); 65 66 // The dot can't be the first or last character in the filename. 67 int length = filename.length(); 68 return dot > 0 && dot < length - 1; 69 } 70 71 static time_t toTimeT(CFAbsoluteTime time) 72 { 73 static const double maxTimeAsDouble = std::numeric_limits<time_t>::max(); 74 static const double minTimeAsDouble = std::numeric_limits<time_t>::min(); 75 return min(max(minTimeAsDouble, time + kCFAbsoluteTimeIntervalSince1970), maxTimeAsDouble); 76 } 77 78 void ResourceResponse::platformLazyInit(InitLevel initLevel) 79 { 80 if (m_initLevel > initLevel) 81 return; 82 83 if (m_isNull) { 84 ASSERT(!m_cfResponse.get()); 85 return; 86 } 87 88 if (m_initLevel < CommonFieldsOnly && initLevel >= CommonFieldsOnly) { 89 m_url = CFURLResponseGetURL(m_cfResponse.get()); 90 m_mimeType = CFURLResponseGetMIMEType(m_cfResponse.get()); 91 m_expectedContentLength = CFURLResponseGetExpectedContentLength(m_cfResponse.get()); 92 m_textEncodingName = CFURLResponseGetTextEncodingName(m_cfResponse.get()); 93 94 // Workaround for <rdar://problem/8757088>, can be removed once that is fixed. 95 unsigned textEncodingNameLength = m_textEncodingName.length(); 96 if (textEncodingNameLength >= 2 && m_textEncodingName[0U] == '"' && m_textEncodingName[textEncodingNameLength - 1] == '"') 97 m_textEncodingName = m_textEncodingName.substring(1, textEncodingNameLength - 2); 98 99 m_lastModifiedDate = toTimeT(CFURLResponseGetLastModifiedDate(m_cfResponse.get())); 100 101 RetainPtr<CFStringRef> suggestedFilename(AdoptCF, CFURLResponseCopySuggestedFilename(m_cfResponse.get())); 102 m_suggestedFilename = suggestedFilename.get(); 103 104 CFHTTPMessageRef httpResponse = CFURLResponseGetHTTPResponse(m_cfResponse.get()); 105 if (httpResponse) { 106 m_httpStatusCode = CFHTTPMessageGetResponseStatusCode(httpResponse); 107 108 RetainPtr<CFDictionaryRef> headers(AdoptCF, CFHTTPMessageCopyAllHeaderFields(httpResponse)); 109 110 for (int i = 0; i < numCommonHeaderFields; i++) { 111 CFStringRef value; 112 if (CFDictionaryGetValueIfPresent(headers.get(), commonHeaderFields[i], (const void **)&value)) 113 m_httpHeaderFields.set(commonHeaderFields[i], value); 114 } 115 } else 116 m_httpStatusCode = 0; 117 } 118 119 if (m_initLevel < AllFields && initLevel >= AllFields) { 120 CFHTTPMessageRef httpResponse = CFURLResponseGetHTTPResponse(m_cfResponse.get()); 121 if (httpResponse) { 122 RetainPtr<CFStringRef> statusLine(AdoptCF, CFHTTPMessageCopyResponseStatusLine(httpResponse)); 123 m_httpStatusText = extractReasonPhraseFromHTTPStatusLine(statusLine.get()); 124 125 RetainPtr<CFDictionaryRef> headers(AdoptCF, CFHTTPMessageCopyAllHeaderFields(httpResponse)); 126 CFIndex headerCount = CFDictionaryGetCount(headers.get()); 127 Vector<const void*, 128> keys(headerCount); 128 Vector<const void*, 128> values(headerCount); 129 CFDictionaryGetKeysAndValues(headers.get(), keys.data(), values.data()); 130 for (int i = 0; i < headerCount; ++i) 131 m_httpHeaderFields.set((CFStringRef)keys[i], (CFStringRef)values[i]); 132 } 133 } 134 135 m_initLevel = initLevel; 136 } 137 138 bool ResourceResponse::platformCompare(const ResourceResponse& a, const ResourceResponse& b) 139 { 140 return CFEqual(a.cfURLResponse(), b.cfURLResponse()); 141 } 142 143 144 } // namespace WebCore 145 146 #endif // USE(CFNETWORK) 147