Import Upstream version 2.72.4
This commit is contained in:
commit
4ef3ff9793
2003 changed files with 1332420 additions and 0 deletions
479
gio/win32/gwinhttpvfs.c
Normal file
479
gio/win32/gwinhttpvfs.c
Normal file
|
|
@ -0,0 +1,479 @@
|
|||
/* 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.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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Alexander Larsson <alexl@redhat.com>
|
||||
* Author: Tor Lillqvist <tml@novell.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
#include "gio/gioerror.h"
|
||||
#include "gio/giomodule.h"
|
||||
#include "gio/gvfs.h"
|
||||
|
||||
#include "gwinhttpfile.h"
|
||||
#include "gwinhttpvfs.h"
|
||||
|
||||
static gboolean lookup_done = FALSE;
|
||||
static gboolean funcs_found = FALSE;
|
||||
static GWinHttpDllFuncs funcs;
|
||||
|
||||
static void
|
||||
lookup_funcs (void)
|
||||
{
|
||||
HMODULE winhttp = NULL;
|
||||
WCHAR winhttp_dll[MAX_PATH + 100];
|
||||
int n;
|
||||
|
||||
if (lookup_done)
|
||||
return;
|
||||
|
||||
n = GetSystemDirectoryW (winhttp_dll, MAX_PATH);
|
||||
if (n > 0 && n < MAX_PATH)
|
||||
{
|
||||
if (winhttp_dll[n-1] != L'\\' &&
|
||||
winhttp_dll[n-1] != L'/')
|
||||
wcscat (winhttp_dll, L"\\");
|
||||
wcscat (winhttp_dll, L"winhttp.dll");
|
||||
winhttp = LoadLibraryW (winhttp_dll);
|
||||
}
|
||||
|
||||
if (winhttp != NULL)
|
||||
{
|
||||
funcs.pWinHttpCloseHandle = (BOOL (WINAPI *) (HINTERNET)) GetProcAddress (winhttp, "WinHttpCloseHandle");
|
||||
funcs.pWinHttpCrackUrl = (BOOL (WINAPI *) (LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS)) GetProcAddress (winhttp, "WinHttpCrackUrl");
|
||||
funcs.pWinHttpConnect = (HINTERNET (WINAPI *) (HINTERNET,LPCWSTR,INTERNET_PORT,DWORD)) GetProcAddress (winhttp, "WinHttpConnect");
|
||||
funcs.pWinHttpCreateUrl = (BOOL (WINAPI *) (LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD)) GetProcAddress (winhttp, "WinHttpCreateUrl");
|
||||
funcs.pWinHttpOpen = (HINTERNET (WINAPI *) (LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD)) GetProcAddress (winhttp, "WinHttpOpen");
|
||||
funcs.pWinHttpOpenRequest = (HINTERNET (WINAPI *) (HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD)) GetProcAddress (winhttp, "WinHttpOpenRequest");
|
||||
funcs.pWinHttpQueryDataAvailable = (BOOL (WINAPI *) (HINTERNET,LPDWORD)) GetProcAddress (winhttp, "WinHttpQueryDataAvailable");
|
||||
funcs.pWinHttpQueryHeaders = (BOOL (WINAPI *) (HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD)) GetProcAddress (winhttp, "WinHttpQueryHeaders");
|
||||
funcs.pWinHttpReadData = (BOOL (WINAPI *) (HINTERNET,LPVOID,DWORD,LPDWORD)) GetProcAddress (winhttp, "WinHttpReadData");
|
||||
funcs.pWinHttpReceiveResponse = (BOOL (WINAPI *) (HINTERNET,LPVOID)) GetProcAddress (winhttp, "WinHttpReceiveResponse");
|
||||
funcs.pWinHttpSendRequest = (BOOL (WINAPI *) (HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR)) GetProcAddress (winhttp, "WinHttpSendRequest");
|
||||
funcs.pWinHttpWriteData = (BOOL (WINAPI *) (HINTERNET,LPCVOID,DWORD,LPDWORD)) GetProcAddress (winhttp, "WinHttpWriteData");
|
||||
|
||||
if (funcs.pWinHttpCloseHandle &&
|
||||
funcs.pWinHttpCrackUrl &&
|
||||
funcs.pWinHttpConnect &&
|
||||
funcs.pWinHttpCreateUrl &&
|
||||
funcs.pWinHttpOpen &&
|
||||
funcs.pWinHttpOpenRequest &&
|
||||
funcs.pWinHttpQueryDataAvailable &&
|
||||
funcs.pWinHttpQueryHeaders &&
|
||||
funcs.pWinHttpReadData &&
|
||||
funcs.pWinHttpReceiveResponse &&
|
||||
funcs.pWinHttpSendRequest &&
|
||||
funcs.pWinHttpWriteData)
|
||||
funcs_found = TRUE;
|
||||
}
|
||||
lookup_done = TRUE;
|
||||
}
|
||||
|
||||
#define g_winhttp_vfs_get_type _g_winhttp_vfs_get_type
|
||||
G_DEFINE_TYPE_WITH_CODE (GWinHttpVfs, g_winhttp_vfs, G_TYPE_VFS,
|
||||
{
|
||||
lookup_funcs ();
|
||||
if (funcs_found)
|
||||
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)->funcs->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;
|
||||
const gchar *prgname = g_get_prgname ();
|
||||
|
||||
vfs->wrapped_vfs = g_vfs_get_local ();
|
||||
|
||||
if (prgname)
|
||||
wagent = g_utf8_to_utf16 (prgname, -1, NULL, NULL, NULL);
|
||||
else
|
||||
wagent = g_utf8_to_utf16 ("GWinHttpVfs", -1, NULL, NULL, NULL);
|
||||
|
||||
vfs->session = (G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpOpen)
|
||||
(wagent,
|
||||
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
||||
WINHTTP_NO_PROXY_NAME,
|
||||
WINHTTP_NO_PROXY_BYPASS,
|
||||
0);
|
||||
|
||||
g_free (wagent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
gsize i;
|
||||
GFile *ret = NULL;
|
||||
|
||||
/* 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])] == ':')
|
||||
{
|
||||
ret = _g_winhttp_file_new (winhttp_vfs, uri);
|
||||
}
|
||||
}
|
||||
|
||||
/* For other URIs fallback to the wrapped GVfs */
|
||||
if (ret == NULL)
|
||||
ret = g_vfs_get_file_for_uri (winhttp_vfs->wrapped_vfs, uri);
|
||||
|
||||
g_assert (ret != NULL);
|
||||
|
||||
return g_steal_pointer (&ret);
|
||||
}
|
||||
|
||||
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);
|
||||
gsize 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;
|
||||
|
||||
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;
|
||||
|
||||
lookup_funcs ();
|
||||
if (funcs_found)
|
||||
class->funcs = &funcs;
|
||||
else
|
||||
class->funcs = NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
_g_winhttp_set_error (GError **error,
|
||||
DWORD error_code,
|
||||
const char *what)
|
||||
{
|
||||
char *emsg = _g_winhttp_error_message (error_code);
|
||||
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"%s failed: %s", what, emsg);
|
||||
g_free (emsg);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_g_winhttp_response (GWinHttpVfs *vfs,
|
||||
HINTERNET request,
|
||||
GError **error,
|
||||
const char *what)
|
||||
{
|
||||
wchar_t *status_code;
|
||||
DWORD status_code_len;
|
||||
|
||||
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpReceiveResponse (request, NULL))
|
||||
{
|
||||
_g_winhttp_set_error (error, GetLastError (), what);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
status_code_len = 0;
|
||||
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
|
||||
(request,
|
||||
WINHTTP_QUERY_STATUS_CODE,
|
||||
NULL,
|
||||
NULL,
|
||||
&status_code_len,
|
||||
NULL) &&
|
||||
GetLastError () != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
_g_winhttp_set_error (error, GetLastError (), what);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
status_code = g_malloc (status_code_len);
|
||||
|
||||
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
|
||||
(request,
|
||||
WINHTTP_QUERY_STATUS_CODE,
|
||||
NULL,
|
||||
status_code,
|
||||
&status_code_len,
|
||||
NULL))
|
||||
{
|
||||
_g_winhttp_set_error (error, GetLastError (), what);
|
||||
g_free (status_code);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (status_code[0] != L'2')
|
||||
{
|
||||
wchar_t *status_text = NULL;
|
||||
DWORD status_text_len;
|
||||
|
||||
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
|
||||
(request,
|
||||
WINHTTP_QUERY_STATUS_TEXT,
|
||||
NULL,
|
||||
NULL,
|
||||
&status_text_len,
|
||||
NULL) &&
|
||||
GetLastError () == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
status_text = g_malloc (status_text_len);
|
||||
|
||||
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
|
||||
(request,
|
||||
WINHTTP_QUERY_STATUS_TEXT,
|
||||
NULL,
|
||||
status_text,
|
||||
&status_text_len,
|
||||
NULL))
|
||||
{
|
||||
g_free (status_text);
|
||||
status_text = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"%s failed: %S %S",
|
||||
what, status_code, status_text ? status_text : L"");
|
||||
g_free (status_code);
|
||||
g_free (status_text);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free (status_code);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_g_winhttp_query_header (GWinHttpVfs *vfs,
|
||||
HINTERNET request,
|
||||
const char *request_description,
|
||||
DWORD which_header,
|
||||
wchar_t **header,
|
||||
GError **error)
|
||||
{
|
||||
DWORD header_len = 0;
|
||||
|
||||
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
|
||||
(request,
|
||||
which_header,
|
||||
NULL,
|
||||
NULL,
|
||||
&header_len,
|
||||
NULL) &&
|
||||
GetLastError () != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
_g_winhttp_set_error (error, GetLastError (), request_description);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*header = g_malloc (header_len);
|
||||
if (!G_WINHTTP_VFS_GET_CLASS (vfs)->funcs->pWinHttpQueryHeaders
|
||||
(request,
|
||||
which_header,
|
||||
NULL,
|
||||
*header,
|
||||
&header_len,
|
||||
NULL))
|
||||
{
|
||||
_g_winhttp_set_error (error, GetLastError (), request_description);
|
||||
g_free (*header);
|
||||
*header = NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue