2 * This file is part of the Nice GLib ICE library.
4 * (C) 2008 Collabora Ltd.
5 * Contact: Youness Alaoui
6 * (C) 2008 Nokia Corporation. All rights reserved.
8 * The contents of this file are subject to the Mozilla Public License Version
9 * 1.1 (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 * http://www.mozilla.org/MPL/
13 * Software distributed under the License is distributed on an "AS IS" basis,
14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15 * for the specific language governing rights and limitations under the
18 * The Original Code is the Nice GLib ICE library.
20 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
21 * Corporation. All Rights Reserved.
24 * Youness Alaoui, Collabora Ltd.
26 * Alternatively, the contents of this file may be used under the terms of the
27 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
28 * case the provisions of LGPL are applicable instead of those above. If you
29 * wish to allow use of your version of this file only under the terms of the
30 * LGPL and not to allow others to use your version of this file under the
31 * MPL, indicate your decision by deleting the provisions above and replace
32 * them with the notice and other provisions required by the LGPL. If you do
33 * not delete the provisions above, a recipient may use your version of this
34 * file under either the MPL or the LGPL.
38 * Implementation of TCP relay socket interface using TCP Berkeley sockets. (See
39 * http://en.wikipedia.org/wiki/Berkeley_sockets.)
46 #include "agent-priv.h"
47 #include "socket-priv.h"
58 #define HTTP_USER_AGENT "libnice"
70 NiceSocket *base_socket;
76 /* Ring buffer for receiving HTTP headers into before they’re parsed. */
78 gsize recv_buf_length; /* allocation size of @recv_buf */
79 gsize recv_buf_pos; /* offset from @recv_buf of the 0th byte in the buffer */
80 gsize recv_buf_fill; /* number of bytes occupied in the buffer */
82 /* Parsed from the Content-Length header provided by the other endpoint. */
87 static void socket_close (NiceSocket *sock);
88 static gint socket_recv_messages (NiceSocket *sock,
89 NiceInputMessage *recv_messages, guint n_recv_messages);
90 static gint socket_send_messages (NiceSocket *sock, const NiceAddress *to,
91 const NiceOutputMessage *messages, guint n_messages);
92 static gint socket_send_messages_reliable (NiceSocket *sock,
93 const NiceAddress *to, const NiceOutputMessage *messages, guint n_messages);
94 static gboolean socket_is_reliable (NiceSocket *sock);
95 static gboolean socket_can_send (NiceSocket *sock, NiceAddress *addr);
96 static void socket_set_writable_callback (NiceSocket *sock,
97 NiceSocketWritableCb callback, gpointer user_data);
98 static gboolean socket_is_based_on (NiceSocket *sock, NiceSocket *other);
101 nice_http_socket_new (NiceSocket *base_socket,
102 NiceAddress *addr, gchar *username, gchar *password)
105 NiceSocket *sock = NULL;
108 sock = g_slice_new0 (NiceSocket);
109 sock->priv = priv = g_slice_new0 (HttpPriv);
111 priv->base_socket = base_socket;
113 priv->username = g_strdup (username);
114 priv->password = g_strdup (password);
115 priv->recv_buf = NULL;
116 priv->recv_buf_length = 0;
117 priv->recv_buf_pos = 0;
118 priv->recv_buf_fill = 0;
119 priv->content_length = 0;
121 sock->type = NICE_SOCKET_TYPE_HTTP;
122 sock->fileno = priv->base_socket->fileno;
123 sock->addr = priv->base_socket->addr;
124 sock->send_messages = socket_send_messages;
125 sock->send_messages_reliable = socket_send_messages_reliable;
126 sock->recv_messages = socket_recv_messages;
127 sock->is_reliable = socket_is_reliable;
128 sock->can_send = socket_can_send;
129 sock->set_writable_callback = socket_set_writable_callback;
130 sock->is_based_on = socket_is_based_on;
131 sock->close = socket_close;
133 /* Send HTTP CONNECT */
136 gchar *credential = NULL;
137 gchar host[INET6_ADDRSTRLEN];
138 gint port = nice_address_get_port (&priv->addr);
139 GOutputVector local_bufs;
140 NiceOutputMessage local_messages;
142 nice_address_to_string (&priv->addr, host);
145 gchar * userpass = g_strdup_printf ("%s:%s", username,
146 password ? password : "");
147 gchar * auth = g_base64_encode ((guchar *)userpass, strlen (userpass));
148 credential = g_strdup_printf ("Proxy-Authorization: Basic %s\r\n", auth);
152 msg = g_strdup_printf ("CONNECT %s:%d HTTP/1.0\r\n"
155 "Content-Length: 0\r\n"
156 "Proxy-Connection: Keep-Alive\r\n"
157 "Connection: Keep-Alive\r\n"
158 "Cache-Control: no-cache\r\n"
159 "Pragma: no-cache\r\n"
160 "%s\r\n", host, port, host, HTTP_USER_AGENT,
161 credential? credential : "" );
164 local_bufs.buffer = msg;
165 local_bufs.size = strlen (msg);
166 local_messages.buffers = &local_bufs;
167 local_messages.n_buffers = 1;
169 nice_socket_send_messages_reliable (priv->base_socket, NULL,
171 priv->state = HTTP_STATE_INIT;
181 socket_close (NiceSocket *sock)
183 HttpPriv *priv = sock->priv;
185 if (priv->base_socket)
186 nice_socket_free (priv->base_socket);
189 g_free (priv->username);
192 g_free (priv->password);
195 g_free (priv->recv_buf);
197 nice_socket_free_send_queue (&priv->send_queue);
199 g_slice_free(HttpPriv, sock->priv);
204 assert_ring_buffer_valid (HttpPriv *priv)
206 g_assert_cmpint (priv->recv_buf_fill, <=, priv->recv_buf_length);
207 g_assert (priv->recv_buf_pos == 0 ||
208 priv->recv_buf_pos < priv->recv_buf_length);
209 g_assert (priv->recv_buf_length == 0 || priv->recv_buf != NULL);
212 /* Pops up to @buffer_length bytes off the ring buffer and copies them into
213 * @buffer. Returns the number of bytes copied. */
215 memcpy_ring_buffer_to_buffer (HttpPriv *priv,
216 guint8 *buffer, gsize buffer_length)
218 gsize len, consumed = 0;
219 gboolean has_wrapped;
222 (priv->recv_buf_pos + priv->recv_buf_fill) > priv->recv_buf_length;
225 len = MIN (priv->recv_buf_length - priv->recv_buf_pos, buffer_length);
226 memcpy (buffer, priv->recv_buf + priv->recv_buf_pos, len);
230 buffer_length -= len;
232 len = MIN (priv->recv_buf_fill - len, buffer_length);
233 memcpy (buffer, priv->recv_buf, len);
236 len = MIN (priv->recv_buf_fill, buffer_length);
237 memcpy (buffer, priv->recv_buf + priv->recv_buf_pos, len);
242 (priv->recv_buf_pos + consumed) % priv->recv_buf_length;
243 priv->recv_buf_fill -= consumed;
248 /* Returns the number of messages touched. Silently drops any data from @buffer
249 * which doesn’t fit in @messages. Updates the ring buffer to pop the copied
250 * data off it. Treats all #GInputVectors in @messages the same; there is no
251 * differentiation between different #NiceInputMessages. */
253 memcpy_ring_buffer_to_input_messages (HttpPriv *priv,
254 NiceInputMessage *messages, guint n_messages)
258 for (i = 0; priv->recv_buf_fill > 0 && i < n_messages; i++) {
259 NiceInputMessage *message = &messages[i];
262 priv->recv_buf_fill > 0 &&
263 ((message->n_buffers >= 0 && j < (guint) message->n_buffers) ||
264 (message->n_buffers < 0 && message->buffers[j].buffer != NULL));
266 message->buffers[j].size =
267 memcpy_ring_buffer_to_buffer (priv,
268 message->buffers[j].buffer, message->buffers[j].size);
275 /* FIXME: The current implementation of socket_recv_message() is a fast
276 * pass-through to nice_socket_recv_message() if the HTTP socket is connected,
277 * but is a slow state machine otherwise, using multiple memcpy()s. Spruce it up
278 * to better to use the recv_messages to avoid the memcpy()s. */
280 socket_recv_messages (NiceSocket *sock,
281 NiceInputMessage *recv_messages, guint n_recv_messages)
283 HttpPriv *priv = sock->priv;
286 /* Make sure socket has not been freed: */
287 g_assert (sock->priv != NULL);
289 if (priv->state == HTTP_STATE_CONNECTED) {
292 /* Fast path: pass through to the base socket once we’re connected. */
293 if (priv->base_socket) {
294 ret = nice_socket_recv_messages (priv->base_socket,
295 recv_messages, n_recv_messages);
301 /* After successfully receiving into at least one NiceInputMessage,
302 * update the from address in each valid NiceInputMessage. */
303 for (i = 0; i < (guint) ret; i++) {
304 if (recv_messages[i].from != NULL)
305 *recv_messages[i].from = priv->addr;
310 /* Slow path: read into a local ring buffer until we’re parsed enough of the
311 * headers. Double the buffer in size every time it fills up. */
312 gboolean has_wrapped;
313 GInputVector local_recv_bufs[2];
314 NiceInputMessage local_recv_message = { local_recv_bufs, 2, NULL, 0 };
316 /* Has the buffer filled up? Start with an initial buffer of 1KB, which
317 * should cover the average size of HTTP response headers. Source:
318 * http://dev.chromium.org/spdy/spdy-whitepaper */
319 if (priv->recv_buf_fill == priv->recv_buf_length) {
320 priv->recv_buf_length = MAX (priv->recv_buf_length * 2, 1024);
321 priv->recv_buf = g_realloc (priv->recv_buf, priv->recv_buf_length);
324 assert_ring_buffer_valid (priv);
326 /* Read some data into the buffer. Use two GInputVectors: one for the tail
327 * of the buffer and one for the head. */
329 (priv->recv_buf_pos + priv->recv_buf_fill) > priv->recv_buf_length;
332 local_recv_bufs[0].buffer =
333 priv->recv_buf + (priv->recv_buf_pos + priv->recv_buf_fill) %
334 priv->recv_buf_length;
335 local_recv_bufs[0].size = priv->recv_buf_length - priv->recv_buf_fill;
336 local_recv_bufs[1].buffer = NULL;
337 local_recv_bufs[1].size = 0;
339 local_recv_bufs[0].buffer =
340 priv->recv_buf + priv->recv_buf_pos + priv->recv_buf_fill;
341 local_recv_bufs[0].size =
342 priv->recv_buf_length - (priv->recv_buf_pos + priv->recv_buf_fill);
343 local_recv_bufs[1].buffer = priv->recv_buf;
344 local_recv_bufs[1].size = priv->recv_buf_pos;
347 if (priv->base_socket) {
348 ret = nice_socket_recv_messages (priv->base_socket,
349 &local_recv_message, 1);
355 /* Update the buffer’s metadata. */
356 priv->recv_buf_fill += local_recv_message.length;
357 assert_ring_buffer_valid (priv);
359 /* Fall through and try parsing the newly received data. */
362 #define GET_BYTE(pos) \
363 priv->recv_buf[(pos + priv->recv_buf_pos) % priv->recv_buf_length]
364 #define EAT_WHITESPACE(pos) \
365 while (pos < priv->recv_buf_fill && GET_BYTE(pos) == ' ') \
367 if (pos >= priv->recv_buf_fill) \
368 goto not_enough_data;
371 nice_debug ("Receiving from HTTP proxy (state %d) : %" G_GSSIZE_FORMAT " \n"
372 "'%s'", priv->state, priv->recv_buf_fill,
373 priv->recv_buf + priv->recv_buf_pos);
375 switch (priv->state) {
376 case HTTP_STATE_INIT:
378 /* This is a logical position in the recv_buf; add
379 * (priv->recv_buf + priv->recv_buf_pos) to get the actual byte in
383 /* Eat leading whitespace and check we have enough data. */
384 EAT_WHITESPACE (pos);
386 if (pos + 7 > priv->recv_buf_fill)
387 goto not_enough_data;
388 if (GET_BYTE (pos + 0) != 'H' ||
389 GET_BYTE (pos + 1) != 'T' ||
390 GET_BYTE (pos + 2) != 'T' ||
391 GET_BYTE (pos + 3) != 'P' ||
392 GET_BYTE (pos + 4) != '/' ||
393 GET_BYTE (pos + 5) != '1' ||
394 GET_BYTE (pos + 6) != '.')
398 if (pos >= priv->recv_buf_fill)
399 goto not_enough_data;
400 if (GET_BYTE (pos) != '0' && GET_BYTE (pos) != '1')
404 /* Make sure we have a space after the HTTP version */
405 if (pos >= priv->recv_buf_fill)
406 goto not_enough_data;
407 if (GET_BYTE (pos) != ' ')
410 EAT_WHITESPACE (pos);
412 /* Check for a successful 2xx code */
413 if (pos + 3 > priv->recv_buf_fill)
414 goto not_enough_data;
415 if (GET_BYTE (pos) != '2' ||
416 GET_BYTE (pos + 1) < '0' || GET_BYTE (pos + 1) > '9' ||
417 GET_BYTE (pos + 2) < '0' || GET_BYTE (pos + 2) > '9')
420 /* Clear any trailing chars */
421 while (pos + 1 < priv->recv_buf_fill &&
422 GET_BYTE (pos) != '\r' && GET_BYTE (pos + 1) != '\n')
424 if (pos + 1 >= priv->recv_buf_fill)
425 goto not_enough_data;
428 /* Consume the data we just parsed. */
429 priv->recv_buf_pos = (priv->recv_buf_pos + pos) % priv->recv_buf_length;
430 priv->recv_buf_fill -= pos;
432 priv->content_length = 0;
433 priv->state = HTTP_STATE_HEADERS;
438 case HTTP_STATE_HEADERS:
442 if (pos + 15 < priv->recv_buf_fill &&
443 (GET_BYTE (pos + 0) == 'C' || GET_BYTE (pos + 0) == 'c') &&
444 (GET_BYTE (pos + 1) == 'o' || GET_BYTE (pos + 1) == 'O') &&
445 (GET_BYTE (pos + 2) == 'n' || GET_BYTE (pos + 2) == 'N') &&
446 (GET_BYTE (pos + 3) == 't' || GET_BYTE (pos + 3) == 'T') &&
447 (GET_BYTE (pos + 4) == 'e' || GET_BYTE (pos + 4) == 'E') &&
448 (GET_BYTE (pos + 5) == 'n' || GET_BYTE (pos + 5) == 'N') &&
449 (GET_BYTE (pos + 6) == 't' || GET_BYTE (pos + 6) == 'T') &&
450 GET_BYTE (pos + 7) == '-' &&
451 (GET_BYTE (pos + 8) == 'L' || GET_BYTE (pos + 8) == 'l') &&
452 (GET_BYTE (pos + 9) == 'e' || GET_BYTE (pos + 9) == 'E') &&
453 (GET_BYTE (pos + 10) == 'n' || GET_BYTE (pos + 10) == 'N') &&
454 (GET_BYTE (pos + 11) == 'g' || GET_BYTE (pos + 11) == 'G') &&
455 (GET_BYTE (pos + 12) == 't' || GET_BYTE (pos + 12) == 'T') &&
456 (GET_BYTE (pos + 13) == 'h' || GET_BYTE (pos + 13) == 'H') &&
457 GET_BYTE (pos + 14) == ':') {
458 /* Found a Content-Length header. Parse and store the value. Note that
459 * the HTTP standard allows for arbitrarily-big content lengths. We
460 * limit it to G_MAXSIZE for sanity’s sake.
462 * The code below is equivalent to strtoul(input, NULL, 10), but
463 * operates on a ring buffer. */
465 EAT_WHITESPACE (pos);
466 priv->content_length = 0;
469 guint8 byte = GET_BYTE (pos);
470 gint val = g_ascii_digit_value (byte);
473 /* Reached the end of the value; fall out to the code below which
474 * will grab the \n. */
476 } else if (val == -1) {
477 priv->content_length = 0;
481 /* Check for overflow. Don’t flag it as an error; just fall through
482 * to the code below which will skip to the \r\n. */
483 if (priv->content_length > G_MAXSIZE / 10 ||
484 priv->content_length * 10 > G_MAXSIZE - val) {
485 priv->content_length = 0;
489 priv->content_length = (priv->content_length * 10) + val;
491 if (pos + 1 > priv->recv_buf_fill)
492 goto not_enough_data;
497 /* Skip over the header. */
498 while (pos + 1 < priv->recv_buf_fill &&
499 GET_BYTE (pos) != '\r' && GET_BYTE (pos + 1) != '\n')
502 nice_debug ("pos = %u, fill = %" G_GSSIZE_FORMAT,
503 pos, priv->recv_buf_fill);
505 if (pos + 1 >= priv->recv_buf_fill)
506 goto not_enough_data;
509 /* Consume the data we just parsed. */
510 priv->recv_buf_pos = (priv->recv_buf_pos + pos) % priv->recv_buf_length;
511 priv->recv_buf_fill -= pos;
514 priv->state = HTTP_STATE_BODY;
519 case HTTP_STATE_BODY:
523 if (priv->content_length == 0) {
524 priv->state = HTTP_STATE_CONNECTED;
528 if (priv->recv_buf_fill == 0)
529 goto not_enough_data;
531 consumed = MIN (priv->content_length, priv->recv_buf_fill);
534 (priv->recv_buf_pos + consumed) % priv->recv_buf_length;
535 priv->recv_buf_fill -= consumed;
536 priv->content_length -= consumed;
541 case HTTP_STATE_CONNECTED:
545 len = memcpy_ring_buffer_to_input_messages (priv,
546 recv_messages, n_recv_messages);
548 /* Send the pending data */
549 nice_socket_flush_send_queue (priv->base_socket,
555 case HTTP_STATE_ERROR:
565 nice_debug ("http error");
566 if (priv->base_socket)
567 nice_socket_free (priv->base_socket);
568 priv->base_socket = NULL;
569 priv->state = HTTP_STATE_ERROR;
575 socket_send_messages (NiceSocket *sock, const NiceAddress *to,
576 const NiceOutputMessage *messages, guint n_messages)
578 HttpPriv *priv = sock->priv;
580 /* Make sure socket has not been freed: */
581 g_assert (sock->priv != NULL);
583 if (priv->state == HTTP_STATE_CONNECTED) {
585 if (!priv->base_socket)
588 return nice_socket_send_messages (priv->base_socket, to, messages,
590 } else if (priv->state == HTTP_STATE_ERROR) {
600 socket_send_messages_reliable (NiceSocket *sock, const NiceAddress *to,
601 const NiceOutputMessage *messages, guint n_messages)
603 HttpPriv *priv = sock->priv;
605 if (priv->state == HTTP_STATE_CONNECTED) {
607 if (!priv->base_socket)
610 return nice_socket_send_messages_reliable (priv->base_socket, to, messages,
612 } else if (priv->state == HTTP_STATE_ERROR) {
615 nice_socket_queue_send (&priv->send_queue, to, messages, n_messages);
622 socket_is_reliable (NiceSocket *sock)
624 HttpPriv *priv = sock->priv;
626 return nice_socket_is_reliable (priv->base_socket);
630 socket_can_send (NiceSocket *sock, NiceAddress *addr)
632 HttpPriv *priv = sock->priv;
634 return nice_socket_can_send (priv->base_socket, addr);
638 socket_set_writable_callback (NiceSocket *sock,
639 NiceSocketWritableCb callback, gpointer user_data)
641 HttpPriv *priv = sock->priv;
643 nice_socket_set_writable_callback (priv->base_socket, callback, user_data);
647 socket_is_based_on (NiceSocket *sock, NiceSocket *other)
649 HttpPriv *priv = sock->priv;
651 return (sock == other) ||
652 (priv && nice_socket_is_based_on (priv->base_socket, other));