diff --git a/gio/ChangeLog b/gio/ChangeLog index f15561274..1ea03f047 100644 --- a/gio/ChangeLog +++ b/gio/ChangeLog @@ -1,3 +1,30 @@ +2008-08-13 Tor Lillqvist + + * win32/gwinhttpvfs.c + * win32/gwinhttpvfs.h + * win32/gwinhttpfile.c + * win32/gwinhttpfile.h + * win32/gwinhttpfileinputstream.c + * win32/gwinhttpfileinputstream.h + * win32/gwinhttpfileoutputstream.c + * win32/gwinhttpfileoutputstream.h: New files implementing + GWinHttpVfs and related classes, a GVfs for HTTP and HTTPS URIs on + Windows. The implementation uses the WinHttp API. Both reading and + writing are supported, i.e. GET and PUT requests. When writing, + each write call is done using a separate PUT request with a + Content-Range header. Requests for file URIs and plain pathnames + are forwarded to GLocalVfs. + + * win32/winhttp.h: Reverse engineered , borrowed from + WINE. Used as there is no bundled with mingw, and + requiring people to download the Windows SDK just for this one + header is not reasonable. + + * win32/Makefile.am: Add above files. + + * giomodule.c: Call _g_winhttp_vfs_get_type() on Windows to set up + the plumbing for the above. + 2008-08-11 Sven Neumann * gfilenamecompleter.c diff --git a/gio/giomodule.c b/gio/giomodule.c index 46c23fd3f..867b14126 100644 --- a/gio/giomodule.c +++ b/gio/giomodule.c @@ -294,6 +294,7 @@ extern GType _g_local_vfs_get_type (void); extern GType _g_win32_volume_monitor_get_type (void); extern GType g_win32_directory_monitor_get_type (void); +extern GType _g_winhttp_vfs_get_type (void); void _g_io_modules_ensure_loaded (void) @@ -363,6 +364,9 @@ _g_io_modules_ensure_loaded (void) #endif #ifdef G_OS_UNIX _g_unix_volume_monitor_get_type (); +#endif +#ifdef G_OS_WIN32 + _g_winhttp_vfs_get_type (); #endif _g_local_vfs_get_type (); diff --git a/gio/win32/Makefile.am b/gio/win32/Makefile.am index 0b8b30a5e..19c4a564b 100644 --- a/gio/win32/Makefile.am +++ b/gio/win32/Makefile.am @@ -4,9 +4,18 @@ NULL = noinst_LTLIBRARIES = libgiowin32.la -libgiowin32_la_SOURCES = \ +libgiowin32_la_SOURCES = \ gwin32directorymonitor.c \ gwin32directorymonitor.h \ + gwinhttpvfs.c \ + gwinhttpvfs.h \ + gwinhttpfile.c \ + gwinhttpfile.h \ + gwinhttpfileinputstream.c \ + gwinhttpfileinputstream.h \ + gwinhttpfileoutputstream.c \ + gwinhttpfileoutputstream.h \ + winhttp.h \ $(NULL) libgiowin32_la_CFLAGS = \ diff --git a/gio/win32/gwinhttpfile.c b/gio/win32/gwinhttpfile.c new file mode 100644 index 000000000..2e24116e4 --- /dev/null +++ b/gio/win32/gwinhttpfile.c @@ -0,0 +1,602 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * Copyright (C) 2008 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + * Author: Tor Lillqvist + */ + +#include "config.h" + +#include + +#include "gfile.h" +#include "gfileattribute.h" +#include "gwinhttpfile.h" +#include "gwinhttpfileinputstream.h" +#include "gwinhttpfileoutputstream.h" +#include "gioerror.h" + +#include "glibintl.h" + +#include "gioalias.h" + +static void g_winhttp_file_file_iface_init (GFileIface *iface); + +#define g_winhttp_file_get_type _g_winhttp_file_get_type +G_DEFINE_TYPE_WITH_CODE (GWinHttpFile, g_winhttp_file, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_FILE, + g_winhttp_file_file_iface_init)) + +static void +g_winhttp_file_finalize (GObject *object) +{ + GWinHttpFile *file; + + file = G_WINHTTP_FILE (object); + + g_free (file->url.lpszScheme); + g_free (file->url.lpszHostName); + g_free (file->url.lpszUserName); + g_free (file->url.lpszPassword); + g_free (file->url.lpszUrlPath); + g_free (file->url.lpszExtraInfo); + + G_OBJECT_CLASS (g_winhttp_file_parent_class)->finalize (object); +} + +static void +g_winhttp_file_class_init (GWinHttpFileClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = g_winhttp_file_finalize; +} + +static void +g_winhttp_file_init (GWinHttpFile *winhttp) +{ +} + +/** + * _g_winhttp_file_new: + * @vfs: GWinHttpVfs to use + * @uri: URI of the GWinHttpFile to create. + * + * Returns: new winhttp #GFile. + **/ +GFile * +_g_winhttp_file_new (GWinHttpVfs *vfs, + const char *uri) +{ + wchar_t *wuri; + GWinHttpFile *file; + + wuri = g_utf8_to_utf16 (uri, -1, NULL, NULL, NULL); + + if (wuri == NULL) + return NULL; + + file = g_object_new (G_TYPE_WINHTTP_FILE, NULL); + file->vfs = vfs; + + memset (&file->url, 0, sizeof (file->url)); + file->url.dwStructSize = sizeof (file->url); + file->url.dwSchemeLength = 1; + file->url.dwHostNameLength = 1; + file->url.dwUserNameLength = 1; + file->url.dwPasswordLength = 1; + file->url.dwUrlPathLength = 1; + file->url.dwExtraInfoLength = 1; + + if (!G_WINHTTP_VFS_GET_CLASS (vfs)->pWinHttpCrackUrl (wuri, 0, 0, &file->url)) + { + g_free (wuri); + return NULL; + } + + file->url.lpszScheme = g_new (wchar_t, ++file->url.dwSchemeLength); + file->url.lpszHostName = g_new (wchar_t, ++file->url.dwHostNameLength); + file->url.lpszUserName = g_new (wchar_t, ++file->url.dwUserNameLength); + file->url.lpszPassword = g_new (wchar_t, ++file->url.dwPasswordLength); + file->url.lpszUrlPath = g_new (wchar_t, ++file->url.dwUrlPathLength); + file->url.lpszExtraInfo = g_new (wchar_t, ++file->url.dwExtraInfoLength); + + if (!G_WINHTTP_VFS_GET_CLASS (vfs)->pWinHttpCrackUrl (wuri, 0, 0, &file->url)) + { + g_free (file->url.lpszScheme); + g_free (file->url.lpszHostName); + g_free (file->url.lpszUserName); + g_free (file->url.lpszPassword); + g_free (file->url.lpszUrlPath); + g_free (file->url.lpszExtraInfo); + g_free (wuri); + return NULL; + } + + g_free (wuri); + return G_FILE (file); +} + +static gboolean +g_winhttp_file_is_native (GFile *file) +{ + return FALSE; +} + +static gboolean +g_winhttp_file_has_uri_scheme (GFile *file, + const char *uri_scheme) +{ + return (g_ascii_strcasecmp (uri_scheme, "http") == 0 || + g_ascii_strcasecmp (uri_scheme, "https") == 0); +} + +static char * +g_winhttp_file_get_uri_scheme (GFile *file) +{ + GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); + + return g_utf16_to_utf8 (winhttp_file->url.lpszScheme, -1, NULL, NULL, NULL); +} + +static char * +g_winhttp_file_get_basename (GFile *file) +{ + GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); + char *basename; + char *last_slash; + char *retval; + + basename = g_utf16_to_utf8 (winhttp_file->url.lpszUrlPath, -1, NULL, NULL, NULL); + last_slash = strrchr (basename, '/'); + /* If no slash, or only "/" fallback to full path part of URI */ + if (last_slash == NULL || last_slash[1] == '\0') + return basename; + + retval = g_strdup (last_slash + 1); + g_free (basename); + + return retval; +} + +static char * +g_winhttp_file_get_path (GFile *file) +{ + return NULL; +} + +static char * +g_winhttp_file_get_uri (GFile *file) +{ + GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); + DWORD len; + wchar_t *wuri; + char *retval; + + len = 0; + if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpCreateUrl (&winhttp_file->url, ICU_ESCAPE, NULL, &len) && + GetLastError () != ERROR_INSUFFICIENT_BUFFER) + return NULL; + + wuri = g_new (wchar_t, ++len); + + if (!G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpCreateUrl (&winhttp_file->url, ICU_ESCAPE, wuri, &len)) + { + g_free (wuri); + return NULL; + } + + retval = g_utf16_to_utf8 (wuri, -1, NULL, NULL, NULL); + g_free (wuri); + + return retval; +} + +static char * +g_winhttp_file_get_parse_name (GFile *file) +{ + /* FIXME: More hair surely needed */ + + return g_winhttp_file_get_uri (file); +} + +static GFile * +g_winhttp_file_get_parent (GFile *file) +{ + GWinHttpFile *winhttp_file; + char *uri; + char *last_slash; + GFile *parent; + + winhttp_file = G_WINHTTP_FILE (file); + + uri = g_winhttp_file_get_uri (file); + if (uri == NULL) + return NULL; + + last_slash = strrchr (uri, '/'); + if (last_slash == NULL || *(last_slash+1) == 0) + { + g_free (uri); + return NULL; + } + + while (last_slash > uri && *last_slash == '/') + last_slash--; + + last_slash[1] = '\0'; + + parent = _g_winhttp_file_new (winhttp_file->vfs, uri); + g_free (uri); + + return parent; +} + +static GFile * +g_winhttp_file_dup (GFile *file) +{ + GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); + char *uri = g_winhttp_file_get_uri (file); + GFile *retval = _g_winhttp_file_new (winhttp_file->vfs, uri); + + g_free (uri); + + return retval; +} + +static guint +g_winhttp_file_hash (GFile *file) +{ + char *uri = g_winhttp_file_get_uri (file); + guint retval = g_str_hash (uri); + + g_free (uri); + + return retval; +} + +static gboolean +g_winhttp_file_equal (GFile *file1, + GFile *file2) +{ + char *uri1 = g_winhttp_file_get_uri (file1); + char *uri2 = g_winhttp_file_get_uri (file2); + gboolean retval = g_str_equal (uri1, uri2); + + g_free (uri1); + g_free (uri2); + + return retval; +} + +static const char * +match_prefix (const char *path, + const char *prefix) +{ + int prefix_len; + + prefix_len = strlen (prefix); + if (strncmp (path, prefix, prefix_len) != 0) + return NULL; + + if (prefix_len > 0 && prefix[prefix_len-1] == '/') + prefix_len--; + + return path + prefix_len; +} + +static gboolean +g_winhttp_file_prefix_matches (GFile *parent, + GFile *descendant) +{ + char *parent_uri = g_winhttp_file_get_uri (parent); + char *descendant_uri = g_winhttp_file_get_uri (descendant); + const char *remainder; + gboolean retval; + + remainder = match_prefix (descendant_uri, parent_uri); + + if (remainder != NULL && *remainder == '/') + retval = TRUE; + else + retval = FALSE; + + g_free (parent_uri); + g_free (descendant_uri); + + return retval; +} + +static char * +g_winhttp_file_get_relative_path (GFile *parent, + GFile *descendant) +{ + char *parent_uri = g_winhttp_file_get_uri (parent); + char *descendant_uri = g_winhttp_file_get_uri (descendant); + const char *remainder; + char *retval; + + remainder = match_prefix (descendant_uri, parent_uri); + + if (remainder != NULL && *remainder == '/') + retval = g_strdup (remainder + 1); + else + retval = NULL; + + g_free (parent_uri); + g_free (descendant_uri); + + return retval; +} + +static GFile * +g_winhttp_file_resolve_relative_path (GFile *file, + const char *relative_path) +{ + GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); + GWinHttpFile *child; + wchar_t *wnew_path = g_utf8_to_utf16 (relative_path, -1, NULL, NULL, NULL); + + if (wnew_path == NULL) + return NULL; + + if (*wnew_path != '/') + { + wchar_t *tmp = g_new (wchar_t, wcslen (winhttp_file->url.lpszUrlPath) + 1 + wcslen (wnew_path) + 1); + wcscpy (tmp, winhttp_file->url.lpszUrlPath); + wcscat (tmp, L"/"); + wcscat (tmp, wnew_path); + + g_free (wnew_path); + wnew_path = tmp; + } + + child = g_object_new (G_TYPE_WINHTTP_FILE, NULL); + child->vfs = winhttp_file->vfs; + child->url = winhttp_file->url; + child->url.lpszScheme = g_memdup (winhttp_file->url.lpszScheme, winhttp_file->url.dwSchemeLength*2); + child->url.lpszHostName = g_memdup (winhttp_file->url.lpszHostName, winhttp_file->url.dwHostNameLength*2); + child->url.lpszUserName = g_memdup (winhttp_file->url.lpszUserName, winhttp_file->url.dwUserNameLength*2); + child->url.lpszPassword = g_memdup (winhttp_file->url.lpszPassword, winhttp_file->url.dwPasswordLength*2); + child->url.lpszUrlPath = wnew_path; + child->url.dwUrlPathLength = 2*(wcslen (wnew_path)+1); + child->url.lpszExtraInfo = NULL; + child->url.dwExtraInfoLength = 0; + + return (GFile *) child; +} + +static GFile * +g_winhttp_file_get_child_for_display_name (GFile *file, + const char *display_name, + GError **error) +{ + GFile *new_file; + char *basename; + + basename = g_locale_from_utf8 (display_name, -1, NULL, NULL, NULL); + if (basename == NULL) + { + g_set_error (error, G_IO_ERROR, + G_IO_ERROR_INVALID_FILENAME, + _("Invalid filename %s"), display_name); + return NULL; + } + + new_file = g_file_get_child (file, basename); + g_free (basename); + + return new_file; +} + +static GFile * +g_winhttp_file_set_display_name (GFile *file, + const char *display_name, + GCancellable *cancellable, + GError **error) +{ + g_set_error_literal (error, G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + _("Operation not supported")); + + return NULL; +} + +static GFileInputStream * +g_winhttp_file_read (GFile *file, + GCancellable *cancellable, + GError **error) +{ + GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); + HINTERNET connection, request; + const wchar_t *accept_types[] = + { + L"*/*", + NULL, + }; + + connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpConnect + (G_WINHTTP_VFS (winhttp_file->vfs)->session, + winhttp_file->url.lpszHostName, + winhttp_file->url.nPort, + 0); + + if (connection == NULL) + { + char *emsg = _g_winhttp_error_message (GetLastError ()); + + g_set_error (error, G_IO_ERROR, + G_IO_ERROR_FAILED, + "%s", emsg); + g_free (emsg); + + return NULL; + } + + request = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpOpenRequest + (connection, + L"GET", + winhttp_file->url.lpszUrlPath, + NULL, + WINHTTP_NO_REFERER, + accept_types, + winhttp_file->url.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0); + + if (request == NULL) + { + char *emsg = _g_winhttp_error_message (GetLastError ()); + + g_set_error (error, G_IO_ERROR, + G_IO_ERROR_FAILED, + "%s", emsg); + g_free (emsg); + + return NULL; + } + + return _g_winhttp_file_input_stream_new (winhttp_file, connection, request); +} + +static GFileOutputStream * +g_winhttp_file_create (GFile *file, + GFileCreateFlags flags, + GCancellable *cancellable, + GError **error) +{ + GWinHttpFile *winhttp_file = G_WINHTTP_FILE (file); + HINTERNET connection, request; + + connection = G_WINHTTP_VFS_GET_CLASS (winhttp_file->vfs)->pWinHttpConnect + (G_WINHTTP_VFS (winhttp_file->vfs)->session, + winhttp_file->url.lpszHostName, + winhttp_file->url.nPort, + 0); + + if (connection == NULL) + { + char *emsg = _g_winhttp_error_message (GetLastError ()); + + g_set_error (error, G_IO_ERROR, + G_IO_ERROR_FAILED, + "%s", emsg); + g_free (emsg); + + return NULL; + } + + return _g_winhttp_file_output_stream_new (winhttp_file, connection); +} + +#if 0 + +static GFileOutputStream * +g_winhttp_file_replace (GFile *file, + const char *etag, + gboolean make_backup, + GFileCreateFlags flags, + GCancellable *cancellable, + GError **error) +{ + /* FIXME: Implement */ + + return NULL; +} + + +static gboolean +g_winhttp_file_delete (GFile *file, + GCancellable *cancellable, + GError **error) +{ + /* FIXME: Implement */ + + return FALSE; +} + +static gboolean +g_winhttp_file_make_directory (GFile *file, + GCancellable *cancellable, + GError **error) +{ + /* FIXME: Implement */ + + return FALSE; +} + +static gboolean +g_winhttp_file_copy (GFile *source, + GFile *destination, + GFileCopyFlags flags, + GCancellable *cancellable, + GFileProgressCallback progress_callback, + gpointer progress_callback_data, + GError **error) +{ + /* Fall back to default copy?? */ + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Copy not supported"); + + return FALSE; +} + +static gboolean +g_winhttp_file_move (GFile *source, + GFile *destination, + GFileCopyFlags flags, + GCancellable *cancellable, + GFileProgressCallback progress_callback, + gpointer progress_callback_data, + GError **error) +{ + /* FIXME: Implement */ + + return FALSE; +} + +#endif + +static void +g_winhttp_file_file_iface_init (GFileIface *iface) +{ + iface->dup = g_winhttp_file_dup; + iface->hash = g_winhttp_file_hash; + iface->equal = g_winhttp_file_equal; + iface->is_native = g_winhttp_file_is_native; + iface->has_uri_scheme = g_winhttp_file_has_uri_scheme; + iface->get_uri_scheme = g_winhttp_file_get_uri_scheme; + iface->get_basename = g_winhttp_file_get_basename; + iface->get_path = g_winhttp_file_get_path; + iface->get_uri = g_winhttp_file_get_uri; + iface->get_parse_name = g_winhttp_file_get_parse_name; + iface->get_parent = g_winhttp_file_get_parent; + iface->prefix_matches = g_winhttp_file_prefix_matches; + iface->get_relative_path = g_winhttp_file_get_relative_path; + iface->resolve_relative_path = g_winhttp_file_resolve_relative_path; + iface->get_child_for_display_name = g_winhttp_file_get_child_for_display_name; + iface->set_display_name = g_winhttp_file_set_display_name; + iface->read_fn = g_winhttp_file_read; + iface->create = g_winhttp_file_create; +#if 0 + iface->replace = g_winhttp_file_replace; + iface->delete_file = g_winhttp_file_delete; + iface->make_directory = g_winhttp_file_make_directory; + iface->copy = g_winhttp_file_copy; + iface->move = g_winhttp_file_move; +#endif +} diff --git a/gio/win32/gwinhttpfile.h b/gio/win32/gwinhttpfile.h new file mode 100644 index 000000000..9a0c3929a --- /dev/null +++ b/gio/win32/gwinhttpfile.h @@ -0,0 +1,64 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * Copyright (C) 2008 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + * Author: Tor Lillqvist + */ + +#ifndef __G_WINHTTP_FILE_H__ +#define __G_WINHTTP_FILE_H__ + +#include + +#include "gwinhttpvfs.h" + +G_BEGIN_DECLS + +#define G_TYPE_WINHTTP_FILE (_g_winhttp_file_get_type ()) +#define G_WINHTTP_FILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_WINHTTP_FILE, GWinHttpFile)) +#define G_WINHTTP_FILE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_WINHTTP_FILE, GWinHttpFileClass)) +#define G_IS_WINHTTP_FILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_WINHTTP_FILE)) +#define G_IS_WINHTTP_FILE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_WINHTTP_FILE)) +#define G_WINHTTP_FILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_WINHTTP_FILE, GWinHttpFileClass)) + +typedef struct _GWinHttpFile GWinHttpFile; +typedef struct _GWinHttpFileClass GWinHttpFileClass; + +struct _GWinHttpFile +{ + GObject parent_instance; + + GWinHttpVfs *vfs; + + URL_COMPONENTS url; +}; + +struct _GWinHttpFileClass +{ + GObjectClass parent_class; +}; + +GType _g_winhttp_file_get_type (void) G_GNUC_CONST; + +GFile * _g_winhttp_file_new (GWinHttpVfs *vfs, const char *uri); + +G_END_DECLS + +#endif /* __G_WINHTTP_FILE_H__ */ diff --git a/gio/win32/gwinhttpfileinputstream.c b/gio/win32/gwinhttpfileinputstream.c new file mode 100644 index 000000000..f00bc7828 --- /dev/null +++ b/gio/win32/gwinhttpfileinputstream.c @@ -0,0 +1,170 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * Copyright (C) 2008 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + * Author: Tor Lillqvist + */ + +#include "config.h" + +#include + +#include "gcancellable.h" +#include "gioerror.h" +#include "gwinhttpfileinputstream.h" +#include "glibintl.h" + +#include "gioalias.h" + +struct _GWinHttpFileInputStream +{ + GFileInputStream parent_instance; + + GWinHttpFile *file; + gboolean request_sent; + HINTERNET connection; + HINTERNET request; +}; + +struct _GWinHttpFileInputStreamClass +{ + GFileInputStreamClass parent_class; +}; + +#define g_winhttp_file_input_stream_get_type _g_winhttp_file_input_stream_get_type +G_DEFINE_TYPE (GWinHttpFileInputStream, g_winhttp_file_input_stream, G_TYPE_FILE_INPUT_STREAM); + +static gssize g_winhttp_file_input_stream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error); + +static void +g_winhttp_file_input_stream_finalize (GObject *object) +{ + GWinHttpFileInputStream *winhttp_stream; + + winhttp_stream = G_WINHTTP_FILE_INPUT_STREAM (object); + + if (winhttp_stream->request != NULL) + G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpCloseHandle (winhttp_stream->request); + if (winhttp_stream->connection != NULL) + G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpCloseHandle (winhttp_stream->connection); + + G_OBJECT_CLASS (g_winhttp_file_input_stream_parent_class)->finalize (object); +} + +static void +g_winhttp_file_input_stream_class_init (GWinHttpFileInputStreamClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass); + + gobject_class->finalize = g_winhttp_file_input_stream_finalize; + + stream_class->read_fn = g_winhttp_file_input_stream_read; +} + +static void +g_winhttp_file_input_stream_init (GWinHttpFileInputStream *info) +{ +} + +/** + * g_winhttp_file_input_stream_new: + * @file: the GWinHttpFile being read + * @connection: handle to the HTTP connection, as from WinHttpConnect() + * @request: handle to the HTTP request, as from WinHttpOpenRequest + * + * Returns: #GFileInputStream for the given request + **/ +GFileInputStream * +_g_winhttp_file_input_stream_new (GWinHttpFile *file, + HINTERNET connection, + HINTERNET request) +{ + GWinHttpFileInputStream *stream; + + stream = g_object_new (G_TYPE_WINHTTP_FILE_INPUT_STREAM, NULL); + + stream->file = file; + stream->request_sent = FALSE; + stream->connection = connection; + stream->request = request; + + return G_FILE_INPUT_STREAM (stream); +} + +static gssize +g_winhttp_file_input_stream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error) +{ + GWinHttpFileInputStream *winhttp_stream = G_WINHTTP_FILE_INPUT_STREAM (stream); + DWORD bytes_read; + + if (!winhttp_stream->request_sent) + { + if (!G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpSendRequest + (winhttp_stream->request, + NULL, 0, + NULL, 0, + 0, + 0)) + { + char *emsg = _g_winhttp_error_message (GetLastError ()); + + g_set_error (error, G_IO_ERROR, + G_IO_ERROR_FAILED, + "%s", emsg); + g_free (emsg); + + return -1; + } + + if (!G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpReceiveResponse + (winhttp_stream->request, NULL)) + { + char *emsg = _g_winhttp_error_message (GetLastError ()); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "%s", emsg); + g_free (emsg); + + return -1; + } + winhttp_stream->request_sent = TRUE; + } + + if (!G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpReadData + (winhttp_stream->request, buffer, count, &bytes_read)) + { + char *emsg = _g_winhttp_error_message (GetLastError ()); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "%s", emsg); + g_free (emsg); + + return -1; + } + + return bytes_read; +} diff --git a/gio/win32/gwinhttpfileinputstream.h b/gio/win32/gwinhttpfileinputstream.h new file mode 100644 index 000000000..80e02b475 --- /dev/null +++ b/gio/win32/gwinhttpfileinputstream.h @@ -0,0 +1,52 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * Copyright (C) 2008 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + * Author: Tor Lillqvist + */ + +#ifndef __G_WINHTTP_FILE_INPUT_STREAM_H__ +#define __G_WINHTTP_FILE_INPUT_STREAM_H__ + +#include + +#include "gwinhttpfile.h" + +G_BEGIN_DECLS + +#define G_TYPE_WINHTTP_FILE_INPUT_STREAM (_g_winhttp_file_input_stream_get_type ()) +#define G_WINHTTP_FILE_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_WINHTTP_FILE_INPUT_STREAM, GWinHttpFileInputStream)) +#define G_WINHTTP_FILE_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_WINHTTP_FILE_INPUT_STREAM, GWinHttpFileInputStreamClass)) +#define G_IS_WINHTTP_FILE_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_WINHTTP_FILE_INPUT_STREAM)) +#define G_IS_WINHTTP_FILE_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_WINHTTP_FILE_INPUT_STREAM)) +#define G_WINHTTP_FILE_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_WINHTTP_FILE_INPUT_STREAM, GWinHttpFileInputStreamClass)) + +typedef struct _GWinHttpFileInputStream GWinHttpFileInputStream; +typedef struct _GWinHttpFileInputStreamClass GWinHttpFileInputStreamClass; + +GType _g_winhttp_file_input_stream_get_type (void) G_GNUC_CONST; + +GFileInputStream *_g_winhttp_file_input_stream_new (GWinHttpFile *file, + HINTERNET connection, + HINTERNET request); + +G_END_DECLS + +#endif /* __G_WINHTTP_FILE_INPUT_STREAM_H__ */ diff --git a/gio/win32/gwinhttpfileoutputstream.c b/gio/win32/gwinhttpfileoutputstream.c new file mode 100644 index 000000000..19b6e8538 --- /dev/null +++ b/gio/win32/gwinhttpfileoutputstream.c @@ -0,0 +1,204 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * Copyright (C) 2008 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + * Author: Tor Lillqvist + */ + +#include "config.h" + +#include + +#include "gcancellable.h" +#include "gioerror.h" +#include "gwinhttpfileoutputstream.h" +#include "glibintl.h" + +#include "gioalias.h" + +struct _GWinHttpFileOutputStream +{ + GFileOutputStream parent_instance; + + GWinHttpFile *file; + HINTERNET connection; + goffset offset; +}; + +struct _GWinHttpFileOutputStreamClass +{ + GFileOutputStreamClass parent_class; +}; + +#define g_winhttp_file_output_stream_get_type _g_winhttp_file_output_stream_get_type +G_DEFINE_TYPE (GWinHttpFileOutputStream, g_winhttp_file_output_stream, G_TYPE_FILE_OUTPUT_STREAM); + +static gssize g_winhttp_file_output_stream_write (GOutputStream *stream, + const void *buffer, + gsize count, + GCancellable *cancellable, + GError **error); + +static void +g_winhttp_file_output_stream_finalize (GObject *object) +{ + GWinHttpFileOutputStream *winhttp_stream; + + winhttp_stream = G_WINHTTP_FILE_OUTPUT_STREAM (object); + + if (winhttp_stream->connection != NULL) + G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpCloseHandle (winhttp_stream->connection); + + G_OBJECT_CLASS (g_winhttp_file_output_stream_parent_class)->finalize (object); +} + +static void +g_winhttp_file_output_stream_class_init (GWinHttpFileOutputStreamClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass); + + gobject_class->finalize = g_winhttp_file_output_stream_finalize; + + stream_class->write_fn = g_winhttp_file_output_stream_write; +} + +static void +g_winhttp_file_output_stream_init (GWinHttpFileOutputStream *info) +{ +} + +/** + * g_winhttp_file_output_stream_new: + * @file: the GWinHttpFile being read + * @connection: handle to the HTTP connection, as from WinHttpConnect() + * @request: handle to the HTTP request, as from WinHttpOpenRequest + * + * Returns: #GFileOutputStream for the given request + **/ +GFileOutputStream * +_g_winhttp_file_output_stream_new (GWinHttpFile *file, + HINTERNET connection) +{ + GWinHttpFileOutputStream *stream; + + stream = g_object_new (G_TYPE_WINHTTP_FILE_OUTPUT_STREAM, NULL); + + stream->file = file; + stream->connection = connection; + stream->offset = 0; + + return G_FILE_OUTPUT_STREAM (stream); +} + +static gssize +g_winhttp_file_output_stream_write (GOutputStream *stream, + const void *buffer, + gsize count, + GCancellable *cancellable, + GError **error) +{ + GWinHttpFileOutputStream *winhttp_stream = G_WINHTTP_FILE_OUTPUT_STREAM (stream); + HINTERNET request; + char *headers; + wchar_t *wheaders; + DWORD bytes_written; + + request = G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpOpenRequest + (winhttp_stream->connection, + L"PUT", + winhttp_stream->file->url.lpszUrlPath, + NULL, + WINHTTP_NO_REFERER, + NULL, + winhttp_stream->file->url.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0); + + if (request == NULL) + { + char *emsg = _g_winhttp_error_message (GetLastError ()); + + g_set_error (error, G_IO_ERROR, + G_IO_ERROR_FAILED, + "%s", emsg); + g_free (emsg); + + return -1; + } + + headers = g_strdup_printf ("Content-Range: bytes %" G_GINT64_FORMAT "-%" G_GINT64_FORMAT "/*\r\n" + "Content-Length: %" G_GSIZE_FORMAT "\r\n", + winhttp_stream->offset, winhttp_stream->offset + count, count); + wheaders = g_utf8_to_utf16 (headers, -1, NULL, NULL, NULL); + g_free (headers); + + if (!G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpSendRequest + (request, + wheaders, -1, + NULL, 0, + 0, + 0)) + { + char *emsg = _g_winhttp_error_message (GetLastError ()); + + g_set_error (error, G_IO_ERROR, + G_IO_ERROR_FAILED, + "%s", emsg); + g_free (emsg); + + G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpCloseHandle (request); + g_free (wheaders); + + return -1; + } + + winhttp_stream->offset += count; + g_free (wheaders); + + if (!G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpWriteData + (request, buffer, count, &bytes_written)) + { + char *emsg = _g_winhttp_error_message (GetLastError ()); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "%s", + emsg); + g_free (emsg); + + G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpCloseHandle (request); + + return -1; + } + + if (!G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpReceiveResponse + (request, NULL)) + { + char *emsg = _g_winhttp_error_message (GetLastError ()); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "%s", + emsg); + g_free (emsg); + + G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpCloseHandle (request); + return -1; + } + + G_WINHTTP_VFS_GET_CLASS (winhttp_stream->file->vfs)->pWinHttpCloseHandle (request); + + return bytes_written; +} diff --git a/gio/win32/gwinhttpfileoutputstream.h b/gio/win32/gwinhttpfileoutputstream.h new file mode 100644 index 000000000..4cc7e6177 --- /dev/null +++ b/gio/win32/gwinhttpfileoutputstream.h @@ -0,0 +1,51 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * Copyright (C) 2008 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + * Author: Tor Lillqvist + */ + +#ifndef __G_WINHTTP_FILE_OUTPUT_STREAM_H__ +#define __G_WINHTTP_FILE_OUTPUT_STREAM_H__ + +#include + +#include "gwinhttpfile.h" + +G_BEGIN_DECLS + +#define G_TYPE_WINHTTP_FILE_OUTPUT_STREAM (_g_winhttp_file_output_stream_get_type ()) +#define G_WINHTTP_FILE_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_WINHTTP_FILE_OUTPUT_STREAM, GWinHttpFileOutputStream)) +#define G_WINHTTP_FILE_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_WINHTTP_FILE_OUTPUT_STREAM, GWinHttpFileOutputStreamClass)) +#define G_IS_WINHTTP_FILE_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_WINHTTP_FILE_OUTPUT_STREAM)) +#define G_IS_WINHTTP_FILE_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_WINHTTP_FILE_OUTPUT_STREAM)) +#define G_WINHTTP_FILE_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_WINHTTP_FILE_OUTPUT_STREAM, GWinHttpFileOutputStreamClass)) + +typedef struct _GWinHttpFileOutputStream GWinHttpFileOutputStream; +typedef struct _GWinHttpFileOutputStreamClass GWinHttpFileOutputStreamClass; + +GType _g_winhttp_file_output_stream_get_type (void) G_GNUC_CONST; + +GFileOutputStream *_g_winhttp_file_output_stream_new (GWinHttpFile *file, + HINTERNET connection); + +G_END_DECLS + +#endif /* __G_WINHTTP_FILE_OUTPUT_STREAM_H__ */ diff --git a/gio/win32/gwinhttpvfs.c b/gio/win32/gwinhttpvfs.c new file mode 100644 index 000000000..dddf12eeb --- /dev/null +++ b/gio/win32/gwinhttpvfs.c @@ -0,0 +1,274 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * Copyright (C) 2008 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + * Author: Tor Lillqvist + */ + +#include "config.h" + +#include "giomodule.h" +#include "gvfs.h" + +#include "gwinhttpfile.h" +#include "gwinhttpvfs.h" + +#include "gioalias.h" + +#define g_winhttp_vfs_get_type _g_winhttp_vfs_get_type +G_DEFINE_TYPE_WITH_CODE (GWinHttpVfs, g_winhttp_vfs, G_TYPE_VFS, + g_io_extension_point_implement (G_VFS_EXTENSION_POINT_NAME, + g_define_type_id, + "winhttp", + 10)) + +static const gchar *winhttp_uri_schemes[] = { "http", "https" }; + +static void +g_winhttp_vfs_finalize (GObject *object) +{ + GWinHttpVfs *vfs; + + vfs = G_WINHTTP_VFS (object); + + (G_WINHTTP_VFS_GET_CLASS (vfs)->pWinHttpCloseHandle) (vfs->session); + vfs->session = NULL; + + if (vfs->wrapped_vfs) + g_object_unref (vfs->wrapped_vfs); + vfs->wrapped_vfs = NULL; + + G_OBJECT_CLASS (g_winhttp_vfs_parent_class)->finalize (object); +} + +static void +g_winhttp_vfs_init (GWinHttpVfs *vfs) +{ + wchar_t *wagent; + + vfs->wrapped_vfs = g_vfs_get_local (); + + wagent = g_utf8_to_utf16 (g_get_prgname (), -1, NULL, NULL, NULL); + + if (!wagent) + wagent = g_utf8_to_utf16 ("GWinHttpVfs", -1, NULL, NULL, NULL); + + vfs->session = (G_WINHTTP_VFS_GET_CLASS (vfs)->pWinHttpOpen) + (wagent, + WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, + 0); +} + +/** + * g_winhttp_vfs_new: + * + * Returns a new #GVfs handle for a WinHttp vfs. + * + * Returns: a new #GVfs handle. + **/ +GVfs * +_g_winhttp_vfs_new (void) +{ + return g_object_new (G_TYPE_WINHTTP_VFS, NULL); +} + +static GFile * +g_winhttp_vfs_get_file_for_path (GVfs *vfs, + const char *path) +{ + return g_vfs_get_file_for_path (G_WINHTTP_VFS (vfs)->wrapped_vfs, path); +} + +static GFile * +g_winhttp_vfs_get_file_for_uri (GVfs *vfs, + const char *uri) +{ + GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs); + int i; + + /* If it matches one of "our" schemes, handle it */ + for (i = 0; i < G_N_ELEMENTS (winhttp_uri_schemes); i++) + if (g_ascii_strncasecmp (uri, winhttp_uri_schemes[i], strlen (winhttp_uri_schemes[i])) == 0 && + uri[strlen (winhttp_uri_schemes[i])] == ':') + return _g_winhttp_file_new (winhttp_vfs, uri); + + /* For other URIs fallback to the wrapped GVfs */ + return g_vfs_parse_name (winhttp_vfs->wrapped_vfs, uri); +} + +static const gchar * const * +g_winhttp_vfs_get_supported_uri_schemes (GVfs *vfs) +{ + GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs); + const gchar * const *wrapped_vfs_uri_schemes = g_vfs_get_supported_uri_schemes (winhttp_vfs->wrapped_vfs); + int i, n; + const gchar **retval; + + n = 0; + while (wrapped_vfs_uri_schemes[n] != NULL) + n++; + + retval = g_new (const gchar *, n + G_N_ELEMENTS (winhttp_uri_schemes) + 1); + n = 0; + while (wrapped_vfs_uri_schemes[n] != NULL) + { + retval[n] = wrapped_vfs_uri_schemes[n]; + n++; + } + + for (i = 0; i < G_N_ELEMENTS (winhttp_uri_schemes); i++) + { + retval[n] = winhttp_uri_schemes[i]; + n++; + } + + retval[n] = NULL; + + return retval; +} + +static GFile * +g_winhttp_vfs_parse_name (GVfs *vfs, + const char *parse_name) +{ + GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs); + + g_return_val_if_fail (G_IS_VFS (vfs), NULL); + g_return_val_if_fail (parse_name != NULL, NULL); + + /* For plain file paths fallback to the wrapped GVfs */ + if (g_path_is_absolute (parse_name)) + return g_vfs_parse_name (winhttp_vfs->wrapped_vfs, parse_name); + + /* Otherwise assume it is an URI, so pass on to + * g_winhttp_vfs_get_file_for_uri(). + */ + return g_winhttp_vfs_get_file_for_uri (vfs, parse_name); +} + +static gboolean +g_winhttp_vfs_is_active (GVfs *vfs) +{ + return TRUE; +} + +static void +g_winhttp_vfs_class_init (GWinHttpVfsClass *class) +{ + GObjectClass *object_class; + GVfsClass *vfs_class; + HMODULE winhttp; + + object_class = (GObjectClass *) class; + + object_class->finalize = g_winhttp_vfs_finalize; + + vfs_class = G_VFS_CLASS (class); + + vfs_class->is_active = g_winhttp_vfs_is_active; + vfs_class->get_file_for_path = g_winhttp_vfs_get_file_for_path; + vfs_class->get_file_for_uri = g_winhttp_vfs_get_file_for_uri; + vfs_class->get_supported_uri_schemes = g_winhttp_vfs_get_supported_uri_schemes; + vfs_class->parse_name = g_winhttp_vfs_parse_name; + + winhttp = LoadLibrary ("winhttp.dll"); + if (winhttp != NULL) + { + class->pWinHttpCloseHandle = (BOOL (WINAPI *) (HINTERNET)) GetProcAddress (winhttp, "WinHttpCloseHandle"); + class->pWinHttpCrackUrl = (BOOL (WINAPI *) (LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS)) GetProcAddress (winhttp, "WinHttpCrackUrl"); + class->pWinHttpConnect = (HINTERNET (WINAPI *) (HINTERNET,LPCWSTR,INTERNET_PORT,DWORD)) GetProcAddress (winhttp, "WinHttpConnect"); + class->pWinHttpCreateUrl = (BOOL (WINAPI *) (LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD)) GetProcAddress (winhttp, "WinHttpCreateUrl"); + class->pWinHttpOpen = (HINTERNET (WINAPI *) (LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD)) GetProcAddress (winhttp, "WinHttpOpen"); + class->pWinHttpOpenRequest = (HINTERNET (WINAPI *) (HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD)) GetProcAddress (winhttp, "WinHttpOpenRequest"); + class->pWinHttpQueryDataAvailable = (BOOL (WINAPI *) (HINTERNET,LPDWORD)) GetProcAddress (winhttp, "WinHttpQueryDataAvailable"); + class->pWinHttpQueryHeaders = (BOOL (WINAPI *) (HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD)) GetProcAddress (winhttp, "WinHttpQueryHeaders"); + class->pWinHttpReadData = (BOOL (WINAPI *) (HINTERNET,LPVOID,DWORD,LPDWORD)) GetProcAddress (winhttp, "WinHttpReadData"); + class->pWinHttpReceiveResponse = (BOOL (WINAPI *) (HINTERNET,LPVOID)) GetProcAddress (winhttp, "WinHttpReceiveResponse"); + class->pWinHttpSendRequest = (BOOL (WINAPI *) (HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR)) GetProcAddress (winhttp, "WinHttpSendRequest"); + class->pWinHttpWriteData = (BOOL (WINAPI *) (HINTERNET,LPCVOID,DWORD,LPDWORD)) GetProcAddress (winhttp, "WinHttpWriteData"); + } +} + +char * +_g_winhttp_error_message (DWORD error_code) +{ + /* The FormatMessage() API that g_win32_error_message() uses doesn't + * seem to know about WinHttp errors, unfortunately. + */ + if (error_code >= WINHTTP_ERROR_BASE && error_code < WINHTTP_ERROR_BASE + 200) + { + switch (error_code) + { + /* FIXME: Use meaningful error messages */ +#define CASE(x) case ERROR_WINHTTP_##x: return g_strdup ("WinHttp error: " #x); + CASE (AUTO_PROXY_SERVICE_ERROR); + CASE (AUTODETECTION_FAILED); + CASE (BAD_AUTO_PROXY_SCRIPT); + CASE (CANNOT_CALL_AFTER_OPEN); + CASE (CANNOT_CALL_AFTER_SEND); + CASE (CANNOT_CALL_BEFORE_OPEN); + CASE (CANNOT_CALL_BEFORE_SEND); + CASE (CANNOT_CONNECT); + CASE (CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW); + CASE (CLIENT_AUTH_CERT_NEEDED); + CASE (CONNECTION_ERROR); + CASE (HEADER_ALREADY_EXISTS); + CASE (HEADER_COUNT_EXCEEDED); + CASE (HEADER_NOT_FOUND); + CASE (HEADER_SIZE_OVERFLOW); + CASE (INCORRECT_HANDLE_STATE); + CASE (INCORRECT_HANDLE_TYPE); + CASE (INTERNAL_ERROR); + CASE (INVALID_OPTION); + CASE (INVALID_QUERY_REQUEST); + CASE (INVALID_SERVER_RESPONSE); + CASE (INVALID_URL); + CASE (LOGIN_FAILURE); + CASE (NAME_NOT_RESOLVED); + CASE (NOT_INITIALIZED); + CASE (OPERATION_CANCELLED); + CASE (OPTION_NOT_SETTABLE); + CASE (OUT_OF_HANDLES); + CASE (REDIRECT_FAILED); + CASE (RESEND_REQUEST); + CASE (RESPONSE_DRAIN_OVERFLOW); + CASE (SECURE_CERT_CN_INVALID); + CASE (SECURE_CERT_DATE_INVALID); + CASE (SECURE_CERT_REV_FAILED); + CASE (SECURE_CERT_REVOKED); + CASE (SECURE_CERT_WRONG_USAGE); + CASE (SECURE_CHANNEL_ERROR); + CASE (SECURE_FAILURE); + CASE (SECURE_INVALID_CA); + CASE (SECURE_INVALID_CERT); + CASE (SHUTDOWN); + CASE (TIMEOUT); + CASE (UNABLE_TO_DOWNLOAD_SCRIPT); + CASE (UNRECOGNIZED_SCHEME); + #undef CASE + default: + return g_strdup_printf ("WinHttp error %ld", error_code); + } + } + else + return g_win32_error_message (error_code); +} diff --git a/gio/win32/gwinhttpvfs.h b/gio/win32/gwinhttpvfs.h new file mode 100644 index 000000000..a7597a477 --- /dev/null +++ b/gio/win32/gwinhttpvfs.h @@ -0,0 +1,88 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * Copyright (C) 2008 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + * Author: Tor Lillqvist + */ + +#ifndef __G_WINHTTP_VFS_H__ +#define __G_WINHTTP_VFS_H__ + +#include + +#include "gvfs.h" + +#define _WIN32_WINNT 0x0500 +#include + +#include "winhttp.h" + +G_BEGIN_DECLS + +#define G_TYPE_WINHTTP_VFS (_g_winhttp_vfs_get_type ()) +#define G_WINHTTP_VFS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_WINHTTP_VFS, GWinHttpVfs)) +#define G_WINHTTP_VFS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), G_TYPE_WINHTTP_VFS, GWinHttpVfsClass)) +#define G_IS_WINHTTP_VFS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_WINHTTP_VFS)) +#define G_IS_WINHTTP_VFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), G_TYPE_WINHTTP_VFS)) +#define G_WINHTTP_VFS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_WINHTTP_VFS, GWinHttpVfsClass)) + +typedef struct _GWinHttpVfs GWinHttpVfs; +typedef struct _GWinHttpVfsClass GWinHttpVfsClass; + +struct _GWinHttpVfs +{ + GVfs parent; + + GVfs *wrapped_vfs; + HINTERNET session; +}; + +struct _GWinHttpVfsClass +{ + GVfsClass parent_class; + + /* As there is no import library for winhttp.dll in mingw, we must + * look up the functions we need dynamically. Store the pointers + * here. + */ + BOOL (WINAPI *pWinHttpCloseHandle) (HINTERNET); + BOOL (WINAPI *pWinHttpCrackUrl) (LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS); + HINTERNET (WINAPI *pWinHttpConnect) (HINTERNET,LPCWSTR,INTERNET_PORT,DWORD); + BOOL (WINAPI *pWinHttpCreateUrl) (LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD); + HINTERNET (WINAPI *pWinHttpOpen) (LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD); + HINTERNET (WINAPI *pWinHttpOpenRequest) (HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD); + BOOL (WINAPI *pWinHttpQueryDataAvailable) (HINTERNET,LPDWORD); + BOOL (WINAPI *pWinHttpQueryHeaders) (HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD); + BOOL (WINAPI *pWinHttpReadData) (HINTERNET,LPVOID,DWORD,LPDWORD); + BOOL (WINAPI *pWinHttpReceiveResponse) (HINTERNET,LPVOID); + BOOL (WINAPI *pWinHttpSendRequest) (HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR); + BOOL (WINAPI *pWinHttpWriteData) (HINTERNET,LPCVOID,DWORD,LPDWORD); +}; + + +GType _g_winhttp_vfs_get_type (void) G_GNUC_CONST; + +GVfs *_g_winhttp_vfs_new (void); + +char *_g_winhttp_error_message (DWORD error_code); + +G_END_DECLS + +#endif /* __G_WINHTTP_VFS_H__ */ diff --git a/gio/win32/winhttp.h b/gio/win32/winhttp.h new file mode 100644 index 000000000..1bc7f4836 --- /dev/null +++ b/gio/win32/winhttp.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2007 Francois Gouget + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WINHTTP_H +#define __WINE_WINHTTP_H + +#define WINHTTPAPI +#define BOOLAPI WINHTTPAPI BOOL WINAPI + + +typedef LPVOID HINTERNET; +typedef HINTERNET *LPHINTERNET; + +#define INTERNET_DEFAULT_PORT 0 +#define INTERNET_DEFAULT_HTTP_PORT 80 +#define INTERNET_DEFAULT_HTTPS_PORT 443 +typedef WORD INTERNET_PORT; +typedef INTERNET_PORT *LPINTERNET_PORT; + +#define INTERNET_SCHEME_HTTP 1 +#define INTERNET_SCHEME_HTTPS 2 +typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; + +/* flags for WinHttpOpen */ +#define WINHTTP_FLAG_ASYNC 0x10000000 + +/* flags for WinHttpOpenRequest */ +#define WINHTTP_FLAG_ESCAPE_PERCENT 0x00000004 +#define WINHTTP_FLAG_NULL_CODEPAGE 0x00000008 +#define WINHTTP_FLAG_ESCAPE_DISABLE 0x00000040 +#define WINHTTP_FLAG_ESCAPE_DISABLE_QUERY 0x00000080 +#define WINHTTP_FLAG_BYPASS_PROXY_CACHE 0x00000100 +#define WINHTTP_FLAG_REFRESH WINHTTP_FLAG_BYPASS_PROXY_CACHE +#define WINHTTP_FLAG_SECURE 0x00800000 + +#define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY 0 +#define WINHTTP_ACCESS_TYPE_NO_PROXY 1 +#define WINHTTP_ACCESS_TYPE_NAMED_PROXY 3 + +#define WINHTTP_NO_PROXY_NAME NULL +#define WINHTTP_NO_PROXY_BYPASS NULL + +#define WINHTTP_NO_REFERER NULL +#define WINHTTP_DEFAULT_ACCEPT_TYPES NULL + +#define WINHTTP_ERROR_BASE 12000 + +/* The original WINE winhttp.h didn't contain symbolic names for the + * error codes. However, the values of most of them are publicly + * documented at + * http://msdn.microsoft.com/en-us/library/aa383770(VS.85).aspx so + * we can add them here. + */ +#define ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR 12178 +#define ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT 12166 +#define ERROR_WINHTTP_CANNOT_CALL_AFTER_OPEN 12103 +#define ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND 12102 +#define ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN 12100 +#define ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND 12101 +#define ERROR_WINHTTP_CANNOT_CONNECT 12029 +#define ERROR_WINHTTP_CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW 12183 +#define ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED 12044 +#define ERROR_WINHTTP_CONNECTION_ERROR 12030 +#define ERROR_WINHTTP_HEADER_ALREADY_EXISTS 12155 +#define ERROR_WINHTTP_HEADER_COUNT_EXCEEDED 12181 +#define ERROR_WINHTTP_HEADER_NOT_FOUND 12150 +#define ERROR_WINHTTP_HEADER_SIZE_OVERFLOW 12182 +#define ERROR_WINHTTP_INCORRECT_HANDLE_STATE 12019 +#define ERROR_WINHTTP_INCORRECT_HANDLE_TYPE 12018 +#define ERROR_WINHTTP_INTERNAL_ERROR 12004 +#define ERROR_WINHTTP_INVALID_OPTION 12009 +#define ERROR_WINHTTP_INVALID_QUERY_REQUEST 12154 +#define ERROR_WINHTTP_INVALID_SERVER_RESPONSE 12152 +#define ERROR_WINHTTP_INVALID_URL 12005 +#define ERROR_WINHTTP_LOGIN_FAILURE 12015 +#define ERROR_WINHTTP_NAME_NOT_RESOLVED 12007 +#define ERROR_WINHTTP_NOT_INITIALIZED 12172 +#define ERROR_WINHTTP_OPERATION_CANCELLED 12017 +#define ERROR_WINHTTP_OPTION_NOT_SETTABLE 12011 +#define ERROR_WINHTTP_OUT_OF_HANDLES 12001 +#define ERROR_WINHTTP_REDIRECT_FAILED 12156 +#define ERROR_WINHTTP_RESEND_REQUEST 12032 +#define ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW 12184 +#define ERROR_WINHTTP_SECURE_CERT_CN_INVALID 12038 +#define ERROR_WINHTTP_SECURE_CERT_DATE_INVALID 12037 +#define ERROR_WINHTTP_SECURE_CERT_REV_FAILED 12057 +#define ERROR_WINHTTP_SECURE_CERT_REVOKED 12170 +#define ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE 12179 +#define ERROR_WINHTTP_SECURE_CHANNEL_ERROR 12157 +#define ERROR_WINHTTP_SECURE_FAILURE 12175 +#define ERROR_WINHTTP_SECURE_INVALID_CA 12045 +#define ERROR_WINHTTP_SECURE_INVALID_CERT 12169 +#define ERROR_WINHTTP_SHUTDOWN 12012 +#define ERROR_WINHTTP_TIMEOUT 12002 +#define ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT 12167 +#define ERROR_WINHTTP_UNRECOGNIZED_SCHEME 12006 +/* End of added error codes */ + +#define ERROR_WINHTTP_AUTODETECTION_FAILED (WINHTTP_ERROR_BASE + 180) + +typedef struct +{ + DWORD dwStructSize; + LPWSTR lpszScheme; + DWORD dwSchemeLength; + INTERNET_SCHEME nScheme; + LPWSTR lpszHostName; + DWORD dwHostNameLength; + INTERNET_PORT nPort; + LPWSTR lpszUserName; + DWORD dwUserNameLength; + LPWSTR lpszPassword; + DWORD dwPasswordLength; + LPWSTR lpszUrlPath; + DWORD dwUrlPathLength; + LPWSTR lpszExtraInfo; + DWORD dwExtraInfoLength; +} URL_COMPONENTS, *LPURL_COMPONENTS; +typedef URL_COMPONENTS URL_COMPONENTSW; +typedef LPURL_COMPONENTS LPURL_COMPONENTSW; + +typedef struct +{ + DWORD_PTR dwResult; + DWORD dwError; +} WINHTTP_ASYNC_RESULT, *LPWINHTTP_ASYNC_RESULT; + +typedef struct +{ + FILETIME ftExpiry; + FILETIME ftStart; + LPWSTR lpszSubjectInfo; + LPWSTR lpszIssuerInfo; + LPWSTR lpszProtocolName; + LPWSTR lpszSignatureAlgName; + LPWSTR lpszEncryptionAlgName; + DWORD dwKeySize; +} WINHTTP_CERTIFICATE_INFO; + +typedef struct +{ + DWORD dwAccessType; + LPCWSTR lpszProxy; + LPCWSTR lpszProxyBypass; +} WINHTTP_PROXY_INFO, *LPWINHTTP_PROXY_INFO; +typedef WINHTTP_PROXY_INFO WINHTTP_PROXY_INFOW; +typedef LPWINHTTP_PROXY_INFO LPWINHTTP_PROXY_INFOW; + +typedef struct +{ + BOOL fAutoDetect; + LPWSTR lpszAutoConfigUrl; + LPWSTR lpszProxy; + LPWSTR lpszProxyBypass; +} WINHTTP_CURRENT_USER_IE_PROXY_CONFIG; + +typedef VOID (CALLBACK *WINHTTP_STATUS_CALLBACK)(HINTERNET,DWORD_PTR,DWORD,LPVOID,DWORD); + +typedef struct +{ + DWORD dwFlags; + DWORD dwAutoDetectFlags; + LPCWSTR lpszAutoConfigUrl; + LPVOID lpvReserved; + DWORD dwReserved; + BOOL fAutoLogonIfChallenged; +} WINHTTP_AUTOPROXY_OPTIONS; + +typedef struct +{ + DWORD dwMajorVersion; + DWORD dwMinorVersion; +} HTTP_VERSION_INFO, *LPHTTP_VERSION_INFO; + + +#ifdef __cplusplus +extern "C" { +#endif + +BOOL WINAPI WinHttpAddRequestHeaders(HINTERNET,LPCWSTR,DWORD,DWORD); +BOOL WINAPI WinHttpDetectAutoProxyConfigUrl(DWORD,LPWSTR*); +BOOL WINAPI WinHttpCheckPlatform(void); +BOOL WINAPI WinHttpCloseHandle(HINTERNET); +HINTERNET WINAPI WinHttpConnect(HINTERNET,LPCWSTR,INTERNET_PORT,DWORD); +BOOL WINAPI WinHttpCrackUrl(LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS); +BOOL WINAPI WinHttpCreateUrl(LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD); +BOOL WINAPI WinHttpGetDefaultProxyConfiguration(WINHTTP_PROXY_INFO*); +BOOL WINAPI WinHttpGetIEProxyConfigForCurrentUser(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* config); +BOOL WINAPI WinHttpGetProxyForUrl(HINTERNET,LPCWSTR,WINHTTP_AUTOPROXY_OPTIONS*,WINHTTP_PROXY_INFO*); +HINTERNET WINAPI WinHttpOpen(LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD); + +/* The sixth parameter to WinHttpOpenRequest was wrong in the original + * WINE header. It should be LPCWSTR*, not LPCWSTR, as it points to an + * array of wide strings. + */ +HINTERNET WINAPI WinHttpOpenRequest(HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD); +BOOL WINAPI WinHttpQueryAuthParams(HINTERNET,DWORD,LPVOID*); +BOOL WINAPI WinHttpQueryAuthSchemes(HINTERNET,LPDWORD,LPDWORD,LPDWORD); +BOOL WINAPI WinHttpQueryDataAvailable(HINTERNET,LPDWORD); +BOOL WINAPI WinHttpQueryHeaders(HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD); +BOOL WINAPI WinHttpReadData(HINTERNET,LPVOID,DWORD,LPDWORD); +BOOL WINAPI WinHttpReceiveResponse(HINTERNET,LPVOID); +BOOL WINAPI WinHttpSendRequest(HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR); +BOOL WINAPI WinHttpSetDefaultProxyConfiguration(WINHTTP_PROXY_INFO*); +BOOL WINAPI WinHttpSetCredentials(HINTERNET,DWORD,DWORD,LPCWSTR,LPCWSTR,LPVOID); +BOOL WINAPI WinHttpSetOption(HINTERNET,DWORD,LPVOID,DWORD); +WINHTTP_STATUS_CALLBACK WINAPI WinHttpSetStatusCallback(HINTERNET,WINHTTP_STATUS_CALLBACK,DWORD,DWORD_PTR); +BOOL WINAPI WinHttpSetTimeouts(HINTERNET,int,int,int,int); +BOOL WINAPI WinHttpTimeFromSystemTime(CONST SYSTEMTIME *,LPWSTR); +BOOL WINAPI WinHttpTimeToSystemTime(LPCWSTR,SYSTEMTIME*); +BOOL WINAPI WinHttpWriteData(HINTERNET,LPCVOID,DWORD,LPDWORD); + +/* Additional definitions, from the public domain in mingw */ +#define ICU_ESCAPE 0x80000000 +#define ICU_DECODE 0x10000000 + +#ifdef __cplusplus +} +#endif + +#endif /* __WINE_WINHTTP_H */