Properly report errors when setting the URI fails

This commit is contained in:
Sebastian Dröge 2016-08-23 00:07:44 +03:00
parent 3d83de761f
commit 82c29d369d
8 changed files with 95 additions and 41 deletions

View file

@ -62,24 +62,24 @@ impl FileSink {
} }
impl Sink for FileSink { impl Sink for FileSink {
fn set_uri(&self, uri: Option<Url>) -> bool { fn set_uri(&self, uri: Option<Url>) -> Result<(), (UriError, String)> {
let location = &mut self.settings.lock().unwrap().location; let location = &mut self.settings.lock().unwrap().location;
match uri { match uri {
None => { None => {
*location = None; *location = None;
true Ok(())
} }
Some(ref uri) => { Some(ref uri) => {
match uri.to_file_path().ok() { match uri.to_file_path().ok() {
Some(p) => { Some(p) => {
*location = Some(p); *location = Some(p);
true Ok(())
} }
None => { None => {
*location = None; *location = None;
println_err!("Unsupported file URI '{}'", uri.as_str()); Err((UriError::UnsupportedProtocol,
false format!("Unsupported file URI '{}'", uri.as_str())))
} }
} }
} }

View file

@ -63,24 +63,24 @@ impl FileSrc {
} }
impl Source for FileSrc { impl Source for FileSrc {
fn set_uri(&self, uri: Option<Url>) -> bool { fn set_uri(&self, uri: Option<Url>) -> Result<(), (UriError, String)> {
let location = &mut self.settings.lock().unwrap().location; let location = &mut self.settings.lock().unwrap().location;
match uri { match uri {
None => { None => {
*location = None; *location = None;
true Ok(())
} }
Some(ref uri) => { Some(ref uri) => {
match uri.to_file_path().ok() { match uri.to_file_path().ok() {
Some(p) => { Some(p) => {
*location = Some(p); *location = Some(p);
true Ok(())
} }
None => { None => {
*location = None; *location = None;
println_err!("Unsupported file URI '{}'", uri.as_str()); Err((UriError::UnsupportedProtocol,
false format!("Unsupported file URI '{}'", uri.as_str())))
} }
} }
} }

View file

@ -141,22 +141,22 @@ impl HttpSrc {
} }
impl Source for HttpSrc { impl Source for HttpSrc {
fn set_uri(&self, uri: Option<Url>) -> bool { fn set_uri(&self, uri: Option<Url>) -> Result<(), (UriError, String)> {
let url = &mut self.settings.lock().unwrap().url; let url = &mut self.settings.lock().unwrap().url;
match uri { match uri {
None => { None => {
*url = None; *url = None;
true Ok(())
} }
Some(uri) => { Some(uri) => {
if uri.scheme() == "http" || uri.scheme() == "https" { if uri.scheme() == "http" || uri.scheme() == "https" {
*url = Some(uri); *url = Some(uri);
true Ok(())
} else { } else {
*url = None; *url = None;
println_err!("Unsupported URI '{}'", uri.as_str()); Err((UriError::UnsupportedProtocol,
false format!("Unsupported URI '{}'", uri.as_str())))
} }
} }
} }

View file

@ -38,7 +38,7 @@ static GHashTable *sinks;
extern gboolean sinks_register (void *plugin); extern gboolean sinks_register (void *plugin);
extern void *sink_new (GstRsSink * sink, void *create_instance); extern void *sink_new (GstRsSink * sink, void *create_instance);
extern GstFlowReturn sink_render (void *rssink, void *data, size_t data_len); extern GstFlowReturn sink_render (void *rssink, void *data, size_t data_len);
extern gboolean sink_set_uri (void *rssink, const char *uri); extern gboolean sink_set_uri (void *rssink, const char *uri, GError ** err);
extern char *sink_get_uri (void *rssink); extern char *sink_get_uri (void *rssink);
extern gboolean sink_start (void *rssink); extern gboolean sink_start (void *rssink);
extern gboolean sink_stop (void *rssink); extern gboolean sink_stop (void *rssink);
@ -140,7 +140,7 @@ gst_rs_sink_set_property (GObject * object, guint prop_id,
switch (prop_id) { switch (prop_id) {
case PROP_URI: case PROP_URI:
sink_set_uri (sink->instance, g_value_get_string (value)); sink_set_uri (sink->instance, g_value_get_string (value), NULL);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -229,11 +229,8 @@ gst_rs_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri,
{ {
GstRsSink *sink = GST_RS_SINK (handler); GstRsSink *sink = GST_RS_SINK (handler);
if (!sink_set_uri (sink->instance, uri)) { if (!sink_set_uri (sink->instance, uri, err))
g_set_error (err, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
"Can't handle URI '%s'", uri);
return FALSE; return FALSE;
}
return TRUE; return TRUE;
} }

View file

@ -21,7 +21,6 @@ use std::os::raw::c_void;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::slice; use std::slice;
use std::ptr; use std::ptr;
use std::io::Write;
use url::Url; use url::Url;
@ -40,7 +39,7 @@ impl SinkController {
pub trait Sink: Sync + Send { pub trait Sink: Sync + Send {
// Called from any thread at any time // Called from any thread at any time
fn set_uri(&self, uri: Option<Url>) -> bool; fn set_uri(&self, uri: Option<Url>) -> Result<(), (UriError, String)>;
fn get_uri(&self) -> Option<Url>; fn get_uri(&self) -> Option<Url>;
// Called from the streaming thread only // Called from the streaming thread only
@ -62,19 +61,37 @@ pub unsafe extern "C" fn sink_drop(ptr: *mut Box<Sink>) {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn sink_set_uri(ptr: *mut Box<Sink>, uri_ptr: *const c_char) -> GBoolean { pub unsafe extern "C" fn sink_set_uri(ptr: *mut Box<Sink>,
uri_ptr: *const c_char,
cerr: *mut c_void)
-> GBoolean {
let sink: &mut Box<Sink> = &mut *ptr; let sink: &mut Box<Sink> = &mut *ptr;
if uri_ptr.is_null() { if uri_ptr.is_null() {
GBoolean::from_bool(sink.set_uri(None)) if let Err((code, msg)) = sink.set_uri(None) {
code.into_gerror(cerr, Some(&msg));
GBoolean::False
} else {
GBoolean::True
}
} else { } else {
let uri_str = CStr::from_ptr(uri_ptr).to_str().unwrap(); let uri_str = CStr::from_ptr(uri_ptr).to_str().unwrap();
match Url::parse(uri_str) { match Url::parse(uri_str) {
Ok(uri) => GBoolean::from_bool(sink.set_uri(Some(uri))), Ok(uri) => {
if let Err((code, msg)) = sink.set_uri(Some(uri)) {
code.into_gerror(cerr, Some(&msg));
GBoolean::False
} else {
GBoolean::True
}
}
Err(err) => { Err(err) => {
sink.set_uri(None); let _ = sink.set_uri(None);
println_err!("Failed to parse URI '{}': {}", uri_str, err); UriError::BadUri.into_gerror(cerr,
Some(&format!("Failed to parse URI '{}': {}",
uri_str,
err)));
GBoolean::False GBoolean::False
} }
} }

View file

@ -39,7 +39,7 @@ extern void source_drop (void *rssource);
extern GstFlowReturn source_fill (void *rssource, extern GstFlowReturn source_fill (void *rssource,
uint64_t offset, void *data, size_t * data_len); uint64_t offset, void *data, size_t * data_len);
extern gboolean source_do_seek (void *rssource, uint64_t start, uint64_t stop); extern gboolean source_do_seek (void *rssource, uint64_t start, uint64_t stop);
extern gboolean source_set_uri (void *rssource, const char *uri); extern gboolean source_set_uri (void *rssource, const char *uri, GError ** err);
extern char *source_get_uri (void *rssource); extern char *source_get_uri (void *rssource);
extern uint64_t source_get_size (void *rssource); extern uint64_t source_get_size (void *rssource);
extern gboolean source_is_seekable (void *rssource); extern gboolean source_is_seekable (void *rssource);
@ -149,7 +149,7 @@ gst_rs_src_set_property (GObject * object, guint prop_id,
switch (prop_id) { switch (prop_id) {
case PROP_URI: case PROP_URI:
source_set_uri (src->instance, g_value_get_string (value)); source_set_uri (src->instance, g_value_get_string (value), NULL);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -274,11 +274,8 @@ gst_rs_src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
{ {
GstRsSrc *src = GST_RS_SRC (handler); GstRsSrc *src = GST_RS_SRC (handler);
if (!source_set_uri (src->instance, uri)) { if (!source_set_uri (src->instance, uri, err))
g_set_error (err, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
"Can't handle URI '%s'", uri);
return FALSE; return FALSE;
}
return TRUE; return TRUE;
} }

View file

@ -20,7 +20,6 @@ use std::os::raw::c_void;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::slice; use std::slice;
use std::ptr; use std::ptr;
use std::io::Write;
use url::Url; use url::Url;
@ -39,7 +38,7 @@ impl SourceController {
pub trait Source: Sync + Send { pub trait Source: Sync + Send {
// Called from any thread at any time // Called from any thread at any time
fn set_uri(&self, uri: Option<Url>) -> bool; fn set_uri(&self, uri: Option<Url>) -> Result<(), (UriError, String)>;
fn get_uri(&self) -> Option<Url>; fn get_uri(&self) -> Option<Url>;
// Called from any thread between start/stop // Called from any thread between start/stop
@ -66,19 +65,37 @@ pub unsafe extern "C" fn source_drop(ptr: *mut Box<Source>) {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn source_set_uri(ptr: *mut Box<Source>, uri_ptr: *const c_char) -> GBoolean { pub unsafe extern "C" fn source_set_uri(ptr: *mut Box<Source>,
uri_ptr: *const c_char,
cerr: *mut c_void)
-> GBoolean {
let source: &mut Box<Source> = &mut *ptr; let source: &mut Box<Source> = &mut *ptr;
if uri_ptr.is_null() { if uri_ptr.is_null() {
GBoolean::from_bool(source.set_uri(None)) if let Err((code, msg)) = source.set_uri(None) {
code.into_gerror(cerr, Some(&msg));
GBoolean::False
} else {
GBoolean::True
}
} else { } else {
let uri_str = CStr::from_ptr(uri_ptr).to_str().unwrap(); let uri_str = CStr::from_ptr(uri_ptr).to_str().unwrap();
match Url::parse(uri_str) { match Url::parse(uri_str) {
Ok(uri) => GBoolean::from_bool(source.set_uri(Some(uri))), Ok(uri) => {
if let Err((code, msg)) = source.set_uri(Some(uri)) {
code.into_gerror(cerr, Some(&msg));
GBoolean::False
} else {
GBoolean::True
}
}
Err(err) => { Err(err) => {
source.set_uri(None); let _ = source.set_uri(None);
println_err!("Failed to parse URI '{}': {}", uri_str, err); UriError::BadUri.into_gerror(cerr,
Some(&format!("Failed to parse URI '{}': {}",
uri_str,
err)));
GBoolean::False GBoolean::False
} }
} }

View file

@ -17,7 +17,9 @@
// //
// //
use libc::c_char; use libc::c_char;
use std::os::raw::c_void;
use std::ffi::CString; use std::ffi::CString;
use std::ptr;
#[macro_export] #[macro_export]
macro_rules! println_err( macro_rules! println_err(
@ -54,3 +56,27 @@ impl GBoolean {
pub unsafe extern "C" fn cstring_drop(ptr: *mut c_char) { pub unsafe extern "C" fn cstring_drop(ptr: *mut c_char) {
CString::from_raw(ptr); CString::from_raw(ptr);
} }
#[repr(C)]
pub enum UriError {
UnsupportedProtocol = 0,
BadUri,
BadState,
BadReference,
}
extern "C" {
fn g_set_error_literal(err: *mut c_void, domain: u32, code: i32, message: *const c_char);
fn gst_uri_error_quark() -> u32;
}
impl UriError {
pub unsafe fn into_gerror(self, err: *mut c_void, message: Option<&String>) {
if let Some(msg) = message {
let cmsg = CString::new(msg.as_str()).unwrap();
g_set_error_literal(err, gst_uri_error_quark(), self as i32, cmsg.as_ptr());
} else {
g_set_error_literal(err, gst_uri_error_quark(), self as i32, ptr::null());
}
}
}