Branch data Line data Source code
1 : : /* GStreamer
2 : : * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br>
3 : : * Copyright (C) <2006> Rosfran Borges <rosfran.borges@indt.org.br>
4 : : * Copyright (C) <2006> Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Library 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 : : * Library General Public License for more
15 : : */
16 : :
17 : : #ifdef HAVE_CONFIG_H
18 : : #include "config.h"
19 : : #endif
20 : :
21 : : #include "gstneonhttpsrc.h"
22 : : #include <stdlib.h>
23 : : #include <string.h>
24 : : #ifdef _HAVE_UNISTD_H
25 : : #include <unistd.h>
26 : : #endif /* _HAVE_UNISTD_H */
27 : :
28 : : #include <ne_redirect.h>
29 : :
30 : : #define STATUS_IS_REDIRECTION(status) ((status) >= 300 && (status) < 400)
31 : :
32 : : GST_DEBUG_CATEGORY_STATIC (neonhttpsrc_debug);
33 : : #define GST_CAT_DEFAULT neonhttpsrc_debug
34 : :
35 : : #define MAX_READ_SIZE (4 * 1024)
36 : :
37 : : /* max number of HTTP redirects, when iterating over a sequence of HTTP 3xx status code */
38 : : #define MAX_HTTP_REDIRECTS_NUMBER 5
39 : :
40 : : static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
41 : : GST_PAD_SRC,
42 : : GST_PAD_ALWAYS,
43 : : GST_STATIC_CAPS_ANY);
44 : :
45 : : #define HTTP_SOCKET_ERROR -2
46 : : #define HTTP_REQUEST_WRONG_PROXY -1
47 : : #define HTTP_DEFAULT_PORT 80
48 : : #define HTTPS_DEFAULT_PORT 443
49 : : #define HTTP_DEFAULT_HOST "localhost"
50 : :
51 : : /* default properties */
52 : : #define DEFAULT_LOCATION "http://"HTTP_DEFAULT_HOST":"G_STRINGIFY(HTTP_DEFAULT_PORT)
53 : : #define DEFAULT_PROXY ""
54 : : #define DEFAULT_USER_AGENT "GStreamer neonhttpsrc"
55 : : #define DEFAULT_IRADIO_MODE FALSE
56 : : #define DEFAULT_IRADIO_NAME NULL
57 : : #define DEFAULT_IRADIO_GENRE NULL
58 : : #define DEFAULT_IRADIO_URL NULL
59 : : #define DEFAULT_AUTOMATIC_REDIRECT TRUE
60 : : #define DEFAULT_ACCEPT_SELF_SIGNED FALSE
61 : : #define DEFAULT_NEON_HTTP_DEBUG FALSE
62 : : #define DEFAULT_CONNECT_TIMEOUT 0
63 : : #define DEFAULT_READ_TIMEOUT 0
64 : :
65 : : enum
66 : : {
67 : : PROP_0,
68 : : PROP_LOCATION,
69 : : PROP_PROXY,
70 : : PROP_USER_AGENT,
71 : : PROP_COOKIES,
72 : : PROP_IRADIO_MODE,
73 : : PROP_IRADIO_NAME,
74 : : PROP_IRADIO_GENRE,
75 : : PROP_IRADIO_URL,
76 : : PROP_AUTOMATIC_REDIRECT,
77 : : PROP_ACCEPT_SELF_SIGNED,
78 : : PROP_CONNECT_TIMEOUT,
79 : : PROP_READ_TIMEOUT,
80 : : #ifndef GST_DISABLE_GST_DEBUG
81 : : PROP_NEON_HTTP_DEBUG
82 : : #endif
83 : : };
84 : :
85 : : static void gst_neonhttp_src_uri_handler_init (gpointer g_iface,
86 : : gpointer iface_data);
87 : : static void gst_neonhttp_src_dispose (GObject * gobject);
88 : : static void gst_neonhttp_src_set_property (GObject * object, guint prop_id,
89 : : const GValue * value, GParamSpec * pspec);
90 : : static void gst_neonhttp_src_get_property (GObject * object, guint prop_id,
91 : : GValue * value, GParamSpec * pspec);
92 : :
93 : : static GstFlowReturn gst_neonhttp_src_create (GstPushSrc * psrc,
94 : : GstBuffer ** outbuf);
95 : : static gboolean gst_neonhttp_src_start (GstBaseSrc * bsrc);
96 : : static gboolean gst_neonhttp_src_stop (GstBaseSrc * bsrc);
97 : : static gboolean gst_neonhttp_src_get_size (GstBaseSrc * bsrc, guint64 * size);
98 : : static gboolean gst_neonhttp_src_is_seekable (GstBaseSrc * bsrc);
99 : : static gboolean gst_neonhttp_src_do_seek (GstBaseSrc * bsrc,
100 : : GstSegment * segment);
101 : :
102 : : static gboolean gst_neonhttp_src_set_proxy (GstNeonhttpSrc * src,
103 : : const gchar * uri);
104 : : static gboolean gst_neonhttp_src_set_location (GstNeonhttpSrc * src,
105 : : const gchar * uri);
106 : : static gint gst_neonhttp_src_send_request_and_redirect (GstNeonhttpSrc * src,
107 : : ne_session ** ses, ne_request ** req, gint64 offset, gboolean do_redir);
108 : : static gint gst_neonhttp_src_request_dispatch (GstNeonhttpSrc * src,
109 : : GstBuffer * outbuf);
110 : : static void gst_neonhttp_src_close_session (GstNeonhttpSrc * src);
111 : : static gchar *gst_neonhttp_src_unicodify (const gchar * str);
112 : : static void oom_callback (void);
113 : :
114 : : static void
115 : 3 : _urihandler_init (GType type)
116 : : {
117 : : static const GInterfaceInfo urihandler_info = {
118 : : gst_neonhttp_src_uri_handler_init,
119 : : NULL,
120 : : NULL
121 : : };
122 : :
123 : 3 : g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
124 : :
125 [ + - ]: 3 : GST_DEBUG_CATEGORY_INIT (neonhttpsrc_debug, "neonhttpsrc", 0,
126 : : "NEON HTTP src");
127 : 3 : }
128 : :
129 [ + + ]: 20 : GST_BOILERPLATE_FULL (GstNeonhttpSrc, gst_neonhttp_src, GstPushSrc,
130 : 20 : GST_TYPE_PUSH_SRC, _urihandler_init);
131 : :
132 : : static void
133 : 3 : gst_neonhttp_src_base_init (gpointer g_class)
134 : : {
135 : 3 : GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
136 : :
137 : 3 : gst_element_class_add_pad_template (element_class,
138 : : gst_static_pad_template_get (&srctemplate));
139 : :
140 : 3 : gst_element_class_set_details_simple (element_class, "HTTP client source",
141 : : "Source/Network",
142 : : "Receive data as a client over the network via HTTP using NEON",
143 : : "Edgard Lima <edgard.lima@indt.org.br>, "
144 : : "Rosfran Borges <rosfran.borges@indt.org.br>, "
145 : : "Andre Moreira Magalhaes <andre.magalhaes@indt.org.br>");
146 : 3 : }
147 : :
148 : : static void
149 : 3 : gst_neonhttp_src_class_init (GstNeonhttpSrcClass * klass)
150 : : {
151 : : GObjectClass *gobject_class;
152 : : GstBaseSrcClass *gstbasesrc_class;
153 : : GstPushSrcClass *gstpushsrc_class;
154 : :
155 : 3 : gobject_class = (GObjectClass *) klass;
156 : 3 : gstbasesrc_class = (GstBaseSrcClass *) klass;
157 : 3 : gstpushsrc_class = (GstPushSrcClass *) klass;
158 : :
159 : 3 : gobject_class->set_property = gst_neonhttp_src_set_property;
160 : 3 : gobject_class->get_property = gst_neonhttp_src_get_property;
161 : 3 : gobject_class->dispose = gst_neonhttp_src_dispose;
162 : :
163 : : g_object_class_install_property
164 : 3 : (gobject_class, PROP_LOCATION,
165 : : g_param_spec_string ("location", "Location",
166 : : "Location to read from", "",
167 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
168 : :
169 : : g_object_class_install_property
170 : 3 : (gobject_class, PROP_PROXY,
171 : : g_param_spec_string ("proxy", "Proxy",
172 : : "Proxy server to use, in the form HOSTNAME:PORT. "
173 : : "Defaults to the http_proxy environment variable",
174 : : "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
175 : :
176 : : g_object_class_install_property
177 : 3 : (gobject_class, PROP_USER_AGENT,
178 : : g_param_spec_string ("user-agent", "User-Agent",
179 : : "Value of the User-Agent HTTP request header field",
180 : : "GStreamer neonhttpsrc", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
181 : :
182 : : /**
183 : : * GstNeonhttpSrc:cookies
184 : : *
185 : : * HTTP request cookies
186 : : *
187 : : * Since: 0.10.20
188 : : */
189 : 3 : g_object_class_install_property (gobject_class, PROP_COOKIES,
190 : : g_param_spec_boxed ("cookies", "Cookies", "HTTP request cookies",
191 : : G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
192 : :
193 : : g_object_class_install_property
194 : 3 : (gobject_class, PROP_IRADIO_MODE,
195 : : g_param_spec_boolean ("iradio-mode", "iradio-mode",
196 : : "Enable internet radio mode (extraction of shoutcast/icecast metadata)",
197 : : FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
198 : :
199 : 3 : g_object_class_install_property (gobject_class,
200 : : PROP_IRADIO_NAME,
201 : : g_param_spec_string ("iradio-name",
202 : : "iradio-name", "Name of the stream", NULL,
203 : : G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
204 : :
205 : 3 : g_object_class_install_property (gobject_class,
206 : : PROP_IRADIO_GENRE,
207 : : g_param_spec_string ("iradio-genre",
208 : : "iradio-genre", "Genre of the stream", NULL,
209 : : G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
210 : :
211 : 3 : g_object_class_install_property (gobject_class,
212 : : PROP_IRADIO_URL,
213 : : g_param_spec_string ("iradio-url",
214 : : "iradio-url",
215 : : "Homepage URL for radio stream", NULL,
216 : : G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
217 : :
218 : : g_object_class_install_property
219 : 3 : (gobject_class, PROP_AUTOMATIC_REDIRECT,
220 : : g_param_spec_boolean ("automatic-redirect", "automatic-redirect",
221 : : "Automatically follow HTTP redirects (HTTP Status Code 3xx)",
222 : : TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
223 : :
224 : : g_object_class_install_property
225 : 3 : (gobject_class, PROP_ACCEPT_SELF_SIGNED,
226 : : g_param_spec_boolean ("accept-self-signed", "accept-self-signed",
227 : : "Accept self-signed SSL/TLS certificates",
228 : : DEFAULT_ACCEPT_SELF_SIGNED,
229 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
230 : :
231 : : /**
232 : : * GstNeonhttpSrc:connect-timeout
233 : : *
234 : : * After how many seconds to timeout a connect attempt (0 = default)
235 : : *
236 : : * Since: 0.10.20
237 : : */
238 : 3 : g_object_class_install_property (gobject_class, PROP_CONNECT_TIMEOUT,
239 : : g_param_spec_uint ("connect-timeout", "connect-timeout",
240 : : "Value in seconds to timeout a blocking connection (0 = default).", 0,
241 : : 3600, DEFAULT_CONNECT_TIMEOUT,
242 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
243 : :
244 : : /**
245 : : * GstNeonhttpSrc:read-timeout
246 : : *
247 : : * After how many seconds to timeout a blocking read (0 = default)
248 : : *
249 : : * Since: 0.10.20
250 : : */
251 : 3 : g_object_class_install_property (gobject_class, PROP_READ_TIMEOUT,
252 : : g_param_spec_uint ("read-timeout", "read-timeout",
253 : : "Value in seconds to timeout a blocking read (0 = default).", 0,
254 : : 3600, DEFAULT_READ_TIMEOUT,
255 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
256 : :
257 : : #ifndef GST_DISABLE_GST_DEBUG
258 : : g_object_class_install_property
259 : 3 : (gobject_class, PROP_NEON_HTTP_DEBUG,
260 : : g_param_spec_boolean ("neon-http-debug", "neon-http-debug",
261 : : "Enable Neon HTTP debug messages",
262 : : DEFAULT_NEON_HTTP_DEBUG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
263 : : #endif
264 : :
265 : 3 : gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_neonhttp_src_start);
266 : 3 : gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_neonhttp_src_stop);
267 : 3 : gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_neonhttp_src_get_size);
268 : 3 : gstbasesrc_class->is_seekable =
269 : 3 : GST_DEBUG_FUNCPTR (gst_neonhttp_src_is_seekable);
270 : 3 : gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_neonhttp_src_do_seek);
271 : :
272 : 3 : gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_neonhttp_src_create);
273 : :
274 [ - + ]: 3 : GST_DEBUG_CATEGORY_INIT (neonhttpsrc_debug, "neonhttpsrc", 0,
275 : : "NEON HTTP Client Source");
276 : 3 : }
277 : :
278 : : static void
279 : 1 : gst_neonhttp_src_init (GstNeonhttpSrc * src, GstNeonhttpSrcClass * g_class)
280 : : {
281 : : const gchar *str;
282 : :
283 : 1 : src->neon_http_debug = DEFAULT_NEON_HTTP_DEBUG;
284 : 1 : src->iradio_mode = DEFAULT_IRADIO_MODE;
285 : 1 : src->iradio_name = DEFAULT_IRADIO_NAME;
286 : 1 : src->iradio_genre = DEFAULT_IRADIO_GENRE;
287 : 1 : src->iradio_url = DEFAULT_IRADIO_URL;
288 : 1 : src->user_agent = g_strdup (DEFAULT_USER_AGENT);
289 : 1 : src->automatic_redirect = DEFAULT_AUTOMATIC_REDIRECT;
290 : 1 : src->accept_self_signed = DEFAULT_ACCEPT_SELF_SIGNED;
291 : 1 : src->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
292 : 1 : src->read_timeout = DEFAULT_READ_TIMEOUT;
293 : :
294 : 1 : src->cookies = NULL;
295 : 1 : src->session = NULL;
296 : 1 : src->request = NULL;
297 : 1 : memset (&src->uri, 0, sizeof (src->uri));
298 : 1 : memset (&src->proxy, 0, sizeof (src->proxy));
299 : 1 : src->content_size = -1;
300 : 1 : src->icy_caps = NULL;
301 : 1 : src->icy_metaint = 0;
302 : 1 : src->seekable = TRUE;
303 : :
304 : 1 : gst_neonhttp_src_set_location (src, DEFAULT_LOCATION);
305 : :
306 : : /* configure proxy */
307 : 1 : str = g_getenv ("http_proxy");
308 [ - + ][ # # ]: 1 : if (str && !gst_neonhttp_src_set_proxy (src, str)) {
309 [ # # ]: 0 : GST_WARNING_OBJECT (src,
310 : : "The proxy set on http_proxy env var ('%s') cannot be parsed.", str);
311 : : }
312 : 1 : }
313 : :
314 : : static void
315 : 1 : gst_neonhttp_src_dispose (GObject * gobject)
316 : : {
317 : 1 : GstNeonhttpSrc *src = GST_NEONHTTP_SRC (gobject);
318 : :
319 : 1 : ne_uri_free (&src->uri);
320 : 1 : ne_uri_free (&src->proxy);
321 : :
322 : 1 : g_free (src->user_agent);
323 : 1 : g_free (src->iradio_name);
324 : 1 : g_free (src->iradio_genre);
325 : 1 : g_free (src->iradio_url);
326 : :
327 [ - + ]: 1 : if (src->cookies) {
328 : 0 : g_strfreev (src->cookies);
329 : 0 : src->cookies = NULL;
330 : : }
331 : :
332 [ - + ]: 1 : if (src->icy_caps) {
333 : 0 : gst_caps_unref (src->icy_caps);
334 : 0 : src->icy_caps = NULL;
335 : : }
336 : :
337 [ - + ]: 1 : if (src->request) {
338 : 0 : ne_request_destroy (src->request);
339 : 0 : src->request = NULL;
340 : : }
341 : :
342 [ - + ]: 1 : if (src->session) {
343 : 0 : ne_close_connection (src->session);
344 : 0 : ne_session_destroy (src->session);
345 : 0 : src->session = NULL;
346 : : }
347 : :
348 [ + - ]: 1 : if (src->location) {
349 : 1 : ne_free (src->location);
350 : : }
351 [ + - ]: 1 : if (src->query_string) {
352 : 1 : ne_free (src->query_string);
353 : : }
354 : :
355 : 1 : G_OBJECT_CLASS (parent_class)->dispose (gobject);
356 : 1 : }
357 : :
358 : : static void
359 : 0 : gst_neonhttp_src_set_property (GObject * object, guint prop_id,
360 : : const GValue * value, GParamSpec * pspec)
361 : : {
362 : 0 : GstNeonhttpSrc *src = GST_NEONHTTP_SRC (object);
363 : :
364 [ # # # # : 0 : switch (prop_id) {
# # # # #
# # ]
365 : : case PROP_PROXY:
366 : : {
367 : : const gchar *proxy;
368 : :
369 : 0 : proxy = g_value_get_string (value);
370 : :
371 [ # # ]: 0 : if (proxy == NULL) {
372 [ # # ]: 0 : GST_WARNING ("proxy property cannot be NULL");
373 : 0 : goto done;
374 : : }
375 [ # # ]: 0 : if (!gst_neonhttp_src_set_proxy (src, proxy)) {
376 [ # # ]: 0 : GST_WARNING ("badly formated proxy");
377 : 0 : goto done;
378 : : }
379 : 0 : break;
380 : : }
381 : : case PROP_LOCATION:
382 : : {
383 : : const gchar *location;
384 : :
385 : 0 : location = g_value_get_string (value);
386 : :
387 [ # # ]: 0 : if (location == NULL) {
388 [ # # ]: 0 : GST_WARNING ("location property cannot be NULL");
389 : 0 : goto done;
390 : : }
391 [ # # ]: 0 : if (!gst_neonhttp_src_set_location (src, location)) {
392 [ # # ]: 0 : GST_WARNING ("badly formated location");
393 : 0 : goto done;
394 : : }
395 : 0 : break;
396 : : }
397 : : case PROP_USER_AGENT:
398 [ # # ]: 0 : if (src->user_agent)
399 : 0 : g_free (src->user_agent);
400 : 0 : src->user_agent = g_strdup (g_value_get_string (value));
401 : 0 : break;
402 : : case PROP_COOKIES:
403 [ # # ]: 0 : if (src->cookies)
404 : 0 : g_strfreev (src->cookies);
405 : 0 : src->cookies = (gchar **) g_value_dup_boxed (value);
406 : 0 : break;
407 : : case PROP_IRADIO_MODE:
408 : 0 : src->iradio_mode = g_value_get_boolean (value);
409 : 0 : break;
410 : : case PROP_AUTOMATIC_REDIRECT:
411 : 0 : src->automatic_redirect = g_value_get_boolean (value);
412 : 0 : break;
413 : : case PROP_ACCEPT_SELF_SIGNED:
414 : 0 : src->accept_self_signed = g_value_get_boolean (value);
415 : 0 : break;
416 : : case PROP_CONNECT_TIMEOUT:
417 : 0 : src->connect_timeout = g_value_get_uint (value);
418 : 0 : break;
419 : : case PROP_READ_TIMEOUT:
420 : 0 : src->read_timeout = g_value_get_uint (value);
421 : 0 : break;
422 : : #ifndef GST_DISABLE_GST_DEBUG
423 : : case PROP_NEON_HTTP_DEBUG:
424 : 0 : src->neon_http_debug = g_value_get_boolean (value);
425 : 0 : break;
426 : : #endif
427 : : default:
428 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
429 : 0 : break;
430 : : }
431 : : done:
432 : 0 : return;
433 : : }
434 : :
435 : : static void
436 : 13 : gst_neonhttp_src_get_property (GObject * object, guint prop_id,
437 : : GValue * value, GParamSpec * pspec)
438 : : {
439 : 13 : GstNeonhttpSrc *neonhttpsrc = GST_NEONHTTP_SRC (object);
440 : :
441 [ + + + + : 13 : switch (prop_id) {
+ + + + +
+ + + +
- ]
442 : : case PROP_PROXY:
443 : : {
444 : : gchar *str;
445 : :
446 [ - + ]: 1 : if (neonhttpsrc->proxy.host) {
447 : 0 : str = ne_uri_unparse (&neonhttpsrc->proxy);
448 [ # # ]: 0 : if (!str)
449 : 0 : break;
450 : 0 : g_value_set_string (value, str);
451 : 0 : ne_free (str);
452 : : } else {
453 : 1 : g_value_set_static_string (value, "");
454 : : }
455 : 1 : break;
456 : : }
457 : : case PROP_LOCATION:
458 : : {
459 : : gchar *str;
460 : :
461 [ + - ]: 1 : if (neonhttpsrc->uri.host) {
462 : 1 : str = ne_uri_unparse (&neonhttpsrc->uri);
463 [ - + ]: 1 : if (!str)
464 : 0 : break;
465 : 1 : g_value_set_string (value, str);
466 : 1 : ne_free (str);
467 : : } else {
468 : 0 : g_value_set_static_string (value, "");
469 : : }
470 : 1 : break;
471 : : }
472 : : case PROP_USER_AGENT:
473 : 1 : g_value_set_string (value, neonhttpsrc->user_agent);
474 : 1 : break;
475 : : case PROP_COOKIES:
476 : 1 : g_value_set_boxed (value, neonhttpsrc->cookies);
477 : 1 : break;
478 : : case PROP_IRADIO_MODE:
479 : 1 : g_value_set_boolean (value, neonhttpsrc->iradio_mode);
480 : 1 : break;
481 : : case PROP_IRADIO_NAME:
482 : 1 : g_value_set_string (value, neonhttpsrc->iradio_name);
483 : 1 : break;
484 : : case PROP_IRADIO_GENRE:
485 : 1 : g_value_set_string (value, neonhttpsrc->iradio_genre);
486 : 1 : break;
487 : : case PROP_IRADIO_URL:
488 : 1 : g_value_set_string (value, neonhttpsrc->iradio_url);
489 : 1 : break;
490 : : case PROP_AUTOMATIC_REDIRECT:
491 : 1 : g_value_set_boolean (value, neonhttpsrc->automatic_redirect);
492 : 1 : break;
493 : : case PROP_ACCEPT_SELF_SIGNED:
494 : 1 : g_value_set_boolean (value, neonhttpsrc->accept_self_signed);
495 : 1 : break;
496 : : case PROP_CONNECT_TIMEOUT:
497 : 1 : g_value_set_uint (value, neonhttpsrc->connect_timeout);
498 : 1 : break;
499 : : case PROP_READ_TIMEOUT:
500 : 1 : g_value_set_uint (value, neonhttpsrc->read_timeout);
501 : 1 : break;
502 : : #ifndef GST_DISABLE_GST_DEBUG
503 : : case PROP_NEON_HTTP_DEBUG:
504 : 1 : g_value_set_boolean (value, neonhttpsrc->neon_http_debug);
505 : 1 : break;
506 : : #endif
507 : : default:
508 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
509 : 0 : break;
510 : : }
511 : 13 : }
512 : :
513 : : /* NEON CALLBACK */
514 : : static void
515 : 0 : oom_callback (void)
516 : : {
517 [ # # ]: 0 : GST_ERROR ("memory exeception in neon");
518 : 0 : }
519 : :
520 : : static GstFlowReturn
521 : 0 : gst_neonhttp_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
522 : : {
523 : : GstNeonhttpSrc *src;
524 : : GstBaseSrc *basesrc;
525 : : GstFlowReturn ret;
526 : : gint read;
527 : :
528 : 0 : src = GST_NEONHTTP_SRC (psrc);
529 : 0 : basesrc = GST_BASE_SRC_CAST (psrc);
530 : :
531 : : /* The caller should know the number of bytes and not read beyond EOS. */
532 [ # # ]: 0 : if (G_UNLIKELY (src->eos))
533 : 0 : goto eos;
534 : :
535 : : /* Create the buffer. */
536 [ # # ]: 0 : ret = gst_pad_alloc_buffer (GST_BASE_SRC_PAD (basesrc),
537 : 0 : basesrc->segment.last_stop, basesrc->blocksize,
538 : 0 : src->icy_caps ? src->icy_caps :
539 : 0 : GST_PAD_CAPS (GST_BASE_SRC_PAD (basesrc)), outbuf);
540 : :
541 [ # # ]: 0 : if (G_UNLIKELY (ret != GST_FLOW_OK))
542 : 0 : goto done;
543 : :
544 : 0 : read = gst_neonhttp_src_request_dispatch (src, *outbuf);
545 [ # # ]: 0 : if (G_UNLIKELY (read < 0))
546 : 0 : goto read_error;
547 : :
548 [ # # ]: 0 : GST_LOG_OBJECT (src, "returning %u bytes", GST_BUFFER_SIZE (*outbuf));
549 : :
550 : : done:
551 : 0 : return ret;
552 : :
553 : : /* ERRORS */
554 : : eos:
555 : : {
556 [ # # ]: 0 : GST_DEBUG_OBJECT (src, "EOS reached");
557 : 0 : return GST_FLOW_UNEXPECTED;
558 : : }
559 : : read_error:
560 : : {
561 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (src, RESOURCE, READ,
[ # # ][ # # ]
562 : : (NULL), ("Could not read any bytes (%i, %s)", read,
563 : : ne_get_error (src->session)));
564 : 0 : gst_buffer_unref (*outbuf);
565 : 0 : *outbuf = NULL;
566 : 0 : return GST_FLOW_ERROR;
567 : : }
568 : : }
569 : :
570 : : /* create a socket for connecting to remote server */
571 : : static gboolean
572 : 0 : gst_neonhttp_src_start (GstBaseSrc * bsrc)
573 : : {
574 : 0 : GstNeonhttpSrc *src = GST_NEONHTTP_SRC (bsrc);
575 : : const gchar *content_length;
576 : : gint res;
577 : :
578 : : #ifndef GST_DISABLE_GST_DEBUG
579 [ # # ]: 0 : if (src->neon_http_debug)
580 : 0 : ne_debug_init (stderr, NE_DBG_HTTP);
581 : : #endif
582 : :
583 : 0 : ne_oom_callback (oom_callback);
584 : :
585 : 0 : res = ne_sock_init ();
586 [ # # ]: 0 : if (res != 0)
587 : 0 : goto init_failed;
588 : :
589 : 0 : res = gst_neonhttp_src_send_request_and_redirect (src,
590 : : &src->session, &src->request, 0, src->automatic_redirect);
591 : :
592 [ # # ][ # # ]: 0 : if (res != NE_OK || !src->session) {
593 [ # # ]: 0 : if (res == HTTP_SOCKET_ERROR) {
594 : 0 : goto socket_error;
595 [ # # ]: 0 : } else if (res == HTTP_REQUEST_WRONG_PROXY) {
596 : 0 : goto wrong_proxy;
597 : : } else {
598 : 0 : goto begin_req_failed;
599 : : }
600 : : }
601 : :
602 : 0 : content_length = ne_get_response_header (src->request, "Content-Length");
603 : :
604 [ # # ]: 0 : if (content_length)
605 : 0 : src->content_size = g_ascii_strtoull (content_length, NULL, 10);
606 : : else
607 : 0 : src->content_size = -1;
608 : :
609 [ # # ]: 0 : if (src->iradio_mode) {
610 : : /* Icecast stuff */
611 : : const gchar *str_value;
612 : : gint gint_value;
613 : :
614 : 0 : str_value = ne_get_response_header (src->request, "icy-metaint");
615 [ # # ]: 0 : if (str_value) {
616 [ # # ]: 0 : if (sscanf (str_value, "%d", &gint_value) == 1) {
617 [ # # ]: 0 : if (src->icy_caps) {
618 : 0 : gst_caps_unref (src->icy_caps);
619 : 0 : src->icy_caps = NULL;
620 : : }
621 : 0 : src->icy_metaint = gint_value;
622 : 0 : src->icy_caps = gst_caps_new_simple ("application/x-icy",
623 : : "metadata-interval", G_TYPE_INT, src->icy_metaint, NULL);
624 : : }
625 : : }
626 : :
627 : 0 : str_value = ne_get_response_header (src->request, "icy-name");
628 [ # # ]: 0 : if (str_value) {
629 [ # # ]: 0 : if (src->iradio_name) {
630 : 0 : g_free (src->iradio_name);
631 : 0 : src->iradio_name = NULL;
632 : : }
633 : 0 : src->iradio_name = gst_neonhttp_src_unicodify (str_value);
634 : : }
635 : 0 : str_value = ne_get_response_header (src->request, "icy-genre");
636 [ # # ]: 0 : if (str_value) {
637 [ # # ]: 0 : if (src->iradio_genre) {
638 : 0 : g_free (src->iradio_genre);
639 : 0 : src->iradio_genre = NULL;
640 : : }
641 : 0 : src->iradio_genre = gst_neonhttp_src_unicodify (str_value);
642 : : }
643 : 0 : str_value = ne_get_response_header (src->request, "icy-url");
644 [ # # ]: 0 : if (str_value) {
645 [ # # ]: 0 : if (src->iradio_url) {
646 : 0 : g_free (src->iradio_url);
647 : 0 : src->iradio_url = NULL;
648 : : }
649 : 0 : src->iradio_url = gst_neonhttp_src_unicodify (str_value);
650 : : }
651 : : }
652 : :
653 : 0 : return TRUE;
654 : :
655 : : /* ERRORS */
656 : : init_failed:
657 : : {
658 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL),
[ # # ][ # # ]
659 : : ("ne_sock_init() failed: %d", res));
660 : 0 : return FALSE;
661 : : }
662 : : socket_error:
663 : : {
664 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
[ # # ][ # # ]
665 : : ("HTTP Request failed when opening socket: %d", res));
666 : 0 : return FALSE;
667 : : }
668 : : wrong_proxy:
669 : : {
670 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
[ # # ][ # # ]
671 : : ("Proxy Server URI is invalid - make sure that either both proxy host "
672 : : "and port are specified or neither."));
673 : 0 : return FALSE;
674 : : }
675 : : begin_req_failed:
676 : : {
677 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
[ # # ][ # # ]
678 : : ("Could not begin request: %d", res));
679 : 0 : return FALSE;
680 : : }
681 : : }
682 : :
683 : : /* close the socket and associated resources
684 : : * used both to recover from errors and go to NULL state */
685 : : static gboolean
686 : 0 : gst_neonhttp_src_stop (GstBaseSrc * bsrc)
687 : : {
688 : : GstNeonhttpSrc *src;
689 : :
690 : 0 : src = GST_NEONHTTP_SRC (bsrc);
691 : :
692 [ # # ]: 0 : if (src->iradio_name) {
693 : 0 : g_free (src->iradio_name);
694 : 0 : src->iradio_name = NULL;
695 : : }
696 : :
697 [ # # ]: 0 : if (src->iradio_genre) {
698 : 0 : g_free (src->iradio_genre);
699 : 0 : src->iradio_genre = NULL;
700 : : }
701 : :
702 [ # # ]: 0 : if (src->iradio_url) {
703 : 0 : g_free (src->iradio_url);
704 : 0 : src->iradio_url = NULL;
705 : : }
706 : :
707 [ # # ]: 0 : if (src->icy_caps) {
708 : 0 : gst_caps_unref (src->icy_caps);
709 : 0 : src->icy_caps = NULL;
710 : : }
711 : :
712 : 0 : src->eos = FALSE;
713 : 0 : src->content_size = -1;
714 : 0 : src->read_position = 0;
715 : 0 : src->seekable = TRUE;
716 : :
717 : 0 : gst_neonhttp_src_close_session (src);
718 : :
719 : : #ifndef GST_DISABLE_GST_DEBUG
720 : 0 : ne_debug_init (NULL, 0);
721 : : #endif
722 : 0 : ne_oom_callback (NULL);
723 : 0 : ne_sock_exit ();
724 : :
725 : 0 : return TRUE;
726 : : }
727 : :
728 : : static gboolean
729 : 0 : gst_neonhttp_src_get_size (GstBaseSrc * bsrc, guint64 * size)
730 : : {
731 : : GstNeonhttpSrc *src;
732 : :
733 : 0 : src = GST_NEONHTTP_SRC (bsrc);
734 : :
735 [ # # ]: 0 : if (src->content_size == -1)
736 : 0 : return FALSE;
737 : :
738 : 0 : *size = src->content_size;
739 : :
740 : 0 : return TRUE;
741 : : }
742 : :
743 : : static gboolean
744 : 0 : gst_neonhttp_src_is_seekable (GstBaseSrc * bsrc)
745 : : {
746 : 0 : return TRUE;
747 : : }
748 : :
749 : : static gboolean
750 : 0 : gst_neonhttp_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
751 : : {
752 : : GstNeonhttpSrc *src;
753 : : gint res;
754 : 0 : ne_session *session = NULL;
755 : 0 : ne_request *request = NULL;
756 : :
757 : 0 : src = GST_NEONHTTP_SRC (bsrc);
758 : :
759 [ # # ]: 0 : if (!src->seekable)
760 : 0 : return FALSE;
761 : :
762 [ # # ]: 0 : if (src->read_position == segment->start)
763 : 0 : return TRUE;
764 : :
765 : 0 : res = gst_neonhttp_src_send_request_and_redirect (src,
766 : : &session, &request, segment->start, src->automatic_redirect);
767 : :
768 : : /* if we are able to seek, replace the session */
769 [ # # ][ # # ]: 0 : if (res == NE_OK && session) {
770 : 0 : gst_neonhttp_src_close_session (src);
771 : 0 : src->session = session;
772 : 0 : src->request = request;
773 : 0 : src->read_position = segment->start;
774 : 0 : return TRUE;
775 : : }
776 : :
777 : 0 : return FALSE;
778 : : }
779 : :
780 : : static gboolean
781 : 1 : gst_neonhttp_src_set_location (GstNeonhttpSrc * src, const gchar * uri)
782 : : {
783 : 1 : ne_uri_free (&src->uri);
784 [ - + ]: 1 : if (src->location) {
785 : 0 : ne_free (src->location);
786 : 0 : src->location = NULL;
787 : : }
788 [ - + ]: 1 : if (src->query_string) {
789 : 0 : ne_free (src->query_string);
790 : 0 : src->query_string = NULL;
791 : : }
792 : :
793 [ - + ]: 1 : if (ne_uri_parse (uri, &src->uri) != 0)
794 : 0 : goto parse_error;
795 : :
796 [ - + ]: 1 : if (src->uri.scheme == NULL)
797 : 0 : src->uri.scheme = g_strdup ("http");
798 : :
799 [ - + ]: 1 : if (src->uri.host == NULL)
800 : 0 : src->uri.host = g_strdup (DEFAULT_LOCATION);
801 : :
802 [ - + ]: 1 : if (src->uri.port == 0) {
803 [ # # ]: 0 : if (!strcmp (src->uri.scheme, "https"))
804 : 0 : src->uri.port = HTTPS_DEFAULT_PORT;
805 : : else
806 : 0 : src->uri.port = HTTP_DEFAULT_PORT;
807 : : }
808 : :
809 [ - + ]: 1 : if (!src->uri.path)
810 : 0 : src->uri.path = g_strdup ("");
811 : :
812 : 1 : src->query_string = g_strjoin ("?", src->uri.path, src->uri.query, NULL);
813 : :
814 : 1 : src->location = ne_uri_unparse (&src->uri);
815 : :
816 : 1 : return TRUE;
817 : :
818 : : /* ERRORS */
819 : : parse_error:
820 : : {
821 [ # # ]: 0 : if (src->location) {
822 : 0 : ne_free (src->location);
823 : 0 : src->location = NULL;
824 : : }
825 [ # # ]: 0 : if (src->query_string) {
826 : 0 : ne_free (src->query_string);
827 : 0 : src->query_string = NULL;
828 : : }
829 : 0 : ne_uri_free (&src->uri);
830 : 1 : return FALSE;
831 : : }
832 : : }
833 : :
834 : : static gboolean
835 : 0 : gst_neonhttp_src_set_proxy (GstNeonhttpSrc * src, const char *uri)
836 : : {
837 : 0 : ne_uri_free (&src->proxy);
838 : :
839 [ # # ]: 0 : if (ne_uri_parse (uri, &src->proxy) != 0)
840 : 0 : goto error;
841 : :
842 [ # # ]: 0 : if (src->proxy.scheme)
843 [ # # ]: 0 : GST_WARNING ("The proxy schema shouldn't be defined (schema is '%s')",
844 : : src->proxy.scheme);
845 : :
846 [ # # ][ # # ]: 0 : if (src->proxy.host && !src->proxy.port)
847 : 0 : goto error;
848 : :
849 [ # # ][ # # ]: 0 : if (!src->proxy.path || src->proxy.userinfo)
850 : : goto error;
851 : 0 : return TRUE;
852 : :
853 : : /* ERRORS */
854 : : error:
855 : : {
856 : 0 : ne_uri_free (&src->proxy);
857 : 0 : return FALSE;
858 : : }
859 : : }
860 : :
861 : : static int
862 : 0 : ssl_verify_callback (void *data, int failures, const ne_ssl_certificate * cert)
863 : : {
864 : 0 : GstNeonhttpSrc *src = GST_NEONHTTP_SRC (data);
865 : :
866 [ # # ][ # # ]: 0 : if ((failures & NE_SSL_UNTRUSTED) &&
867 [ # # ]: 0 : src->accept_self_signed && !ne_ssl_cert_signedby (cert)) {
868 [ # # ][ # # ]: 0 : GST_ELEMENT_INFO (src, RESOURCE, READ,
[ # # ][ # # ]
869 : : (NULL), ("Accepting self-signed server certificate"));
870 : :
871 : 0 : failures &= ~NE_SSL_UNTRUSTED;
872 : : }
873 : :
874 [ # # ]: 0 : if (failures & NE_SSL_NOTYETVALID)
875 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (src, RESOURCE, READ,
[ # # ][ # # ]
876 : : (NULL), ("Server certificate not valid yet"));
877 [ # # ]: 0 : if (failures & NE_SSL_EXPIRED)
878 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (src, RESOURCE, READ,
[ # # ][ # # ]
879 : : (NULL), ("Server certificate has expired"));
880 [ # # ]: 0 : if (failures & NE_SSL_IDMISMATCH)
881 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (src, RESOURCE, READ,
[ # # ][ # # ]
882 : : (NULL), ("Server certificate doesn't match hostname"));
883 [ # # ]: 0 : if (failures & NE_SSL_UNTRUSTED)
884 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (src, RESOURCE, READ,
[ # # ][ # # ]
885 : : (NULL), ("Server certificate signer not trusted"));
886 : :
887 [ # # ]: 0 : GST_DEBUG_OBJECT (src, "failures: %d\n", failures);
888 : :
889 : 0 : return failures;
890 : : }
891 : :
892 : : /* Try to send the HTTP request to the Icecast server, and if possible deals with
893 : : * all the probable redirections (HTTP status code == 3xx)
894 : : */
895 : : static gint
896 : 0 : gst_neonhttp_src_send_request_and_redirect (GstNeonhttpSrc * src,
897 : : ne_session ** ses, ne_request ** req, gint64 offset, gboolean do_redir)
898 : : {
899 : 0 : ne_session *session = NULL;
900 : 0 : ne_request *request = NULL;
901 : : gchar **c;
902 : : gint res;
903 : 0 : gint http_status = 0;
904 : 0 : guint request_count = 0;
905 : :
906 : : do {
907 [ # # ][ # # ]: 0 : if (src->proxy.host && src->proxy.port) {
908 : 0 : session =
909 : 0 : ne_session_create (src->uri.scheme, src->uri.host, src->uri.port);
910 : 0 : ne_session_proxy (session, src->proxy.host, src->proxy.port);
911 [ # # ][ # # ]: 0 : } else if (src->proxy.host || src->proxy.port) {
912 : : /* both proxy host and port must be specified or none */
913 : 0 : return HTTP_REQUEST_WRONG_PROXY;
914 : : } else {
915 : 0 : session =
916 : 0 : ne_session_create (src->uri.scheme, src->uri.host, src->uri.port);
917 : : }
918 : :
919 [ # # ]: 0 : if (src->connect_timeout > 0) {
920 : 0 : ne_set_connect_timeout (session, src->connect_timeout);
921 : : }
922 : :
923 [ # # ]: 0 : if (src->read_timeout > 0) {
924 : 0 : ne_set_read_timeout (session, src->read_timeout);
925 : : }
926 : :
927 : 0 : ne_set_session_flag (session, NE_SESSFLAG_ICYPROTO, 1);
928 : 0 : ne_ssl_set_verify (session, ssl_verify_callback, src);
929 : :
930 : 0 : request = ne_request_create (session, "GET", src->query_string);
931 : :
932 [ # # ]: 0 : if (src->user_agent) {
933 : 0 : ne_add_request_header (request, "User-Agent", src->user_agent);
934 : : }
935 : :
936 [ # # ][ # # ]: 0 : for (c = src->cookies; c != NULL && *c != NULL; ++c) {
937 [ # # ]: 0 : GST_INFO ("Adding header Cookie : %s", *c);
938 : 0 : ne_add_request_header (request, "Cookies", *c);
939 : : }
940 : :
941 [ # # ]: 0 : if (src->iradio_mode) {
942 : 0 : ne_add_request_header (request, "icy-metadata", "1");
943 : : }
944 : :
945 [ # # ]: 0 : if (offset > 0) {
946 : 0 : ne_print_request_header (request, "Range",
947 : : "bytes=%" G_GINT64_FORMAT "-", offset);
948 : : }
949 : :
950 : 0 : res = ne_begin_request (request);
951 : :
952 [ # # ]: 0 : if (res == NE_OK) {
953 : : /* When the HTTP status code is 3xx, it is not the SHOUTcast streaming content yet;
954 : : * Reload the HTTP request with a new URI value */
955 : 0 : http_status = ne_get_status (request)->code;
956 [ # # ][ # # ]: 0 : if (STATUS_IS_REDIRECTION (http_status) && do_redir) {
[ # # ]
957 : : const gchar *redir;
958 : :
959 : : /* the new URI value to go when redirecting can be found on the 'Location' HTTP header */
960 : 0 : redir = ne_get_response_header (request, "Location");
961 [ # # ]: 0 : if (redir != NULL) {
962 : 0 : ne_uri_free (&src->uri);
963 : 0 : gst_neonhttp_src_set_location (src, redir);
964 [ # # ]: 0 : GST_LOG_OBJECT (src, "Got HTTP Status Code %d", http_status);
965 [ # # ]: 0 : GST_LOG_OBJECT (src, "Using 'Location' header [%s]", src->uri.host);
966 : : }
967 : : }
968 : : }
969 : :
970 [ # # ][ # # ]: 0 : if ((res != NE_OK) ||
971 [ # # ][ # # ]: 0 : (offset == 0 && http_status != 200) ||
972 [ # # ][ # # ]: 0 : (offset > 0 && http_status != 206 &&
973 [ # # ]: 0 : !STATUS_IS_REDIRECTION (http_status))) {
974 : 0 : ne_request_destroy (request);
975 : 0 : request = NULL;
976 : 0 : ne_close_connection (session);
977 : 0 : ne_session_destroy (session);
978 : 0 : session = NULL;
979 [ # # ][ # # ]: 0 : if (offset > 0 && http_status != 206 &&
[ # # ]
980 [ # # ]: 0 : !STATUS_IS_REDIRECTION (http_status)) {
981 : 0 : src->seekable = FALSE;
982 : : }
983 : : }
984 : :
985 : : /* if - NE_OK */
986 [ # # ][ # # ]: 0 : if (STATUS_IS_REDIRECTION (http_status) && do_redir) {
[ # # ]
987 : 0 : ++request_count;
988 [ # # ]: 0 : GST_LOG_OBJECT (src, "redirect request_count is now %d", request_count);
989 [ # # ][ # # ]: 0 : if (request_count < MAX_HTTP_REDIRECTS_NUMBER && do_redir) {
990 [ # # ]: 0 : GST_INFO_OBJECT (src, "Redirecting to %s", src->uri.host);
991 : : } else {
992 [ # # ]: 0 : GST_WARNING_OBJECT (src, "Will not redirect, try again with a "
993 : : "different URI or redirect location %s", src->uri.host);
994 : : }
995 : : /* FIXME: when not redirecting automatically, shouldn't we post a
996 : : * redirect element message on the bus? */
997 : : }
998 : : /* do the redirect, go back to send another HTTP request now using the 'Location' */
999 [ # # ]: 0 : } while (do_redir && (request_count < MAX_HTTP_REDIRECTS_NUMBER)
1000 [ # # ][ # # ]: 0 : && STATUS_IS_REDIRECTION (http_status));
[ # # ]
1001 : :
1002 [ # # ]: 0 : if (session) {
1003 : 0 : *ses = session;
1004 : 0 : *req = request;
1005 : : }
1006 : :
1007 : 0 : return res;
1008 : : }
1009 : :
1010 : : static gint
1011 : 0 : gst_neonhttp_src_request_dispatch (GstNeonhttpSrc * src, GstBuffer * outbuf)
1012 : : {
1013 : : gint ret;
1014 : 0 : gint read = 0;
1015 : 0 : gint sizetoread = GST_BUFFER_SIZE (outbuf);
1016 : :
1017 : : /* Loop sending the request:
1018 : : * Retry whilst authentication fails and we supply it. */
1019 : :
1020 : 0 : ssize_t len = 0;
1021 : :
1022 [ # # ]: 0 : while (sizetoread > 0) {
1023 : 0 : len = ne_read_response_block (src->request,
1024 : 0 : (gchar *) GST_BUFFER_DATA (outbuf) + read, sizetoread);
1025 [ # # ]: 0 : if (len > 0) {
1026 : 0 : read += len;
1027 : 0 : sizetoread -= len;
1028 : : } else {
1029 : 0 : break;
1030 : : }
1031 : :
1032 : : }
1033 : :
1034 : 0 : GST_BUFFER_SIZE (outbuf) = read;
1035 : :
1036 [ # # ]: 0 : if (len < 0) {
1037 : 0 : read = -2;
1038 : 0 : goto done;
1039 [ # # ]: 0 : } else if (len == 0) {
1040 : 0 : ret = ne_end_request (src->request);
1041 [ # # ]: 0 : if (ret != NE_RETRY) {
1042 [ # # ]: 0 : if (ret == NE_OK) {
1043 : 0 : src->eos = TRUE;
1044 : : } else {
1045 : 0 : read = -3;
1046 : : }
1047 : : }
1048 : 0 : goto done;
1049 : : }
1050 : :
1051 [ # # ]: 0 : if (read > 0)
1052 : 0 : src->read_position += read;
1053 : :
1054 : : done:
1055 : 0 : return read;
1056 : : }
1057 : :
1058 : : static void
1059 : 0 : gst_neonhttp_src_close_session (GstNeonhttpSrc * src)
1060 : : {
1061 [ # # ]: 0 : if (src->request) {
1062 : 0 : ne_request_destroy (src->request);
1063 : 0 : src->request = NULL;
1064 : : }
1065 : :
1066 [ # # ]: 0 : if (src->session) {
1067 : 0 : ne_close_connection (src->session);
1068 : 0 : ne_session_destroy (src->session);
1069 : 0 : src->session = NULL;
1070 : : }
1071 : 0 : }
1072 : :
1073 : : /* The following two charset mangling functions were copied from gnomevfssrc.
1074 : : * Preserve them under the unverified assumption that they do something vaguely
1075 : : * worthwhile.
1076 : : */
1077 : : static gchar *
1078 : 0 : unicodify (const gchar * str, gint len, ...)
1079 : : {
1080 : 0 : gchar *ret = NULL, *cset;
1081 : : va_list args;
1082 : : gsize bytes_read, bytes_written;
1083 : :
1084 [ # # ]: 0 : if (g_utf8_validate (str, len, NULL))
1085 [ # # ]: 0 : return g_strndup (str, len >= 0 ? len : strlen (str));
1086 : :
1087 : 0 : va_start (args, len);
1088 [ # # ][ # # ]: 0 : while ((cset = va_arg (args, gchar *)) != NULL) {
1089 [ # # ]: 0 : if (!strcmp (cset, "locale"))
1090 : 0 : ret = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL);
1091 : : else
1092 : 0 : ret = g_convert (str, len, "UTF-8", cset,
1093 : : &bytes_read, &bytes_written, NULL);
1094 [ # # ]: 0 : if (ret)
1095 : 0 : break;
1096 : : }
1097 : 0 : va_end (args);
1098 : :
1099 : 0 : return ret;
1100 : : }
1101 : :
1102 : : static gchar *
1103 : 0 : gst_neonhttp_src_unicodify (const gchar * str)
1104 : : {
1105 : 0 : return unicodify (str, -1, "locale", "ISO-8859-1", NULL);
1106 : : }
1107 : :
1108 : : /* GstURIHandler Interface */
1109 : : static guint
1110 : 3 : gst_neonhttp_src_uri_get_type (void)
1111 : : {
1112 : 3 : return GST_URI_SRC;
1113 : : }
1114 : :
1115 : : static gchar **
1116 : 3 : gst_neonhttp_src_uri_get_protocols (void)
1117 : : {
1118 : : static const gchar *protocols[] = { "http", "https", NULL };
1119 : 3 : return (gchar **) protocols;
1120 : : }
1121 : :
1122 : : static const gchar *
1123 : 0 : gst_neonhttp_src_uri_get_uri (GstURIHandler * handler)
1124 : : {
1125 : 0 : GstNeonhttpSrc *src = GST_NEONHTTP_SRC (handler);
1126 : :
1127 : 0 : return src->location;
1128 : : }
1129 : :
1130 : : static gboolean
1131 : 0 : gst_neonhttp_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
1132 : : {
1133 : 0 : GstNeonhttpSrc *src = GST_NEONHTTP_SRC (handler);
1134 : :
1135 : 0 : return gst_neonhttp_src_set_location (src, uri);
1136 : : }
1137 : :
1138 : : static void
1139 : 3 : gst_neonhttp_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
1140 : : {
1141 : 3 : GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
1142 : :
1143 : 3 : iface->get_type = gst_neonhttp_src_uri_get_type;
1144 : 3 : iface->get_protocols = gst_neonhttp_src_uri_get_protocols;
1145 : 3 : iface->get_uri = gst_neonhttp_src_uri_get_uri;
1146 : 3 : iface->set_uri = gst_neonhttp_src_uri_set_uri;
1147 : 3 : }
1148 : :
1149 : : /* entry point to initialize the plug-in
1150 : : * initialize the plug-in itself
1151 : : * register the element factories and pad templates
1152 : : * register the features
1153 : : */
1154 : : static gboolean
1155 : 3 : plugin_init (GstPlugin * plugin)
1156 : : {
1157 : 3 : return gst_element_register (plugin, "neonhttpsrc", GST_RANK_NONE,
1158 : : GST_TYPE_NEONHTTP_SRC);
1159 : : }
1160 : :
1161 : : /* this is the structure that gst-register looks for
1162 : : * so keep the name plugin_desc, or you cannot get your plug-in registered */
1163 : : GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1164 : : GST_VERSION_MINOR,
1165 : : "neon",
1166 : : "lib neon http client src",
1167 : : plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|