It is 'registered', not 'registred'
[glib.git] / gio / win32 / gwinhttpvfs.c
blob1fcc1678c9b346ae24419ce5c3151258a47d68ee
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>
25 #include "config.h"
27 #include <wchar.h>
29 #include "gio/gioerror.h"
30 #include "gio/giomodule.h"
31 #include "gio/gvfs.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;
40 static void
41 lookup_funcs (void)
43 HMODULE winhttp = NULL;
44 char winhttp_dll[MAX_PATH + 100];
45 int n;
47 if (lookup_done)
48 return;
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);
60 if (winhttp != NULL)
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 &&
79 funcs.pWinHttpOpen &&
80 funcs.pWinHttpOpenRequest &&
81 funcs.pWinHttpQueryDataAvailable &&
82 funcs.pWinHttpQueryHeaders &&
83 funcs.pWinHttpReadData &&
84 funcs.pWinHttpReceiveResponse &&
85 funcs.pWinHttpSendRequest &&
86 funcs.pWinHttpWriteData)
87 funcs_found = TRUE;
89 lookup_done = TRUE;
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,
95 lookup_funcs ();
96 if (funcs_found)
97 g_io_extension_point_implement (G_VFS_EXTENSION_POINT_NAME,
98 g_define_type_id,
99 "winhttp",
100 10);
103 static const gchar *winhttp_uri_schemes[] = { "http", "https" };
105 static void
106 g_winhttp_vfs_finalize (GObject *object)
108 GWinHttpVfs *vfs;
110 vfs = G_WINHTTP_VFS (object);
112 (G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpCloseHandle) (vfs->session);
113 vfs->session = NULL;
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);
122 static void
123 g_winhttp_vfs_init (GWinHttpVfs *vfs)
125 wchar_t *wagent;
127 vfs->wrapped_vfs = g_vfs_get_local ();
129 wagent = g_utf8_to_utf16 (g_get_prgname (), -1, NULL, NULL, NULL);
131 if (!wagent)
132 wagent = g_utf8_to_utf16 ("GWinHttpVfs", -1, NULL, NULL, NULL);
134 vfs->session = (G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpOpen)
135 (wagent,
136 WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
137 WINHTTP_NO_PROXY_NAME,
138 WINHTTP_NO_PROXY_BYPASS,
141 g_free (wagent);
145 * g_winhttp_vfs_new:
147 * Returns a new #GVfs handle for a WinHttp vfs.
149 * Returns: a new #GVfs handle.
151 GVfs *
152 _g_winhttp_vfs_new (void)
154 return g_object_new (G_TYPE_WINHTTP_VFS, NULL);
157 static GFile *
158 g_winhttp_vfs_get_file_for_path (GVfs *vfs,
159 const char *path)
161 return g_vfs_get_file_for_path (G_WINHTTP_VFS (vfs)->wrapped_vfs, path);
164 static GFile *
165 g_winhttp_vfs_get_file_for_uri (GVfs *vfs,
166 const char *uri)
168 GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs);
169 int i;
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);
186 int i, n;
187 const gchar **retval;
189 n = 0;
190 while (wrapped_vfs_uri_schemes[n] != NULL)
191 n++;
193 retval = g_new (const gchar *, n + G_N_ELEMENTS (winhttp_uri_schemes) + 1);
194 n = 0;
195 while (wrapped_vfs_uri_schemes[n] != NULL)
197 retval[n] = wrapped_vfs_uri_schemes[n];
198 n++;
201 for (i = 0; i < G_N_ELEMENTS (winhttp_uri_schemes); i++)
203 retval[n] = winhttp_uri_schemes[i];
204 n++;
207 retval[n] = NULL;
209 return retval;
212 static GFile *
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);
231 static gboolean
232 g_winhttp_vfs_is_active (GVfs *vfs)
234 return TRUE;
237 static void
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;
255 lookup_funcs ();
256 if (funcs_found)
257 class->funcs = &funcs;
258 else
259 class->funcs = NULL;
262 char *
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)
270 switch (error_code)
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);
295 CASE (INVALID_URL);
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);
314 CASE (SHUTDOWN);
315 CASE (TIMEOUT);
316 CASE (UNABLE_TO_DOWNLOAD_SCRIPT);
317 CASE (UNRECOGNIZED_SCHEME);
318 #undef CASE
319 default:
320 return g_strdup_printf ("WinHttp error %ld", error_code);
323 else
324 return g_win32_error_message (error_code);
327 void
328 _g_winhttp_set_error (GError **error,
329 DWORD error_code,
330 const char *what)
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);
336 g_free (emsg);
339 gboolean
340 _g_winhttp_response (GWinHttpVfs *vfs,
341 HINTERNET request,
342 GError **error,
343 const char *what)
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);
352 return FALSE;
355 status_code_len = 0;
356 if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
357 (request,
358 WINHTTP_QUERY_STATUS_CODE,
359 NULL,
360 NULL,
361 &status_code_len,
362 NULL) &&
363 GetLastError () != ERROR_INSUFFICIENT_BUFFER)
365 _g_winhttp_set_error (error, GetLastError (), what);
367 return FALSE;
370 status_code = g_malloc (status_code_len);
372 if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
373 (request,
374 WINHTTP_QUERY_STATUS_CODE,
375 NULL,
376 status_code,
377 &status_code_len,
378 NULL))
380 _g_winhttp_set_error (error, GetLastError (), what);
381 g_free (status_code);
383 return FALSE;
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
392 (request,
393 WINHTTP_QUERY_STATUS_TEXT,
394 NULL,
395 NULL,
396 &status_text_len,
397 NULL) &&
398 GetLastError () == ERROR_INSUFFICIENT_BUFFER)
400 status_text = g_malloc (status_text_len);
402 if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
403 (request,
404 WINHTTP_QUERY_STATUS_TEXT,
405 NULL,
406 status_text,
407 &status_text_len,
408 NULL))
410 g_free (status_text);
411 status_text = NULL;
415 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
416 "%s failed: %S %S",
417 what, status_code, status_text ? status_text : L"");
418 g_free (status_code);
419 g_free (status_text);
421 return FALSE;
424 g_free (status_code);
426 return TRUE;
429 gboolean
430 _g_winhttp_query_header (GWinHttpVfs *vfs,
431 HINTERNET request,
432 const char *request_description,
433 DWORD which_header,
434 wchar_t **header,
435 GError **error)
437 DWORD header_len = 0;
439 if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
440 (request,
441 which_header,
442 NULL,
443 NULL,
444 &header_len,
445 NULL) &&
446 GetLastError () != ERROR_INSUFFICIENT_BUFFER)
448 _g_winhttp_set_error (error, GetLastError (), request_description);
450 return FALSE;
453 *header = g_malloc (header_len);
454 if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
455 (request,
456 which_header,
457 NULL,
458 *header,
459 &header_len,
460 NULL))
462 _g_winhttp_set_error (error, GetLastError (), request_description);
463 g_free (*header);
464 *header = NULL;
466 return FALSE;
469 return TRUE;