win32/gwinhttpvfs.c win32/gwinhttpvfs.h win32/gwinhttpfile.c
[platform/upstream/glib.git] / gio / win32 / gwinhttpfile.c
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 <string.h>
28
29 #include "gfile.h"
30 #include "gfileattribute.h"
31 #include "gfileinfo.h"
32 #include "gwinhttpfile.h"
33 #include "gwinhttpfileinputstream.h"
34 #include "gwinhttpfileoutputstream.h"
35 #include "gioerror.h"
36
37 #include "glibintl.h"
38
39 #include "gioalias.h"
40
41 static void g_winhttp_file_file_iface_init (GFileIface *iface);
42
43 #define g_winhttp_file_get_type _g_winhttp_file_get_type
44 G_DEFINE_TYPE_WITH_CODE (GWinHttpFile, g_winhttp_file, G_TYPE_OBJECT,
45                          G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
46                                                 g_winhttp_file_file_iface_init))
47
48 static void
49 g_winhttp_file_finalize (GObject *object)
50 {
51   GWinHttpFile *file;
52
53   file = G_WINHTTP_FILE (object);
54
55   g_free (file->url.lpszScheme);
56   g_free (file->url.lpszHostName);
57   g_free (file->url.lpszUserName);
58   g_free (file->url.lpszPassword);
59   g_free (file->url.lpszUrlPath);
60   g_free (file->url.lpszExtraInfo);
61
62   G_OBJECT_CLASS (g_winhttp_file_parent_class)->finalize (object);
63 }
64
65 static void
66 g_winhttp_file_class_init (GWinHttpFileClass *klass)
67 {
68   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
69
70   gobject_class->finalize = g_winhttp_file_finalize;
71 }
72
73 static void
74 g_winhttp_file_init (GWinHttpFile *winhttp)
75 {
76 }
77
78 /**
79  * _g_winhttp_file_new:
80  * @vfs: GWinHttpVfs to use
81  * @uri: URI of the GWinHttpFile to create.
82  *
83  * Returns: new winhttp #GFile.
84  **/
85 GFile *
86 _g_winhttp_file_new (GWinHttpVfs *vfs,
87                      const char  *uri)
88 {
89   wchar_t *wuri;
90   GWinHttpFile *file;
91
92   wuri = g_utf8_to_utf16 (uri, -1, NULL, NULL, NULL);
93
94   if (wuri == NULL)
95     return NULL;
96
97   file = g_object_new (G_TYPE_WINHTTP_FILE, NULL);
98   file->vfs = vfs;
99
100   memset (&file->url, 0, sizeof (file->url));
101   file->url.dwStructSize = sizeof (file->url);
102   file->url.dwSchemeLength = 1;
103   file->url.dwHostNameLength = 1;
104   file->url.dwUserNameLength = 1;
105   file->url.dwPasswordLength = 1;
106   file->url.dwUrlPathLength = 1;
107   file->url.dwExtraInfoLength = 1;
108
109   if (!G_WINHTTP_VFS_GET_CLASS (vfs)->pWinHttpCrackUrl (wuri, 0, 0, &file->url))
110     {
111       g_free (wuri);
112       return NULL;
113     }
114
115   file->url.lpszScheme = g_new (wchar_t, ++file->url.dwSchemeLength);
116   file->url.lpszHostName = g_new (wchar_t, ++file->url.dwHostNameLength);
117   file->url.lpszUserName = g_new (wchar_t, ++file->url.dwUserNameLength);
118   file->url.lpszPassword = g_new (wchar_t, ++file->url.dwPasswordLength);
119   file->url.lpszUrlPath = g_new (wchar_t, ++file->url.dwUrlPathLength);
120   file->url.lpszExtraInfo = g_new (wchar_t, ++file->url.dwExtraInfoLength);
121
122   if (!G_WINHTTP_VFS_GET_CLASS (vfs)->pWinHttpCrackUrl (wuri, 0, 0, &file->url))
123     {
124       g_free (file->url.lpszScheme);
125       g_free (file->url.lpszHostName);
126       g_free (file->url.lpszUserName);
127       g_free (file->url.lpszPassword);
128       g_free (file->url.lpszUrlPath);
129       g_free (file->url.lpszExtraInfo);
130       g_free (wuri);
131       return NULL;
132     }
133
134   g_free (wuri);
135   return G_FILE (file);
136 }
137
138 static gboolean
139 g_winhttp_file_is_native (GFile *file)
140 {
141   return FALSE;
142 }
143
144 static gboolean
145 g_winhttp_file_has_uri_scheme (GFile      *file,
146                                const char *uri_scheme)
147 {
148   return (g_ascii_strcasecmp (uri_scheme, "http") == 0 ||
149           g_ascii_strcasecmp (uri_scheme, "https") == 0);
150 }
151
152 static char *
153 g_winhttp_file_get_uri_scheme (GFile *file)
154 {
155   GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
156
157   return g_utf16_to_utf8 (winhttp_file->url.lpszScheme, -1, NULL, NULL, NULL);
158 }
159
160 static char *
161 g_winhttp_file_get_basename (GFile *file)
162 {
163   GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
164   char *basename;
165   char *last_slash;
166   char *retval;
167
168   basename = g_utf16_to_utf8 (winhttp_file->url.lpszUrlPath, -1, NULL, NULL, NULL);
169   last_slash = strrchr (basename, '/');
170   /* If no slash, or only "/" fallback to full path part of URI */
171   if (last_slash == NULL || last_slash[1] == '\0')
172     return basename;
173
174   retval = g_strdup (last_slash + 1);
175   g_free (basename);
176
177   return retval;
178 }
179
180 static char *
181 g_winhttp_file_get_path (GFile *file)
182 {
183   return NULL;
184 }
185
186 static char *
187 g_winhttp_file_get_uri (GFile *file)
188 {
189   GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
190   DWORD len;
191   wchar_t *wuri;
192   char *retval;
193
194   len = 0;
195   if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpCreateUrl (&winhttp_file->url, ICU_ESCAPE, NULL, &len) &&
196       GetLastError () != ERROR_INSUFFICIENT_BUFFER)
197     return NULL;
198
199   wuri = g_new (wchar_t, ++len);
200
201   if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpCreateUrl (&winhttp_file->url, ICU_ESCAPE, wuri, &len))
202     {
203       g_free (wuri);
204       return NULL;
205     }
206
207   retval = g_utf16_to_utf8 (wuri, -1, NULL, NULL, NULL);
208   g_free (wuri);
209
210   if (g_str_has_prefix (retval, "http://:@"))
211     {
212       memmove (retval + 7, retval + 9, strlen (retval) - 9);
213       retval[strlen (retval) - 2] = '\0';
214     }
215   else if (g_str_has_prefix (retval, "https://:@"))
216     {
217       memmove (retval + 8, retval + 10, strlen (retval) - 10);
218       retval[strlen (retval) - 2] = '\0';
219     }
220
221   return retval;
222 }
223
224 static char *
225 g_winhttp_file_get_parse_name (GFile *file)
226 {
227   /* FIXME: More hair surely needed */
228
229   return g_winhttp_file_get_uri (file);
230 }
231
232 static GFile *
233 g_winhttp_file_get_parent (GFile *file)
234 {
235   GWinHttpFile *winhttp_file;
236   char *uri;
237   char *last_slash;
238   GFile *parent;
239
240   winhttp_file = G_WINHTTP_FILE (file);
241
242   uri = g_winhttp_file_get_uri (file);
243   if (uri == NULL)
244     return NULL;
245
246   last_slash = strrchr (uri, '/');
247   if (last_slash == NULL || *(last_slash+1) == 0)
248     {
249       g_free (uri);
250       return NULL;
251     }
252
253   while (last_slash > uri && *last_slash == '/')
254     last_slash--;
255
256   last_slash[1] = '\0';
257
258   parent = _g_winhttp_file_new (winhttp_file->vfs, uri);
259   g_free (uri);
260
261   return parent;
262 }
263
264 static GFile *
265 g_winhttp_file_dup (GFile *file)
266 {
267   GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
268   char *uri = g_winhttp_file_get_uri (file);
269   GFile *retval = _g_winhttp_file_new (winhttp_file->vfs, uri);
270
271   g_free (uri);
272
273   return retval;
274 }
275
276 static guint
277 g_winhttp_file_hash (GFile *file)
278 {
279   char *uri = g_winhttp_file_get_uri (file);
280   guint retval = g_str_hash (uri);
281
282   g_free (uri);
283
284   return retval;
285 }
286
287 static gboolean
288 g_winhttp_file_equal (GFile *file1,
289                       GFile *file2)
290 {
291   char *uri1 = g_winhttp_file_get_uri (file1);
292   char *uri2 = g_winhttp_file_get_uri (file2);
293   gboolean retval = g_str_equal (uri1, uri2);
294
295   g_free (uri1);
296   g_free (uri2);
297
298   return retval;
299 }
300
301 static const char *
302 match_prefix (const char *path,
303               const char *prefix)
304 {
305   int prefix_len;
306
307   prefix_len = strlen (prefix);
308   if (strncmp (path, prefix, prefix_len) != 0)
309     return NULL;
310
311   if (prefix_len > 0 && prefix[prefix_len-1] == '/')
312     prefix_len--;
313
314   return path + prefix_len;
315 }
316
317 static gboolean
318 g_winhttp_file_prefix_matches (GFile *parent,
319                                GFile *descendant)
320 {
321   char *parent_uri = g_winhttp_file_get_uri (parent);
322   char *descendant_uri = g_winhttp_file_get_uri (descendant);
323   const char *remainder;
324   gboolean retval;
325
326   remainder = match_prefix (descendant_uri, parent_uri);
327
328   if (remainder != NULL && *remainder == '/')
329     retval = TRUE;
330   else
331     retval = FALSE;
332
333   g_free (parent_uri);
334   g_free (descendant_uri);
335
336   return retval;
337 }
338
339 static char *
340 g_winhttp_file_get_relative_path (GFile *parent,
341                                   GFile *descendant)
342 {
343   char *parent_uri = g_winhttp_file_get_uri (parent);
344   char *descendant_uri = g_winhttp_file_get_uri (descendant);
345   const char *remainder;
346   char *retval;
347
348   remainder = match_prefix (descendant_uri, parent_uri);
349
350   if (remainder != NULL && *remainder == '/')
351     retval = g_strdup (remainder + 1);
352   else
353     retval = NULL;
354
355   g_free (parent_uri);
356   g_free (descendant_uri);
357
358   return retval;
359 }
360
361 static GFile *
362 g_winhttp_file_resolve_relative_path (GFile      *file,
363                                       const char *relative_path)
364 {
365   GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
366   GWinHttpFile *child;
367   wchar_t *wnew_path = g_utf8_to_utf16 (relative_path, -1, NULL, NULL, NULL);
368
369   if (wnew_path == NULL)
370     return NULL;
371
372   if (*wnew_path != '/')
373     {
374       wchar_t *tmp = g_new (wchar_t, wcslen (winhttp_file->url.lpszUrlPath) + 1 + wcslen (wnew_path) + 1);
375       wcscpy (tmp, winhttp_file->url.lpszUrlPath);
376       wcscat (tmp, L"/");
377       wcscat (tmp, wnew_path);
378
379       g_free (wnew_path);
380       wnew_path = tmp;
381     }
382
383   child = g_object_new (G_TYPE_WINHTTP_FILE, NULL);
384   child->vfs = winhttp_file->vfs;
385   child->url = winhttp_file->url;
386   child->url.lpszScheme = g_memdup (winhttp_file->url.lpszScheme, winhttp_file->url.dwSchemeLength*2);
387   child->url.lpszHostName = g_memdup (winhttp_file->url.lpszHostName, winhttp_file->url.dwHostNameLength*2);
388   child->url.lpszUserName = g_memdup (winhttp_file->url.lpszUserName, winhttp_file->url.dwUserNameLength*2);
389   child->url.lpszPassword = g_memdup (winhttp_file->url.lpszPassword, winhttp_file->url.dwPasswordLength*2);
390   child->url.lpszUrlPath = wnew_path;
391   child->url.dwUrlPathLength = 2*(wcslen (wnew_path)+1);
392   child->url.lpszExtraInfo = NULL;
393   child->url.dwExtraInfoLength = 0;
394
395   return (GFile *) child;
396 }
397
398 static GFile *
399 g_winhttp_file_get_child_for_display_name (GFile        *file,
400                                            const char   *display_name,
401                                            GError      **error)
402 {
403   GFile *new_file;
404   char *basename;
405
406   basename = g_locale_from_utf8 (display_name, -1, NULL, NULL, NULL);
407   if (basename == NULL)
408     {
409       g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME,
410                    _("Invalid filename %s"), display_name);
411       return NULL;
412     }
413
414   new_file = g_file_get_child (file, basename);
415   g_free (basename);
416
417   return new_file;
418 }
419
420 static GFile *
421 g_winhttp_file_set_display_name (GFile         *file,
422                                  const char    *display_name,
423                                  GCancellable  *cancellable,
424                                  GError       **error)
425 {
426   g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
427                        _("Operation not supported"));
428
429   return NULL;
430 }
431
432 static time_t
433 mktime_utc (SYSTEMTIME *t)
434 {
435   time_t retval;
436
437   static const gint days_before[] =
438   {
439     0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
440   };
441
442   if (t->wMonth < 1 || t->wMonth > 12)
443     return (time_t) -1;
444
445   retval = (t->wYear - 1970) * 365;
446   retval += (t->wYear - 1968) / 4;
447   retval += days_before[t->wMonth-1] + t->wDay - 1;
448
449   if (t->wYear % 4 == 0 && t->wMonth < 3)
450     retval -= 1;
451
452   retval = ((((retval * 24) + t->wHour) * 60) + t->wMinute) * 60 + t->wSecond;
453
454   return retval;
455 }
456
457 static GFileInfo *
458 g_winhttp_file_query_info (GFile                *file,
459                            const char           *attributes,
460                            GFileQueryInfoFlags   flags,
461                            GCancellable         *cancellable,
462                            GError              **error)
463 {
464   GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
465   HINTERNET connection, request;
466   const wchar_t *accept_types[] =
467     {
468       L"*/*",
469       NULL,
470     };
471   GFileInfo *info;
472   GFileAttributeMatcher *matcher;
473   char *basename;
474   wchar_t *content_length;
475   wchar_t *content_type;
476   SYSTEMTIME last_modified;
477   DWORD last_modified_len;
478
479   connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpConnect
480     (G_WINHTTP_VFS (winhttp_file->vfs)->session,
481      winhttp_file->url.lpszHostName,
482      winhttp_file->url.nPort,
483      0);
484
485   if (connection == NULL)
486     {
487       _g_winhttp_set_error (error, GetLastError (), "HTTP connection");
488
489       return NULL;
490     }
491
492   request = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpOpenRequest
493     (connection,
494      L"HEAD",
495      winhttp_file->url.lpszUrlPath,
496      NULL,
497      WINHTTP_NO_REFERER,
498      accept_types,
499      winhttp_file->url.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0);
500
501   if (request == NULL)
502     {
503       _g_winhttp_set_error (error, GetLastError (), "HEAD request");
504
505       return NULL;
506     }
507
508   if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpSendRequest
509       (request,
510        NULL, 0,
511        NULL, 0,
512        0,
513        0))
514     {
515       _g_winhttp_set_error (error, GetLastError (), "HEAD request");
516
517       return NULL;
518     }
519
520   if (!_g_winhttp_response (winhttp_file->vfs, request, error, "HEAD request"))
521     return NULL;
522
523   matcher = g_file_attribute_matcher_new (attributes);
524   info = g_file_info_new ();
525   g_file_info_set_attribute_mask (info, matcher);
526
527   basename = g_winhttp_file_get_basename (file);
528   g_file_info_set_name (info, basename);
529   g_free (basename);
530
531   content_length = NULL;
532   if (_g_winhttp_query_header (winhttp_file->vfs,
533                                request,
534                                "HEAD request",
535                                WINHTTP_QUERY_CONTENT_LENGTH,
536                                &content_length,
537                                NULL))
538     {
539       gint64 cl;
540       int n;
541
542       if (swscanf (content_length, L"%I64d%n", &cl, &n) == 1 &&
543           n == wcslen (content_length))
544         g_file_info_set_size (info, cl);
545
546       g_free (content_length);
547     }
548
549   if (matcher == NULL)
550     return info;
551
552   content_type = NULL;
553   if (_g_winhttp_query_header (winhttp_file->vfs,
554                                request,
555                                "HEAD request",
556                                WINHTTP_QUERY_CONTENT_TYPE,
557                                &content_type,
558                                NULL))
559     {
560       char *ct = g_utf16_to_utf8 (content_type, -1, NULL, NULL, NULL);
561
562       if (ct != NULL)
563         {
564           char *p = strchr (ct, ';');
565
566           if (p != NULL)
567             {
568               char *tmp = g_strndup (ct, p - ct);
569
570               g_file_info_set_content_type (info, tmp);
571               g_free (tmp);
572             }
573           else
574             g_file_info_set_content_type (info, ct);
575         }
576
577       g_free (ct);
578     }
579
580   last_modified_len = sizeof (last_modified);
581   if (G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpQueryHeaders
582       (request,
583        WINHTTP_QUERY_LAST_MODIFIED | WINHTTP_QUERY_FLAG_SYSTEMTIME,
584        NULL,
585        &last_modified,
586        &last_modified_len,
587        NULL) &&
588       last_modified_len == sizeof (last_modified) &&
589       /* Don't bother comparing to the exact Y2038 moment */
590       last_modified.wYear >= 1970 &&
591       last_modified.wYear < 2038)
592     {
593       GTimeVal tv;
594
595       tv.tv_sec = mktime_utc (&last_modified);
596       tv.tv_usec = last_modified.wMilliseconds * 1000;
597
598       g_file_info_set_modification_time (info, &tv);
599     }
600
601   g_file_attribute_matcher_unref (matcher);
602
603   return info;
604 }
605
606 static GFileInputStream *
607 g_winhttp_file_read (GFile         *file,
608                      GCancellable  *cancellable,
609                      GError       **error)
610 {
611   GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
612   HINTERNET connection, request;
613   const wchar_t *accept_types[] =
614     {
615       L"*/*",
616       NULL,
617     };
618
619   connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpConnect
620     (G_WINHTTP_VFS (winhttp_file->vfs)->session,
621      winhttp_file->url.lpszHostName,
622      winhttp_file->url.nPort,
623      0);
624
625   if (connection == NULL)
626     {
627       _g_winhttp_set_error (error, GetLastError (), "HTTP connection");
628
629       return NULL;
630     }
631
632   request = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpOpenRequest
633     (connection,
634      L"GET",
635      winhttp_file->url.lpszUrlPath,
636      NULL,
637      WINHTTP_NO_REFERER,
638      accept_types,
639      winhttp_file->url.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0);
640
641   if (request == NULL)
642     {
643       _g_winhttp_set_error (error, GetLastError (), "GET request");
644
645       return NULL;
646     }
647
648   return _g_winhttp_file_input_stream_new (winhttp_file, connection, request);
649 }
650
651 static GFileOutputStream *
652 g_winhttp_file_create (GFile             *file,
653                        GFileCreateFlags   flags,
654                        GCancellable      *cancellable,
655                        GError           **error)
656 {
657   GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
658   HINTERNET connection;
659
660   connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpConnect
661     (G_WINHTTP_VFS (winhttp_file->vfs)->session,
662      winhttp_file->url.lpszHostName,
663      winhttp_file->url.nPort,
664      0);
665
666   if (connection == NULL)
667     {
668       _g_winhttp_set_error (error, GetLastError (), "HTTP connection");
669
670       return NULL;
671     }
672
673   return _g_winhttp_file_output_stream_new (winhttp_file, connection);
674 }
675
676 #if 0
677
678 static GFileOutputStream *
679 g_winhttp_file_replace (GFile             *file,
680                         const char        *etag,
681                         gboolean           make_backup,
682                         GFileCreateFlags   flags,
683                         GCancellable      *cancellable,
684                         GError           **error)
685 {
686   /* FIXME: Implement */
687
688   return NULL;
689 }
690
691
692 static gboolean
693 g_winhttp_file_delete (GFile         *file,
694                        GCancellable  *cancellable,
695                        GError       **error)
696 {
697   /* FIXME: Implement */
698
699   return FALSE;
700 }
701
702 static gboolean
703 g_winhttp_file_make_directory (GFile         *file,
704                                GCancellable  *cancellable,
705                                GError       **error)
706 {
707   /* FIXME: Implement */
708
709   return FALSE;
710 }
711
712 static gboolean
713 g_winhttp_file_copy (GFile                  *source,
714                      GFile                  *destination,
715                      GFileCopyFlags          flags,
716                      GCancellable           *cancellable,
717                      GFileProgressCallback   progress_callback,
718                      gpointer                progress_callback_data,
719                      GError                **error)
720 {
721   /* Fall back to default copy?? */
722   g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
723                        "Copy not supported");
724
725   return FALSE;
726 }
727
728 static gboolean
729 g_winhttp_file_move (GFile                  *source,
730                      GFile                  *destination,
731                      GFileCopyFlags          flags,
732                      GCancellable           *cancellable,
733                      GFileProgressCallback   progress_callback,
734                      gpointer                progress_callback_data,
735                      GError                **error)
736 {
737   /* FIXME: Implement */
738
739   return FALSE;
740 }
741
742 #endif
743
744 static void
745 g_winhttp_file_file_iface_init (GFileIface *iface)
746 {
747   iface->dup = g_winhttp_file_dup;
748   iface->hash = g_winhttp_file_hash;
749   iface->equal = g_winhttp_file_equal;
750   iface->is_native = g_winhttp_file_is_native;
751   iface->has_uri_scheme = g_winhttp_file_has_uri_scheme;
752   iface->get_uri_scheme = g_winhttp_file_get_uri_scheme;
753   iface->get_basename = g_winhttp_file_get_basename;
754   iface->get_path = g_winhttp_file_get_path;
755   iface->get_uri = g_winhttp_file_get_uri;
756   iface->get_parse_name = g_winhttp_file_get_parse_name;
757   iface->get_parent = g_winhttp_file_get_parent;
758   iface->prefix_matches = g_winhttp_file_prefix_matches;
759   iface->get_relative_path = g_winhttp_file_get_relative_path;
760   iface->resolve_relative_path = g_winhttp_file_resolve_relative_path;
761   iface->get_child_for_display_name = g_winhttp_file_get_child_for_display_name;
762   iface->set_display_name = g_winhttp_file_set_display_name;
763   iface->query_info = g_winhttp_file_query_info;
764   iface->read_fn = g_winhttp_file_read;
765   iface->create = g_winhttp_file_create;
766 #if 0
767   iface->replace = g_winhttp_file_replace;
768   iface->delete_file = g_winhttp_file_delete;
769   iface->make_directory = g_winhttp_file_make_directory;
770   iface->copy = g_winhttp_file_copy;
771   iface->move = g_winhttp_file_move;
772 #endif
773 }