~ubuntu-branches/debian/squeeze/glib2.0/squeeze

« back to all changes in this revision

Viewing changes to gio/win32/gwinhttpvfs.c

  • Committer: Bazaar Package Importer
  • Author(s): Gustavo Noronha Silva
  • Date: 2009-02-15 13:00:43 UTC
  • mfrom: (1.3.1 upstream) (69.1.10 intrepid)
  • Revision ID: james.westby@ubuntu.com-20090215130043-q47fbt3owmt42m2f
Tags: 2.18.4-2
* Release to unstable
* debian/rules:
- bump SHVER, since we are already forcing a 2.18.0 dependecy on the
  symbols introduced in the development versions
* debian/control.in:
- added Homepage and Vcs-* control fields

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GIO - GLib Input, Output and Streaming Library
 
2
 *
 
3
 * Copyright (C) 2006-2007 Red Hat, Inc.
 
4
 * Copyright (C) 2008 Novell, Inc.
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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.
 
20
 *
 
21
 * Author: Alexander Larsson <alexl@redhat.com>
 
22
 * Author: Tor Lillqvist <tml@novell.com>
 
23
 */
 
24
 
 
25
#include "config.h"
 
26
 
 
27
#include <wchar.h>
 
28
 
 
29
#include "gioerror.h"
 
30
#include "giomodule.h"
 
31
#include "gvfs.h"
 
32
 
 
33
#include "gwinhttpfile.h"
 
34
#include "gwinhttpvfs.h"
 
35
 
 
36
#include "gioalias.h"
 
37
 
 
38
static gboolean lookup_done = FALSE;
 
39
static gboolean funcs_found = FALSE;
 
40
static GWinHttpDllFuncs funcs;
 
41
 
 
42
static void
 
43
lookup_funcs (void)
 
44
{
 
45
  HMODULE winhttp;
 
46
 
 
47
  if (lookup_done)
 
48
    return;
 
49
 
 
50
  winhttp = LoadLibrary ("winhttp.dll");
 
51
  if (winhttp != NULL)
 
52
    {
 
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");
 
65
 
 
66
      if (funcs.pWinHttpCloseHandle &&
 
67
          funcs.pWinHttpCrackUrl &&
 
68
          funcs.pWinHttpConnect &&
 
69
          funcs.pWinHttpCreateUrl &&
 
70
          funcs.pWinHttpOpen &&
 
71
          funcs.pWinHttpOpenRequest &&
 
72
          funcs.pWinHttpQueryDataAvailable &&
 
73
          funcs.pWinHttpQueryHeaders &&
 
74
          funcs.pWinHttpReadData &&
 
75
          funcs.pWinHttpReceiveResponse &&
 
76
          funcs.pWinHttpSendRequest &&
 
77
          funcs.pWinHttpWriteData)
 
78
        funcs_found = TRUE;
 
79
    }
 
80
  lookup_done = TRUE;
 
81
}
 
82
 
 
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,
 
85
                         {
 
86
                           lookup_funcs ();
 
87
                           if (funcs_found)
 
88
                             g_io_extension_point_implement (G_VFS_EXTENSION_POINT_NAME,
 
89
                                                             g_define_type_id,
 
90
                                                             "winhttp",
 
91
                                                             10);
 
92
                         })
 
93
 
 
94
static const gchar *winhttp_uri_schemes[] = { "http", "https" };
 
95
 
 
96
static void
 
97
g_winhttp_vfs_finalize (GObject *object)
 
98
{
 
99
  GWinHttpVfs *vfs;
 
100
 
 
101
  vfs = G_WINHTTP_VFS (object);
 
102
 
 
103
  (G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpCloseHandle) (vfs->session);
 
104
  vfs->session = NULL;
 
105
 
 
106
  if (vfs->wrapped_vfs)
 
107
    g_object_unref (vfs->wrapped_vfs);
 
108
  vfs->wrapped_vfs = NULL;
 
109
 
 
110
  G_OBJECT_CLASS (g_winhttp_vfs_parent_class)->finalize (object);
 
111
}
 
112
 
 
113
static void
 
114
g_winhttp_vfs_init (GWinHttpVfs *vfs)
 
115
{
 
116
  wchar_t *wagent;
 
117
 
 
118
  vfs->wrapped_vfs = g_vfs_get_local ();
 
119
 
 
120
  wagent = g_utf8_to_utf16 (g_get_prgname (), -1, NULL, NULL, NULL);
 
121
 
 
122
  if (!wagent)
 
123
    wagent = g_utf8_to_utf16 ("GWinHttpVfs", -1, NULL, NULL, NULL);
 
124
 
 
125
  vfs->session = (G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpOpen)
 
126
    (wagent,
 
127
     WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
 
128
     WINHTTP_NO_PROXY_NAME,
 
129
     WINHTTP_NO_PROXY_BYPASS,
 
130
     0);
 
131
}
 
132
 
 
133
/**
 
134
 * g_winhttp_vfs_new:
 
135
 *
 
136
 * Returns a new #GVfs handle for a WinHttp vfs.
 
137
 *
 
138
 * Returns: a new #GVfs handle.
 
139
 **/
 
140
GVfs *
 
141
_g_winhttp_vfs_new (void)
 
142
{
 
143
  return g_object_new (G_TYPE_WINHTTP_VFS, NULL);
 
144
}
 
145
 
 
146
static GFile *
 
147
g_winhttp_vfs_get_file_for_path (GVfs       *vfs,
 
148
                                 const char *path)
 
149
{
 
150
  return g_vfs_get_file_for_path (G_WINHTTP_VFS (vfs)->wrapped_vfs, path);
 
151
}
 
152
 
 
153
static GFile *
 
154
g_winhttp_vfs_get_file_for_uri (GVfs       *vfs,
 
155
                                const char *uri)
 
156
{
 
157
  GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs);
 
158
  int i;
 
159
 
 
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);
 
165
 
 
166
  /* For other URIs fallback to the wrapped GVfs */
 
167
  return g_vfs_parse_name (winhttp_vfs->wrapped_vfs, uri);
 
168
}
 
169
 
 
170
static const gchar * const *
 
171
g_winhttp_vfs_get_supported_uri_schemes (GVfs *vfs)
 
172
{
 
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);
 
175
  int i, n;
 
176
  const gchar **retval;
 
177
 
 
178
  n = 0;
 
179
  while (wrapped_vfs_uri_schemes[n] != NULL)
 
180
    n++;
 
181
 
 
182
  retval = g_new (const gchar *, n + G_N_ELEMENTS (winhttp_uri_schemes) + 1);
 
183
  n = 0;
 
184
  while (wrapped_vfs_uri_schemes[n] != NULL)
 
185
    {
 
186
      retval[n] = wrapped_vfs_uri_schemes[n];
 
187
      n++;
 
188
    }
 
189
 
 
190
  for (i = 0; i < G_N_ELEMENTS (winhttp_uri_schemes); i++)
 
191
    {
 
192
      retval[n] = winhttp_uri_schemes[i];
 
193
      n++;
 
194
    }
 
195
 
 
196
  retval[n] = NULL;
 
197
 
 
198
  return retval;
 
199
}
 
200
 
 
201
static GFile *
 
202
g_winhttp_vfs_parse_name (GVfs       *vfs,
 
203
                          const char *parse_name)
 
204
{
 
205
  GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs);
 
206
 
 
207
  g_return_val_if_fail (G_IS_VFS (vfs), NULL);
 
208
  g_return_val_if_fail (parse_name != NULL, NULL);
 
209
 
 
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);
 
213
 
 
214
  /* Otherwise assume it is an URI, so pass on to
 
215
   * g_winhttp_vfs_get_file_for_uri().
 
216
   */
 
217
  return g_winhttp_vfs_get_file_for_uri (vfs, parse_name);
 
218
}
 
219
 
 
220
static gboolean
 
221
g_winhttp_vfs_is_active (GVfs *vfs)
 
222
{
 
223
  return TRUE;
 
224
}
 
225
 
 
226
static void
 
227
g_winhttp_vfs_class_init (GWinHttpVfsClass *class)
 
228
{
 
229
  GObjectClass *object_class;
 
230
  GVfsClass *vfs_class;
 
231
 
 
232
  object_class = (GObjectClass *) class;
 
233
 
 
234
  object_class->finalize = g_winhttp_vfs_finalize;
 
235
 
 
236
  vfs_class = G_VFS_CLASS (class);
 
237
 
 
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;
 
243
 
 
244
  lookup_funcs ();
 
245
  if (funcs_found)
 
246
    class->funcs = &funcs;
 
247
  else
 
248
    class->funcs = NULL;
 
249
}
 
250
 
 
251
char *
 
252
_g_winhttp_error_message (DWORD error_code)
 
253
{
 
254
  /* The FormatMessage() API that g_win32_error_message() uses doesn't
 
255
   * seem to know about WinHttp errors, unfortunately.
 
256
   */
 
257
  if (error_code >= WINHTTP_ERROR_BASE && error_code < WINHTTP_ERROR_BASE + 200)
 
258
    {
 
259
      switch (error_code)
 
260
        {
 
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);
 
284
          CASE (INVALID_URL);
 
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);
 
303
          CASE (SHUTDOWN);
 
304
          CASE (TIMEOUT);
 
305
          CASE (UNABLE_TO_DOWNLOAD_SCRIPT);
 
306
          CASE (UNRECOGNIZED_SCHEME);
 
307
          #undef CASE
 
308
        default:
 
309
          return g_strdup_printf ("WinHttp error %ld", error_code);
 
310
        }
 
311
    }
 
312
  else
 
313
    return g_win32_error_message (error_code);
 
314
}
 
315
 
 
316
void
 
317
_g_winhttp_set_error (GError     **error,
 
318
                      DWORD        error_code,
 
319
                      const char  *what)
 
320
{
 
321
  char *emsg = _g_winhttp_error_message (error_code);
 
322
 
 
323
  g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
 
324
               "%s failed: %s", what, emsg);
 
325
  g_free (emsg);
 
326
}
 
327
 
 
328
gboolean
 
329
_g_winhttp_response (GWinHttpVfs *vfs,
 
330
                     HINTERNET    request,
 
331
                     GError     **error,
 
332
                     const char  *what)
 
333
{
 
334
  wchar_t *status_code;
 
335
  DWORD status_code_len;
 
336
 
 
337
  if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpReceiveResponse (request, NULL))
 
338
    {
 
339
      _g_winhttp_set_error (error, GetLastError (), what);
 
340
 
 
341
      return FALSE;
 
342
    }
 
343
 
 
344
  status_code_len = 0;
 
345
  if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
 
346
      (request,
 
347
       WINHTTP_QUERY_STATUS_CODE,
 
348
       NULL,
 
349
       NULL,
 
350
       &status_code_len,
 
351
       NULL) &&
 
352
      GetLastError () != ERROR_INSUFFICIENT_BUFFER)
 
353
    {
 
354
      _g_winhttp_set_error (error, GetLastError (), what);
 
355
 
 
356
      return FALSE;
 
357
    }
 
358
 
 
359
  status_code = g_malloc (status_code_len);
 
360
 
 
361
  if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
 
362
      (request,
 
363
       WINHTTP_QUERY_STATUS_CODE,
 
364
       NULL,
 
365
       status_code,
 
366
       &status_code_len,
 
367
       NULL))
 
368
    {
 
369
      _g_winhttp_set_error (error, GetLastError (), what);
 
370
      g_free (status_code);
 
371
 
 
372
      return FALSE;
 
373
    }
 
374
 
 
375
  if (status_code[0] != L'2')
 
376
    {
 
377
      wchar_t *status_text = NULL;
 
378
      DWORD status_text_len;
 
379
 
 
380
      if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
 
381
          (request,
 
382
           WINHTTP_QUERY_STATUS_TEXT,
 
383
           NULL,
 
384
           NULL,
 
385
           &status_text_len,
 
386
           NULL) &&
 
387
          GetLastError () == ERROR_INSUFFICIENT_BUFFER)
 
388
        {
 
389
          status_text = g_malloc (status_text_len);
 
390
 
 
391
          if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
 
392
              (request,
 
393
               WINHTTP_QUERY_STATUS_TEXT,
 
394
               NULL,
 
395
               status_text,
 
396
               &status_text_len,
 
397
               NULL))
 
398
            {
 
399
              g_free (status_text);
 
400
              status_text = NULL;
 
401
            }
 
402
        }
 
403
 
 
404
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
 
405
                   "%s failed: %S %S",
 
406
                   what, status_code, status_text ? status_text : L"");
 
407
      g_free (status_code);
 
408
      g_free (status_text);
 
409
 
 
410
      return FALSE;
 
411
    }
 
412
 
 
413
  g_free (status_code);
 
414
 
 
415
  return TRUE;
 
416
}
 
417
 
 
418
gboolean
 
419
_g_winhttp_query_header (GWinHttpVfs *vfs,
 
420
                         HINTERNET    request,
 
421
                         const char  *request_description,
 
422
                         DWORD        which_header,
 
423
                         wchar_t    **header,
 
424
                         GError     **error)
 
425
{
 
426
  DWORD header_len = 0;
 
427
 
 
428
  if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
 
429
      (request,
 
430
       which_header,
 
431
       NULL,
 
432
       NULL,
 
433
       &header_len,
 
434
       NULL) &&
 
435
      GetLastError () != ERROR_INSUFFICIENT_BUFFER)
 
436
    {
 
437
      _g_winhttp_set_error (error, GetLastError (), request_description);
 
438
 
 
439
      return FALSE;
 
440
    }
 
441
 
 
442
  *header = g_malloc (header_len);
 
443
  if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
 
444
      (request,
 
445
       which_header,
 
446
       NULL,
 
447
       *header,
 
448
       &header_len,
 
449
       NULL))
 
450
    {
 
451
      _g_winhttp_set_error (error, GetLastError (), request_description);
 
452
      g_free (*header);
 
453
      *header = NULL;
 
454
 
 
455
      return FALSE;
 
456
    }
 
457
 
 
458
  return TRUE;
 
459
}