1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 * Copyright (C) 2008 Novell, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
21 * Author: Alexander Larsson <alexl@redhat.com>
22 * Author: Tor Lillqvist <tml@novell.com>
29 #include "gio/gioerror.h"
30 #include "gio/giomodule.h"
33 #include "gwinhttpfile.h"
34 #include "gwinhttpvfs.h"
36 static gboolean lookup_done
= FALSE
;
37 static gboolean funcs_found
= FALSE
;
38 static GWinHttpDllFuncs funcs
;
43 HMODULE winhttp
= NULL
;
44 char winhttp_dll
[MAX_PATH
+ 100];
50 n
= GetSystemDirectory (winhttp_dll
, MAX_PATH
);
51 if (n
> 0 && n
< MAX_PATH
)
53 if (winhttp_dll
[n
-1] != '\\' &&
54 winhttp_dll
[n
-1] != '/')
55 strcat (winhttp_dll
, "\\");
56 strcat (winhttp_dll
, "winhttp.dll");
57 winhttp
= LoadLibrary (winhttp_dll
);
62 funcs
.pWinHttpCloseHandle
= (BOOL (WINAPI
*) (HINTERNET
)) GetProcAddress (winhttp
, "WinHttpCloseHandle");
63 funcs
.pWinHttpCrackUrl
= (BOOL (WINAPI
*) (LPCWSTR
,DWORD
,DWORD
,LPURL_COMPONENTS
)) GetProcAddress (winhttp
, "WinHttpCrackUrl");
64 funcs
.pWinHttpConnect
= (HINTERNET (WINAPI
*) (HINTERNET
,LPCWSTR
,INTERNET_PORT
,DWORD
)) GetProcAddress (winhttp
, "WinHttpConnect");
65 funcs
.pWinHttpCreateUrl
= (BOOL (WINAPI
*) (LPURL_COMPONENTS
,DWORD
,LPWSTR
,LPDWORD
)) GetProcAddress (winhttp
, "WinHttpCreateUrl");
66 funcs
.pWinHttpOpen
= (HINTERNET (WINAPI
*) (LPCWSTR
,DWORD
,LPCWSTR
,LPCWSTR
,DWORD
)) GetProcAddress (winhttp
, "WinHttpOpen");
67 funcs
.pWinHttpOpenRequest
= (HINTERNET (WINAPI
*) (HINTERNET
,LPCWSTR
,LPCWSTR
,LPCWSTR
,LPCWSTR
,LPCWSTR
*,DWORD
)) GetProcAddress (winhttp
, "WinHttpOpenRequest");
68 funcs
.pWinHttpQueryDataAvailable
= (BOOL (WINAPI
*) (HINTERNET
,LPDWORD
)) GetProcAddress (winhttp
, "WinHttpQueryDataAvailable");
69 funcs
.pWinHttpQueryHeaders
= (BOOL (WINAPI
*) (HINTERNET
,DWORD
,LPCWSTR
,LPVOID
,LPDWORD
,LPDWORD
)) GetProcAddress (winhttp
, "WinHttpQueryHeaders");
70 funcs
.pWinHttpReadData
= (BOOL (WINAPI
*) (HINTERNET
,LPVOID
,DWORD
,LPDWORD
)) GetProcAddress (winhttp
, "WinHttpReadData");
71 funcs
.pWinHttpReceiveResponse
= (BOOL (WINAPI
*) (HINTERNET
,LPVOID
)) GetProcAddress (winhttp
, "WinHttpReceiveResponse");
72 funcs
.pWinHttpSendRequest
= (BOOL (WINAPI
*) (HINTERNET
,LPCWSTR
,DWORD
,LPVOID
,DWORD
,DWORD
,DWORD_PTR
)) GetProcAddress (winhttp
, "WinHttpSendRequest");
73 funcs
.pWinHttpWriteData
= (BOOL (WINAPI
*) (HINTERNET
,LPCVOID
,DWORD
,LPDWORD
)) GetProcAddress (winhttp
, "WinHttpWriteData");
75 if (funcs
.pWinHttpCloseHandle
&&
76 funcs
.pWinHttpCrackUrl
&&
77 funcs
.pWinHttpConnect
&&
78 funcs
.pWinHttpCreateUrl
&&
80 funcs
.pWinHttpOpenRequest
&&
81 funcs
.pWinHttpQueryDataAvailable
&&
82 funcs
.pWinHttpQueryHeaders
&&
83 funcs
.pWinHttpReadData
&&
84 funcs
.pWinHttpReceiveResponse
&&
85 funcs
.pWinHttpSendRequest
&&
86 funcs
.pWinHttpWriteData
)
92 #define g_winhttp_vfs_get_type _g_winhttp_vfs_get_type
93 G_DEFINE_TYPE_WITH_CODE (GWinHttpVfs
, g_winhttp_vfs
, G_TYPE_VFS
,
97 g_io_extension_point_implement (G_VFS_EXTENSION_POINT_NAME
,
103 static const gchar
*winhttp_uri_schemes
[] = { "http", "https" };
106 g_winhttp_vfs_finalize (GObject
*object
)
110 vfs
= G_WINHTTP_VFS (object
);
112 (G_WINHTTP_VFS_GET_CLASS (vfs
)->funcs
->pWinHttpCloseHandle
) (vfs
->session
);
115 if (vfs
->wrapped_vfs
)
116 g_object_unref (vfs
->wrapped_vfs
);
117 vfs
->wrapped_vfs
= NULL
;
119 G_OBJECT_CLASS (g_winhttp_vfs_parent_class
)->finalize (object
);
123 g_winhttp_vfs_init (GWinHttpVfs
*vfs
)
127 vfs
->wrapped_vfs
= g_vfs_get_local ();
129 wagent
= g_utf8_to_utf16 (g_get_prgname (), -1, NULL
, NULL
, NULL
);
132 wagent
= g_utf8_to_utf16 ("GWinHttpVfs", -1, NULL
, NULL
, NULL
);
134 vfs
->session
= (G_WINHTTP_VFS_GET_CLASS (vfs
)->funcs
->pWinHttpOpen
)
136 WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
,
137 WINHTTP_NO_PROXY_NAME
,
138 WINHTTP_NO_PROXY_BYPASS
,
147 * Returns a new #GVfs handle for a WinHttp vfs.
149 * Returns: a new #GVfs handle.
152 _g_winhttp_vfs_new (void)
154 return g_object_new (G_TYPE_WINHTTP_VFS
, NULL
);
158 g_winhttp_vfs_get_file_for_path (GVfs
*vfs
,
161 return g_vfs_get_file_for_path (G_WINHTTP_VFS (vfs
)->wrapped_vfs
, path
);
165 g_winhttp_vfs_get_file_for_uri (GVfs
*vfs
,
168 GWinHttpVfs
*winhttp_vfs
= G_WINHTTP_VFS (vfs
);
171 /* If it matches one of "our" schemes, handle it */
172 for (i
= 0; i
< G_N_ELEMENTS (winhttp_uri_schemes
); i
++)
173 if (g_ascii_strncasecmp (uri
, winhttp_uri_schemes
[i
], strlen (winhttp_uri_schemes
[i
])) == 0 &&
174 uri
[strlen (winhttp_uri_schemes
[i
])] == ':')
175 return _g_winhttp_file_new (winhttp_vfs
, uri
);
177 /* For other URIs fallback to the wrapped GVfs */
178 return g_vfs_parse_name (winhttp_vfs
->wrapped_vfs
, uri
);
181 static const gchar
* const *
182 g_winhttp_vfs_get_supported_uri_schemes (GVfs
*vfs
)
184 GWinHttpVfs
*winhttp_vfs
= G_WINHTTP_VFS (vfs
);
185 const gchar
* const *wrapped_vfs_uri_schemes
= g_vfs_get_supported_uri_schemes (winhttp_vfs
->wrapped_vfs
);
187 const gchar
**retval
;
190 while (wrapped_vfs_uri_schemes
[n
] != NULL
)
193 retval
= g_new (const gchar
*, n
+ G_N_ELEMENTS (winhttp_uri_schemes
) + 1);
195 while (wrapped_vfs_uri_schemes
[n
] != NULL
)
197 retval
[n
] = wrapped_vfs_uri_schemes
[n
];
201 for (i
= 0; i
< G_N_ELEMENTS (winhttp_uri_schemes
); i
++)
203 retval
[n
] = winhttp_uri_schemes
[i
];
213 g_winhttp_vfs_parse_name (GVfs
*vfs
,
214 const char *parse_name
)
216 GWinHttpVfs
*winhttp_vfs
= G_WINHTTP_VFS (vfs
);
218 g_return_val_if_fail (G_IS_VFS (vfs
), NULL
);
219 g_return_val_if_fail (parse_name
!= NULL
, NULL
);
221 /* For plain file paths fallback to the wrapped GVfs */
222 if (g_path_is_absolute (parse_name
))
223 return g_vfs_parse_name (winhttp_vfs
->wrapped_vfs
, parse_name
);
225 /* Otherwise assume it is an URI, so pass on to
226 * g_winhttp_vfs_get_file_for_uri().
228 return g_winhttp_vfs_get_file_for_uri (vfs
, parse_name
);
232 g_winhttp_vfs_is_active (GVfs
*vfs
)
238 g_winhttp_vfs_class_init (GWinHttpVfsClass
*class)
240 GObjectClass
*object_class
;
241 GVfsClass
*vfs_class
;
243 object_class
= (GObjectClass
*) class;
245 object_class
->finalize
= g_winhttp_vfs_finalize
;
247 vfs_class
= G_VFS_CLASS (class);
249 vfs_class
->is_active
= g_winhttp_vfs_is_active
;
250 vfs_class
->get_file_for_path
= g_winhttp_vfs_get_file_for_path
;
251 vfs_class
->get_file_for_uri
= g_winhttp_vfs_get_file_for_uri
;
252 vfs_class
->get_supported_uri_schemes
= g_winhttp_vfs_get_supported_uri_schemes
;
253 vfs_class
->parse_name
= g_winhttp_vfs_parse_name
;
257 class->funcs
= &funcs
;
263 _g_winhttp_error_message (DWORD error_code
)
265 /* The FormatMessage() API that g_win32_error_message() uses doesn't
266 * seem to know about WinHttp errors, unfortunately.
268 if (error_code
>= WINHTTP_ERROR_BASE
&& error_code
< WINHTTP_ERROR_BASE
+ 200)
272 /* FIXME: Use meaningful error messages */
273 #define CASE(x) case ERROR_WINHTTP_##x: return g_strdup ("WinHttp error: " #x);
274 CASE (AUTO_PROXY_SERVICE_ERROR
);
275 CASE (AUTODETECTION_FAILED
);
276 CASE (BAD_AUTO_PROXY_SCRIPT
);
277 CASE (CANNOT_CALL_AFTER_OPEN
);
278 CASE (CANNOT_CALL_AFTER_SEND
);
279 CASE (CANNOT_CALL_BEFORE_OPEN
);
280 CASE (CANNOT_CALL_BEFORE_SEND
);
281 CASE (CANNOT_CONNECT
);
282 CASE (CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW
);
283 CASE (CLIENT_AUTH_CERT_NEEDED
);
284 CASE (CONNECTION_ERROR
);
285 CASE (HEADER_ALREADY_EXISTS
);
286 CASE (HEADER_COUNT_EXCEEDED
);
287 CASE (HEADER_NOT_FOUND
);
288 CASE (HEADER_SIZE_OVERFLOW
);
289 CASE (INCORRECT_HANDLE_STATE
);
290 CASE (INCORRECT_HANDLE_TYPE
);
291 CASE (INTERNAL_ERROR
);
292 CASE (INVALID_OPTION
);
293 CASE (INVALID_QUERY_REQUEST
);
294 CASE (INVALID_SERVER_RESPONSE
);
296 CASE (LOGIN_FAILURE
);
297 CASE (NAME_NOT_RESOLVED
);
298 CASE (NOT_INITIALIZED
);
299 CASE (OPERATION_CANCELLED
);
300 CASE (OPTION_NOT_SETTABLE
);
301 CASE (OUT_OF_HANDLES
);
302 CASE (REDIRECT_FAILED
);
303 CASE (RESEND_REQUEST
);
304 CASE (RESPONSE_DRAIN_OVERFLOW
);
305 CASE (SECURE_CERT_CN_INVALID
);
306 CASE (SECURE_CERT_DATE_INVALID
);
307 CASE (SECURE_CERT_REV_FAILED
);
308 CASE (SECURE_CERT_REVOKED
);
309 CASE (SECURE_CERT_WRONG_USAGE
);
310 CASE (SECURE_CHANNEL_ERROR
);
311 CASE (SECURE_FAILURE
);
312 CASE (SECURE_INVALID_CA
);
313 CASE (SECURE_INVALID_CERT
);
316 CASE (UNABLE_TO_DOWNLOAD_SCRIPT
);
317 CASE (UNRECOGNIZED_SCHEME
);
320 return g_strdup_printf ("WinHttp error %ld", error_code
);
324 return g_win32_error_message (error_code
);
328 _g_winhttp_set_error (GError
**error
,
332 char *emsg
= _g_winhttp_error_message (error_code
);
334 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
335 "%s failed: %s", what
, emsg
);
340 _g_winhttp_response (GWinHttpVfs
*vfs
,
345 wchar_t *status_code
;
346 DWORD status_code_len
;
348 if (!G_WINHTTP_VFS_GET_CLASS (vfs
)->funcs
->pWinHttpReceiveResponse (request
, NULL
))
350 _g_winhttp_set_error (error
, GetLastError (), what
);
356 if (!G_WINHTTP_VFS_GET_CLASS (vfs
)->funcs
->pWinHttpQueryHeaders
358 WINHTTP_QUERY_STATUS_CODE
,
363 GetLastError () != ERROR_INSUFFICIENT_BUFFER
)
365 _g_winhttp_set_error (error
, GetLastError (), what
);
370 status_code
= g_malloc (status_code_len
);
372 if (!G_WINHTTP_VFS_GET_CLASS (vfs
)->funcs
->pWinHttpQueryHeaders
374 WINHTTP_QUERY_STATUS_CODE
,
380 _g_winhttp_set_error (error
, GetLastError (), what
);
381 g_free (status_code
);
386 if (status_code
[0] != L
'2')
388 wchar_t *status_text
= NULL
;
389 DWORD status_text_len
;
391 if (!G_WINHTTP_VFS_GET_CLASS (vfs
)->funcs
->pWinHttpQueryHeaders
393 WINHTTP_QUERY_STATUS_TEXT
,
398 GetLastError () == ERROR_INSUFFICIENT_BUFFER
)
400 status_text
= g_malloc (status_text_len
);
402 if (!G_WINHTTP_VFS_GET_CLASS (vfs
)->funcs
->pWinHttpQueryHeaders
404 WINHTTP_QUERY_STATUS_TEXT
,
410 g_free (status_text
);
415 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
417 what
, status_code
, status_text
? status_text
: L
"");
418 g_free (status_code
);
419 g_free (status_text
);
424 g_free (status_code
);
430 _g_winhttp_query_header (GWinHttpVfs
*vfs
,
432 const char *request_description
,
437 DWORD header_len
= 0;
439 if (!G_WINHTTP_VFS_GET_CLASS (vfs
)->funcs
->pWinHttpQueryHeaders
446 GetLastError () != ERROR_INSUFFICIENT_BUFFER
)
448 _g_winhttp_set_error (error
, GetLastError (), request_description
);
453 *header
= g_malloc (header_len
);
454 if (!G_WINHTTP_VFS_GET_CLASS (vfs
)->funcs
->pWinHttpQueryHeaders
462 _g_winhttp_set_error (error
, GetLastError (), request_description
);