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.)
56 #define HTTP_USER_AGENT "libnice"
68 NiceSocket
*base_socket
;
86 static void socket_close (NiceSocket
*sock
);
87 static gint
socket_recv (NiceSocket
*sock
, NiceAddress
*from
,
88 guint len
, gchar
*buf
);
89 static gboolean
socket_send (NiceSocket
*sock
, const NiceAddress
*to
,
90 guint len
, const gchar
*buf
);
91 static gboolean
socket_is_reliable (NiceSocket
*sock
);
93 static void add_to_be_sent (NiceSocket
*sock
, const NiceAddress
*to
,
94 const gchar
*buf
, guint len
);
95 static void free_to_be_sent (struct to_be_sent
*tbs
);
99 nice_http_socket_new (NiceSocket
*base_socket
,
100 NiceAddress
*addr
, gchar
*username
, gchar
*password
)
103 NiceSocket
*sock
= NULL
;
106 sock
= g_slice_new0 (NiceSocket
);
107 sock
->priv
= priv
= g_slice_new0 (HttpPriv
);
109 priv
->base_socket
= base_socket
;
111 priv
->username
= g_strdup (username
);
112 priv
->password
= g_strdup (password
);
113 priv
->recv_buf
= NULL
;
115 priv
->content_length
= 0;
118 sock
->fileno
= priv
->base_socket
->fileno
;
119 sock
->addr
= priv
->base_socket
->addr
;
120 sock
->send
= socket_send
;
121 sock
->recv
= socket_recv
;
122 sock
->is_reliable
= socket_is_reliable
;
123 sock
->close
= socket_close
;
125 /* Send HTTP CONNECT */
128 gchar
*credential
= NULL
;
129 gchar host
[INET6_ADDRSTRLEN
];
130 gint port
= nice_address_get_port (&priv
->addr
);
131 nice_address_to_string (&priv
->addr
, host
);
134 gchar
* userpass
= g_strdup_printf ("%s:%s", username
,
135 password
? password
: "");
136 gchar
* auth
= g_base64_encode ((guchar
*)userpass
, strlen (userpass
));
137 credential
= g_strdup_printf ("Proxy-Authorization: Basic %s\r\n", auth
);
141 msg
= g_strdup_printf ("CONNECT %s:%d HTTP/1.0\r\n"
144 "Content-Length: 0\r\n"
145 "Proxy-Connection: Keep-Alive\r\n"
146 "Connection: Keep-Alive\r\n"
147 "Cache-Control: no-cache\r\n"
148 "Pragma: no-cache\r\n"
149 "%s\r\n", host
, port
, host
, HTTP_USER_AGENT
,
150 credential
? credential
: "" );
153 nice_socket_send (priv
->base_socket
, NULL
, strlen (msg
), msg
);
154 priv
->state
= HTTP_STATE_INIT
;
164 socket_close (NiceSocket
*sock
)
166 HttpPriv
*priv
= sock
->priv
;
168 if (priv
->base_socket
)
169 nice_socket_free (priv
->base_socket
);
172 g_free (priv
->username
);
175 g_free (priv
->password
);
178 g_free (priv
->recv_buf
);
180 g_queue_foreach (&priv
->send_queue
, (GFunc
) free_to_be_sent
, NULL
);
181 g_queue_clear (&priv
->send_queue
);
183 g_slice_free(HttpPriv
, sock
->priv
);
188 socket_recv (NiceSocket
*sock
, NiceAddress
*from
, guint len
, gchar
*buf
)
190 HttpPriv
*priv
= sock
->priv
;
193 if (priv
->base_socket
)
194 read
= nice_socket_recv (priv
->base_socket
, from
, len
, buf
);
196 if (read
<= 0 || priv
->state
== HTTP_STATE_CONNECTED
) {
199 priv
->recv_buf
= g_realloc (priv
->recv_buf
, priv
->recv_len
+ read
);
200 memcpy (priv
->recv_buf
+ priv
->recv_len
, buf
, read
);
201 priv
->recv_len
+= read
;
205 nice_debug ("Receiving from HTTP proxy (state %d) : %d \n'%s'", priv
->state
, priv
->recv_len
, priv
->recv_buf
);
206 switch (priv
->state
) {
207 case HTTP_STATE_INIT
:
211 /* Remove any leading spaces (could happen!) */
212 while (pos
< priv
->recv_len
&& priv
->recv_buf
[pos
] == ' ')
215 /* Make sure we have enough data */
216 if (pos
>= priv
->recv_len
)
217 goto not_enough_data
;
219 if (pos
+ 7 > priv
->recv_len
)
220 goto not_enough_data
;
221 if (strncmp (priv
->recv_buf
+ pos
, "HTTP/1.", 7) != 0)
225 if (pos
>= priv
->recv_len
)
226 goto not_enough_data
;
227 if(priv
->recv_buf
[pos
] != '0' && priv
->recv_buf
[pos
] != '1')
231 /* Make sure we have a space after the HTTP version */
232 if (pos
>= priv
->recv_len
)
233 goto not_enough_data
;
234 if (priv
->recv_buf
[pos
] != ' ')
237 /* Skip all spaces (could be more than one!) */
238 while (pos
< priv
->recv_len
&& priv
->recv_buf
[pos
] == ' ')
240 if (pos
>= priv
->recv_len
)
241 goto not_enough_data
;
243 /* Check for a successfull 2xx code */
244 if (pos
+ 3 > priv
->recv_len
)
245 goto not_enough_data
;
246 if (priv
->recv_buf
[pos
] != '2' ||
247 priv
->recv_buf
[pos
+1] < '0' || priv
->recv_buf
[pos
+1] > '9' ||
248 priv
->recv_buf
[pos
+2] < '0' || priv
->recv_buf
[pos
+2] > '9')
251 /* Clear any trailing chars */
252 while (pos
+ 1 < priv
->recv_len
&&
253 priv
->recv_buf
[pos
] != '\r' && priv
->recv_buf
[pos
+1] != '\n')
255 if (pos
+ 1 >= priv
->recv_len
)
256 goto not_enough_data
;
259 /* consume the data we just parsed */
260 priv
->recv_len
-= pos
;
261 memmove (priv
->recv_buf
, priv
->recv_buf
+ pos
, priv
->recv_len
);
262 priv
->recv_buf
= g_realloc (priv
->recv_buf
, priv
->recv_len
);
264 priv
->content_length
= 0;
265 priv
->state
= HTTP_STATE_HEADERS
;
269 case HTTP_STATE_HEADERS
:
273 if (pos
+ 15 < priv
->recv_len
&&
274 g_ascii_strncasecmp (priv
->recv_buf
, "Content-Length:", 15) == 0) {
275 priv
->content_length
= atoi(priv
->recv_buf
+ 15);
277 while (pos
+ 1 < priv
->recv_len
&&
278 priv
->recv_buf
[pos
] != '\r' && priv
->recv_buf
[pos
+1] != '\n')
280 nice_debug ("pos = %d, len = %d", pos
, priv
->recv_len
);
281 if (pos
+ 1 >= priv
->recv_len
)
282 goto not_enough_data
;
285 /* consume the data we just parsed */
286 priv
->recv_len
-= pos
;
287 memmove (priv
->recv_buf
, priv
->recv_buf
+ pos
, priv
->recv_len
);
288 priv
->recv_buf
= g_realloc (priv
->recv_buf
, priv
->recv_len
);
291 priv
->state
= HTTP_STATE_BODY
;
295 case HTTP_STATE_BODY
:
297 gint consumed
= priv
->content_length
;
298 if (priv
->content_length
== 0) {
299 priv
->state
= HTTP_STATE_CONNECTED
;
302 if (priv
->recv_len
== 0)
303 goto not_enough_data
;
305 if (priv
->content_length
> priv
->recv_len
)
306 consumed
= priv
->recv_len
;
308 priv
->recv_len
-= consumed
;
309 priv
->content_length
-= consumed
;
310 memmove (priv
->recv_buf
, priv
->recv_buf
+ consumed
, priv
->recv_len
);
311 priv
->recv_buf
= g_realloc (priv
->recv_buf
, priv
->recv_len
);
315 case HTTP_STATE_CONNECTED
:
317 guint read
= priv
->recv_len
;
318 struct to_be_sent
*tbs
= NULL
;
323 memcpy (buf
, priv
->recv_buf
, read
);
325 /* consume the data we returned */
326 priv
->recv_len
-= read
;
327 memmove (priv
->recv_buf
, priv
->recv_buf
+ read
, priv
->recv_len
);
328 priv
->recv_buf
= g_realloc (priv
->recv_buf
, priv
->recv_len
);
330 /* Send the pending data */
331 while ((tbs
= g_queue_pop_head (&priv
->send_queue
))) {
332 nice_socket_send (priv
->base_socket
, &tbs
->to
,
333 tbs
->length
, tbs
->buf
);
335 g_slice_free (struct to_be_sent
, tbs
);
350 nice_debug ("http error");
351 if (priv
->base_socket
)
352 nice_socket_free (priv
->base_socket
);
353 priv
->base_socket
= NULL
;
354 priv
->state
= HTTP_STATE_ERROR
;
360 socket_send (NiceSocket
*sock
, const NiceAddress
*to
,
361 guint len
, const gchar
*buf
)
363 HttpPriv
*priv
= sock
->priv
;
365 if (priv
->state
== HTTP_STATE_CONNECTED
) {
366 if (priv
->base_socket
)
367 return nice_socket_send (priv
->base_socket
, to
, len
, buf
);
370 } else if (priv
->state
== HTTP_STATE_ERROR
) {
373 add_to_be_sent (sock
, to
, buf
, len
);
380 socket_is_reliable (NiceSocket
*sock
)
387 add_to_be_sent (NiceSocket
*sock
, const NiceAddress
*to
,
388 const gchar
*buf
, guint len
)
390 HttpPriv
*priv
= sock
->priv
;
391 struct to_be_sent
*tbs
= NULL
;
396 tbs
= g_slice_new0 (struct to_be_sent
);
397 tbs
->buf
= g_memdup (buf
, len
);
401 g_queue_push_tail (&priv
->send_queue
, tbs
);
407 free_to_be_sent (struct to_be_sent
*tbs
)
410 g_slice_free (struct to_be_sent
, tbs
);