Progress towards building AppleWin with CMake
[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 "WebURLResponse.h"
27
28 #include "WebKitDLL.h"
29 #include "WebKit.h"
30
31 #include "COMPropertyBag.h"
32 #include "MarshallingHelpers.h"
33
34 #if USE(CG)
35 #include <CoreGraphics/CoreGraphics.h>
36 #endif
37
38 #if USE(CFNETWORK)
39 #include <WebKitSystemInterface/WebKitSystemInterface.h>
40 #endif
41
42 #include <WebCore/BString.h>
43 #include <WebCore/URL.h>
44 #include <WebCore/LocalizedStrings.h>
45 #include <WebCore/ResourceHandle.h>
46 #include <shlobj.h>
47 #include <shlwapi.h>
48 #include <wchar.h>
49
50 using namespace WebCore;
51
52 static String localizedShortDescriptionForStatusCode(int statusCode)
53 {
54     String result;
55     if (statusCode < 100 || statusCode >= 600)
56         result = WEB_UI_STRING("server error", "HTTP result code string");
57     else if (statusCode >= 100 && statusCode <= 199) {
58         switch (statusCode) {
59             case 100:
60                 result = WEB_UI_STRING("continue", "HTTP result code string");
61                 break;
62             case 101:
63                 result = WEB_UI_STRING("switching protocols", "HTTP result code string");
64                 break;
65             default:
66                 result = WEB_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 = WEB_UI_STRING("no error", "HTTP result code string");
73                 break;
74             case 201:
75                 result = WEB_UI_STRING("created", "HTTP result code string");
76                 break;
77             case 202:
78                 result = WEB_UI_STRING("accepted", "HTTP result code string");
79                 break;
80             case 203:
81                 result = WEB_UI_STRING("non-authoritative information", "HTTP result code string");
82                 break;
83             case 204:
84                 result = WEB_UI_STRING("no content", "HTTP result code string");
85                 break;
86             case 205:
87                 result = WEB_UI_STRING("reset content", "HTTP result code string");
88                 break;
89             case 206:
90                 result = WEB_UI_STRING("partial content", "HTTP result code string");
91                 break;
92             default:
93                 result = WEB_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 = WEB_UI_STRING("multiple choices", "HTTP result code string");
100                 break;
101             case 301:
102                 result = WEB_UI_STRING("moved permanently", "HTTP result code string");
103                 break;
104             case 302:
105                 result = WEB_UI_STRING("found", "HTTP result code string");
106                 break;
107             case 303:
108                 result = WEB_UI_STRING("see other", "HTTP result code string");
109                 break;
110             case 304:
111                 result = WEB_UI_STRING("not modified", "HTTP result code string");
112                 break;
113             case 305:
114                 result = WEB_UI_STRING("needs proxy", "HTTP result code string");
115                 break;
116             case 307:
117                 result = WEB_UI_STRING("temporarily redirected", "HTTP result code string");
118                 break;
119             case 306:   // 306 status code unused in HTTP
120             default:
121                 result = WEB_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 = WEB_UI_STRING("bad request", "HTTP result code string");
128                 break;
129             case 401:
130                 result = WEB_UI_STRING("unauthorized", "HTTP result code string");
131                 break;
132             case 402:
133                 result = WEB_UI_STRING("payment required", "HTTP result code string");
134                 break;
135             case 403:
136                 result = WEB_UI_STRING("forbidden", "HTTP result code string");
137                 break;
138             case 404:
139                 result = WEB_UI_STRING("not found", "HTTP result code string");
140                 break;
141             case 405:
142                 result = WEB_UI_STRING("method not allowed", "HTTP result code string");
143                 break;
144             case 406:
145                 result = WEB_UI_STRING("unacceptable", "HTTP result code string");
146                 break;
147             case 407:
148                 result = WEB_UI_STRING("proxy authentication required", "HTTP result code string");
149                 break;
150             case 408:
151                 result = WEB_UI_STRING("request timed out", "HTTP result code string");
152                 break;
153             case 409:
154                 result = WEB_UI_STRING("conflict", "HTTP result code string");
155                 break;
156             case 410:
157                 result = WEB_UI_STRING("no longer exists", "HTTP result code string");
158                 break;
159             case 411:
160                 result = WEB_UI_STRING("length required", "HTTP result code string");
161                 break;
162             case 412:
163                 result = WEB_UI_STRING("precondition failed", "HTTP result code string");
164                 break;
165             case 413:
166                 result = WEB_UI_STRING("request too large", "HTTP result code string");
167                 break;
168             case 414:
169                 result = WEB_UI_STRING("requested URL too long", "HTTP result code string");
170                 break;
171             case 415:
172                 result = WEB_UI_STRING("unsupported media type", "HTTP result code string");
173                 break;
174             case 416:
175                 result = WEB_UI_STRING("requested range not satisfiable", "HTTP result code string");
176                 break;
177             case 417:
178                 result = WEB_UI_STRING("expectation failed", "HTTP result code string");
179                 break;
180             default:
181                 result = WEB_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 = WEB_UI_STRING("internal server error", "HTTP result code string");
188                 break;
189             case 501:
190                 result = WEB_UI_STRING("unimplemented", "HTTP result code string");
191                 break;
192             case 502:
193                 result = WEB_UI_STRING("bad gateway", "HTTP result code string");
194                 break;
195             case 503:
196                 result = WEB_UI_STRING("service unavailable", "HTTP result code string");
197                 break;
198             case 504:
199                 result = WEB_UI_STRING("gateway timed out", "HTTP result code string");
200                 break;
201             case 505:
202                 result = WEB_UI_STRING("unsupported version", "HTTP result code string");
203                 break;
204             default:
205                 result = WEB_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(WebCore::URL(ParsedURLString, "http://"), String(), 0, 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));
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     HashMap<String, String, CaseFoldingHash> fields;
367     for (const auto& keyValuePair : m_response.httpHeaderFields())
368         fields.add(keyValuePair.key, keyValuePair.value);
369
370     *headerFields = COMPropertyBag<String, String, CaseFoldingHash>::adopt(fields);
371     return S_OK;
372 }
373
374 HRESULT STDMETHODCALLTYPE WebURLResponse::localizedStringForStatusCode( 
375     /* [in] */ int statusCode,
376     /* [retval][out] */ BSTR* statusString)
377 {
378     ASSERT(m_response.isHTTP());
379     if (statusString)
380         *statusString = 0;
381     const String& statusText = localizedShortDescriptionForStatusCode(statusCode);
382     if (!statusText)
383         return E_FAIL;
384     if (statusString)
385         *statusString = BString(statusText).release();
386     return S_OK;
387 }
388
389 HRESULT STDMETHODCALLTYPE WebURLResponse::statusCode( 
390     /* [retval][out] */ int* statusCode)
391 {
392     ASSERT(m_response.isHTTP());
393     if (statusCode)
394         *statusCode = m_response.httpStatusCode();
395     return S_OK;
396 }
397
398 HRESULT STDMETHODCALLTYPE WebURLResponse::isAttachment( 
399     /* [retval][out] */ BOOL *attachment)
400 {
401     *attachment = m_response.isAttachment();
402     return S_OK;
403 }
404
405
406 HRESULT WebURLResponse::sslPeerCertificate(/* [retval][out] */ ULONG_PTR* result)
407 {
408     if (!result)
409         return E_POINTER;
410     *result = 0;
411
412 #if USE(CFNETWORK)
413     CFDictionaryRef dict = certificateDictionary();
414     if (!dict)
415         return E_FAIL;
416     void* data = wkGetSSLPeerCertificateDataBytePtr(dict);
417     if (!data)
418         return E_FAIL;
419     *result = reinterpret_cast<ULONG_PTR>(data);
420 #endif
421
422     return *result ? S_OK : E_FAIL;
423 }
424
425 // WebURLResponse -------------------------------------------------------------
426
427 HRESULT WebURLResponse::suggestedFileExtension(BSTR *result)
428 {
429     if (!result)
430         return E_POINTER;
431
432     *result = 0;
433
434     if (m_response.mimeType().isEmpty())
435         return E_FAIL;
436
437     BString mimeType(m_response.mimeType());
438     HKEY key;
439     LONG err = RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("MIME\\Database\\Content Type"), 0, KEY_QUERY_VALUE, &key);
440     if (!err) {
441         HKEY subKey;
442         err = RegOpenKeyEx(key, mimeType, 0, KEY_QUERY_VALUE, &subKey);
443         if (!err) {
444             DWORD keyType = REG_SZ;
445             WCHAR extension[MAX_PATH];
446             DWORD keySize = sizeof(extension)/sizeof(extension[0]);
447             err = RegQueryValueEx(subKey, TEXT("Extension"), 0, &keyType, (LPBYTE)extension, &keySize);
448             if (!err && keyType != REG_SZ)
449                 err = ERROR_INVALID_DATA;
450             if (err) {
451                 // fallback handlers
452                 if (!wcscmp(mimeType, L"text/html")) {
453                     wcscpy(extension, L".html");
454                     err = 0;
455                 } else if (!wcscmp(mimeType, L"application/xhtml+xml")) {
456                     wcscpy(extension, L".xhtml");
457                     err = 0;
458                 } else if (!wcscmp(mimeType, L"image/svg+xml")) {
459                     wcscpy(extension, L".svg");
460                     err = 0;
461                 }
462             }
463             if (!err) {
464                 *result = SysAllocString(extension);
465                 if (!*result)
466                     err = ERROR_OUTOFMEMORY;
467             }
468             RegCloseKey(subKey);
469         }
470         RegCloseKey(key);
471     }
472
473     return HRESULT_FROM_WIN32(err);
474 }
475
476 const ResourceResponse& WebURLResponse::resourceResponse() const
477 {
478     return m_response;
479 }
480
481 #if USE(CFNETWORK)
482 CFDictionaryRef WebURLResponse::certificateDictionary() const
483 {
484     if (m_SSLCertificateInfo)
485         return m_SSLCertificateInfo.get();
486
487     CFURLResponseRef cfResponse = m_response.cfURLResponse();
488     if (!cfResponse)
489         return 0;
490     m_SSLCertificateInfo = wkGetSSLCertificateInfo(cfResponse);
491     return m_SSLCertificateInfo.get();
492 }
493 #endif