[Win] Replace MIDL [in/out] comments with equivalent SAL
[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 {
216     gClassCount++;
217     gClassNameCount().add("WebURLResponse");
218 }
219
220 WebURLResponse::~WebURLResponse()
221 {
222     gClassCount--;
223     gClassNameCount().remove("WebURLResponse");
224 }
225
226 WebURLResponse* WebURLResponse::createInstance()
227 {
228     WebURLResponse* instance = new WebURLResponse();
229     // fake an http response - so it has the IWebHTTPURLResponse interface
230     instance->m_response = ResourceResponse(WebCore::URL(ParsedURLString, "http://"), String(), 0, String());
231     instance->AddRef();
232     return instance;
233 }
234
235 WebURLResponse* WebURLResponse::createInstance(const ResourceResponse& response)
236 {
237     if (response.isNull())
238         return 0;
239
240     WebURLResponse* instance = new WebURLResponse();
241     instance->AddRef();
242     instance->m_response = response;
243
244     return instance;
245 }
246
247 // IUnknown -------------------------------------------------------------------
248
249 HRESULT WebURLResponse::QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject)
250 {
251     if (!ppvObject)
252         return E_POINTER;
253     *ppvObject = nullptr;
254     if (IsEqualGUID(riid, IID_IUnknown))
255         *ppvObject = static_cast<IWebURLResponse*>(this);
256     else if (IsEqualGUID(riid, __uuidof(this)))
257         *ppvObject = this;
258     else if (IsEqualGUID(riid, IID_IWebURLResponse))
259         *ppvObject = static_cast<IWebURLResponse*>(this);
260     else if (IsEqualGUID(riid, IID_IWebURLResponsePrivate))
261         *ppvObject = static_cast<IWebURLResponsePrivate*>(this);
262     else if (m_response.isHTTP() && IsEqualGUID(riid, IID_IWebHTTPURLResponse))
263         *ppvObject = static_cast<IWebHTTPURLResponse*>(this);
264     else
265         return E_NOINTERFACE;
266
267     AddRef();
268     return S_OK;
269 }
270
271 ULONG WebURLResponse::AddRef()
272 {
273     return ++m_refCount;
274 }
275
276 ULONG WebURLResponse::Release(void)
277 {
278     ULONG newRef = --m_refCount;
279     if (!newRef)
280         delete(this);
281
282     return newRef;
283 }
284
285 // IWebURLResponse --------------------------------------------------------------------
286
287 HRESULT WebURLResponse::expectedContentLength(_Out_ long long* result)
288 {
289     if (!result)
290         return E_POINTER;
291     *result = m_response.expectedContentLength();
292     return S_OK;
293 }
294
295 HRESULT WebURLResponse::initWithURL(_In_ BSTR url, _In_ BSTR mimeType, int expectedContentLength, _In_ BSTR textEncodingName)
296 {
297     m_response = ResourceResponse(MarshallingHelpers::BSTRToKURL(url), String(mimeType), expectedContentLength, String(textEncodingName));
298     return S_OK;
299 }
300
301 HRESULT WebURLResponse::MIMEType(__deref_opt_out BSTR* result)
302 {
303     if (!result)
304         return E_POINTER;
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 WebURLResponse::suggestedFilename(__deref_opt_out BSTR* result)
315 {
316     if (!result) {
317         ASSERT_NOT_REACHED();
318         return E_POINTER;
319     }
320
321     *result = nullptr;
322
323     if (m_response.url().isEmpty())
324         return E_FAIL;
325
326     *result = BString(m_response.suggestedFilename()).release();
327     return S_OK;
328 }
329
330 HRESULT WebURLResponse::textEncodingName(__deref_opt_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 WebURLResponse::URL(__deref_opt_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 WebURLResponse::allHeaderFields(_COM_Outptr_opt_ IPropertyBag** headerFields)
359 {
360     ASSERT(m_response.isHTTP());
361
362     if (!headerFields)
363         return E_POINTER;
364
365     HashMap<String, String, CaseFoldingHash> fields;
366     for (const auto& keyValuePair : m_response.httpHeaderFields())
367         fields.add(keyValuePair.key, keyValuePair.value);
368
369     *headerFields = COMPropertyBag<String, String, CaseFoldingHash>::adopt(fields);
370     return S_OK;
371 }
372
373 HRESULT WebURLResponse::localizedStringForStatusCode(int statusCode, __deref_opt_out BSTR* statusString)
374 {
375     ASSERT(m_response.isHTTP());
376     if (!statusString)
377         return E_POINTER;
378
379     *statusString = nullptr;
380     const String& statusText = localizedShortDescriptionForStatusCode(statusCode);
381     if (!statusText)
382         return E_FAIL;
383     *statusString = BString(statusText).release();
384     return S_OK;
385 }
386
387 HRESULT WebURLResponse::statusCode(_Out_ int* statusCode)
388 {
389     ASSERT(m_response.isHTTP());
390     if (statusCode)
391         *statusCode = m_response.httpStatusCode();
392     return S_OK;
393 }
394
395 HRESULT WebURLResponse::isAttachment(_Out_ BOOL* attachment)
396 {
397     if (!attachment)
398         return E_POINTER;
399     *attachment = m_response.isAttachment();
400     return S_OK;
401 }
402
403 HRESULT WebURLResponse::sslPeerCertificate(_Out_ ULONG_PTR* 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 = wkGetSSLPeerCertificateDataBytePtr(dict);
414     if (!data)
415         return E_FAIL;
416     *result = reinterpret_cast<ULONG_PTR>(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 = nullptr;
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             WCHAR 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 (!wcscmp(mimeType, L"text/html")) {
450                     wcscpy(extension, L".html");
451                     err = 0;
452                 } else if (!wcscmp(mimeType, L"application/xhtml+xml")) {
453                     wcscpy(extension, L".xhtml");
454                     err = 0;
455                 } else if (!wcscmp(mimeType, L"image/svg+xml")) {
456                     wcscpy(extension, L".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 nullptr;
487     m_SSLCertificateInfo = wkGetSSLCertificateInfo(cfResponse);
488     return m_SSLCertificateInfo.get();
489 }
490 #endif