• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CFHTTPMessageCopyLocalizedShortDescriptionForStatusCode(CFIndex statusCode)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 
WebURLResponse()214 WebURLResponse::WebURLResponse()
215     :m_refCount(0)
216 {
217     gClassCount++;
218     gClassNameCount.add("WebURLResponse");
219 }
220 
~WebURLResponse()221 WebURLResponse::~WebURLResponse()
222 {
223     gClassCount--;
224     gClassNameCount.remove("WebURLResponse");
225 }
226 
createInstance()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("http://"), String(), 0, String(), String());
232     instance->AddRef();
233     return instance;
234 }
235 
createInstance(const ResourceResponse & response)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 
QueryInterface(REFIID riid,void ** ppvObject)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 
AddRef(void)270 ULONG STDMETHODCALLTYPE WebURLResponse::AddRef(void)
271 {
272     return ++m_refCount;
273 }
274 
Release(void)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 
expectedContentLength(long long * result)286 HRESULT STDMETHODCALLTYPE WebURLResponse::expectedContentLength(
287     /* [retval][out] */ long long* result)
288 {
289     *result = m_response.expectedContentLength();
290     return S_OK;
291 }
292 
initWithURL(BSTR url,BSTR mimeType,int expectedContentLength,BSTR textEncodingName)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 
MIMEType(BSTR * result)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 
suggestedFilename(BSTR * result)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 
textEncodingName(BSTR * result)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 
URL(BSTR * result)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 
allHeaderFields(IPropertyBag ** headerFields)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 
localizedStringForStatusCode(int statusCode,BSTR * statusString)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 
statusCode(int * statusCode)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 
isAttachment(BOOL * attachment)394 HRESULT STDMETHODCALLTYPE WebURLResponse::isAttachment(
395     /* [retval][out] */ BOOL *attachment)
396 {
397     *attachment = m_response.isAttachment();
398     return S_OK;
399 }
400 
401 
sslPeerCertificate(OLE_HANDLE * result)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 
suggestedFileExtension(BSTR * result)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 
resourceResponse() const473 const ResourceResponse& WebURLResponse::resourceResponse() const
474 {
475     return m_response;
476 }
477 
478 #if USE(CFNETWORK)
certificateDictionary() const479 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