1 /* HTTP source element for use in tests
2 *
3 * Copyright (c) <2015> YouView TV Ltd
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include <gst/check/gstcheck.h>
22 #include <gst/base/gstbasesrc.h>
23
24 #include "test_http_src.h"
25
26 #ifndef GST_PACKAGE_NAME
27 #define GST_PACKAGE_NAME "gst-plugins-bad"
28 #endif
29
30 #ifndef GST_PACKAGE_ORIGIN
31 #define GST_PACKAGE_ORIGIN "https://developer.gnome.org/gstreamer/"
32 #endif
33
34 #define GST_TEST_HTTP_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TEST_HTTP_SRC, GstTestHTTPSrc))
35 #define GST_TEST_HTTP_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TEST_HTTP_SRC, GstTestHTTPSrcClass))
36 #define GST_IS_TEST_HTTP_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TEST_HTTP_SRC))
37 #define GST_IS_TEST_HTTP_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TEST_HTTP_SRC))
38 #define GST_TEST_HTTP_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TEST_HTTP_SRC, GstTestHTTPSrcClass))
39
40 #define DEFAULT_USER_AGENT "GStreamer testhttpsrc "
41 #define DEFAULT_COMPRESS FALSE
42 #define DEFAULT_HTTP_METHOD NULL
43 #define DEFAULT_KEEP_ALIVE FALSE
44
45 enum
46 {
47 PROP_0,
48 PROP_USER_AGENT,
49 PROP_EXTRA_HEADERS,
50 PROP_COMPRESS,
51 PROP_KEEP_ALIVE,
52 PROP_METHOD,
53 PROP_LAST
54 };
55
56 typedef enum
57 {
58 METHOD_INVALID,
59 METHOD_GET,
60 METHOD_POST,
61 METHOD_HEAD,
62 METHOD_OPTIONS
63 } HttpMethod;
64
65 typedef struct _GstTestHTTPSrcMethodName
66 {
67 const gchar *name;
68 HttpMethod method;
69 } GstTestHTTPSrcMethodName;
70
71 static const GstTestHTTPSrcMethodName gst_test_http_src_methods[] = {
72 {"GET", METHOD_GET},
73 {"POST", METHOD_POST},
74 {"HEAD", METHOD_HEAD},
75 {"OPTIONS", METHOD_OPTIONS},
76 {NULL, METHOD_INVALID}
77 };
78
79 typedef struct _GstTestHTTPSrc
80 {
81 GstBaseSrc parent;
82
83 GMutex mutex;
84
85 GstTestHTTPSrcInput input;
86
87 gchar *uri; /* the uri for which data is being requested */
88 gboolean compress;
89 gboolean keep_alive;
90 gchar *http_method_name;
91 HttpMethod http_method;
92 GstStructure *extra_headers;
93 gchar *user_agent;
94
95 guint64 position;
96 /* index immediately after the last byte from the segment to be retrieved */
97 guint64 segment_end;
98
99 GstEvent *http_headers_event;
100 gboolean duration_changed;
101 } GstTestHTTPSrc;
102
103 typedef struct _GstTestHTTPSrcClass
104 {
105 GstBaseSrcClass parent_class;
106 } GstTestHTTPSrcClass;
107
108 typedef struct _PluginInitContext
109 {
110 const gchar *name;
111 guint rank;
112 GType type;
113 } PluginInitContext;
114
115 static const GstTestHTTPSrcCallbacks *gst_test_http_src_callbacks = NULL;
116 static gpointer gst_test_http_src_callback_user_data = NULL;
117 static guint gst_test_http_src_blocksize = 0;
118
119 static GstStaticPadTemplate gst_dashdemux_test_source_template =
120 GST_STATIC_PAD_TEMPLATE ("src",
121 GST_PAD_SRC,
122 GST_PAD_ALWAYS,
123 GST_STATIC_CAPS_ANY);
124
125 static void gst_test_http_src_uri_handler_init (gpointer g_iface,
126 gpointer iface_data);
127 static void gst_test_http_src_finalize (GObject * object);
128 static gboolean gst_test_http_src_is_seekable (GstBaseSrc * basesrc);
129 static gboolean gst_test_http_src_do_seek (GstBaseSrc * basesrc,
130 GstSegment * segment);
131 static gboolean gst_test_http_src_start (GstBaseSrc * basesrc);
132 static gboolean gst_test_http_src_stop (GstBaseSrc * basesrc);
133 static gboolean gst_test_http_src_get_size (GstBaseSrc * basesrc,
134 guint64 * size);
135 static GstFlowReturn gst_test_http_src_create (GstBaseSrc * basesrc,
136 guint64 offset, guint length, GstBuffer ** ret);
137 static void gst_test_http_src_set_property (GObject * object, guint prop_id,
138 const GValue * value, GParamSpec * pspec);
139 static void gst_test_http_src_get_property (GObject * object, guint prop_id,
140 GValue * value, GParamSpec * pspec);
141
142
143 #define _do_init \
144 G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_test_http_src_uri_handler_init);
145
146 #define gst_test_http_src_parent_class parent_class
147 G_DEFINE_TYPE_WITH_CODE (GstTestHTTPSrc, gst_test_http_src,
148 GST_TYPE_BASE_SRC, _do_init);
149
150 static void
gst_test_http_src_class_init(GstTestHTTPSrcClass * klass)151 gst_test_http_src_class_init (GstTestHTTPSrcClass * klass)
152 {
153 GObjectClass *gobject_class;
154 GstElementClass *gstelement_class;
155 GstBaseSrcClass *gstbasesrc_class;
156
157 gobject_class = G_OBJECT_CLASS (klass);
158 gstelement_class = GST_ELEMENT_CLASS (klass);
159 gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
160
161 gobject_class->set_property = gst_test_http_src_set_property;
162 gobject_class->get_property = gst_test_http_src_get_property;
163 gobject_class->finalize = gst_test_http_src_finalize;
164
165 g_object_class_install_property (gobject_class, PROP_COMPRESS,
166 g_param_spec_boolean ("compress", "Compress",
167 "Allow compressed content encodings",
168 DEFAULT_COMPRESS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
169
170 g_object_class_install_property (gobject_class, PROP_EXTRA_HEADERS,
171 g_param_spec_boxed ("extra-headers", "Extra Headers",
172 "Extra headers to append to the HTTP request",
173 GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
174
175 g_object_class_install_property (gobject_class, PROP_KEEP_ALIVE,
176 g_param_spec_boolean ("keep-alive", "keep-alive",
177 "Use HTTP persistent connections", DEFAULT_KEEP_ALIVE,
178 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
179
180 g_object_class_install_property (gobject_class, PROP_METHOD,
181 g_param_spec_string ("method", "HTTP method",
182 "The HTTP method to use (GET, HEAD, OPTIONS, etc)",
183 DEFAULT_HTTP_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
184
185 g_object_class_install_property (gobject_class,
186 PROP_USER_AGENT,
187 g_param_spec_string ("user-agent", "User-Agent",
188 "Value of the User-Agent HTTP request header field",
189 DEFAULT_USER_AGENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
190
191 gst_element_class_set_metadata (gstelement_class,
192 "Test HTTP source element for unit tests",
193 "Source/Network",
194 "Use in unit tests", "Alex Ashley <alex.ashley@youview.com>");
195 gst_element_class_add_static_pad_template (gstelement_class,
196 &gst_dashdemux_test_source_template);
197
198 gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_test_http_src_start);
199 gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_test_http_src_stop);
200 gstbasesrc_class->is_seekable =
201 GST_DEBUG_FUNCPTR (gst_test_http_src_is_seekable);
202 gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_test_http_src_do_seek);
203 gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_test_http_src_get_size);
204 gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_test_http_src_create);
205
206 }
207
208 static void
gst_test_http_src_init(GstTestHTTPSrc * src)209 gst_test_http_src_init (GstTestHTTPSrc * src)
210 {
211 g_mutex_init (&src->mutex);
212 src->uri = NULL;
213 memset (&src->input, 0, sizeof (src->input));
214 src->compress = FALSE;
215 src->keep_alive = FALSE;
216 src->http_method_name = NULL;
217 src->http_method = METHOD_GET;
218 src->user_agent = NULL;
219 src->position = 0;
220 src->segment_end = 0;
221 src->http_headers_event = NULL;
222 src->duration_changed = FALSE;
223 if (gst_test_http_src_blocksize)
224 gst_base_src_set_blocksize (GST_BASE_SRC (src),
225 gst_test_http_src_blocksize);
226 }
227
228 static void
gst_test_http_src_reset_input(GstTestHTTPSrc * src)229 gst_test_http_src_reset_input (GstTestHTTPSrc * src)
230 {
231 src->input.context = NULL;
232 src->input.size = 0;
233 src->input.status_code = 0;
234 if (src->input.request_headers) {
235 gst_structure_free (src->input.request_headers);
236 src->input.request_headers = NULL;
237 }
238 if (src->input.response_headers) {
239 gst_structure_free (src->input.response_headers);
240 src->input.response_headers = NULL;
241 }
242 if (src->http_headers_event) {
243 gst_event_unref (src->http_headers_event);
244 src->http_headers_event = NULL;
245 }
246 if (src->extra_headers) {
247 gst_structure_free (src->extra_headers);
248 src->extra_headers = NULL;
249 }
250 g_free (src->http_method_name);
251 src->http_method_name = NULL;
252 g_free (src->user_agent);
253 src->user_agent = NULL;
254 src->duration_changed = FALSE;
255 }
256
257 static void
gst_test_http_src_finalize(GObject * object)258 gst_test_http_src_finalize (GObject * object)
259 {
260 GstTestHTTPSrc *src;
261
262 src = GST_TEST_HTTP_SRC (object);
263
264 g_free (src->uri);
265 gst_test_http_src_reset_input (src);
266 g_mutex_clear (&src->mutex);
267
268 G_OBJECT_CLASS (parent_class)->finalize (object);
269 }
270
271 static gboolean
gst_test_http_src_start(GstBaseSrc * basesrc)272 gst_test_http_src_start (GstBaseSrc * basesrc)
273 {
274 GstTestHTTPSrc *src;
275 GstStructure *http_headers;
276
277 src = GST_TEST_HTTP_SRC (basesrc);
278 g_mutex_lock (&src->mutex);
279 gst_test_http_src_reset_input (src);
280 if (!src->uri) {
281 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (("No URL set.")),
282 ("Missing location property"));
283 g_mutex_unlock (&src->mutex);
284 return FALSE;
285 }
286 if (!gst_test_http_src_callbacks) {
287 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
288 (("Callbacks not registered.")), ("Callbacks not registered"));
289 g_mutex_unlock (&src->mutex);
290 return FALSE;
291 }
292 if (!gst_test_http_src_callbacks->src_start) {
293 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
294 (("src_start callback not defined.")),
295 ("src_start callback not registered"));
296 g_mutex_unlock (&src->mutex);
297 return FALSE;
298 }
299 if (!gst_test_http_src_callbacks->src_start (src, src->uri, &src->input,
300 gst_test_http_src_callback_user_data)) {
301 if (src->input.status_code == 0) {
302 src->input.status_code = 404;
303 }
304 } else {
305 if (src->input.status_code == 0) {
306 src->input.status_code = 200;
307 }
308 src->position = 0;
309 src->segment_end = src->input.size;
310 gst_base_src_set_dynamic_size (basesrc, FALSE);
311 basesrc->segment.duration = src->input.size;
312 src->duration_changed = TRUE;
313 }
314 http_headers = gst_structure_new_empty ("http-headers");
315 gst_structure_set (http_headers, "uri", G_TYPE_STRING, src->uri, NULL);
316 if (!src->input.request_headers) {
317 src->input.request_headers =
318 gst_structure_new_empty (TEST_HTTP_SRC_REQUEST_HEADERS_NAME);
319 }
320 if (!gst_structure_has_field_typed (src->input.request_headers,
321 "User-Agent", G_TYPE_STRING)) {
322 gst_structure_set (src->input.request_headers,
323 "User-Agent", G_TYPE_STRING,
324 src->user_agent ? src->user_agent : DEFAULT_USER_AGENT, NULL);
325 }
326 if (!gst_structure_has_field_typed (src->input.request_headers,
327 "Connection", G_TYPE_STRING)) {
328 gst_structure_set (src->input.request_headers,
329 "Connection", G_TYPE_STRING,
330 src->keep_alive ? "Keep-Alive" : "Close", NULL);
331 }
332 if (src->compress
333 && !gst_structure_has_field_typed (src->input.request_headers,
334 "Accept-Encoding", G_TYPE_STRING)) {
335 gst_structure_set (src->input.request_headers, "Accept-Encoding",
336 G_TYPE_STRING, "compress, gzip", NULL);
337 }
338 gst_structure_set (http_headers, TEST_HTTP_SRC_REQUEST_HEADERS_NAME,
339 GST_TYPE_STRUCTURE, src->input.request_headers, NULL);
340 if (!src->input.response_headers) {
341 src->input.response_headers =
342 gst_structure_new_empty (TEST_HTTP_SRC_RESPONSE_HEADERS_NAME);
343 }
344 if (!gst_structure_has_field_typed (src->input.response_headers,
345 "Connection", G_TYPE_STRING)) {
346 gst_structure_set (src->input.response_headers,
347 "Connection", G_TYPE_STRING,
348 src->keep_alive ? "keep-alive" : "close", NULL);
349 }
350 if (!gst_structure_has_field_typed (src->input.response_headers,
351 "Date", G_TYPE_STRING)) {
352 GDateTime *now;
353 gchar *date_str;
354
355 now = g_date_time_new_now_local ();
356 fail_unless (now != NULL);
357 date_str = g_date_time_format (now, "%a, %e %b %Y %T %Z");
358 fail_unless (date_str != NULL);
359 gst_structure_set (src->input.response_headers,
360 "Date", G_TYPE_STRING, date_str, NULL);
361 g_free (date_str);
362 g_date_time_unref (now);
363 }
364 gst_structure_set (http_headers, TEST_HTTP_SRC_RESPONSE_HEADERS_NAME,
365 GST_TYPE_STRUCTURE, src->input.response_headers, NULL);
366 if (src->http_headers_event) {
367 gst_event_unref (src->http_headers_event);
368 }
369 src->http_headers_event =
370 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_STICKY, http_headers);
371 g_mutex_unlock (&src->mutex);
372 return TRUE;
373 }
374
375 static gboolean
gst_test_http_src_stop(GstBaseSrc * basesrc)376 gst_test_http_src_stop (GstBaseSrc * basesrc)
377 {
378 GstTestHTTPSrc *src;
379
380 src = GST_TEST_HTTP_SRC (basesrc);
381 g_mutex_lock (&src->mutex);
382 src->position = 0;
383 gst_test_http_src_reset_input (src);
384 g_mutex_unlock (&src->mutex);
385 return TRUE;
386 }
387
388 static gboolean
gst_test_http_src_is_seekable(GstBaseSrc * basesrc)389 gst_test_http_src_is_seekable (GstBaseSrc * basesrc)
390 {
391 GstTestHTTPSrc *src;
392 gboolean ret;
393
394 src = GST_TEST_HTTP_SRC (basesrc);
395 g_mutex_lock (&src->mutex);
396 /* if size is set, we can seek */
397 ret = src->input.size > 0;
398 g_mutex_unlock (&src->mutex);
399 return ret;
400 }
401
402 static gboolean
gst_test_http_src_do_seek(GstBaseSrc * basesrc,GstSegment * segment)403 gst_test_http_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment)
404 {
405 GstTestHTTPSrc *src = GST_TEST_HTTP_SRC (basesrc);
406
407 GST_DEBUG ("gst_test_http_src_do_seek start = %" G_GUINT64_FORMAT,
408 segment->start);
409
410 /*
411 According to RFC7233, the range is inclusive:
412 The first-byte-pos value in a byte-range-spec gives the byte-offset
413 of the first byte in a range. The last-byte-pos value gives the
414 byte-offset of the last byte in the range; that is, the byte
415 positions specified are inclusive. Byte offsets start at zero.
416 */
417
418 g_mutex_lock (&src->mutex);
419 if (!src->uri) {
420 GST_DEBUG ("attempt to seek before URI set");
421 g_mutex_unlock (&src->mutex);
422 return FALSE;
423 }
424 if (src->input.status_code >= 200 && src->input.status_code < 300) {
425 if (segment->start >= src->input.size) {
426 GST_DEBUG ("attempt to seek to %" G_GUINT64_FORMAT " but size is %"
427 G_GUINT64_FORMAT, segment->start, src->input.size);
428 g_mutex_unlock (&src->mutex);
429 return FALSE;
430 }
431 if (segment->stop != -1 && segment->stop > src->input.size) {
432 g_mutex_unlock (&src->mutex);
433 return FALSE;
434 }
435 } else {
436 GST_DEBUG ("Attempt to seek on a URL that will generate HTTP error %u",
437 src->input.status_code);
438 }
439 src->position = segment->start;
440
441 if (segment->stop != -1) {
442 src->segment_end = segment->stop;
443 } else {
444 src->segment_end = src->input.size;
445 }
446 g_mutex_unlock (&src->mutex);
447 return TRUE;
448 }
449
450 static gboolean
gst_test_http_src_get_size(GstBaseSrc * basesrc,guint64 * size)451 gst_test_http_src_get_size (GstBaseSrc * basesrc, guint64 * size)
452 {
453 GstTestHTTPSrc *src;
454
455 src = GST_TEST_HTTP_SRC (basesrc);
456
457 g_mutex_lock (&src->mutex);
458 /* if it was started, size is set */
459 if (src->uri && src->input.status_code >= 200 && src->input.status_code < 300) {
460 *size = src->input.size;
461 g_mutex_unlock (&src->mutex);
462 return TRUE;
463 }
464 /* cannot get the size if it wasn't started */
465 g_mutex_unlock (&src->mutex);
466 return FALSE;
467 }
468
469 static GstFlowReturn
gst_test_http_src_create(GstBaseSrc * basesrc,guint64 offset,guint length,GstBuffer ** retbuf)470 gst_test_http_src_create (GstBaseSrc * basesrc, guint64 offset,
471 guint length, GstBuffer ** retbuf)
472 {
473 GstTestHTTPSrc *src = GST_TEST_HTTP_SRC (basesrc);
474 guint bytes_read;
475 GstFlowReturn ret = GST_FLOW_OK;
476 guint blocksize;
477
478 fail_unless (gst_test_http_src_callbacks != NULL);
479 fail_unless (gst_test_http_src_callbacks->src_create != NULL);
480
481 GST_OBJECT_LOCK (src);
482 blocksize = basesrc->blocksize;
483 GST_OBJECT_UNLOCK (src);
484
485 g_mutex_lock (&src->mutex);
486 GST_DEBUG ("gst_test_http_src_create feeding from %" G_GUINT64_FORMAT,
487 src->position);
488 if (src->uri == NULL) {
489 GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
490 g_mutex_unlock (&src->mutex);
491 return GST_FLOW_ERROR;
492 }
493 if (src->input.status_code < 200 || src->input.status_code >= 300) {
494 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s",
495 "Generated requested error"), ("%s (%d), URL: %s, Redirect to: %s",
496 "Generated requested error", src->input.status_code, src->uri,
497 GST_STR_NULL (NULL)));
498 g_mutex_unlock (&src->mutex);
499 return GST_FLOW_ERROR;
500 }
501 if (src->http_method == METHOD_INVALID) {
502 GST_ELEMENT_ERROR (src, RESOURCE, READ, ("%s",
503 "Invalid HTTP method"), ("%s (%s), URL: %s",
504 "Invalid HTTP method", src->http_method_name, src->uri));
505 g_mutex_unlock (&src->mutex);
506 return GST_FLOW_ERROR;
507 } else if (src->http_method == METHOD_HEAD) {
508 ret = GST_FLOW_EOS;
509 goto http_events;
510 }
511 fail_unless_equals_uint64 (offset, src->position);
512 bytes_read = MIN ((src->segment_end - src->position), blocksize);
513 if (bytes_read == 0) {
514 ret = GST_FLOW_EOS;
515 goto http_events;
516 }
517 ret = gst_test_http_src_callbacks->src_create (src,
518 offset, bytes_read, retbuf,
519 src->input.context, gst_test_http_src_callback_user_data);
520 if (ret != GST_FLOW_OK) {
521 goto http_events;
522 }
523
524 GST_BUFFER_OFFSET (*retbuf) = src->position;
525 GST_BUFFER_OFFSET_END (*retbuf) = src->position + bytes_read;
526
527 src->position += bytes_read;
528 http_events:
529 if (src->http_headers_event) {
530 gst_pad_push_event (GST_BASE_SRC_PAD (src), src->http_headers_event);
531 src->http_headers_event = NULL;
532 }
533 if (src->duration_changed) {
534 src->duration_changed = FALSE;
535 gst_element_post_message (GST_ELEMENT (src),
536 gst_message_new_duration_changed (GST_OBJECT (src)));
537 }
538
539 g_mutex_unlock (&src->mutex);
540 return ret;
541 }
542
543 static void
gst_test_http_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)544 gst_test_http_src_set_property (GObject * object, guint prop_id,
545 const GValue * value, GParamSpec * pspec)
546 {
547 GstTestHTTPSrc *src = GST_TEST_HTTP_SRC (object);
548
549 switch (prop_id) {
550 case PROP_USER_AGENT:
551 g_free (src->user_agent);
552 src->user_agent = g_value_dup_string (value);
553 break;
554 case PROP_EXTRA_HEADERS:{
555 const GstStructure *s = gst_value_get_structure (value);
556 if (src->extra_headers)
557 gst_structure_free (src->extra_headers);
558 src->extra_headers = s ? gst_structure_copy (s) : NULL;
559 break;
560 }
561 case PROP_COMPRESS:
562 src->compress = g_value_get_boolean (value);
563 GST_DEBUG ("Set compress=%s", src->compress ? "TRUE" : "FALSE");
564 break;
565 case PROP_KEEP_ALIVE:
566 src->keep_alive = g_value_get_boolean (value);
567 break;
568 case PROP_METHOD:{
569 guint i;
570
571 g_free (src->http_method_name);
572 src->http_method_name = g_value_dup_string (value);
573 src->http_method = METHOD_INVALID;
574 for (i = 0; gst_test_http_src_methods[i].name; ++i) {
575 if (strcmp (gst_test_http_src_methods[i].name,
576 src->http_method_name) == 0) {
577 src->http_method = gst_test_http_src_methods[i].method;
578 break;
579 }
580 }
581 /* we don't cause an error for an invalid method at this point,
582 as GstSoupHTTPSrc does not use the http_method_name string until
583 trying to open a connection.
584 */
585 break;
586 }
587 default:
588 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
589 break;
590 }
591 }
592
593 static void
gst_test_http_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)594 gst_test_http_src_get_property (GObject * object, guint prop_id,
595 GValue * value, GParamSpec * pspec)
596 {
597 GstTestHTTPSrc *src = GST_TEST_HTTP_SRC (object);
598
599 switch (prop_id) {
600 case PROP_USER_AGENT:
601 g_value_set_string (value, src->user_agent);
602 break;
603 case PROP_EXTRA_HEADERS:
604 gst_value_set_structure (value, src->extra_headers);
605 break;
606 case PROP_COMPRESS:
607 g_value_set_boolean (value, src->compress);
608 break;
609 case PROP_KEEP_ALIVE:
610 g_value_set_boolean (value, src->keep_alive);
611 break;
612 case PROP_METHOD:
613 g_value_set_string (value, src->http_method_name);
614 break;
615 default:
616 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
617 break;
618 }
619 }
620
621 static gboolean
gst_test_http_src_set_location(GstTestHTTPSrc * src,const gchar * uri,GError ** error)622 gst_test_http_src_set_location (GstTestHTTPSrc * src,
623 const gchar * uri, GError ** error)
624 {
625 g_mutex_lock (&src->mutex);
626 g_free (src->uri);
627 src->uri = g_strdup (uri);
628 g_mutex_unlock (&src->mutex);
629 return TRUE;
630 }
631
632 static GstURIType
gst_test_http_src_uri_get_type(GType type)633 gst_test_http_src_uri_get_type (GType type)
634 {
635 return GST_URI_SRC;
636 }
637
638 static const gchar *const *
gst_test_http_src_uri_get_protocols(GType type)639 gst_test_http_src_uri_get_protocols (GType type)
640 {
641 static const gchar *protocols[] = { "http", NULL };
642
643 return protocols;
644 }
645
646 static gchar *
gst_test_http_src_uri_get_uri(GstURIHandler * handler)647 gst_test_http_src_uri_get_uri (GstURIHandler * handler)
648 {
649 GstTestHTTPSrc *src = GST_TEST_HTTP_SRC (handler);
650 gchar *ret;
651 g_mutex_lock (&src->mutex);
652 ret = g_strdup (src->uri);
653 g_mutex_unlock (&src->mutex);
654 return ret;
655 }
656
657 static gboolean
gst_test_http_src_uri_set_uri(GstURIHandler * handler,const gchar * uri,GError ** err)658 gst_test_http_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
659 GError ** err)
660 {
661 GstTestHTTPSrc *src = GST_TEST_HTTP_SRC (handler);
662
663 return gst_test_http_src_set_location (src, uri, err);
664 }
665
666 static void
gst_test_http_src_uri_handler_init(gpointer g_iface,gpointer iface_data)667 gst_test_http_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
668 {
669 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
670
671 iface->get_type = gst_test_http_src_uri_get_type;
672 iface->get_protocols = gst_test_http_src_uri_get_protocols;
673 iface->get_uri = gst_test_http_src_uri_get_uri;
674 iface->set_uri = gst_test_http_src_uri_set_uri;
675 }
676
677 static gboolean
gst_test_http_src_plugin_init_func(GstPlugin * plugin,gpointer user_data)678 gst_test_http_src_plugin_init_func (GstPlugin * plugin, gpointer user_data)
679 {
680 PluginInitContext *context = (PluginInitContext *) user_data;
681 gboolean ret;
682
683 ret =
684 gst_element_register (plugin, context->name, context->rank,
685 context->type);
686 return ret;
687 }
688
689 gboolean
gst_test_http_src_register_plugin(GstRegistry * registry,const gchar * name)690 gst_test_http_src_register_plugin (GstRegistry * registry, const gchar * name)
691 {
692 gboolean ret;
693 PluginInitContext context;
694
695 context.name = name;
696 context.rank = GST_RANK_PRIMARY + 1;
697 context.type = GST_TYPE_TEST_HTTP_SRC;
698 ret = gst_plugin_register_static_full (GST_VERSION_MAJOR, /* version */
699 GST_VERSION_MINOR, /* version */
700 name, /* name */
701 "Replaces a souphttpsrc plugin and returns predefined data.", /* description */
702 gst_test_http_src_plugin_init_func, /* init function */
703 "0.0.0", /* version string */
704 GST_LICENSE_UNKNOWN, /* license */
705 __FILE__, /* source */
706 GST_PACKAGE_NAME, /* package */
707 GST_PACKAGE_ORIGIN, /* origin */
708 &context /* user_data */
709 );
710 return ret;
711 }
712
713 void
gst_test_http_src_install_callbacks(const GstTestHTTPSrcCallbacks * callbacks,gpointer user_data)714 gst_test_http_src_install_callbacks (const GstTestHTTPSrcCallbacks *
715 callbacks, gpointer user_data)
716 {
717 gst_test_http_src_callbacks = callbacks;
718 gst_test_http_src_callback_user_data = user_data;
719 }
720
721 void
gst_test_http_src_set_default_blocksize(guint blocksize)722 gst_test_http_src_set_default_blocksize (guint blocksize)
723 {
724 gst_test_http_src_blocksize = blocksize;
725 }
726