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 #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