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>
31
#include "gfileattribute.h"
32
#include "gfileinfo.h"
33
#include "gwinhttpfile.h"
34
#include "gwinhttpfileinputstream.h"
35
#include "gwinhttpfileoutputstream.h"
42
static void g_winhttp_file_file_iface_init (GFileIface *iface);
44
#define g_winhttp_file_get_type _g_winhttp_file_get_type
45
G_DEFINE_TYPE_WITH_CODE (GWinHttpFile, g_winhttp_file, G_TYPE_OBJECT,
46
G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
47
g_winhttp_file_file_iface_init))
50
g_winhttp_file_finalize (GObject *object)
54
file = G_WINHTTP_FILE (object);
56
g_free (file->url.lpszScheme);
57
g_free (file->url.lpszHostName);
58
g_free (file->url.lpszUserName);
59
g_free (file->url.lpszPassword);
60
g_free (file->url.lpszUrlPath);
61
g_free (file->url.lpszExtraInfo);
63
G_OBJECT_CLASS (g_winhttp_file_parent_class)->finalize (object);
67
g_winhttp_file_class_init (GWinHttpFileClass *klass)
69
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
71
gobject_class->finalize = g_winhttp_file_finalize;
75
g_winhttp_file_init (GWinHttpFile *winhttp)
80
* _g_winhttp_file_new:
81
* @vfs: GWinHttpVfs to use
82
* @uri: URI of the GWinHttpFile to create.
84
* Returns: new winhttp #GFile.
87
_g_winhttp_file_new (GWinHttpVfs *vfs,
93
wuri = g_utf8_to_utf16 (uri, -1, NULL, NULL, NULL);
98
file = g_object_new (G_TYPE_WINHTTP_FILE, NULL);
101
memset (&file->url, 0, sizeof (file->url));
102
file->url.dwStructSize = sizeof (file->url);
103
file->url.dwSchemeLength = 1;
104
file->url.dwHostNameLength = 1;
105
file->url.dwUserNameLength = 1;
106
file->url.dwPasswordLength = 1;
107
file->url.dwUrlPathLength = 1;
108
file->url.dwExtraInfoLength = 1;
110
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpCrackUrl (wuri, 0, 0, &file->url))
116
file->url.lpszScheme = g_new (wchar_t, ++file->url.dwSchemeLength);
117
file->url.lpszHostName = g_new (wchar_t, ++file->url.dwHostNameLength);
118
file->url.lpszUserName = g_new (wchar_t, ++file->url.dwUserNameLength);
119
file->url.lpszPassword = g_new (wchar_t, ++file->url.dwPasswordLength);
120
file->url.lpszUrlPath = g_new (wchar_t, ++file->url.dwUrlPathLength);
121
file->url.lpszExtraInfo = g_new (wchar_t, ++file->url.dwExtraInfoLength);
123
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpCrackUrl (wuri, 0, 0, &file->url))
125
g_free (file->url.lpszScheme);
126
g_free (file->url.lpszHostName);
127
g_free (file->url.lpszUserName);
128
g_free (file->url.lpszPassword);
129
g_free (file->url.lpszUrlPath);
130
g_free (file->url.lpszExtraInfo);
136
return G_FILE (file);
140
g_winhttp_file_is_native (GFile *file)
146
g_winhttp_file_has_uri_scheme (GFile *file,
147
const char *uri_scheme)
149
return (g_ascii_strcasecmp (uri_scheme, "http") == 0 ||
150
g_ascii_strcasecmp (uri_scheme, "https") == 0);
154
g_winhttp_file_get_uri_scheme (GFile *file)
156
GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
158
return g_utf16_to_utf8 (winhttp_file->url.lpszScheme, -1, NULL, NULL, NULL);
162
g_winhttp_file_get_basename (GFile *file)
164
GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
169
basename = g_utf16_to_utf8 (winhttp_file->url.lpszUrlPath, -1, NULL, NULL, NULL);
170
last_slash = strrchr (basename, '/');
171
/* If no slash, or only "/" fallback to full path part of URI */
172
if (last_slash == NULL || last_slash[1] == '\0')
175
retval = g_strdup (last_slash + 1);
182
g_winhttp_file_get_path (GFile *file)
188
g_winhttp_file_get_uri (GFile *file)
190
GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
196
if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpCreateUrl (&winhttp_file->url, ICU_ESCAPE, NULL, &len) &&
197
GetLastError () != ERROR_INSUFFICIENT_BUFFER)
200
wuri = g_new (wchar_t, ++len);
202
if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpCreateUrl (&winhttp_file->url, ICU_ESCAPE, wuri, &len))
208
retval = g_utf16_to_utf8 (wuri, -1, NULL, NULL, NULL);
211
if (g_str_has_prefix (retval, "http://:@"))
213
memmove (retval + 7, retval + 9, strlen (retval) - 9);
214
retval[strlen (retval) - 2] = '\0';
216
else if (g_str_has_prefix (retval, "https://:@"))
218
memmove (retval + 8, retval + 10, strlen (retval) - 10);
219
retval[strlen (retval) - 2] = '\0';
226
g_winhttp_file_get_parse_name (GFile *file)
228
/* FIXME: More hair surely needed */
230
return g_winhttp_file_get_uri (file);
234
g_winhttp_file_get_parent (GFile *file)
236
GWinHttpFile *winhttp_file;
241
winhttp_file = G_WINHTTP_FILE (file);
243
uri = g_winhttp_file_get_uri (file);
247
last_slash = strrchr (uri, '/');
248
if (last_slash == NULL || *(last_slash+1) == 0)
254
while (last_slash > uri && *last_slash == '/')
257
last_slash[1] = '\0';
259
parent = _g_winhttp_file_new (winhttp_file->vfs, uri);
266
g_winhttp_file_dup (GFile *file)
268
GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
269
char *uri = g_winhttp_file_get_uri (file);
270
GFile *retval = _g_winhttp_file_new (winhttp_file->vfs, uri);
278
g_winhttp_file_hash (GFile *file)
280
char *uri = g_winhttp_file_get_uri (file);
281
guint retval = g_str_hash (uri);
289
g_winhttp_file_equal (GFile *file1,
292
char *uri1 = g_winhttp_file_get_uri (file1);
293
char *uri2 = g_winhttp_file_get_uri (file2);
294
gboolean retval = g_str_equal (uri1, uri2);
303
match_prefix (const char *path,
308
prefix_len = strlen (prefix);
309
if (strncmp (path, prefix, prefix_len) != 0)
312
if (prefix_len > 0 && prefix[prefix_len-1] == '/')
315
return path + prefix_len;
319
g_winhttp_file_prefix_matches (GFile *parent,
322
char *parent_uri = g_winhttp_file_get_uri (parent);
323
char *descendant_uri = g_winhttp_file_get_uri (descendant);
324
const char *remainder;
327
remainder = match_prefix (descendant_uri, parent_uri);
329
if (remainder != NULL && *remainder == '/')
335
g_free (descendant_uri);
341
g_winhttp_file_get_relative_path (GFile *parent,
344
char *parent_uri = g_winhttp_file_get_uri (parent);
345
char *descendant_uri = g_winhttp_file_get_uri (descendant);
346
const char *remainder;
349
remainder = match_prefix (descendant_uri, parent_uri);
351
if (remainder != NULL && *remainder == '/')
352
retval = g_strdup (remainder + 1);
357
g_free (descendant_uri);
363
g_winhttp_file_resolve_relative_path (GFile *file,
364
const char *relative_path)
366
GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
368
wchar_t *wnew_path = g_utf8_to_utf16 (relative_path, -1, NULL, NULL, NULL);
370
if (wnew_path == NULL)
373
if (*wnew_path != '/')
375
wchar_t *tmp = g_new (wchar_t, wcslen (winhttp_file->url.lpszUrlPath) + 1 + wcslen (wnew_path) + 1);
376
wcscpy (tmp, winhttp_file->url.lpszUrlPath);
378
wcscat (tmp, wnew_path);
384
child = g_object_new (G_TYPE_WINHTTP_FILE, NULL);
385
child->vfs = winhttp_file->vfs;
386
child->url = winhttp_file->url;
387
child->url.lpszScheme = g_memdup (winhttp_file->url.lpszScheme, winhttp_file->url.dwSchemeLength*2);
388
child->url.lpszHostName = g_memdup (winhttp_file->url.lpszHostName, winhttp_file->url.dwHostNameLength*2);
389
child->url.lpszUserName = g_memdup (winhttp_file->url.lpszUserName, winhttp_file->url.dwUserNameLength*2);
390
child->url.lpszPassword = g_memdup (winhttp_file->url.lpszPassword, winhttp_file->url.dwPasswordLength*2);
391
child->url.lpszUrlPath = wnew_path;
392
child->url.dwUrlPathLength = 2*(wcslen (wnew_path)+1);
393
child->url.lpszExtraInfo = NULL;
394
child->url.dwExtraInfoLength = 0;
396
return (GFile *) child;
400
g_winhttp_file_get_child_for_display_name (GFile *file,
401
const char *display_name,
407
basename = g_locale_from_utf8 (display_name, -1, NULL, NULL, NULL);
408
if (basename == NULL)
410
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME,
411
_("Invalid filename %s"), display_name);
415
new_file = g_file_get_child (file, basename);
422
g_winhttp_file_set_display_name (GFile *file,
423
const char *display_name,
424
GCancellable *cancellable,
427
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
428
_("Operation not supported"));
434
mktime_utc (SYSTEMTIME *t)
438
static const gint days_before[] =
440
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
443
if (t->wMonth < 1 || t->wMonth > 12)
446
retval = (t->wYear - 1970) * 365;
447
retval += (t->wYear - 1968) / 4;
448
retval += days_before[t->wMonth-1] + t->wDay - 1;
450
if (t->wYear % 4 == 0 && t->wMonth < 3)
453
retval = ((((retval * 24) + t->wHour) * 60) + t->wMinute) * 60 + t->wSecond;
459
g_winhttp_file_query_info (GFile *file,
460
const char *attributes,
461
GFileQueryInfoFlags flags,
462
GCancellable *cancellable,
465
GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
466
HINTERNET connection, request;
467
const wchar_t *accept_types[] =
473
GFileAttributeMatcher *matcher;
475
wchar_t *content_length;
476
wchar_t *content_type;
477
SYSTEMTIME last_modified;
478
DWORD last_modified_len;
480
connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpConnect
481
(G_WINHTTP_VFS (winhttp_file->vfs)->session,
482
winhttp_file->url.lpszHostName,
483
winhttp_file->url.nPort,
486
if (connection == NULL)
488
_g_winhttp_set_error (error, GetLastError (), "HTTP connection");
493
request = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpOpenRequest
496
winhttp_file->url.lpszUrlPath,
500
winhttp_file->url.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0);
504
_g_winhttp_set_error (error, GetLastError (), "HEAD request");
509
if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpSendRequest
516
_g_winhttp_set_error (error, GetLastError (), "HEAD request");
521
if (!_g_winhttp_response (winhttp_file->vfs, request, error, "HEAD request"))
524
matcher = g_file_attribute_matcher_new (attributes);
525
info = g_file_info_new ();
526
g_file_info_set_attribute_mask (info, matcher);
528
basename = g_winhttp_file_get_basename (file);
529
g_file_info_set_name (info, basename);
532
content_length = NULL;
533
if (_g_winhttp_query_header (winhttp_file->vfs,
536
WINHTTP_QUERY_CONTENT_LENGTH,
543
if (swscanf (content_length, L"%I64d%n", &cl, &n) == 1 &&
544
n == wcslen (content_length))
545
g_file_info_set_size (info, cl);
547
g_free (content_length);
554
if (_g_winhttp_query_header (winhttp_file->vfs,
557
WINHTTP_QUERY_CONTENT_TYPE,
561
char *ct = g_utf16_to_utf8 (content_type, -1, NULL, NULL, NULL);
565
char *p = strchr (ct, ';');
569
char *tmp = g_strndup (ct, p - ct);
571
g_file_info_set_content_type (info, tmp);
575
g_file_info_set_content_type (info, ct);
581
last_modified_len = sizeof (last_modified);
582
if (G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpQueryHeaders
584
WINHTTP_QUERY_LAST_MODIFIED | WINHTTP_QUERY_FLAG_SYSTEMTIME,
589
last_modified_len == sizeof (last_modified) &&
590
/* Don't bother comparing to the exact Y2038 moment */
591
last_modified.wYear >= 1970 &&
592
last_modified.wYear < 2038)
596
tv.tv_sec = mktime_utc (&last_modified);
597
tv.tv_usec = last_modified.wMilliseconds * 1000;
599
g_file_info_set_modification_time (info, &tv);
602
g_file_attribute_matcher_unref (matcher);
607
static GFileInputStream *
608
g_winhttp_file_read (GFile *file,
609
GCancellable *cancellable,
612
GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
613
HINTERNET connection, request;
614
const wchar_t *accept_types[] =
620
connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpConnect
621
(G_WINHTTP_VFS (winhttp_file->vfs)->session,
622
winhttp_file->url.lpszHostName,
623
winhttp_file->url.nPort,
626
if (connection == NULL)
628
_g_winhttp_set_error (error, GetLastError (), "HTTP connection");
633
request = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpOpenRequest
636
winhttp_file->url.lpszUrlPath,
640
winhttp_file->url.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0);
644
_g_winhttp_set_error (error, GetLastError (), "GET request");
649
return _g_winhttp_file_input_stream_new (winhttp_file, connection, request);
652
static GFileOutputStream *
653
g_winhttp_file_create (GFile *file,
654
GFileCreateFlags flags,
655
GCancellable *cancellable,
658
GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file);
659
HINTERNET connection;
661
connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->funcs->pWinHttpConnect
662
(G_WINHTTP_VFS (winhttp_file->vfs)->session,
663
winhttp_file->url.lpszHostName,
664
winhttp_file->url.nPort,
667
if (connection == NULL)
669
_g_winhttp_set_error (error, GetLastError (), "HTTP connection");
674
return _g_winhttp_file_output_stream_new (winhttp_file, connection);
679
static GFileOutputStream *
680
g_winhttp_file_replace (GFile *file,
682
gboolean make_backup,
683
GFileCreateFlags flags,
684
GCancellable *cancellable,
687
/* FIXME: Implement */
694
g_winhttp_file_delete (GFile *file,
695
GCancellable *cancellable,
698
/* FIXME: Implement */
704
g_winhttp_file_make_directory (GFile *file,
705
GCancellable *cancellable,
708
/* FIXME: Implement */
714
g_winhttp_file_copy (GFile *source,
716
GFileCopyFlags flags,
717
GCancellable *cancellable,
718
GFileProgressCallback progress_callback,
719
gpointer progress_callback_data,
722
/* Fall back to default copy?? */
723
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
724
"Copy not supported");
730
g_winhttp_file_move (GFile *source,
732
GFileCopyFlags flags,
733
GCancellable *cancellable,
734
GFileProgressCallback progress_callback,
735
gpointer progress_callback_data,
738
/* FIXME: Implement */
746
g_winhttp_file_file_iface_init (GFileIface *iface)
748
iface->dup = g_winhttp_file_dup;
749
iface->hash = g_winhttp_file_hash;
750
iface->equal = g_winhttp_file_equal;
751
iface->is_native = g_winhttp_file_is_native;
752
iface->has_uri_scheme = g_winhttp_file_has_uri_scheme;
753
iface->get_uri_scheme = g_winhttp_file_get_uri_scheme;
754
iface->get_basename = g_winhttp_file_get_basename;
755
iface->get_path = g_winhttp_file_get_path;
756
iface->get_uri = g_winhttp_file_get_uri;
757
iface->get_parse_name = g_winhttp_file_get_parse_name;
758
iface->get_parent = g_winhttp_file_get_parent;
759
iface->prefix_matches = g_winhttp_file_prefix_matches;
760
iface->get_relative_path = g_winhttp_file_get_relative_path;
761
iface->resolve_relative_path = g_winhttp_file_resolve_relative_path;
762
iface->get_child_for_display_name = g_winhttp_file_get_child_for_display_name;
763
iface->set_display_name = g_winhttp_file_set_display_name;
764
iface->query_info = g_winhttp_file_query_info;
765
iface->read_fn = g_winhttp_file_read;
766
iface->create = g_winhttp_file_create;
768
iface->replace = g_winhttp_file_replace;
769
iface->delete_file = g_winhttp_file_delete;
770
iface->make_directory = g_winhttp_file_make_directory;
771
iface->copy = g_winhttp_file_copy;
772
iface->move = g_winhttp_file_move;