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