From 29241c4f835797f635816a9f37528aa981f722b5 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Fri, 16 Sep 2011 21:06:12 +0200
Subject: input_plugin: add method check()

To check for errors without reading.  The decoder thread wants to do
that, before it passes the input stream to the plugin.
---
 src/input/curl_input_plugin.c   | 18 ++++++++++++++++++
 src/input/rewind_input_plugin.c |  9 +++++++++
 src/input/soup_input_plugin.c   | 18 ++++++++++++++++++
 src/input_plugin.h              |  8 ++++++++
 src/input_stream.c              | 10 ++++++++++
 src/input_stream.h              |  9 +++++++++
 test/run_input.c                |  6 ++++++
 7 files changed, 78 insertions(+)

diff --git a/src/input/curl_input_plugin.c b/src/input/curl_input_plugin.c
index 824fc9bad..4f3e9c6e4 100644
--- a/src/input/curl_input_plugin.c
+++ b/src/input/curl_input_plugin.c
@@ -774,6 +774,23 @@ input_curl_free(struct input_curl *c)
 	g_free(c);
 }
 
+static bool
+input_curl_check(struct input_stream *is, GError **error_r)
+{
+	struct input_curl *c = (struct input_curl *)is;
+
+	g_mutex_lock(c->mutex);
+
+	bool success = c->postponed_error == NULL;
+	if (!success) {
+		g_propagate_error(error_r, c->postponed_error);
+		c->postponed_error = NULL;
+	}
+
+	g_mutex_unlock(c->mutex);
+	return success;
+}
+
 static struct tag *
 input_curl_tag(struct input_stream *is)
 {
@@ -1318,6 +1335,7 @@ const struct input_plugin input_plugin_curl = {
 
 	.open = input_curl_open,
 	.close = input_curl_close,
+	.check = input_curl_check,
 	.tag = input_curl_tag,
 	.buffer = input_curl_buffer,
 	.read = input_curl_read,
diff --git a/src/input/rewind_input_plugin.c b/src/input/rewind_input_plugin.c
index fa2065d61..2a3eecf82 100644
--- a/src/input/rewind_input_plugin.c
+++ b/src/input/rewind_input_plugin.c
@@ -107,6 +107,14 @@ input_rewind_close(struct input_stream *is)
 	g_free(r);
 }
 
+static bool
+input_rewind_check(struct input_stream *is, GError **error_r)
+{
+	struct input_rewind *r = (struct input_rewind *)is;
+
+	return input_stream_check(r->input, error_r);
+}
+
 static void
 input_rewind_update(struct input_stream *is)
 {
@@ -221,6 +229,7 @@ input_rewind_seek(struct input_stream *is, goffset offset, int whence,
 
 static const struct input_plugin rewind_input_plugin = {
 	.close = input_rewind_close,
+	.check = input_rewind_check,
 	.update = input_rewind_update,
 	.tag = input_rewind_tag,
 	.buffer = input_rewind_buffer,
diff --git a/src/input/soup_input_plugin.c b/src/input/soup_input_plugin.c
index ff73da559..23665c1a2 100644
--- a/src/input/soup_input_plugin.c
+++ b/src/input/soup_input_plugin.c
@@ -320,6 +320,23 @@ input_soup_close(struct input_stream *is)
 	g_free(s);
 }
 
+static bool
+input_soup_check(struct input_stream *is, GError **error_r)
+{
+	struct input_soup *s = (struct input_soup *)is;
+
+	g_mutex_lock(s->mutex);
+
+	bool success = s->postponed_error == NULL;
+	if (!success) {
+		g_propagate_error(error_r, s->postponed_error);
+		s->postponed_error = NULL;
+	}
+
+	g_mutex_unlock(s->mutex);
+	return success;
+}
+
 static int
 input_soup_buffer(struct input_stream *is, GError **error_r)
 {
@@ -444,6 +461,7 @@ const struct input_plugin input_plugin_soup = {
 
 	.open = input_soup_open,
 	.close = input_soup_close,
+	.check = input_soup_check,
 	.buffer = input_soup_buffer,
 	.read = input_soup_read,
 	.eof = input_soup_eof,
diff --git a/src/input_plugin.h b/src/input_plugin.h
index 3ac0bdf40..4e0993d12 100644
--- a/src/input_plugin.h
+++ b/src/input_plugin.h
@@ -51,6 +51,14 @@ struct input_plugin {
 	struct input_stream *(*open)(const char *uri, GError **error_r);
 	void (*close)(struct input_stream *is);
 
+	/**
+	 * Check for errors that may have occurred in the I/O thread.
+	 * May be unimplemented for synchronous plugins.
+	 *
+	 * @return false on error
+	 */
+	bool (*check)(struct input_stream *is, GError **error_r);
+
 	/**
 	 * Update the public attributes.  Call before access.  Can be
 	 * NULL if the plugin always keeps its attributes up to date.
diff --git a/src/input_stream.c b/src/input_stream.c
index 44ab7159f..164df9860 100644
--- a/src/input_stream.c
+++ b/src/input_stream.c
@@ -67,6 +67,16 @@ input_stream_open(const char *url, GError **error_r)
 	return NULL;
 }
 
+bool
+input_stream_check(struct input_stream *is, GError **error_r)
+{
+	assert(is != NULL);
+	assert(is->plugin != NULL);
+
+	return is->plugin->check == NULL ||
+		is->plugin->check(is, error_r);
+}
+
 void
 input_stream_update(struct input_stream *is)
 {
diff --git a/src/input_stream.h b/src/input_stream.h
index 2901f6ea6..7866562ae 100644
--- a/src/input_stream.h
+++ b/src/input_stream.h
@@ -90,6 +90,15 @@ gcc_nonnull(1)
 void
 input_stream_close(struct input_stream *is);
 
+/**
+ * Check for errors that may have occurred in the I/O thread.
+ *
+ * @return false on error
+ */
+gcc_nonnull(1)
+bool
+input_stream_check(struct input_stream *is, GError **error_r);
+
 /**
  * Update the public attributes.  Call before accessing attributes
  * such as "ready" or "offset".
diff --git a/test/run_input.c b/test/run_input.c
index c00698dff..651d36480 100644
--- a/test/run_input.c
+++ b/test/run_input.c
@@ -100,6 +100,12 @@ dump_input_stream(struct input_stream *is)
 			break;
 	}
 
+	if (!input_stream_check(is, &error)) {
+		g_warning("%s", error->message);
+		g_error_free(error);
+		return EXIT_FAILURE;
+	}
+
 	return 0;
 }
 
-- 
cgit v1.2.3