• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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