nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2010 Collabora, Ltd.
4 * Copyright (C) 2014 Red Hat, 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, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
20 * Marc-André Lureau <marcandre.lureau@redhat.com>
21 */
22  
23 #include "config.h"
24  
25 #include "ghttpproxy.h"
26  
27 #include <string.h>
28 #include <stdlib.h>
29  
30 #include "giomodule.h"
31 #include "giomodule-priv.h"
32 #include "giostream.h"
33 #include "ginputstream.h"
34 #include "glibintl.h"
35 #include "goutputstream.h"
36 #include "gproxy.h"
37 #include "gproxyaddress.h"
38 #include "gsocketconnectable.h"
39 #include "gtask.h"
40 #include "gtlsclientconnection.h"
41 #include "gtlsconnection.h"
42  
43  
44 struct _GHttpProxy
45 {
46 GObject parent;
47 };
48  
49 struct _GHttpProxyClass
50 {
51 GObjectClass parent_class;
52 };
53  
54 static void g_http_proxy_iface_init (GProxyInterface *proxy_iface);
55  
56 #define g_http_proxy_get_type _g_http_proxy_get_type
57 G_DEFINE_TYPE_WITH_CODE (GHttpProxy, g_http_proxy, G_TYPE_OBJECT,
58 G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
59 g_http_proxy_iface_init)
60 _g_io_modules_ensure_extension_points_registered ();
61 g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
62 g_define_type_id,
63 "http",
64 0))
65  
66 static void
67 g_http_proxy_init (GHttpProxy *proxy)
68 {
69 }
70  
71 static gchar *
72 create_request (GProxyAddress *proxy_address,
73 gboolean *has_cred)
74 {
75 const gchar *hostname;
76 gint port;
77 const gchar *username;
78 const gchar *password;
79 GString *request;
80 gchar *ascii_hostname;
81  
82 if (has_cred)
83 *has_cred = FALSE;
84  
85 hostname = g_proxy_address_get_destination_hostname (proxy_address);
86 port = g_proxy_address_get_destination_port (proxy_address);
87 username = g_proxy_address_get_username (proxy_address);
88 password = g_proxy_address_get_password (proxy_address);
89  
90 request = g_string_new (NULL);
91  
92 ascii_hostname = g_hostname_to_ascii (hostname);
93 g_string_append_printf (request,
94 "CONNECT %s:%i HTTP/1.0\r\n"
95 "Host: %s:%i\r\n"
96 "Proxy-Connection: keep-alive\r\n"
97 "User-Agent: GLib/%i.%i\r\n",
98 ascii_hostname, port,
99 ascii_hostname, port,
100 GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION);
101 g_free (ascii_hostname);
102  
103 if (username != NULL && password != NULL)
104 {
105 gchar *cred;
106 gchar *base64_cred;
107  
108 if (has_cred)
109 *has_cred = TRUE;
110  
111 cred = g_strdup_printf ("%s:%s", username, password);
112 base64_cred = g_base64_encode ((guchar *) cred, strlen (cred));
113 g_free (cred);
114 g_string_append_printf (request,
115 "Proxy-Authorization: Basic %s\r\n",
116 base64_cred);
117 g_free (base64_cred);
118 }
119  
120 g_string_append (request, "\r\n");
121  
122 return g_string_free (request, FALSE);
123 }
124  
125 static gboolean
126 check_reply (const gchar *buffer,
127 gboolean has_cred,
128 GError **error)
129 {
130 gint err_code;
131 const gchar *ptr = buffer + 7;
132  
133 if (strncmp (buffer, "HTTP/1.", 7) != 0 || (*ptr != '0' && *ptr != '1'))
134 {
135 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
136 _("Bad HTTP proxy reply"));
137 return FALSE;
138 }
139  
140 ptr++;
141 while (*ptr == ' ')
142 ptr++;
143  
144 err_code = atoi (ptr);
145  
146 if (err_code < 200 || err_code >= 300)
147 {
148 switch (err_code)
149 {
150 case 403:
151 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_NOT_ALLOWED,
152 _("HTTP proxy connection not allowed"));
153 break;
154 case 407:
155 if (has_cred)
156 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_AUTH_FAILED,
157 _("HTTP proxy authentication failed"));
158 else
159 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_NEED_AUTH,
160 _("HTTP proxy authentication required"));
161 break;
162 default:
163 g_set_error (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
164 _("HTTP proxy connection failed: %i"), err_code);
165 }
166  
167 return FALSE;
168 }
169  
170 return TRUE;
171 }
172  
173 #define HTTP_END_MARKER "\r\n\r\n"
174  
175 static GIOStream *
176 g_http_proxy_connect (GProxy *proxy,
177 GIOStream *io_stream,
178 GProxyAddress *proxy_address,
179 GCancellable *cancellable,
180 GError **error)
181 {
182 GInputStream *in;
183 GOutputStream *out;
184 gchar *buffer = NULL;
185 gsize buffer_length;
186 gssize bytes_read;
187 gboolean has_cred;
188 GIOStream *tlsconn = NULL;
189  
190 if (G_IS_HTTPS_PROXY (proxy))
191 {
192 tlsconn = g_tls_client_connection_new (io_stream,
193 G_SOCKET_CONNECTABLE (proxy_address),
194 error);
195 if (!tlsconn)
196 goto error;
197  
198 #ifdef DEBUG
199 {
200 GTlsCertificateFlags tls_validation_flags = G_TLS_CERTIFICATE_VALIDATE_ALL;
201  
202 tls_validation_flags &= ~(G_TLS_CERTIFICATE_UNKNOWN_CA | G_TLS_CERTIFICATE_BAD_IDENTITY);
203 g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (tlsconn),
204 tls_validation_flags);
205 }
206 #endif
207  
208 if (!g_tls_connection_handshake (G_TLS_CONNECTION (tlsconn), cancellable, error))
209 goto error;
210  
211 io_stream = tlsconn;
212 }
213  
214 in = g_io_stream_get_input_stream (io_stream);
215 out = g_io_stream_get_output_stream (io_stream);
216  
217 buffer = create_request (proxy_address, &has_cred);
218 if (!g_output_stream_write_all (out, buffer, strlen (buffer), NULL,
219 cancellable, error))
220 goto error;
221  
222 g_free (buffer);
223  
224 bytes_read = 0;
225 buffer_length = 1024;
226 buffer = g_malloc (buffer_length);
227  
228 /* Read byte-by-byte instead of using GDataInputStream
229 * since we do not want to read beyond the end marker
230 */
231 do
232 {
233 gsize nread;
234  
235 nread = g_input_stream_read (in, buffer + bytes_read, 1, cancellable, error);
236 if (nread == -1)
237 goto error;
238  
239 if (nread == 0)
240 break;
241  
242 ++bytes_read;
243  
244 if (bytes_read == buffer_length)
245 {
246 buffer_length = 2 * buffer_length;
247 buffer = g_realloc (buffer, buffer_length);
248 }
249  
250 *(buffer + bytes_read) = '\0';
251  
252 if (g_str_has_suffix (buffer, HTTP_END_MARKER))
253 break;
254 }
255 while (TRUE);
256  
257 if (bytes_read == 0)
258 {
259 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED,
260 _("HTTP proxy server closed connection unexpectedly."));
261 goto error;
262 }
263  
264 if (!check_reply (buffer, has_cred, error))
265 goto error;
266  
267 g_free (buffer);
268  
269 g_object_ref (io_stream);
270 g_clear_object (&tlsconn);
271  
272 return io_stream;
273  
274 error:
275 g_clear_object (&tlsconn);
276 g_free (buffer);
277 return NULL;
278 }
279  
280 typedef struct
281 {
282 GIOStream *io_stream;
283 GProxyAddress *proxy_address;
284 } ConnectAsyncData;
285  
286 static void
287 free_connect_data (ConnectAsyncData *data)
288 {
289 g_object_unref (data->io_stream);
290 g_object_unref (data->proxy_address);
291 g_slice_free (ConnectAsyncData, data);
292 }
293  
294 static void
295 connect_thread (GTask *task,
296 gpointer source_object,
297 gpointer task_data,
298 GCancellable *cancellable)
299 {
300 GProxy *proxy = source_object;
301 ConnectAsyncData *data = task_data;
302 GIOStream *res;
303 GError *error = NULL;
304  
305 res = g_http_proxy_connect (proxy, data->io_stream, data->proxy_address,
306 cancellable, &error);
307  
308 if (res == NULL)
309 g_task_return_error (task, error);
310 else
311 g_task_return_pointer (task, res, g_object_unref);
312 }
313  
314 static void
315 g_http_proxy_connect_async (GProxy *proxy,
316 GIOStream *io_stream,
317 GProxyAddress *proxy_address,
318 GCancellable *cancellable,
319 GAsyncReadyCallback callback,
320 gpointer user_data)
321 {
322 ConnectAsyncData *data;
323 GTask *task;
324  
325 data = g_slice_new0 (ConnectAsyncData);
326 data->io_stream = g_object_ref (io_stream);
327 data->proxy_address = g_object_ref (proxy_address);
328  
329 task = g_task_new (proxy, cancellable, callback, user_data);
330 g_task_set_task_data (task, data, (GDestroyNotify) free_connect_data);
331  
332 g_task_run_in_thread (task, connect_thread);
333 g_object_unref (task);
334 }
335  
336 static GIOStream *
337 g_http_proxy_connect_finish (GProxy *proxy,
338 GAsyncResult *result,
339 GError **error)
340 {
341 return g_task_propagate_pointer (G_TASK (result), error);
342 }
343  
344 static gboolean
345 g_http_proxy_supports_hostname (GProxy *proxy)
346 {
347 return TRUE;
348 }
349  
350 static void
351 g_http_proxy_class_init (GHttpProxyClass *class)
352 {
353 }
354  
355 static void
356 g_http_proxy_iface_init (GProxyInterface *proxy_iface)
357 {
358 proxy_iface->connect = g_http_proxy_connect;
359 proxy_iface->connect_async = g_http_proxy_connect_async;
360 proxy_iface->connect_finish = g_http_proxy_connect_finish;
361 proxy_iface->supports_hostname = g_http_proxy_supports_hostname;
362 }
363  
364 struct _GHttpsProxy
365 {
366 GHttpProxy parent;
367 };
368  
369 struct _GHttpsProxyClass
370 {
371 GHttpProxyClass parent_class;
372 };
373  
374 #define g_https_proxy_get_type _g_https_proxy_get_type
375 G_DEFINE_TYPE_WITH_CODE (GHttpsProxy, g_https_proxy, G_TYPE_HTTP_PROXY,
376 G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
377 g_http_proxy_iface_init)
378 _g_io_modules_ensure_extension_points_registered ();
379 g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
380 g_define_type_id,
381 "https",
382 0))
383  
384 static void
385 g_https_proxy_init (GHttpsProxy *proxy)
386 {
387 }
388  
389 static void
390 g_https_proxy_class_init (GHttpsProxyClass *class)
391 {
392 }