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