mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
curl: refactor curlsink, rename to curlhttpsink
Split into base, tls and http classes. https://bugzilla.gnome.org/show_bug.cgi?id=653741
This commit is contained in:
parent
e9cba00c6a
commit
ae39cbfa57
13 changed files with 1609 additions and 633 deletions
|
@ -310,7 +310,7 @@ GST_PLUGINS_NONPORTED=" aiff \
|
|||
sdi siren speed subenc stereo tta videofilters \
|
||||
videomeasure videosignal vmnc \
|
||||
decklink fbdev linsys vcd \
|
||||
apexsink cdaudio cog curl dc1394 dirac directfb resindvd \
|
||||
apexsink cdaudio cog dc1394 dirac directfb resindvd \
|
||||
gsettings jp2k ladspa mimic \
|
||||
musepack musicbrainz nas neon ofa openal opencv rsvg sdl sndfile soundtouch spandsp spc timidity \
|
||||
directsound direct3d directdraw direct3d9 acm wininet \
|
||||
|
|
|
@ -61,11 +61,17 @@ IGNORE_CFILES =
|
|||
EXAMPLE_CFILES = \
|
||||
$(top_srcdir)/ext/directfb/dfb-example.c
|
||||
|
||||
# $(top_srcdir)/ext/curl/gstcurlfilesink.h
|
||||
# $(top_srcdir)/ext/curl/gstcurlftpsink.h
|
||||
# $(top_srcdir)/ext/curl/gstcurlsmtpsink.h
|
||||
|
||||
EXTRA_HFILES = \
|
||||
$(top_srcdir)/ext/assrender/gstassrender.h \
|
||||
$(top_srcdir)/ext/celt/gstceltdec.h \
|
||||
$(top_srcdir)/ext/celt/gstceltenc.h \
|
||||
$(top_srcdir)/ext/curl/gstcurlsink.h \
|
||||
$(top_srcdir)/ext/curl/gstcurlbasesink.h \
|
||||
$(top_srcdir)/ext/curl/gstcurlhttpsink.h \
|
||||
$(top_srcdir)/ext/curl/gstcurltlssink.h \
|
||||
$(top_srcdir)/ext/dc1394/gstdc1394.h \
|
||||
$(top_srcdir)/ext/directfb/dfbvideosink.h \
|
||||
$(top_srcdir)/ext/dts/gstdtsdec.h \
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
plugin_LTLIBRARIES = libgstcurl.la
|
||||
|
||||
libgstcurl_la_SOURCES = gstcurl.c gstcurlsink.c
|
||||
libgstcurl_la_SOURCES = gstcurl.c \
|
||||
gstcurlbasesink.c \
|
||||
gstcurltlssink.c \
|
||||
gstcurlhttpsink.c
|
||||
libgstcurl_la_CFLAGS = \
|
||||
$(GST_PLUGINS_BAD_CFLAGS) \
|
||||
$(GST_BASE_CFLAGS) \
|
||||
$(GST_CFLAGS) \
|
||||
$(CURL_CFLAGS)
|
||||
libgstcurl_la_LIBADD = \
|
||||
$(GST_PLUGINS_BASE_LIBS) \
|
||||
$(GST_BASE_LIBS) \
|
||||
$(GST_LIBS) \
|
||||
$(CURL_LIBS)
|
||||
libgstcurl_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstcurl_la_LIBTOOLFLAGS = --tag=disable-static
|
||||
|
||||
noinst_HEADERS = gstcurlsink.h
|
||||
noinst_HEADERS = gstcurlbasesink.h \
|
||||
gstcurltlssink.h \
|
||||
gstcurlhttpsink.h
|
||||
|
|
|
@ -20,14 +20,16 @@
|
|||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "gstcurlsink.h"
|
||||
#include "gstcurlbasesink.h"
|
||||
#include "gstcurltlssink.h"
|
||||
#include "gstcurlhttpsink.h"
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
|
||||
if (!gst_element_register (plugin, "curlsink", GST_RANK_NONE,
|
||||
GST_TYPE_CURL_SINK))
|
||||
if (!gst_element_register (plugin, "curlhttpsink", GST_RANK_NONE,
|
||||
GST_TYPE_CURL_HTTP_SINK))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
|
|
File diff suppressed because it is too large
Load diff
116
ext/curl/gstcurlbasesink.h
Normal file
116
ext/curl/gstcurlbasesink.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2011 Axis Communications <dev-gstreamer@axis.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CURL_BASE_SINK__
|
||||
#define __GST_CURL_BASE_SINK__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesink.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
#define GST_TYPE_CURL_BASE_SINK \
|
||||
(gst_curl_base_sink_get_type())
|
||||
#define GST_CURL_BASE_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CURL_BASE_SINK, GstCurlBaseSink))
|
||||
#define GST_CURL_BASE_SINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CURL_BASE_SINK, GstCurlBaseSinkClass))
|
||||
#define GST_CURL_BASE_SINK_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CURL_BASE_SINK, GstCurlBaseSinkClass))
|
||||
#define GST_IS_CURL_BASE_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_CURL_BASE_SINK))
|
||||
#define GST_IS_CURL_BASE_SINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_CURL_BASE_SINK))
|
||||
typedef struct _GstCurlBaseSink GstCurlBaseSink;
|
||||
typedef struct _GstCurlBaseSinkClass GstCurlBaseSinkClass;
|
||||
|
||||
typedef struct _TransferBuffer TransferBuffer;
|
||||
typedef struct _TransferCondition TransferCondition;
|
||||
|
||||
struct _TransferBuffer
|
||||
{
|
||||
guint8 *ptr;
|
||||
size_t len;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
struct _TransferCondition
|
||||
{
|
||||
GCond *cond;
|
||||
gboolean data_sent;
|
||||
gboolean data_available;
|
||||
gboolean wait_for_response;
|
||||
};
|
||||
|
||||
struct _GstCurlBaseSink
|
||||
{
|
||||
GstBaseSink parent;
|
||||
|
||||
/*< private > */
|
||||
CURLM *multi_handle;
|
||||
CURL *curl;
|
||||
GstPollFD fd;
|
||||
GstPoll *fdset;
|
||||
GThread *transfer_thread;
|
||||
GstFlowReturn flow_ret;
|
||||
TransferBuffer *transfer_buf;
|
||||
TransferCondition *transfer_cond;
|
||||
gint num_buffers_per_packet;
|
||||
gint timeout;
|
||||
gchar *url;
|
||||
gchar *user;
|
||||
gchar *passwd;
|
||||
gchar *file_name;
|
||||
guint qos_dscp;
|
||||
gboolean transfer_thread_close;
|
||||
gboolean new_file;
|
||||
gboolean is_live;
|
||||
};
|
||||
|
||||
struct _GstCurlBaseSinkClass
|
||||
{
|
||||
GstBaseSinkClass parent_class;
|
||||
|
||||
/* vmethods */
|
||||
gboolean (*set_protocol_dynamic_options_unlocked) (GstCurlBaseSink * sink);
|
||||
gboolean (*set_options_unlocked) (GstCurlBaseSink * sink);
|
||||
void (*set_mime_type) (GstCurlBaseSink * sink, GstCaps * caps);
|
||||
void (*transfer_prepare_poll_wait) (GstCurlBaseSink * sink);
|
||||
glong (*transfer_get_response_code) (GstCurlBaseSink * sink, glong resp);
|
||||
gboolean (*transfer_verify_response_code) (GstCurlBaseSink * sink);
|
||||
GstFlowReturn (*prepare_transfer) (GstCurlBaseSink * sink);
|
||||
void (*handle_transfer) (GstCurlBaseSink * sink);
|
||||
size_t (*transfer_read_cb) (void *curl_ptr, size_t size, size_t nmemb,
|
||||
void *stream);
|
||||
size_t (*transfer_data_buffer) (GstCurlBaseSink * sink, void *curl_ptr,
|
||||
size_t block_size, guint * last_chunk);
|
||||
size_t (*flush_data_unlocked) (GstCurlBaseSink * sink, void *curl_ptr,
|
||||
size_t block_size, gboolean new_file);
|
||||
};
|
||||
|
||||
GType gst_curl_base_sink_get_type (void);
|
||||
|
||||
void gst_curl_base_sink_transfer_thread_notify_unlocked
|
||||
(GstCurlBaseSink * sink);
|
||||
void gst_curl_base_sink_transfer_thread_close (GstCurlBaseSink * sink);
|
||||
void gst_curl_base_sink_set_live (GstCurlBaseSink * sink, gboolean live);
|
||||
gboolean gst_curl_base_sink_is_live (GstCurlBaseSink * sink);
|
||||
|
||||
G_END_DECLS
|
||||
#endif
|
476
ext/curl/gstcurlhttpsink.c
Normal file
476
ext/curl/gstcurlhttpsink.c
Normal file
|
@ -0,0 +1,476 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2011 Axis Communications <dev-gstreamer@axis.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:element-curlhttpsink
|
||||
* @short_description: sink that uploads data to a server using libcurl
|
||||
* @see_also:
|
||||
*
|
||||
* This is a network sink that uses libcurl as a client to upload data to
|
||||
* an HTTP server.
|
||||
*
|
||||
* <refsect2>
|
||||
* <title>Example launch line (upload a JPEG file to an HTTP server)</title>
|
||||
* |[
|
||||
* gst-launch filesrc location=image.jpg ! jpegparse ! curlhttpsink \
|
||||
* file-name=image.jpg \
|
||||
* location=http://192.168.0.1:8080/cgi-bin/patupload.cgi/ \
|
||||
* user=test passwd=test \
|
||||
* content-type=image/jpeg \
|
||||
* use-content-length=false
|
||||
* ]|
|
||||
* </refsect2>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "gstcurltlssink.h"
|
||||
#include "gstcurlhttpsink.h"
|
||||
|
||||
/* Default values */
|
||||
#define GST_CAT_DEFAULT gst_curl_http_sink_debug
|
||||
#define DEFAULT_TIMEOUT 30
|
||||
#define DEFAULT_PROXY_PORT 3128
|
||||
#define DEFAULT_USE_CONTENT_LENGTH FALSE
|
||||
|
||||
#define RESPONSE_CONNECT_PROXY 200
|
||||
|
||||
/* Plugin specific settings */
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_curl_http_sink_debug);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_PROXY,
|
||||
PROP_PROXY_PORT,
|
||||
PROP_PROXY_USER_NAME,
|
||||
PROP_PROXY_USER_PASSWD,
|
||||
PROP_USE_CONTENT_LENGTH,
|
||||
PROP_CONTENT_TYPE
|
||||
};
|
||||
|
||||
|
||||
/* Object class function declarations */
|
||||
|
||||
static void gst_curl_http_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_curl_http_sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void gst_curl_http_sink_finalize (GObject * gobject);
|
||||
static gboolean gst_curl_http_sink_set_header_unlocked
|
||||
(GstCurlBaseSink * bcsink);
|
||||
static gboolean gst_curl_http_sink_set_options_unlocked
|
||||
(GstCurlBaseSink * bcsink);
|
||||
static void gst_curl_http_sink_set_mime_type
|
||||
(GstCurlBaseSink * bcsink, GstCaps * caps);
|
||||
static gboolean gst_curl_http_sink_transfer_verify_response_code
|
||||
(GstCurlBaseSink * bcsink);
|
||||
static void gst_curl_http_sink_transfer_prepare_poll_wait
|
||||
(GstCurlBaseSink * bcsink);
|
||||
|
||||
#define gst_curl_http_sink_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstCurlHttpSink, gst_curl_http_sink, GST_TYPE_CURL_TLS_SINK);
|
||||
|
||||
/* private functions */
|
||||
|
||||
static gboolean proxy_setup (GstCurlBaseSink * bcsink);
|
||||
|
||||
static void
|
||||
gst_curl_http_sink_class_init (GstCurlHttpSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GstCurlBaseSinkClass *gstcurlbasesink_class = (GstCurlBaseSinkClass *) klass;
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_curl_http_sink_debug, "curlhttpsink", 0,
|
||||
"curl http sink element");
|
||||
GST_DEBUG_OBJECT (klass, "class_init");
|
||||
|
||||
gst_element_class_set_details_simple (element_class,
|
||||
"Curl http sink",
|
||||
"Sink/Network",
|
||||
"Upload data over HTTP/HTTPS protocol using libcurl",
|
||||
"Patricia Muscalu <patricia@axis.com>");
|
||||
|
||||
gstcurlbasesink_class->set_protocol_dynamic_options_unlocked =
|
||||
gst_curl_http_sink_set_header_unlocked;
|
||||
gstcurlbasesink_class->set_options_unlocked =
|
||||
gst_curl_http_sink_set_options_unlocked;
|
||||
gstcurlbasesink_class->set_mime_type = gst_curl_http_sink_set_mime_type;
|
||||
gstcurlbasesink_class->transfer_verify_response_code =
|
||||
gst_curl_http_sink_transfer_verify_response_code;
|
||||
gstcurlbasesink_class->transfer_prepare_poll_wait =
|
||||
gst_curl_http_sink_transfer_prepare_poll_wait;
|
||||
|
||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_curl_http_sink_finalize);
|
||||
|
||||
gobject_class->set_property = gst_curl_http_sink_set_property;
|
||||
gobject_class->get_property = gst_curl_http_sink_get_property;
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_PROXY,
|
||||
g_param_spec_string ("proxy", "Proxy", "HTTP proxy server URI", NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_PROXY_PORT,
|
||||
g_param_spec_int ("proxy-port", "Proxy port",
|
||||
"HTTP proxy server port", 0, G_MAXINT, DEFAULT_PROXY_PORT,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_PROXY_USER_NAME,
|
||||
g_param_spec_string ("proxy-user", "Proxy user name",
|
||||
"Proxy user name to use for proxy authentication",
|
||||
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_PROXY_USER_PASSWD,
|
||||
g_param_spec_string ("proxy-passwd", "Proxy user password",
|
||||
"Proxy user password to use for proxy authentication",
|
||||
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_USE_CONTENT_LENGTH,
|
||||
g_param_spec_boolean ("use-content-length", "Use content length header",
|
||||
"Use the Content-Length HTTP header instead of "
|
||||
"Transfer-Encoding header", DEFAULT_USE_CONTENT_LENGTH,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_CONTENT_TYPE,
|
||||
g_param_spec_string ("content-type", "Content type",
|
||||
"The mime type of the body of the request", NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_curl_http_sink_init (GstCurlHttpSink * sink)
|
||||
{
|
||||
sink->header_list = NULL;
|
||||
sink->use_content_length = DEFAULT_USE_CONTENT_LENGTH;
|
||||
sink->content_type = NULL;
|
||||
|
||||
sink->proxy_port = DEFAULT_PROXY_PORT;
|
||||
sink->proxy_headers_set = FALSE;
|
||||
sink->proxy_auth = FALSE;
|
||||
sink->use_proxy = FALSE;
|
||||
sink->proxy_conn_established = FALSE;
|
||||
sink->proxy_resp = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_curl_http_sink_finalize (GObject * gobject)
|
||||
{
|
||||
GstCurlHttpSink *this = GST_CURL_HTTP_SINK (gobject);
|
||||
|
||||
GST_DEBUG ("finalizing curlhttpsink");
|
||||
g_free (this->proxy);
|
||||
g_free (this->proxy_user);
|
||||
g_free (this->proxy_passwd);
|
||||
g_free (this->content_type);
|
||||
|
||||
if (this->header_list) {
|
||||
curl_slist_free_all (this->header_list);
|
||||
this->header_list = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_curl_http_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstCurlHttpSink *sink;
|
||||
GstState cur_state;
|
||||
|
||||
g_return_if_fail (GST_IS_CURL_HTTP_SINK (object));
|
||||
sink = GST_CURL_HTTP_SINK (object);
|
||||
|
||||
gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0);
|
||||
if (cur_state != GST_STATE_PLAYING && cur_state != GST_STATE_PAUSED) {
|
||||
GST_OBJECT_LOCK (sink);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_PROXY:
|
||||
g_free (sink->proxy);
|
||||
sink->proxy = g_value_dup_string (value);
|
||||
GST_DEBUG_OBJECT (sink, "proxy set to %s", sink->proxy);
|
||||
break;
|
||||
case PROP_PROXY_PORT:
|
||||
sink->proxy_port = g_value_get_int (value);
|
||||
GST_DEBUG_OBJECT (sink, "proxy port set to %d", sink->proxy_port);
|
||||
break;
|
||||
case PROP_PROXY_USER_NAME:
|
||||
g_free (sink->proxy_user);
|
||||
sink->proxy_user = g_value_dup_string (value);
|
||||
GST_DEBUG_OBJECT (sink, "proxy user set to %s", sink->proxy_user);
|
||||
break;
|
||||
case PROP_PROXY_USER_PASSWD:
|
||||
g_free (sink->proxy_passwd);
|
||||
sink->proxy_passwd = g_value_dup_string (value);
|
||||
GST_DEBUG_OBJECT (sink, "proxy password set to %s", sink->proxy_passwd);
|
||||
break;
|
||||
case PROP_USE_CONTENT_LENGTH:
|
||||
sink->use_content_length = g_value_get_boolean (value);
|
||||
GST_DEBUG_OBJECT (sink, "use_content_length set to %d",
|
||||
sink->use_content_length);
|
||||
break;
|
||||
case PROP_CONTENT_TYPE:
|
||||
g_free (sink->content_type);
|
||||
sink->content_type = g_value_dup_string (value);
|
||||
GST_DEBUG_OBJECT (sink, "content type set to %s", sink->content_type);
|
||||
break;
|
||||
default:
|
||||
GST_DEBUG_OBJECT (sink, "invalid property id %d", prop_id);
|
||||
break;
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (sink);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* in PLAYING or PAUSED state */
|
||||
GST_OBJECT_LOCK (sink);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_CONTENT_TYPE:
|
||||
g_free (sink->content_type);
|
||||
sink->content_type = g_value_dup_string (value);
|
||||
GST_DEBUG_OBJECT (sink, "content type set to %s", sink->content_type);
|
||||
break;
|
||||
default:
|
||||
GST_WARNING_OBJECT (sink, "cannot set property when PLAYING");
|
||||
break;
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (sink);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_curl_http_sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstCurlHttpSink *sink;
|
||||
|
||||
g_return_if_fail (GST_IS_CURL_HTTP_SINK (object));
|
||||
sink = GST_CURL_HTTP_SINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_PROXY:
|
||||
g_value_set_string (value, sink->proxy);
|
||||
break;
|
||||
case PROP_PROXY_PORT:
|
||||
g_value_set_int (value, sink->proxy_port);
|
||||
break;
|
||||
case PROP_PROXY_USER_NAME:
|
||||
g_value_set_string (value, sink->proxy_user);
|
||||
break;
|
||||
case PROP_PROXY_USER_PASSWD:
|
||||
g_value_set_string (value, sink->proxy_passwd);
|
||||
break;
|
||||
case PROP_USE_CONTENT_LENGTH:
|
||||
g_value_set_boolean (value, sink->use_content_length);
|
||||
break;
|
||||
case PROP_CONTENT_TYPE:
|
||||
g_value_set_string (value, sink->content_type);
|
||||
break;
|
||||
default:
|
||||
GST_DEBUG_OBJECT (sink, "invalid property id");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_curl_http_sink_set_header_unlocked (GstCurlBaseSink * bcsink)
|
||||
{
|
||||
GstCurlHttpSink *sink = GST_CURL_HTTP_SINK (bcsink);
|
||||
gchar *tmp;
|
||||
|
||||
if (sink->header_list) {
|
||||
curl_slist_free_all (sink->header_list);
|
||||
sink->header_list = NULL;
|
||||
}
|
||||
|
||||
if (!sink->proxy_headers_set && sink->use_proxy) {
|
||||
sink->header_list = curl_slist_append (sink->header_list,
|
||||
"Content-Length: 0");
|
||||
sink->proxy_headers_set = TRUE;
|
||||
goto set_headers;
|
||||
}
|
||||
|
||||
if (sink->use_content_length) {
|
||||
/* if content length is used we assume that every buffer is one
|
||||
* entire file, which is the case when uploading several jpegs */
|
||||
tmp =
|
||||
g_strdup_printf ("Content-Length: %d", (int) bcsink->transfer_buf->len);
|
||||
sink->header_list = curl_slist_append (sink->header_list, tmp);
|
||||
g_free (tmp);
|
||||
} else {
|
||||
/* when sending a POST request to a HTTP 1.1 server, you can send data
|
||||
* without knowing the size before starting the POST if you use chunked
|
||||
* encoding */
|
||||
sink->header_list = curl_slist_append (sink->header_list,
|
||||
"Transfer-Encoding: chunked");
|
||||
}
|
||||
|
||||
tmp = g_strdup_printf ("Content-Type: %s", sink->content_type);
|
||||
sink->header_list = curl_slist_append (sink->header_list, tmp);
|
||||
g_free (tmp);
|
||||
|
||||
set_headers:
|
||||
|
||||
tmp = g_strdup_printf ("Content-Disposition: attachment; filename="
|
||||
"\"%s\"", bcsink->file_name);
|
||||
sink->header_list = curl_slist_append (sink->header_list, tmp);
|
||||
g_free (tmp);
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_HTTPHEADER, sink->header_list);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_curl_http_sink_set_options_unlocked (GstCurlBaseSink * bcsink)
|
||||
{
|
||||
GstCurlHttpSink *sink = GST_CURL_HTTP_SINK (bcsink);
|
||||
GstCurlTlsSinkClass *parent_class;
|
||||
|
||||
/* proxy settings */
|
||||
if (sink->proxy != NULL && strlen (sink->proxy)) {
|
||||
if (!proxy_setup (bcsink)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_POST, 1L);
|
||||
|
||||
/* FIXME: check user & passwd */
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
|
||||
|
||||
parent_class = GST_CURL_TLS_SINK_GET_CLASS (sink);
|
||||
|
||||
if (g_str_has_prefix (bcsink->url, "https://")) {
|
||||
return parent_class->set_options_unlocked (bcsink);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_curl_http_sink_transfer_verify_response_code (GstCurlBaseSink * bcsink)
|
||||
{
|
||||
GstCurlHttpSink *sink = GST_CURL_HTTP_SINK (bcsink);
|
||||
glong resp;
|
||||
|
||||
curl_easy_getinfo (bcsink->curl, CURLINFO_RESPONSE_CODE, &resp);
|
||||
GST_DEBUG_OBJECT (sink, "response code: %ld", resp);
|
||||
|
||||
if (resp < 100 || resp >= 300) {
|
||||
GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
|
||||
("HTTP response error: (received: %ld)", resp), (NULL));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_curl_http_sink_transfer_prepare_poll_wait (GstCurlBaseSink * bcsink)
|
||||
{
|
||||
GstCurlHttpSink *sink = GST_CURL_HTTP_SINK (bcsink);
|
||||
|
||||
if (!sink->proxy_conn_established
|
||||
&& (sink->proxy_resp != RESPONSE_CONNECT_PROXY)
|
||||
&& sink->proxy_auth) {
|
||||
curl_easy_getinfo (bcsink->curl, CURLINFO_HTTP_CONNECTCODE,
|
||||
&sink->proxy_resp);
|
||||
if ((sink->proxy_resp == RESPONSE_CONNECT_PROXY)) {
|
||||
GST_LOG ("received HTTP/1.0 200 Connection Established");
|
||||
/* Workaround: redefine HTTP headers before connecting to HTTP server.
|
||||
* When talking to proxy, the Content-Length: 0 is send with the request.
|
||||
*/
|
||||
curl_multi_remove_handle (bcsink->multi_handle, bcsink->curl);
|
||||
gst_curl_http_sink_set_header_unlocked (bcsink);
|
||||
curl_multi_add_handle (bcsink->multi_handle, bcsink->curl);
|
||||
sink->proxy_conn_established = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME check this: why critical when no mime is set???
|
||||
static void
|
||||
gst_curl_http_sink_set_mime_type (GstCurlBaseSink * bcsink, GstCaps * caps)
|
||||
{
|
||||
GstCurlHttpSink *sink = GST_CURL_HTTP_SINK (bcsink);
|
||||
GstStructure *structure;
|
||||
const gchar *mime_type;
|
||||
|
||||
if (sink->content_type != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
mime_type = gst_structure_get_name (structure);
|
||||
sink->content_type = g_strdup (mime_type);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
proxy_setup (GstCurlBaseSink * bcsink)
|
||||
{
|
||||
GstCurlHttpSink *sink = GST_CURL_HTTP_SINK (bcsink);
|
||||
|
||||
if (curl_easy_setopt (bcsink->curl, CURLOPT_PROXY, sink->proxy)
|
||||
!= CURLE_OK) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (curl_easy_setopt (bcsink->curl, CURLOPT_PROXYPORT, sink->proxy_port)
|
||||
!= CURLE_OK) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (sink->proxy_user != NULL &&
|
||||
strlen (sink->proxy_user) &&
|
||||
sink->proxy_passwd != NULL && strlen (sink->proxy_passwd)) {
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_PROXYUSERNAME, sink->proxy_user);
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_PROXYPASSWORD, sink->proxy_passwd);
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
||||
sink->proxy_auth = TRUE;
|
||||
}
|
||||
|
||||
if (g_str_has_prefix (bcsink->url, "https://")) {
|
||||
/* tunnel all operations through a given HTTP proxy */
|
||||
if (curl_easy_setopt (bcsink->curl, CURLOPT_HTTPPROXYTUNNEL, 1L)
|
||||
!= CURLE_OK) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
sink->use_proxy = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
69
ext/curl/gstcurlhttpsink.h
Normal file
69
ext/curl/gstcurlhttpsink.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2011 Axis Communications <dev-gstreamer@axis.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CURL_HTTP_SINK__
|
||||
#define __GST_CURL_HTTP_SINK__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesink.h>
|
||||
#include <curl/curl.h>
|
||||
#include "gstcurltlssink.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
#define GST_TYPE_CURL_HTTP_SINK \
|
||||
(gst_curl_http_sink_get_type())
|
||||
#define GST_CURL_HTTP_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CURL_HTTP_SINK, GstCurlHttpSink))
|
||||
#define GST_CURL_HTTP_SINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CURL_HTTP_SINK, GstCurlHttpSinkClass))
|
||||
#define GST_IS_CURL_HTTP_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_CURL_HTTP_SINK))
|
||||
#define GST_IS_CURL_HTTP_SINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_CURL_HTTP_SINK))
|
||||
typedef struct _GstCurlHttpSink GstCurlHttpSink;
|
||||
typedef struct _GstCurlHttpSinkClass GstCurlHttpSinkClass;
|
||||
|
||||
struct _GstCurlHttpSink
|
||||
{
|
||||
GstCurlTlsSink parent;
|
||||
|
||||
/*< private > */
|
||||
struct curl_slist *header_list;
|
||||
gchar *proxy;
|
||||
guint proxy_port;
|
||||
gchar *proxy_user;
|
||||
gchar *proxy_passwd;
|
||||
gboolean use_content_length;
|
||||
gchar *content_type;
|
||||
gboolean use_proxy;
|
||||
gboolean proxy_headers_set;
|
||||
gboolean proxy_auth;
|
||||
gboolean proxy_conn_established;
|
||||
glong proxy_resp;
|
||||
};
|
||||
|
||||
struct _GstCurlHttpSinkClass
|
||||
{
|
||||
GstCurlTlsSinkClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_curl_http_sink_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
#endif
|
|
@ -1,100 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2011 Axis Communications <dev-gstreamer@axis.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CURL_SINK__
|
||||
#define __GST_CURL_SINK__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesink.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_CURL_SINK \
|
||||
(gst_curl_sink_get_type())
|
||||
#define GST_CURL_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CURL_SINK, GstCurlSink))
|
||||
#define GST_CURL_SINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CURL_SINK, GstCurlSinkClass))
|
||||
#define GST_IS_CURL_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_CURL_SINK))
|
||||
#define GST_IS_CURL_SINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_CURL_SINK))
|
||||
|
||||
typedef struct _GstCurlSink GstCurlSink;
|
||||
typedef struct _GstCurlSinkClass GstCurlSinkClass;
|
||||
|
||||
typedef struct _TransferBuffer TransferBuffer;
|
||||
typedef struct _TransferCondition TransferCondition;
|
||||
|
||||
struct _TransferBuffer {
|
||||
guint8 *ptr;
|
||||
size_t len;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
struct _TransferCondition {
|
||||
GCond *cond;
|
||||
gboolean data_sent;
|
||||
gboolean data_available;
|
||||
};
|
||||
|
||||
struct _GstCurlSink
|
||||
{
|
||||
GstBaseSink parent;
|
||||
|
||||
/*< private >*/
|
||||
CURLM *multi_handle;
|
||||
CURL *curl;
|
||||
struct curl_slist *header_list;
|
||||
GstPollFD fd;
|
||||
GstPoll *fdset;
|
||||
GThread *transfer_thread;
|
||||
GstFlowReturn flow_ret;
|
||||
TransferBuffer *transfer_buf;
|
||||
TransferCondition *transfer_cond;
|
||||
gint num_buffers_per_packet;
|
||||
gint timeout;
|
||||
gchar *url;
|
||||
gchar *user;
|
||||
gchar *passwd;
|
||||
gchar *proxy;
|
||||
guint proxy_port;
|
||||
gchar *proxy_user;
|
||||
gchar *proxy_passwd;
|
||||
gchar *file_name;
|
||||
guint qos_dscp;
|
||||
gboolean accept_self_signed;
|
||||
gboolean use_content_length;
|
||||
gboolean transfer_thread_close;
|
||||
gboolean new_file;
|
||||
gchar *content_type;
|
||||
gboolean proxy_headers_set;
|
||||
};
|
||||
|
||||
struct _GstCurlSinkClass
|
||||
{
|
||||
GstBaseSinkClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_curl_sink_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
279
ext/curl/gstcurltlssink.c
Normal file
279
ext/curl/gstcurltlssink.c
Normal file
|
@ -0,0 +1,279 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2011 Axis Communications <dev-gstreamer@axis.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:element-curltlssink
|
||||
* @short_description: sink that uploads data to a server using libcurl
|
||||
* @see_also:
|
||||
*
|
||||
* This is a network sink that uses libcurl.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "gstcurlbasesink.h"
|
||||
#include "gstcurltlssink.h"
|
||||
|
||||
/* Default values */
|
||||
#define GST_CAT_DEFAULT gst_curl_tls_sink_debug
|
||||
#define DEFAULT_INSECURE TRUE
|
||||
|
||||
|
||||
/* Plugin specific settings */
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_curl_tls_sink_debug);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_CA_CERT,
|
||||
PROP_CA_PATH,
|
||||
PROP_CRYPTO_ENGINE,
|
||||
PROP_INSECURE
|
||||
};
|
||||
|
||||
|
||||
/* Object class function declarations */
|
||||
|
||||
static void gst_curl_tls_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_curl_tls_sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void gst_curl_tls_sink_finalize (GObject * gobject);
|
||||
static gboolean gst_curl_tls_sink_set_options_unlocked
|
||||
(GstCurlBaseSink * bcsink);
|
||||
|
||||
#define gst_curl_tls_sink_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstCurlTlsSink, gst_curl_tls_sink, GST_TYPE_CURL_BASE_SINK);
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
gst_curl_tls_sink_class_init (GstCurlTlsSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_curl_tls_sink_debug, "curltlssink", 0,
|
||||
"curl tls sink element");
|
||||
GST_DEBUG_OBJECT (klass, "class_init");
|
||||
|
||||
gst_element_class_set_details_simple (element_class,
|
||||
"Curl tls sink",
|
||||
"Sink/Network",
|
||||
"Upload data over TLS protocol using libcurl",
|
||||
"Patricia Muscalu <patricia@axis.com>");
|
||||
|
||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_curl_tls_sink_finalize);
|
||||
|
||||
gobject_class->set_property = gst_curl_tls_sink_set_property;
|
||||
gobject_class->get_property = gst_curl_tls_sink_get_property;
|
||||
|
||||
klass->set_options_unlocked = gst_curl_tls_sink_set_options_unlocked;
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_CA_CERT,
|
||||
g_param_spec_string ("ca-cert",
|
||||
"CA certificate",
|
||||
"CA certificate to use in order to verify the peer",
|
||||
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_CA_PATH,
|
||||
g_param_spec_string ("ca-path",
|
||||
"CA path",
|
||||
"CA directory path to use in order to verify the peer",
|
||||
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_CRYPTO_ENGINE,
|
||||
g_param_spec_string ("crypto-engine",
|
||||
"OpenSSL crypto engine",
|
||||
"OpenSSL crytpo engine to use for cipher operations",
|
||||
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_INSECURE,
|
||||
g_param_spec_boolean ("insecure",
|
||||
"Perform insecure SSL connections",
|
||||
"Allow curl to perform insecure SSL connections",
|
||||
DEFAULT_INSECURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_curl_tls_sink_init (GstCurlTlsSink * sink)
|
||||
{
|
||||
sink->ca_cert = NULL;
|
||||
sink->ca_path = NULL;
|
||||
sink->crypto_engine = NULL;
|
||||
sink->insecure = DEFAULT_INSECURE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_curl_tls_sink_finalize (GObject * gobject)
|
||||
{
|
||||
GstCurlTlsSink *this = GST_CURL_TLS_SINK (gobject);
|
||||
|
||||
GST_DEBUG ("finalizing curltlssink");
|
||||
|
||||
g_free (this->ca_cert);
|
||||
g_free (this->ca_path);
|
||||
g_free (this->crypto_engine);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_curl_tls_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstCurlTlsSink *sink;
|
||||
GstState cur_state;
|
||||
|
||||
g_return_if_fail (GST_IS_CURL_TLS_SINK (object));
|
||||
sink = GST_CURL_TLS_SINK (object);
|
||||
|
||||
gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0);
|
||||
if (cur_state != GST_STATE_PLAYING && cur_state != GST_STATE_PAUSED) {
|
||||
GST_OBJECT_LOCK (sink);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_CA_CERT:
|
||||
g_free (sink->ca_cert);
|
||||
sink->ca_cert = g_value_dup_string (value);
|
||||
sink->insecure = FALSE;
|
||||
GST_DEBUG_OBJECT (sink, "ca_cert set to %s", sink->ca_cert);
|
||||
break;
|
||||
case PROP_CA_PATH:
|
||||
g_free (sink->ca_path);
|
||||
sink->ca_path = g_value_dup_string (value);
|
||||
sink->insecure = FALSE;
|
||||
GST_DEBUG_OBJECT (sink, "ca_path set to %s", sink->ca_path);
|
||||
break;
|
||||
case PROP_CRYPTO_ENGINE:
|
||||
g_free (sink->crypto_engine);
|
||||
sink->crypto_engine = g_value_dup_string (value);
|
||||
GST_DEBUG_OBJECT (sink, "crypto_engine set to %s", sink->crypto_engine);
|
||||
break;
|
||||
case PROP_INSECURE:
|
||||
sink->insecure = g_value_get_boolean (value);
|
||||
GST_DEBUG_OBJECT (sink, "insecure set to %d", sink->insecure);
|
||||
break;
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (sink);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (sink);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_curl_tls_sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstCurlTlsSink *sink;
|
||||
|
||||
g_return_if_fail (GST_IS_CURL_TLS_SINK (object));
|
||||
sink = GST_CURL_TLS_SINK (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_CA_CERT:
|
||||
g_value_set_string (value, sink->ca_cert);
|
||||
break;
|
||||
case PROP_CA_PATH:
|
||||
g_value_set_string (value, sink->ca_path);
|
||||
break;
|
||||
case PROP_CRYPTO_ENGINE:
|
||||
g_value_set_string (value, sink->crypto_engine);
|
||||
break;
|
||||
case PROP_INSECURE:
|
||||
g_value_set_boolean (value, sink->insecure);
|
||||
break;
|
||||
default:
|
||||
GST_DEBUG_OBJECT (sink, "invalid property id");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_curl_tls_sink_set_options_unlocked (GstCurlBaseSink * bcsink)
|
||||
{
|
||||
GstCurlTlsSink *sink = GST_CURL_TLS_SINK (bcsink);
|
||||
|
||||
if (!g_str_has_prefix (bcsink->url, "http")) {
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_USE_SSL, 1L);
|
||||
}
|
||||
|
||||
/* crypto engine */
|
||||
if ((g_strcmp0 (sink->crypto_engine, "auto") == 0) ||
|
||||
(sink->crypto_engine == NULL)) {
|
||||
if (curl_easy_setopt (bcsink->curl, CURLOPT_SSLENGINE_DEFAULT, 1L)
|
||||
!= CURLE_OK) {
|
||||
GST_WARNING ("Error setting up default SSL engine.");
|
||||
}
|
||||
} else {
|
||||
if (curl_easy_setopt (bcsink->curl, CURLOPT_SSLENGINE,
|
||||
sink->crypto_engine) == CURLE_SSL_ENGINE_NOTFOUND) {
|
||||
GST_WARNING ("Error setting up SSL engine: %s.", sink->crypto_engine);
|
||||
}
|
||||
}
|
||||
|
||||
/* note that, using ca-path can allow libcurl to make SSL-connections much more
|
||||
* efficiently than using ca-cert if the ca-cert ile
|
||||
* contains many CA certificates. */
|
||||
if (sink->ca_cert != NULL && strlen (sink->ca_cert)) {
|
||||
GST_DEBUG ("setting ca cert");
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_CAINFO, sink->ca_cert);
|
||||
}
|
||||
|
||||
if (sink->ca_path != NULL && strlen (sink->ca_path)) {
|
||||
GST_DEBUG ("setting ca path");
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_CAPATH, sink->ca_path);
|
||||
}
|
||||
|
||||
if (!sink->insecure) {
|
||||
/* identify authenticity of the peer's certificate */
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||
/* when CURLOPT_SSL_VERIFYHOST is 2, the commonName or subjectAltName
|
||||
* fields are verified */
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_SSL_VERIFYHOST, 2L);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* allow "insecure" SSL connections and transfers */
|
||||
if (sink->insecure) {
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
curl_easy_setopt (bcsink->curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
66
ext/curl/gstcurltlssink.h
Normal file
66
ext/curl/gstcurltlssink.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2011 Axis Communications <dev-gstreamer@axis.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_CURL_TLS_SINK__
|
||||
#define __GST_CURL_TLS_SINK__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesink.h>
|
||||
#include <curl/curl.h>
|
||||
#include "gstcurlbasesink.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
#define GST_TYPE_CURL_TLS_SINK \
|
||||
(gst_curl_tls_sink_get_type())
|
||||
#define GST_CURL_TLS_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CURL_TLS_SINK, GstCurlTlsSink))
|
||||
#define GST_CURL_TLS_SINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CURL_TLS_SINK, GstCurlTlsSinkClass))
|
||||
#define GST_CURL_TLS_SINK_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CURL_TLS_SINK, GstCurlTlsSinkClass))
|
||||
#define GST_IS_CURL_TLS_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_CURL_TLS_SINK))
|
||||
#define GST_IS_CURL_TLS_SINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_CURL_TLS_SINK))
|
||||
typedef struct _GstCurlTlsSink GstCurlTlsSink;
|
||||
typedef struct _GstCurlTlsSinkClass GstCurlTlsSinkClass;
|
||||
|
||||
struct _GstCurlTlsSink
|
||||
{
|
||||
GstCurlBaseSink parent;
|
||||
|
||||
/*< private > */
|
||||
gchar *ca_cert;
|
||||
gchar *ca_path;
|
||||
gchar *crypto_engine;
|
||||
gboolean insecure;
|
||||
};
|
||||
|
||||
struct _GstCurlTlsSinkClass
|
||||
{
|
||||
GstCurlBaseSinkClass parent_class;
|
||||
|
||||
/* vmethods */
|
||||
gboolean (*set_options_unlocked) (GstCurlBaseSink * sink);
|
||||
};
|
||||
|
||||
GType gst_curl_tls_sink_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
#endif
|
|
@ -147,6 +147,12 @@ else
|
|||
check_opus =
|
||||
endif
|
||||
|
||||
if USE_CURL
|
||||
check_curl = elements/curlhttpsink
|
||||
else
|
||||
check_curl =
|
||||
endif
|
||||
|
||||
VALGRIND_TO_FIX = \
|
||||
elements/mpeg2enc \
|
||||
elements/mplex \
|
||||
|
@ -177,6 +183,7 @@ check_PROGRAMS = \
|
|||
$(check_timidity) \
|
||||
$(check_kate) \
|
||||
$(check_opus) \
|
||||
$(check_curl) \
|
||||
elements/autoconvert \
|
||||
elements/autovideoconvert \
|
||||
elements/asfmux \
|
||||
|
|
136
tests/check/elements/curlhttpsink.c
Normal file
136
tests/check/elements/curlhttpsink.c
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Unittest for curlhttpsink
|
||||
*/
|
||||
|
||||
#include <gst/check/gstcheck.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
static GstPad *srcpad;
|
||||
|
||||
static GstElement *sink;
|
||||
|
||||
static GstElement *
|
||||
setup_curlhttpsink (void)
|
||||
{
|
||||
GST_DEBUG ("setup_curlhttpsink");
|
||||
sink = gst_check_setup_element ("curlhttpsink");
|
||||
srcpad = gst_check_setup_src_pad (sink, &srctemplate);
|
||||
gst_pad_set_active (srcpad, TRUE);
|
||||
|
||||
return sink;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_curlhttpsink (GstElement * sink)
|
||||
{
|
||||
GST_DEBUG ("cleanup_curlhttpsink");
|
||||
|
||||
gst_check_teardown_src_pad (sink);
|
||||
gst_check_teardown_element (sink);
|
||||
}
|
||||
|
||||
|
||||
GST_START_TEST (test_properties)
|
||||
{
|
||||
GstElement *sink;
|
||||
gchar *res_location = NULL;
|
||||
gchar *res_file_name = NULL;
|
||||
gchar *res_user;
|
||||
gchar *res_passwd;
|
||||
gchar *res_proxy;
|
||||
guint res_proxy_port;
|
||||
gchar *res_proxy_user;
|
||||
gchar *res_proxy_passwd;
|
||||
gchar *res_content_type;
|
||||
gboolean res_use_content_length;
|
||||
|
||||
sink = setup_curlhttpsink ();
|
||||
|
||||
g_object_set (G_OBJECT (sink),
|
||||
"location", "mylocation",
|
||||
"file-name","myfile",
|
||||
"user", "user",
|
||||
"passwd", "passwd",
|
||||
"proxy", "myproxy",
|
||||
"proxy-port", 7777,
|
||||
"proxy-user", "proxy_user",
|
||||
"proxy-passwd", "proxy_passwd",
|
||||
"content-type", "image/jpeg",
|
||||
"use-content-length", TRUE,
|
||||
NULL);
|
||||
|
||||
g_object_get (sink,
|
||||
"location", &res_location,
|
||||
"file-name", &res_file_name,
|
||||
"user", &res_user,
|
||||
"passwd", &res_passwd,
|
||||
"proxy", &res_proxy,
|
||||
"proxy-port", &res_proxy_port,
|
||||
"proxy-user", &res_proxy_user,
|
||||
"proxy-passwd", &res_proxy_passwd,
|
||||
"content-type", &res_content_type,
|
||||
"use-content-length", &res_use_content_length,
|
||||
NULL);
|
||||
|
||||
fail_unless (strncmp (res_location, "mylocation", strlen ("mylocation"))
|
||||
== 0);
|
||||
fail_unless (strncmp (res_file_name, "myfile", strlen ("myfile"))
|
||||
== 0);
|
||||
fail_unless (strncmp (res_user, "user", strlen ("user")) == 0);
|
||||
fail_unless (strncmp (res_passwd, "passwd", strlen ("passwd")) == 0);
|
||||
fail_unless (strncmp (res_proxy, "myproxy", strlen ("myproxy")) == 0);
|
||||
fail_unless (res_proxy_port == 7777);
|
||||
fail_unless (strncmp (res_proxy_user, "proxy_user", strlen ("proxy_user"))
|
||||
== 0);
|
||||
fail_unless (strncmp (res_proxy_passwd, "proxy_passwd",
|
||||
strlen ("proxy_passwd")) == 0);
|
||||
fail_unless (strncmp (res_content_type, "image/jpeg", strlen ("image/jpeg"))
|
||||
== 0);
|
||||
fail_unless (res_use_content_length == TRUE);
|
||||
|
||||
g_free (res_location);
|
||||
g_free (res_file_name);
|
||||
g_free (res_user);
|
||||
g_free (res_passwd);
|
||||
g_free (res_proxy);
|
||||
g_free (res_proxy_user);
|
||||
g_free (res_proxy_passwd);
|
||||
g_free (res_content_type);
|
||||
|
||||
/* new properties */
|
||||
g_object_set (G_OBJECT (sink), "location", "newlocation", NULL);
|
||||
g_object_get (sink, "location", &res_location, NULL);
|
||||
fail_unless (strncmp (res_location, "newlocation", strlen ("newlocation"))
|
||||
== 0);
|
||||
g_free (res_location);
|
||||
|
||||
g_object_set (G_OBJECT (sink), "file-name", "newfile", NULL);
|
||||
g_object_get (sink, "file-name", &res_file_name, NULL);
|
||||
fail_unless (strncmp (res_file_name, "newfile", strlen ("newfile"))
|
||||
== 0);
|
||||
g_free (res_file_name);
|
||||
|
||||
cleanup_curlhttpsink (sink);
|
||||
}
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
curlsink_suite (void)
|
||||
{
|
||||
Suite *s = suite_create ("curlhttpsink");
|
||||
TCase *tc_chain = tcase_create ("general");
|
||||
|
||||
suite_add_tcase (s, tc_chain);
|
||||
tcase_set_timeout (tc_chain, 20);
|
||||
tcase_add_test (tc_chain, test_properties);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
GST_CHECK_MAIN (curlsink);
|
Loading…
Reference in a new issue