|
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 |
|
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 |
|
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(KURL(ParsedURLString, "http://"), String(), 0, String(), 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), String()); |
|
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 *headerFields = COMPropertyBag<String, AtomicString, CaseFoldingHash>::createInstance(m_response.httpHeaderFields()); |
|
367 return S_OK; |
|
368 } |
|
369 |
|
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 |
|
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 |
|
394 HRESULT STDMETHODCALLTYPE WebURLResponse::isAttachment( |
|
395 /* [retval][out] */ BOOL *attachment) |
|
396 { |
|
397 *attachment = m_response.isAttachment(); |
|
398 return S_OK; |
|
399 } |
|
400 |
|
401 |
|
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 |
|
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 |
|
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 0; |
|
487 m_SSLCertificateInfo = wkGetSSLCertificateInfo(cfResponse); |
|
488 return m_SSLCertificateInfo.get(); |
|
489 } |
|
490 #endif |