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