initial import
[vuplus_webkit] / Source / WebKit / win / WebURLResponse.cpp
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