Don't write the Content-Length header ourselves, WinHttpSendRequest()
[platform/upstream/glib.git] / gio / win32 / gwinhttpvfs.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 "giomodule.h"
28 #include "gvfs.h"
29
30 #include "gwinhttpfile.h"
31 #include "gwinhttpvfs.h"
32
33 #include "gioalias.h"
34
35 #define g_winhttp_vfs_get_type _g_winhttp_vfs_get_type
36 G_DEFINE_TYPE_WITH_CODE (GWinHttpVfs, g_winhttp_vfs, G_TYPE_VFS,
37                          g_io_extension_point_implement (G_VFS_EXTENSION_POINT_NAME,
38                                                          g_define_type_id,
39                                                          "winhttp",
40                                                          10))
41
42 static const gchar *winhttp_uri_schemes[] = { "http", "https" };
43
44 static void
45 g_winhttp_vfs_finalize (GObject *object)
46 {
47   GWinHttpVfs *vfs;
48
49   vfs = G_WINHTTP_VFS (object);
50
51   (G_WINHTTP_VFS_GET_CLASS (vfs)->pWinHttpCloseHandle) (vfs->session);
52   vfs->session = NULL;
53
54   if (vfs->wrapped_vfs)
55     g_object_unref (vfs->wrapped_vfs);
56   vfs->wrapped_vfs = NULL;
57
58   G_OBJECT_CLASS (g_winhttp_vfs_parent_class)->finalize (object);
59 }
60
61 static void
62 g_winhttp_vfs_init (GWinHttpVfs *vfs)
63 {
64   wchar_t *wagent;
65
66   vfs->wrapped_vfs = g_vfs_get_local ();
67
68   wagent = g_utf8_to_utf16 (g_get_prgname (), -1, NULL, NULL, NULL);
69
70   if (!wagent)
71     wagent = g_utf8_to_utf16 ("GWinHttpVfs", -1, NULL, NULL, NULL);
72   
73   vfs->session = (G_WINHTTP_VFS_GET_CLASS (vfs)->pWinHttpOpen)
74     (wagent,
75      WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
76      WINHTTP_NO_PROXY_NAME,
77      WINHTTP_NO_PROXY_BYPASS,
78      0);
79 }
80
81 /**
82  * g_winhttp_vfs_new:
83  *
84  * Returns a new #GVfs handle for a WinHttp vfs.
85  *
86  * Returns: a new #GVfs handle.
87  **/
88 GVfs *
89 _g_winhttp_vfs_new (void)
90 {
91   return g_object_new (G_TYPE_WINHTTP_VFS, NULL);
92 }
93
94 static GFile *
95 g_winhttp_vfs_get_file_for_path (GVfs       *vfs,
96                                  const char *path)
97 {
98   return g_vfs_get_file_for_path (G_WINHTTP_VFS (vfs)->wrapped_vfs, path);
99 }
100
101 static GFile *
102 g_winhttp_vfs_get_file_for_uri (GVfs       *vfs,
103                                 const char *uri)
104 {
105   GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs);
106   int i;
107
108   /* If it matches one of "our" schemes, handle it */
109   for (i = 0; i < G_N_ELEMENTS (winhttp_uri_schemes); i++)
110     if (g_ascii_strncasecmp (uri, winhttp_uri_schemes[i], strlen (winhttp_uri_schemes[i])) == 0 &&
111         uri[strlen (winhttp_uri_schemes[i])] == ':')
112       return _g_winhttp_file_new (winhttp_vfs, uri);
113
114   /* For other URIs fallback to the wrapped GVfs */
115   return g_vfs_parse_name (winhttp_vfs->wrapped_vfs, uri);
116 }
117
118 static const gchar * const *
119 g_winhttp_vfs_get_supported_uri_schemes (GVfs *vfs)
120 {
121   GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs);
122   const gchar * const *wrapped_vfs_uri_schemes = g_vfs_get_supported_uri_schemes (winhttp_vfs->wrapped_vfs);
123   int i, n;
124   const gchar **retval;
125
126   n = 0;
127   while (wrapped_vfs_uri_schemes[n] != NULL)
128     n++;
129
130   retval = g_new (const gchar *, n + G_N_ELEMENTS (winhttp_uri_schemes) + 1);
131   n = 0;
132   while (wrapped_vfs_uri_schemes[n] != NULL)
133     {
134       retval[n] = wrapped_vfs_uri_schemes[n];
135       n++;
136     }
137
138   for (i = 0; i < G_N_ELEMENTS (winhttp_uri_schemes); i++)
139     {
140       retval[n] = winhttp_uri_schemes[i];
141       n++;
142     }
143
144   retval[n] = NULL;
145   
146   return retval;
147 }
148
149 static GFile *
150 g_winhttp_vfs_parse_name (GVfs       *vfs,
151                           const char *parse_name)
152 {
153   GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs);
154   
155   g_return_val_if_fail (G_IS_VFS (vfs), NULL);
156   g_return_val_if_fail (parse_name != NULL, NULL);
157
158   /* For plain file paths fallback to the wrapped GVfs */
159   if (g_path_is_absolute (parse_name))
160     return g_vfs_parse_name (winhttp_vfs->wrapped_vfs, parse_name);
161
162   /* Otherwise assume it is an URI, so pass on to
163    * g_winhttp_vfs_get_file_for_uri().
164    */
165   return g_winhttp_vfs_get_file_for_uri (vfs, parse_name);
166 }
167
168 static gboolean
169 g_winhttp_vfs_is_active (GVfs *vfs)
170 {
171   return TRUE;
172 }
173
174 static void
175 g_winhttp_vfs_class_init (GWinHttpVfsClass *class)
176 {
177   GObjectClass *object_class;
178   GVfsClass *vfs_class;
179   HMODULE winhttp;
180   
181   object_class = (GObjectClass *) class;
182
183   object_class->finalize = g_winhttp_vfs_finalize;
184
185   vfs_class = G_VFS_CLASS (class);
186
187   vfs_class->is_active = g_winhttp_vfs_is_active;
188   vfs_class->get_file_for_path = g_winhttp_vfs_get_file_for_path;
189   vfs_class->get_file_for_uri = g_winhttp_vfs_get_file_for_uri;
190   vfs_class->get_supported_uri_schemes = g_winhttp_vfs_get_supported_uri_schemes;
191   vfs_class->parse_name = g_winhttp_vfs_parse_name;
192
193   winhttp = LoadLibrary ("winhttp.dll");
194   if (winhttp != NULL)
195     {
196       class->pWinHttpCloseHandle = (BOOL (WINAPI *) (HINTERNET)) GetProcAddress (winhttp, "WinHttpCloseHandle");
197       class->pWinHttpCrackUrl = (BOOL (WINAPI *) (LPCWSTR,DWORD,DWORD,LPURL_COMPONENTS)) GetProcAddress (winhttp, "WinHttpCrackUrl");
198       class->pWinHttpConnect = (HINTERNET (WINAPI *) (HINTERNET,LPCWSTR,INTERNET_PORT,DWORD)) GetProcAddress (winhttp, "WinHttpConnect");
199       class->pWinHttpCreateUrl = (BOOL (WINAPI *) (LPURL_COMPONENTS,DWORD,LPWSTR,LPDWORD)) GetProcAddress (winhttp, "WinHttpCreateUrl");
200       class->pWinHttpOpen = (HINTERNET (WINAPI *) (LPCWSTR,DWORD,LPCWSTR,LPCWSTR,DWORD)) GetProcAddress (winhttp, "WinHttpOpen");
201       class->pWinHttpOpenRequest = (HINTERNET (WINAPI *) (HINTERNET,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR*,DWORD)) GetProcAddress (winhttp, "WinHttpOpenRequest");
202       class->pWinHttpQueryDataAvailable = (BOOL (WINAPI *) (HINTERNET,LPDWORD)) GetProcAddress (winhttp, "WinHttpQueryDataAvailable");
203       class->pWinHttpQueryHeaders = (BOOL (WINAPI *) (HINTERNET,DWORD,LPCWSTR,LPVOID,LPDWORD,LPDWORD)) GetProcAddress (winhttp, "WinHttpQueryHeaders");
204       class->pWinHttpReadData = (BOOL (WINAPI *) (HINTERNET,LPVOID,DWORD,LPDWORD)) GetProcAddress (winhttp, "WinHttpReadData");
205       class->pWinHttpReceiveResponse = (BOOL (WINAPI *) (HINTERNET,LPVOID)) GetProcAddress (winhttp, "WinHttpReceiveResponse");
206       class->pWinHttpSendRequest = (BOOL (WINAPI *) (HINTERNET,LPCWSTR,DWORD,LPVOID,DWORD,DWORD,DWORD_PTR)) GetProcAddress (winhttp, "WinHttpSendRequest");
207       class->pWinHttpWriteData = (BOOL (WINAPI *) (HINTERNET,LPCVOID,DWORD,LPDWORD)) GetProcAddress (winhttp, "WinHttpWriteData");
208     }
209 }
210
211 char *
212 _g_winhttp_error_message (DWORD error_code)
213 {
214   /* The FormatMessage() API that g_win32_error_message() uses doesn't
215    * seem to know about WinHttp errors, unfortunately.
216    */
217   if (error_code >= WINHTTP_ERROR_BASE && error_code < WINHTTP_ERROR_BASE + 200)
218     {
219       switch (error_code)
220         {
221           /* FIXME: Use meaningful error messages */
222 #define CASE(x) case ERROR_WINHTTP_##x: return g_strdup ("WinHttp error: " #x);
223           CASE (AUTO_PROXY_SERVICE_ERROR);
224           CASE (AUTODETECTION_FAILED);
225           CASE (BAD_AUTO_PROXY_SCRIPT);
226           CASE (CANNOT_CALL_AFTER_OPEN);
227           CASE (CANNOT_CALL_AFTER_SEND);
228           CASE (CANNOT_CALL_BEFORE_OPEN);
229           CASE (CANNOT_CALL_BEFORE_SEND);
230           CASE (CANNOT_CONNECT);
231           CASE (CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW);
232           CASE (CLIENT_AUTH_CERT_NEEDED);
233           CASE (CONNECTION_ERROR);
234           CASE (HEADER_ALREADY_EXISTS);
235           CASE (HEADER_COUNT_EXCEEDED);
236           CASE (HEADER_NOT_FOUND);
237           CASE (HEADER_SIZE_OVERFLOW);
238           CASE (INCORRECT_HANDLE_STATE);
239           CASE (INCORRECT_HANDLE_TYPE);
240           CASE (INTERNAL_ERROR);
241           CASE (INVALID_OPTION);
242           CASE (INVALID_QUERY_REQUEST);
243           CASE (INVALID_SERVER_RESPONSE);
244           CASE (INVALID_URL);
245           CASE (LOGIN_FAILURE);
246           CASE (NAME_NOT_RESOLVED);
247           CASE (NOT_INITIALIZED);
248           CASE (OPERATION_CANCELLED);
249           CASE (OPTION_NOT_SETTABLE);
250           CASE (OUT_OF_HANDLES);
251           CASE (REDIRECT_FAILED);
252           CASE (RESEND_REQUEST);
253           CASE (RESPONSE_DRAIN_OVERFLOW);
254           CASE (SECURE_CERT_CN_INVALID);
255           CASE (SECURE_CERT_DATE_INVALID);
256           CASE (SECURE_CERT_REV_FAILED);
257           CASE (SECURE_CERT_REVOKED);
258           CASE (SECURE_CERT_WRONG_USAGE);
259           CASE (SECURE_CHANNEL_ERROR);
260           CASE (SECURE_FAILURE);
261           CASE (SECURE_INVALID_CA);
262           CASE (SECURE_INVALID_CERT);
263           CASE (SHUTDOWN);
264           CASE (TIMEOUT);
265           CASE (UNABLE_TO_DOWNLOAD_SCRIPT);
266           CASE (UNRECOGNIZED_SCHEME);
267           #undef CASE
268         default:
269           return g_strdup_printf ("WinHttp error %ld", error_code); 
270         }
271     }
272   else
273     return g_win32_error_message (error_code);
274 }