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 "WebURLResponse.h" 28 29 #include "WebKitDLL.h" 30 #include "WebKit.h" 31 32 #include "COMPropertyBag.h" 33 #include "MarshallingHelpers.h" 34 #include "WebLocalizableStrings.h" 35 36 #if USE(CFNETWORK) 37 #include <WebKitSystemInterface/WebKitSystemInterface.h> 38 #endif 39 40 #include <wtf/platform.h> 41 #pragma warning( push, 0 ) 42 #include <WebCore/BString.h> 43 #include <WebCore/KURL.h> 44 #include <WebCore/ResourceHandle.h> 45 #pragma warning( pop ) 46 #include <shlobj.h> 47 #include <shlwapi.h> 48 #include <tchar.h> 49 50 using namespace WebCore; 51 52 static LPCTSTR CFHTTPMessageCopyLocalizedShortDescriptionForStatusCode(CFIndex statusCode) 53 { 54 LPCTSTR result = 0; 55 if (statusCode < 100 || statusCode >= 600) 56 result = LPCTSTR_UI_STRING("server error", "HTTP result code string"); 57 else if (statusCode >= 100 && statusCode <= 199) { 58 switch (statusCode) { 59 case 100: 60 result = LPCTSTR_UI_STRING("continue", "HTTP result code string"); 61 break; 62 case 101: 63 result = LPCTSTR_UI_STRING("switching protocols", "HTTP result code string"); 64 break; 65 default: 66 result = LPCTSTR_UI_STRING("informational", "HTTP result code string"); 67 break; 68 } 69 } else if (statusCode >= 200 && statusCode <= 299) { 70 switch (statusCode) { 71 case 200: 72 result = LPCTSTR_UI_STRING("no error", "HTTP result code string"); 73 break; 74 case 201: 75 result = LPCTSTR_UI_STRING("created", "HTTP result code string"); 76 break; 77 case 202: 78 result = LPCTSTR_UI_STRING("accepted", "HTTP result code string"); 79 break; 80 case 203: 81 result = LPCTSTR_UI_STRING("non-authoritative information", "HTTP result code string"); 82 break; 83 case 204: 84 result = LPCTSTR_UI_STRING("no content", "HTTP result code string"); 85 break; 86 case 205: 87 result = LPCTSTR_UI_STRING("reset content", "HTTP result code string"); 88 break; 89 case 206: 90 result = LPCTSTR_UI_STRING("partial content", "HTTP result code string"); 91 break; 92 default: 93 result = LPCTSTR_UI_STRING("success", "HTTP result code string"); 94 break; 95 } 96 } else if (statusCode >= 300 && statusCode <= 399) { 97 switch (statusCode) { 98 case 300: 99 result = LPCTSTR_UI_STRING("multiple choices", "HTTP result code string"); 100 break; 101 case 301: 102 result = LPCTSTR_UI_STRING("moved permanently", "HTTP result code string"); 103 break; 104 case 302: 105 result = LPCTSTR_UI_STRING("found", "HTTP result code string"); 106 break; 107 case 303: 108 result = LPCTSTR_UI_STRING("see other", "HTTP result code string"); 109 break; 110 case 304: 111 result = LPCTSTR_UI_STRING("not modified", "HTTP result code string"); 112 break; 113 case 305: 114 result = LPCTSTR_UI_STRING("needs proxy", "HTTP result code string"); 115 break; 116 case 307: 117 result = LPCTSTR_UI_STRING("temporarily redirected", "HTTP result code string"); 118 break; 119 case 306: // 306 status code unused in HTTP 120 default: 121 result = LPCTSTR_UI_STRING("redirected", "HTTP result code string"); 122 break; 123 } 124 } else if (statusCode >= 400 && statusCode <= 499) { 125 switch (statusCode) { 126 case 400: 127 result = LPCTSTR_UI_STRING("bad request", "HTTP result code string"); 128 break; 129 case 401: 130 result = LPCTSTR_UI_STRING("unauthorized", "HTTP result code string"); 131 break; 132 case 402: 133 result = LPCTSTR_UI_STRING("payment required", "HTTP result code string"); 134 break; 135 case 403: 136 result = LPCTSTR_UI_STRING("forbidden", "HTTP result code string"); 137 break; 138 case 404: 139 result = LPCTSTR_UI_STRING("not found", "HTTP result code string"); 140 break; 141 case 405: 142 result = LPCTSTR_UI_STRING("method not allowed", "HTTP result code string"); 143 break; 144 case 406: 145 result = LPCTSTR_UI_STRING("unacceptable", "HTTP result code string"); 146 break; 147 case 407: 148 result = LPCTSTR_UI_STRING("proxy authentication required", "HTTP result code string"); 149 break; 150 case 408: 151 result = LPCTSTR_UI_STRING("request timed out", "HTTP result code string"); 152 break; 153 case 409: 154 result = LPCTSTR_UI_STRING("conflict", "HTTP result code string"); 155 break; 156 case 410: 157 result = LPCTSTR_UI_STRING("no longer exists", "HTTP result code string"); 158 break; 159 case 411: 160 result = LPCTSTR_UI_STRING("length required", "HTTP result code string"); 161 break; 162 case 412: 163 result = LPCTSTR_UI_STRING("precondition failed", "HTTP result code string"); 164 break; 165 case 413: 166 result = LPCTSTR_UI_STRING("request too large", "HTTP result code string"); 167 break; 168 case 414: 169 result = LPCTSTR_UI_STRING("requested URL too long", "HTTP result code string"); 170 break; 171 case 415: 172 result = LPCTSTR_UI_STRING("unsupported media type", "HTTP result code string"); 173 break; 174 case 416: 175 result = LPCTSTR_UI_STRING("requested range not satisfiable", "HTTP result code string"); 176 break; 177 case 417: 178 result = LPCTSTR_UI_STRING("expectation failed", "HTTP result code string"); 179 break; 180 default: 181 result = LPCTSTR_UI_STRING("client error", "HTTP result code string"); 182 break; 183 } 184 } else if (statusCode >= 500 && statusCode <= 599) { 185 switch (statusCode) { 186 case 500: 187 result = LPCTSTR_UI_STRING("internal server error", "HTTP result code string"); 188 break; 189 case 501: 190 result = LPCTSTR_UI_STRING("unimplemented", "HTTP result code string"); 191 break; 192 case 502: 193 result = LPCTSTR_UI_STRING("bad gateway", "HTTP result code string"); 194 break; 195 case 503: 196 result = LPCTSTR_UI_STRING("service unavailable", "HTTP result code string"); 197 break; 198 case 504: 199 result = LPCTSTR_UI_STRING("gateway timed out", "HTTP result code string"); 200 break; 201 case 505: 202 result = LPCTSTR_UI_STRING("unsupported version", "HTTP result code string"); 203 break; 204 default: 205 result = LPCTSTR_UI_STRING("server error", "HTTP result code string"); 206 break; 207 } 208 } 209 return result; 210 } 211 212 // IWebURLResponse ---------------------------------------------------------------- 213 214 WebURLResponse::WebURLResponse() 215 :m_refCount(0) 216 { 217 gClassCount++; 218 gClassNameCount.add("WebURLResponse"); 219 } 220 221 WebURLResponse::~WebURLResponse() 222 { 223 gClassCount--; 224 gClassNameCount.remove("WebURLResponse"); 225 } 226 227 WebURLResponse* WebURLResponse::createInstance() 228 { 229 WebURLResponse* instance = new WebURLResponse(); 230 // fake an http response - so it has the IWebHTTPURLResponse interface 231 instance->m_response = ResourceResponse(KURL(ParsedURLString, "http://"), String(), 0, String(), String()); 232 instance->AddRef(); 233 return instance; 234 } 235 236 WebURLResponse* WebURLResponse::createInstance(const ResourceResponse& response) 237 { 238 if (response.isNull()) 239 return 0; 240 241 WebURLResponse* instance = new WebURLResponse(); 242 instance->AddRef(); 243 instance->m_response = response; 244 245 return instance; 246 } 247 248 // IUnknown ------------------------------------------------------------------- 249 250 HRESULT STDMETHODCALLTYPE WebURLResponse::QueryInterface(REFIID riid, void** ppvObject) 251 { 252 *ppvObject = 0; 253 if (IsEqualGUID(riid, IID_IUnknown)) 254 *ppvObject = static_cast<IWebURLResponse*>(this); 255 else if (IsEqualGUID(riid, __uuidof(this))) 256 *ppvObject = this; 257 else if (IsEqualGUID(riid, IID_IWebURLResponse)) 258 *ppvObject = static_cast<IWebURLResponse*>(this); 259 else if (IsEqualGUID(riid, IID_IWebURLResponsePrivate)) 260 *ppvObject = static_cast<IWebURLResponsePrivate*>(this); 261 else if (m_response.isHTTP() && IsEqualGUID(riid, IID_IWebHTTPURLResponse)) 262 *ppvObject = static_cast<IWebHTTPURLResponse*>(this); 263 else 264 return E_NOINTERFACE; 265 266 AddRef(); 267 return S_OK; 268 } 269 270 ULONG STDMETHODCALLTYPE WebURLResponse::AddRef(void) 271 { 272 return ++m_refCount; 273 } 274 275 ULONG STDMETHODCALLTYPE WebURLResponse::Release(void) 276 { 277 ULONG newRef = --m_refCount; 278 if (!newRef) 279 delete(this); 280 281 return newRef; 282 } 283 284 // IWebURLResponse -------------------------------------------------------------------- 285 286 HRESULT STDMETHODCALLTYPE WebURLResponse::expectedContentLength( 287 /* [retval][out] */ long long* result) 288 { 289 *result = m_response.expectedContentLength(); 290 return S_OK; 291 } 292 293 HRESULT STDMETHODCALLTYPE WebURLResponse::initWithURL( 294 /* [in] */ BSTR url, 295 /* [in] */ BSTR mimeType, 296 /* [in] */ int expectedContentLength, 297 /* [in] */ BSTR textEncodingName) 298 { 299 m_response = ResourceResponse(MarshallingHelpers::BSTRToKURL(url), String(mimeType), expectedContentLength, String(textEncodingName), String()); 300 return S_OK; 301 } 302 303 HRESULT STDMETHODCALLTYPE WebURLResponse::MIMEType( 304 /* [retval][out] */ BSTR* result) 305 { 306 BString mimeType(m_response.mimeType()); 307 *result = mimeType.release(); 308 if (!m_response.mimeType().isNull() && !*result) 309 return E_OUTOFMEMORY; 310 311 return S_OK; 312 } 313 314 HRESULT STDMETHODCALLTYPE WebURLResponse::suggestedFilename( 315 /* [retval][out] */ BSTR* result) 316 { 317 if (!result) { 318 ASSERT_NOT_REACHED(); 319 return E_POINTER; 320 } 321 322 *result = 0; 323 324 if (m_response.url().isEmpty()) 325 return E_FAIL; 326 327 *result = BString(m_response.suggestedFilename()).release(); 328 return S_OK; 329 } 330 331 HRESULT STDMETHODCALLTYPE WebURLResponse::textEncodingName( 332 /* [retval][out] */ BSTR* result) 333 { 334 if (!result) 335 return E_INVALIDARG; 336 337 BString textEncodingName(m_response.textEncodingName()); 338 *result = textEncodingName.release(); 339 if (!m_response.textEncodingName().isNull() && !*result) 340 return E_OUTOFMEMORY; 341 342 return S_OK; 343 } 344 345 HRESULT STDMETHODCALLTYPE WebURLResponse::URL( 346 /* [retval][out] */ BSTR* result) 347 { 348 if (!result) 349 return E_INVALIDARG; 350 351 BString url(m_response.url().string()); 352 *result = url.release(); 353 if (!m_response.url().isEmpty() && !*result) 354 return E_OUTOFMEMORY; 355 356 return S_OK; 357 } 358 359 // IWebHTTPURLResponse -------------------------------------------------------- 360 361 HRESULT STDMETHODCALLTYPE WebURLResponse::allHeaderFields( 362 /* [retval][out] */ IPropertyBag** headerFields) 363 { 364 ASSERT(m_response.isHTTP()); 365 366 *headerFields = COMPropertyBag<String, AtomicString, CaseFoldingHash>::createInstance(m_response.httpHeaderFields()); 367 return S_OK; 368 } 369 370 HRESULT STDMETHODCALLTYPE WebURLResponse::localizedStringForStatusCode( 371 /* [in] */ int statusCode, 372 /* [retval][out] */ BSTR* statusString) 373 { 374 ASSERT(m_response.isHTTP()); 375 if (statusString) 376 *statusString = 0; 377 LPCTSTR statusText = CFHTTPMessageCopyLocalizedShortDescriptionForStatusCode(statusCode); 378 if (!statusText) 379 return E_FAIL; 380 if (statusString) 381 *statusString = SysAllocString(statusText); 382 return S_OK; 383 } 384 385 HRESULT STDMETHODCALLTYPE WebURLResponse::statusCode( 386 /* [retval][out] */ int* statusCode) 387 { 388 ASSERT(m_response.isHTTP()); 389 if (statusCode) 390 *statusCode = m_response.httpStatusCode(); 391 return S_OK; 392 } 393 394 HRESULT STDMETHODCALLTYPE WebURLResponse::isAttachment( 395 /* [retval][out] */ BOOL *attachment) 396 { 397 *attachment = m_response.isAttachment(); 398 return S_OK; 399 } 400 401 402 HRESULT STDMETHODCALLTYPE WebURLResponse::sslPeerCertificate( 403 /* [retval][out] */ OLE_HANDLE* result) 404 { 405 if (!result) 406 return E_POINTER; 407 *result = 0; 408 409 #if USE(CFNETWORK) 410 CFDictionaryRef dict = certificateDictionary(); 411 if (!dict) 412 return E_FAIL; 413 void* data = wkGetSSLPeerCertificateData(dict); 414 if (!data) 415 return E_FAIL; 416 *result = (OLE_HANDLE)(ULONG64)data; 417 #endif 418 419 return *result ? S_OK : E_FAIL; 420 } 421 422 // WebURLResponse ------------------------------------------------------------- 423 424 HRESULT WebURLResponse::suggestedFileExtension(BSTR *result) 425 { 426 if (!result) 427 return E_POINTER; 428 429 *result = 0; 430 431 if (m_response.mimeType().isEmpty()) 432 return E_FAIL; 433 434 BString mimeType(m_response.mimeType()); 435 HKEY key; 436 LONG err = RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("MIME\\Database\\Content Type"), 0, KEY_QUERY_VALUE, &key); 437 if (!err) { 438 HKEY subKey; 439 err = RegOpenKeyEx(key, mimeType, 0, KEY_QUERY_VALUE, &subKey); 440 if (!err) { 441 DWORD keyType = REG_SZ; 442 TCHAR extension[MAX_PATH]; 443 DWORD keySize = sizeof(extension)/sizeof(extension[0]); 444 err = RegQueryValueEx(subKey, TEXT("Extension"), 0, &keyType, (LPBYTE)extension, &keySize); 445 if (!err && keyType != REG_SZ) 446 err = ERROR_INVALID_DATA; 447 if (err) { 448 // fallback handlers 449 if (!_tcscmp(mimeType, TEXT("text/html"))) { 450 _tcscpy(extension, TEXT(".html")); 451 err = 0; 452 } else if (!_tcscmp(mimeType, TEXT("application/xhtml+xml"))) { 453 _tcscpy(extension, TEXT(".xhtml")); 454 err = 0; 455 } else if (!_tcscmp(mimeType, TEXT("image/svg+xml"))) { 456 _tcscpy(extension, TEXT(".svg")); 457 err = 0; 458 } 459 } 460 if (!err) { 461 *result = SysAllocString(extension); 462 if (!*result) 463 err = ERROR_OUTOFMEMORY; 464 } 465 RegCloseKey(subKey); 466 } 467 RegCloseKey(key); 468 } 469 470 return HRESULT_FROM_WIN32(err); 471 } 472 473 const ResourceResponse& WebURLResponse::resourceResponse() const 474 { 475 return m_response; 476 } 477 478 #if USE(CFNETWORK) 479 CFDictionaryRef WebURLResponse::certificateDictionary() const 480 { 481 if (m_SSLCertificateInfo) 482 return m_SSLCertificateInfo.get(); 483 484 CFURLResponseRef cfResponse = m_response.cfURLResponse(); 485 if (!cfResponse) 486 return 0; 487 m_SSLCertificateInfo = wkGetSSLCertificateInfo(cfResponse); 488 return m_SSLCertificateInfo.get(); 489 } 490 #endif 491