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>
30
#include "giomodule.h"
33
#include "gwinhttpfile.h"
34
#include "gwinhttpvfs.h"
38
static gboolean lookup_done = FALSE;
39
static gboolean funcs_found = FALSE;
40
static GWinHttpDllFuncs funcs;
50
winhttp = LoadLibrary ("winhttp.dll");
53
funcs.pWinHttpCloseHandle = (BOOL (WINAPI *) (HINTERNET)) GetProcAddress (winhttp, "WinHttpCloseHandle");
54
funcs.pWinHttpCrackUrl = (BOOL (WINAPI *) (LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS)) GetProcAddress (winhttp, "WinHttpCrackUrl");
55
funcs.pWinHttpConnect = (HINTERNET (WINAPI *) (HINTERNET,LPCWSTR,INTERNET_PORT,DWORD)) GetProcAddress (winhttp, "WinHttpConnect");
56
funcs.pWinHttpCreateUrl = (BOOL (WINAPI *) (LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD)) GetProcAddress (winhttp, "WinHttpCreateUrl");
57
funcs.pWinHttpOpen = (HINTERNET (WINAPI *) (LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD)) GetProcAddress (winhttp, "WinHttpOpen");
58
funcs.pWinHttpOpenRequest = (HINTERNET (WINAPI *) (HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD)) GetProcAddress (winhttp, "WinHttpOpenRequest");
59
funcs.pWinHttpQueryDataAvailable = (BOOL (WINAPI *) (HINTERNET,LPDWORD)) GetProcAddress (winhttp, "WinHttpQueryDataAvailable");
60
funcs.pWinHttpQueryHeaders = (BOOL (WINAPI *) (HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD)) GetProcAddress (winhttp, "WinHttpQueryHeaders");
61
funcs.pWinHttpReadData = (BOOL (WINAPI *) (HINTERNET,LPVOID,DWORD,LPDWORD)) GetProcAddress (winhttp, "WinHttpReadData");
62
funcs.pWinHttpReceiveResponse = (BOOL (WINAPI *) (HINTERNET,LPVOID)) GetProcAddress (winhttp, "WinHttpReceiveResponse");
63
funcs.pWinHttpSendRequest = (BOOL (WINAPI *) (HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR)) GetProcAddress (winhttp, "WinHttpSendRequest");
64
funcs.pWinHttpWriteData = (BOOL (WINAPI *) (HINTERNET,LPCVOID,DWORD,LPDWORD)) GetProcAddress (winhttp, "WinHttpWriteData");
66
if (funcs.pWinHttpCloseHandle &&
67
funcs.pWinHttpCrackUrl &&
68
funcs.pWinHttpConnect &&
69
funcs.pWinHttpCreateUrl &&
71
funcs.pWinHttpOpenRequest &&
72
funcs.pWinHttpQueryDataAvailable &&
73
funcs.pWinHttpQueryHeaders &&
74
funcs.pWinHttpReadData &&
75
funcs.pWinHttpReceiveResponse &&
76
funcs.pWinHttpSendRequest &&
77
funcs.pWinHttpWriteData)
83
#define g_winhttp_vfs_get_type _g_winhttp_vfs_get_type
84
G_DEFINE_TYPE_WITH_CODE (GWinHttpVfs, g_winhttp_vfs, G_TYPE_VFS,
88
g_io_extension_point_implement (G_VFS_EXTENSION_POINT_NAME,
94
static const gchar *winhttp_uri_schemes[] = { "http", "https" };
97
g_winhttp_vfs_finalize (GObject *object)
101
vfs = G_WINHTTP_VFS (object);
103
(G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpCloseHandle) (vfs->session);
106
if (vfs->wrapped_vfs)
107
g_object_unref (vfs->wrapped_vfs);
108
vfs->wrapped_vfs = NULL;
110
G_OBJECT_CLASS (g_winhttp_vfs_parent_class)->finalize (object);
114
g_winhttp_vfs_init (GWinHttpVfs *vfs)
118
vfs->wrapped_vfs = g_vfs_get_local ();
120
wagent = g_utf8_to_utf16 (g_get_prgname (), -1, NULL, NULL, NULL);
123
wagent = g_utf8_to_utf16 ("GWinHttpVfs", -1, NULL, NULL, NULL);
125
vfs->session = (G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpOpen)
127
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
128
WINHTTP_NO_PROXY_NAME,
129
WINHTTP_NO_PROXY_BYPASS,
136
* Returns a new #GVfs handle for a WinHttp vfs.
138
* Returns: a new #GVfs handle.
141
_g_winhttp_vfs_new (void)
143
return g_object_new (G_TYPE_WINHTTP_VFS, NULL);
147
g_winhttp_vfs_get_file_for_path (GVfs *vfs,
150
return g_vfs_get_file_for_path (G_WINHTTP_VFS (vfs)->wrapped_vfs, path);
154
g_winhttp_vfs_get_file_for_uri (GVfs *vfs,
157
GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs);
160
/* If it matches one of "our" schemes, handle it */
161
for (i = 0; i < G_N_ELEMENTS (winhttp_uri_schemes); i++)
162
if (g_ascii_strncasecmp (uri, winhttp_uri_schemes[i], strlen (winhttp_uri_schemes[i])) == 0 &&
163
uri[strlen (winhttp_uri_schemes[i])] == ':')
164
return _g_winhttp_file_new (winhttp_vfs, uri);
166
/* For other URIs fallback to the wrapped GVfs */
167
return g_vfs_parse_name (winhttp_vfs->wrapped_vfs, uri);
170
static const gchar * const *
171
g_winhttp_vfs_get_supported_uri_schemes (GVfs *vfs)
173
GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs);
174
const gchar * const *wrapped_vfs_uri_schemes = g_vfs_get_supported_uri_schemes (winhttp_vfs->wrapped_vfs);
176
const gchar **retval;
179
while (wrapped_vfs_uri_schemes[n] != NULL)
182
retval = g_new (const gchar *, n + G_N_ELEMENTS (winhttp_uri_schemes) + 1);
184
while (wrapped_vfs_uri_schemes[n] != NULL)
186
retval[n] = wrapped_vfs_uri_schemes[n];
190
for (i = 0; i < G_N_ELEMENTS (winhttp_uri_schemes); i++)
192
retval[n] = winhttp_uri_schemes[i];
202
g_winhttp_vfs_parse_name (GVfs *vfs,
203
const char *parse_name)
205
GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs);
207
g_return_val_if_fail (G_IS_VFS (vfs), NULL);
208
g_return_val_if_fail (parse_name != NULL, NULL);
210
/* For plain file paths fallback to the wrapped GVfs */
211
if (g_path_is_absolute (parse_name))
212
return g_vfs_parse_name (winhttp_vfs->wrapped_vfs, parse_name);
214
/* Otherwise assume it is an URI, so pass on to
215
* g_winhttp_vfs_get_file_for_uri().
217
return g_winhttp_vfs_get_file_for_uri (vfs, parse_name);
221
g_winhttp_vfs_is_active (GVfs *vfs)
227
g_winhttp_vfs_class_init (GWinHttpVfsClass *class)
229
GObjectClass *object_class;
230
GVfsClass *vfs_class;
232
object_class = (GObjectClass *) class;
234
object_class->finalize = g_winhttp_vfs_finalize;
236
vfs_class = G_VFS_CLASS (class);
238
vfs_class->is_active = g_winhttp_vfs_is_active;
239
vfs_class->get_file_for_path = g_winhttp_vfs_get_file_for_path;
240
vfs_class->get_file_for_uri = g_winhttp_vfs_get_file_for_uri;
241
vfs_class->get_supported_uri_schemes = g_winhttp_vfs_get_supported_uri_schemes;
242
vfs_class->parse_name = g_winhttp_vfs_parse_name;
246
class->funcs = &funcs;
252
_g_winhttp_error_message (DWORD error_code)
254
/* The FormatMessage() API that g_win32_error_message() uses doesn't
255
* seem to know about WinHttp errors, unfortunately.
257
if (error_code >= WINHTTP_ERROR_BASE && error_code < WINHTTP_ERROR_BASE + 200)
261
/* FIXME: Use meaningful error messages */
262
#define CASE(x) case ERROR_WINHTTP_##x: return g_strdup ("WinHttp error: " #x);
263
CASE (AUTO_PROXY_SERVICE_ERROR);
264
CASE (AUTODETECTION_FAILED);
265
CASE (BAD_AUTO_PROXY_SCRIPT);
266
CASE (CANNOT_CALL_AFTER_OPEN);
267
CASE (CANNOT_CALL_AFTER_SEND);
268
CASE (CANNOT_CALL_BEFORE_OPEN);
269
CASE (CANNOT_CALL_BEFORE_SEND);
270
CASE (CANNOT_CONNECT);
271
CASE (CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW);
272
CASE (CLIENT_AUTH_CERT_NEEDED);
273
CASE (CONNECTION_ERROR);
274
CASE (HEADER_ALREADY_EXISTS);
275
CASE (HEADER_COUNT_EXCEEDED);
276
CASE (HEADER_NOT_FOUND);
277
CASE (HEADER_SIZE_OVERFLOW);
278
CASE (INCORRECT_HANDLE_STATE);
279
CASE (INCORRECT_HANDLE_TYPE);
280
CASE (INTERNAL_ERROR);
281
CASE (INVALID_OPTION);
282
CASE (INVALID_QUERY_REQUEST);
283
CASE (INVALID_SERVER_RESPONSE);
285
CASE (LOGIN_FAILURE);
286
CASE (NAME_NOT_RESOLVED);
287
CASE (NOT_INITIALIZED);
288
CASE (OPERATION_CANCELLED);
289
CASE (OPTION_NOT_SETTABLE);
290
CASE (OUT_OF_HANDLES);
291
CASE (REDIRECT_FAILED);
292
CASE (RESEND_REQUEST);
293
CASE (RESPONSE_DRAIN_OVERFLOW);
294
CASE (SECURE_CERT_CN_INVALID);
295
CASE (SECURE_CERT_DATE_INVALID);
296
CASE (SECURE_CERT_REV_FAILED);
297
CASE (SECURE_CERT_REVOKED);
298
CASE (SECURE_CERT_WRONG_USAGE);
299
CASE (SECURE_CHANNEL_ERROR);
300
CASE (SECURE_FAILURE);
301
CASE (SECURE_INVALID_CA);
302
CASE (SECURE_INVALID_CERT);
305
CASE (UNABLE_TO_DOWNLOAD_SCRIPT);
306
CASE (UNRECOGNIZED_SCHEME);
309
return g_strdup_printf ("WinHttp error %ld", error_code);
313
return g_win32_error_message (error_code);
317
_g_winhttp_set_error (GError **error,
321
char *emsg = _g_winhttp_error_message (error_code);
323
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
324
"%s failed: %s", what, emsg);
329
_g_winhttp_response (GWinHttpVfs *vfs,
334
wchar_t *status_code;
335
DWORD status_code_len;
337
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpReceiveResponse (request, NULL))
339
_g_winhttp_set_error (error, GetLastError (), what);
345
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
347
WINHTTP_QUERY_STATUS_CODE,
352
GetLastError () != ERROR_INSUFFICIENT_BUFFER)
354
_g_winhttp_set_error (error, GetLastError (), what);
359
status_code = g_malloc (status_code_len);
361
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
363
WINHTTP_QUERY_STATUS_CODE,
369
_g_winhttp_set_error (error, GetLastError (), what);
370
g_free (status_code);
375
if (status_code[0] != L'2')
377
wchar_t *status_text = NULL;
378
DWORD status_text_len;
380
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
382
WINHTTP_QUERY_STATUS_TEXT,
387
GetLastError () == ERROR_INSUFFICIENT_BUFFER)
389
status_text = g_malloc (status_text_len);
391
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
393
WINHTTP_QUERY_STATUS_TEXT,
399
g_free (status_text);
404
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
406
what, status_code, status_text ? status_text : L"");
407
g_free (status_code);
408
g_free (status_text);
413
g_free (status_code);
419
_g_winhttp_query_header (GWinHttpVfs *vfs,
421
const char *request_description,
426
DWORD header_len = 0;
428
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
435
GetLastError () != ERROR_INSUFFICIENT_BUFFER)
437
_g_winhttp_set_error (error, GetLastError (), request_description);
442
*header = g_malloc (header_len);
443
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
451
_g_winhttp_set_error (error, GetLastError (), request_description);