diff -upNar gst-plugins-bad.orig/configure.ac gst-plugins-bad.new/configure.ac
--- gst-plugins-bad.orig/configure.ac	2008-01-29 08:38:25.000000000 +0100
+++ gst-plugins-bad.new/configure.ac	2008-01-29 22:21:43.000000000 +0100
@@ -822,8 +822,8 @@ AG_GST_CHECK_FEATURE(NEON, [neon http cl
 
 dnl *** soup ***
 translit(dnm, m, l) AM_CONDITIONAL(USE_SOUP, true)
-AG_GST_CHECK_FEATURE(SOUP, [soup http client plugins], souphttpsrc, [
-  PKG_CHECK_MODULES(SOUP, libsoup-2.2 >= 2.2.104, HAVE_SOUP="yes", [
+AG_GST_CHECK_FEATURE(SOUP, [soup http client plugin (2.4)], souphttpsrc, [
+  PKG_CHECK_MODULES(SOUP, libsoup-2.4, HAVE_SOUP="yes", [
     HAVE_SOUP="no"
     AC_MSG_RESULT(no)
   ])
diff -upNar gst-plugins-bad.orig/docs/plugins/Makefile.am gst-plugins-bad.new/docs/plugins/Makefile.am
--- gst-plugins-bad.orig/docs/plugins/Makefile.am	2008-01-29 08:38:25.000000000 +0100
+++ gst-plugins-bad.new/docs/plugins/Makefile.am	2008-01-29 22:21:43.000000000 +0100
@@ -103,6 +103,7 @@ EXTRA_HFILES = \
 	$(top_srcdir)/ext/gio/gstgiosrc.h \
 	$(top_srcdir)/ext/gio/gstgiostreamsink.h \
 	$(top_srcdir)/ext/gio/gstgiostreamsrc.h \
+	$(top_srcdir)/ext/soup/gstsouphttpsrc.h \
 	$(top_srcdir)/ext/ivorbis/vorbisdec.h \
 	$(top_srcdir)/ext/jack/gstjackaudiosink.h \
 	$(top_srcdir)/ext/musicbrainz/gsttrm.h \
diff -upNar gst-plugins-bad.orig/docs/plugins/gst-plugins-bad-plugins-sections.txt gst-plugins-bad.new/docs/plugins/gst-plugins-bad-plugins-sections.txt
--- gst-plugins-bad.orig/docs/plugins/gst-plugins-bad-plugins-sections.txt	2008-01-29 12:32:27.000000000 +0100
+++ gst-plugins-bad.new/docs/plugins/gst-plugins-bad-plugins-sections.txt	2008-01-29 22:21:43.000000000 +0100
@@ -267,6 +267,20 @@ gst_gio_stream_src_get_type
 </SECTION>
 
 <SECTION>
+<FILE>element-souphttpsrc</FILE>
+<TITLE>souphttpsrc</TITLE>
+GstSouphttpSrc
+<SUBSECTION Standard>
+GstSouphttpSrcClass
+GST_SOUPHTTP_SRC
+GST_SOUPHTTP_SRC_CLASS
+GST_IS_SOUPHTTP_SRC
+GST_IS_SOUPHTTP_SRC_CLASS
+GST_TYPE_SOUPHTTP_SRC
+gst_souphttp_src_get_type
+</SECTION>
+
+<SECTION>
 <FILE>element-bpwsinc</FILE>
 <TITLE>bpwsinc</TITLE>
 GstBPWSinc
diff -upNar gst-plugins-bad.orig/ext/soup/gstsouphttpsrc.c gst-plugins-bad.new/ext/soup/gstsouphttpsrc.c
--- gst-plugins-bad.orig/ext/soup/gstsouphttpsrc.c	2008-01-20 06:07:52.000000000 +0100
+++ gst-plugins-bad.new/ext/soup/gstsouphttpsrc.c	2008-01-29 22:22:23.000000000 +0100
@@ -1,5 +1,5 @@
 /* GStreamer
- * Copyright (C) <2007> Wouter Cloetens <wouter@mind.be>
+ * Copyright (C) 2007-2008 Wouter Cloetens <wouter@mind.be>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -12,6 +12,72 @@
  * Library General Public License for more
  */
 
+/**
+ * SECTION:element-souphttpsrc
+ * @short_description: Read from an HTTP/HTTPS/WebDAV/Icecast/Shoutcast
+ * location.
+ *
+ * <refsect2>
+ * <para>
+ * This plugin reads data from a remote location specified by a URI.
+ * Supported protocols are 'http', 'https', 'dav', or 'davs'.
+ * </para>
+ * <para>
+ * In case the element-souphttpsrc::iradio-mode property is set and the
+ * location is a http resource, souphttpsrc will send special Icecast HTTP
+ * headers to the server to request additional Icecast meta-information. If
+ * the server is not an Icecast server, it will behave as if the
+ * element-souphttpsrc::iradio-mode property were not set. If it is,
+ * souphttpsrc will output data with a media type of application/x-icy,
+ * in which case you will need to use the #ICYDemux element as follow-up
+ * element to extract the Icecast metadata and to determine the underlying
+ * media type.
+ * </para>
+ * <para>
+ * Example pipeline:
+ * <programlisting>
+ * gst-launch -v souphttpsrc location=https://some.server.org/index.html
+ * ! filesink location=/home/joe/server.html
+ * </programlisting>
+ * The above pipeline reads a web page from a server using the HTTPS protocol
+ * and writes it to a local file.
+ * </para>
+ * <para>
+ * Another example pipeline:
+ * <programlisting>
+ * gst-launch -v souphttpsrc user-agent="FooPlayer 0.99 beta"
+ * automatic-redirect=false proxy=http://proxy.intranet.local:8080
+ * location=http://music.foobar.com/demo.mp3 ! mad ! audioconvert
+ * ! audioresample ! alsasink
+ * </programlisting>
+ * The above pipeline will read and decode and play an mp3 file from a
+ * web server using the HTTP protocol. If the server sends redirects,
+ * the request fails instead of following the redirect. The specified
+ * HTTP proxy server is used. The User-Agent HTTP request header
+ * is set to a custom string instead of "GStreamer souphttpsrc."
+ * </para>
+ * <para>
+ * Yet another example pipeline:
+ * <programlisting>
+ * gst-launch -v souphttpsrc location=http://10.11.12.13/mjpeg
+ * do-timestamp=true ! multipartdemux
+ * ! image/jpeg,width=640,height=480 ! matroskamux
+ * ! filesink location=mjpeg.mkv
+ * </programlisting>
+ * The above pipeline reads a motion JPEG stream from an IP camera
+ * using the HTTP protocol, encoded as mime/multipart image/jpeg
+ * parts, and writes a Matroska motion JPEG file. The width and
+ * height properties are set in the caps to provide the Matroska
+ * multiplexer with the information to set this in the header.
+ * Timestamps are set on the buffers as they arrive from the camera.
+ * These are used by the mime/multipart demultiplexer to emit timestamps
+ * on the JPEG-encoded video frame buffers. This allows the Matroska
+ * multiplexer to timestamp the frames in the resulting file.
+ * </para>
+ * </refsect2>
+ *
+ */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -43,6 +109,8 @@ enum
   PROP_0,
   PROP_LOCATION,
   PROP_USER_AGENT,
+  PROP_AUTOMATIC_REDIRECT,
+  PROP_PROXY,
   PROP_IRADIO_MODE,
   PROP_IRADIO_NAME,
   PROP_IRADIO_GENRE,
@@ -75,18 +143,32 @@ static gboolean gst_souphttp_src_unlock_
 
 static gboolean gst_souphttp_src_set_location (GstSouphttpSrc * src,
     const gchar * uri);
-static gboolean soup_add_range_header (GstSouphttpSrc * src, guint64 offset);
-
-static void soup_got_headers (SoupMessage * msg, GstSouphttpSrc * src);
-static void soup_finished (SoupMessage * msg, GstSouphttpSrc * src);
-static void soup_got_body (SoupMessage * msg, GstSouphttpSrc * src);
-static void soup_got_chunk (SoupMessage * msg, GstSouphttpSrc * src);
-static void soup_response (SoupMessage * msg, gpointer user_data);
-static void soup_parse_status (SoupMessage * msg, GstSouphttpSrc * src);
-static void soup_session_close (GstSouphttpSrc * src);
+static gboolean gst_souphttp_src_set_proxy (GstSouphttpSrc * src,
+    const gchar * uri);
 
 static char *gst_souphttp_src_unicodify (const char *str);
 
+static void gst_souphttp_src_cancel_message (GstSouphttpSrc *src);
+static void gst_souphttp_src_queue_message (GstSouphttpSrc *src);
+static gboolean gst_souphttp_src_add_range_header (GstSouphttpSrc *src,
+    guint64 offset);
+static void gst_souphttp_src_session_unpause_message (GstSouphttpSrc *src);
+static void gst_souphttp_src_session_pause_message (GstSouphttpSrc *src);
+static void gst_souphttp_src_session_close (GstSouphttpSrc *src);
+static void gst_souphttp_src_parse_status (SoupMessage *msg,
+    GstSouphttpSrc *src);
+static void gst_souphttp_src_got_chunk_cb (SoupMessage *msg, SoupBuffer *chunk,
+    GstSouphttpSrc *src);
+static void gst_souphttp_src_response_cb (SoupSession *session,
+    SoupMessage *msg, GstSouphttpSrc *src);
+static void gst_souphttp_src_got_headers_cb (SoupMessage *msg,
+    GstSouphttpSrc *src);
+static void gst_souphttp_src_got_body_cb (SoupMessage *msg,
+    GstSouphttpSrc *src);
+static void gst_souphttp_src_finished_cb (SoupMessage *msg,
+    GstSouphttpSrc *src);
+
+
 static void
 _do_init (GType type)
 {
@@ -140,6 +222,15 @@ gst_souphttp_src_class_init (GstSouphttp
       g_param_spec_string ("user-agent", "User-Agent",
           "Value of the User-Agent HTTP request header field",
           DEFAULT_USER_AGENT, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class,
+      PROP_AUTOMATIC_REDIRECT,
+      g_param_spec_boolean ("automatic-redirect", "automatic-redirect",
+          "Automatically follow HTTP redirects (HTTP Status Code 3xx)",
+          TRUE, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class,
+      PROP_PROXY,
+      g_param_spec_string ("proxy", "Proxy",
+          "HTTP proxy server URI", "", G_PARAM_READWRITE));
 
   /* icecast stuff */
   g_object_class_install_property (gobject_class,
@@ -187,6 +278,8 @@ static void
 gst_souphttp_src_init (GstSouphttpSrc * src, GstSouphttpSrcClass * g_class)
 {
   src->location = NULL;
+  src->proxy = NULL;
+  src->automatic_redirect = TRUE;
   src->user_agent = g_strdup (DEFAULT_USER_AGENT);
   src->icy_caps = NULL;
   src->iradio_mode = FALSE;
@@ -215,6 +308,10 @@ gst_souphttp_src_dispose (GObject * gobj
   src->location = NULL;
   g_free (src->user_agent);
   src->user_agent = NULL;
+  if (src->proxy != NULL) {
+    soup_uri_free (src->proxy);
+    src->proxy = NULL;
+  }
   g_free (src->iradio_name);
   src->iradio_name = NULL;
   g_free (src->iradio_genre);
@@ -265,6 +362,25 @@ gst_souphttp_src_set_property (GObject *
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
+    case PROP_AUTOMATIC_REDIRECT:
+      src->automatic_redirect = g_value_get_boolean (value);
+      break;
+    case PROP_PROXY:
+    {
+      const gchar *proxy;
+
+      proxy = g_value_get_string (value);
+
+      if (proxy == NULL) {
+        GST_WARNING ("proxy property cannot be NULL");
+        goto done;
+      }
+      if (!gst_souphttp_src_set_proxy (src, proxy)) {
+        GST_WARNING ("badly formatted proxy URI");
+        goto done;
+      }
+      break;
+    }
   }
 done:
   return;
@@ -283,6 +399,18 @@ gst_souphttp_src_get_property (GObject *
     case PROP_USER_AGENT:
       g_value_set_string (value, src->user_agent);
       break;
+    case PROP_AUTOMATIC_REDIRECT:
+      g_value_set_boolean (value, src->automatic_redirect);
+      break;
+    case PROP_PROXY:
+      if (src->proxy == NULL)
+        g_value_set_string (value, "");
+      else {
+        char *proxy = soup_uri_to_string (src->proxy, FALSE);
+        g_value_set_string (value, proxy);
+        free (proxy);
+      }
+      break;
     case PROP_IRADIO_MODE:
       g_value_set_boolean (value, src->iradio_mode);
       break;
@@ -314,247 +442,64 @@ gst_souphttp_src_unicodify (const gchar 
   return gst_tag_freeform_string_to_utf8 (str, -1, env_vars);
 }
 
-static GstFlowReturn
-gst_souphttp_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
-{
-  GstSouphttpSrc *src;
-
-  src = GST_SOUPHTTP_SRC (psrc);
-
-  if (src->msg && (src->request_position != src->read_position)) {
-    if (src->msg->status == SOUP_MESSAGE_STATUS_IDLE) {
-      soup_add_range_header (src, src->request_position);
-    } else {
-      GST_DEBUG_OBJECT (src, "Seek from position %" G_GUINT64_FORMAT
-          " to %" G_GUINT64_FORMAT ": requeueing connection request",
-          src->read_position, src->request_position);
-      soup_session_cancel_message (src->session, src->msg);
-      src->msg = NULL;
-    }
-  }
-  if (!src->msg) {
-    src->msg = soup_message_new (SOUP_METHOD_GET, src->location);
-    if (!src->msg) {
-      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
-          (NULL), ("Error parsing URL \"%s\"", src->location));
-      return GST_FLOW_ERROR;
-    }
-    soup_message_add_header (src->msg->request_headers, "Connection", "close");
-    if (src->user_agent) {
-      soup_message_add_header (src->msg->request_headers, "User-Agent",
-          src->user_agent);
-    }
-    if (src->iradio_mode) {
-      soup_message_add_header (src->msg->request_headers, "icy-metadata", "1");
-    }
-
-    g_signal_connect (src->msg, "got_headers",
-        G_CALLBACK (soup_got_headers), src);
-    g_signal_connect (src->msg, "got_body", G_CALLBACK (soup_got_body), src);
-    g_signal_connect (src->msg, "finished", G_CALLBACK (soup_finished), src);
-    g_signal_connect (src->msg, "got_chunk", G_CALLBACK (soup_got_chunk), src);
-    soup_message_set_flags (src->msg, SOUP_MESSAGE_OVERWRITE_CHUNKS);
-    soup_add_range_header (src, src->request_position);
-  }
-
-  src->ret = GST_FLOW_CUSTOM_ERROR;
-  src->outbuf = outbuf;
-  do {
-    if (src->interrupted) {
-      soup_session_cancel_message (src->session, src->msg);
-      src->msg = NULL;
-      break;
-    }
-    if (!src->msg) {
-      GST_DEBUG_OBJECT (src, "EOS reached");
-      break;
-    }
-
-    switch (src->msg->status) {
-      case SOUP_MESSAGE_STATUS_IDLE:
-        GST_DEBUG_OBJECT (src, "Queueing connection request");
-        soup_session_queue_message (src->session, src->msg, soup_response, src);
-        break;
-      case SOUP_MESSAGE_STATUS_FINISHED:
-        GST_DEBUG_OBJECT (src, "Connection closed");
-        soup_session_cancel_message (src->session, src->msg);
-        src->msg = NULL;
-        break;
-      case SOUP_MESSAGE_STATUS_QUEUED:
-        break;
-      case SOUP_MESSAGE_STATUS_CONNECTING:
-      case SOUP_MESSAGE_STATUS_RUNNING:
-      default:
-        soup_message_io_unpause (src->msg);
-        break;
-    }
-
-    if (src->ret == GST_FLOW_CUSTOM_ERROR)
-      g_main_loop_run (src->loop);
-  } while (src->ret == GST_FLOW_CUSTOM_ERROR);
-
-  if (src->ret == GST_FLOW_CUSTOM_ERROR)
-    src->ret = GST_FLOW_UNEXPECTED;
-  return src->ret;
-}
-
-static gboolean
-gst_souphttp_src_start (GstBaseSrc * bsrc)
-{
-  GstSouphttpSrc *src = GST_SOUPHTTP_SRC (bsrc);
-
-  GST_DEBUG_OBJECT (src, "start(\"%s\")", src->location);
-
-  if (!src->location) {
-    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
-        (NULL), ("Missing location property"));
-    return FALSE;
-  }
-
-  src->context = g_main_context_new ();
-
-  src->loop = g_main_loop_new (src->context, TRUE);
-  if (!src->loop) {
-    GST_ELEMENT_ERROR (src, LIBRARY, INIT,
-        (NULL), ("Failed to start GMainLoop"));
-    g_main_context_unref (src->context);
-    return FALSE;
-  }
-
-  src->session =
-      soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
-      src->context, NULL);
-  if (!src->session) {
-    GST_ELEMENT_ERROR (src, LIBRARY, INIT,
-        (NULL), ("Failed to create async session"));
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-/* Close the socket and associated resources
- * used both to recover from errors and go to NULL state. */
-static gboolean
-gst_souphttp_src_stop (GstBaseSrc * bsrc)
-{
-  GstSouphttpSrc *src;
-
-  src = GST_SOUPHTTP_SRC (bsrc);
-  GST_DEBUG_OBJECT (src, "stop()");
-  soup_session_close (src);
-  if (src->loop) {
-    g_main_loop_unref (src->loop);
-    g_main_context_unref (src->context);
-    src->loop = NULL;
-    src->context = NULL;
-  }
-
-  return TRUE;
-}
-
-/* Interrupt a blocking request. */
-static gboolean
-gst_souphttp_src_unlock (GstBaseSrc * bsrc)
-{
-  GstSouphttpSrc *src;
-
-  src = GST_SOUPHTTP_SRC (bsrc);
-  GST_DEBUG_OBJECT (src, "unlock()");
-
-  src->interrupted = TRUE;
-  if (src->loop)
-    g_main_loop_quit (src->loop);
-  return TRUE;
-}
-
-/* Interrupt interrupt. */
-static gboolean
-gst_souphttp_src_unlock_stop (GstBaseSrc * bsrc)
-{
-  GstSouphttpSrc *src;
-
-  src = GST_SOUPHTTP_SRC (bsrc);
-  GST_DEBUG_OBJECT (src, "unlock_stop()");
-
-  src->interrupted = FALSE;
-  return TRUE;
-}
-
-static gboolean
-gst_souphttp_src_get_size (GstBaseSrc * bsrc, guint64 * size)
-{
-  GstSouphttpSrc *src;
-
-  src = GST_SOUPHTTP_SRC (bsrc);
-
-  if (src->have_size) {
-    GST_DEBUG_OBJECT (src, "get_size() = %" G_GUINT64_FORMAT,
-        src->content_size);
-    *size = src->content_size;
-    return TRUE;
-  }
-  GST_DEBUG_OBJECT (src, "get_size() = FALSE");
-  return FALSE;
-}
-
-static gboolean
-gst_souphttp_src_is_seekable (GstBaseSrc * bsrc)
+static void
+gst_souphttp_src_cancel_message (GstSouphttpSrc *src)
 {
-  GstSouphttpSrc *src = GST_SOUPHTTP_SRC (bsrc);
-
-  return src->seekable;
+  soup_session_cancel_message (src->session, src->msg, SOUP_STATUS_CANCELLED);
+  src->session_io_status = GST_SOUPHTTP_SRC_SESSION_IO_STATUS_IDLE;
+  src->msg = NULL;
 }
 
-static gboolean
-gst_souphttp_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
+static void
+gst_souphttp_src_queue_message (GstSouphttpSrc *src)
 {
-  GstSouphttpSrc *src = GST_SOUPHTTP_SRC (bsrc);
-
-  GST_DEBUG_OBJECT (src, "do_seek(%" G_GUINT64_FORMAT ")", segment->start);
-
-  if (src->read_position == segment->start)
-    return TRUE;
-
-  if (!src->seekable)
-    return FALSE;
-
-  /* Wait for create() to handle the jump in offset. */
-  src->request_position = segment->start;
-  return TRUE;
+  soup_session_queue_message (src->session, src->msg,
+      (SoupSessionCallback) gst_souphttp_src_response_cb, src);
+  src->session_io_status = GST_SOUPHTTP_SRC_SESSION_IO_STATUS_QUEUED;
 }
 
 static gboolean
-soup_add_range_header (GstSouphttpSrc * src, guint64 offset)
+gst_souphttp_src_add_range_header (GstSouphttpSrc *src, guint64 offset)
 {
   gchar buf[64];
   gint rc;
 
-  soup_message_remove_header (src->msg->request_headers, "Range");
+  soup_message_headers_remove (src->msg->request_headers, "Range");
   if (offset) {
     rc = g_snprintf (buf, sizeof (buf), "bytes=%" G_GUINT64_FORMAT "-", offset);
     if (rc > sizeof (buf) || rc < 0)
       return FALSE;
-    soup_message_add_header (src->msg->request_headers, "Range", buf);
+    soup_message_headers_append (src->msg->request_headers, "Range", buf);
   }
   src->read_position = offset;
   return TRUE;
 }
 
-static gboolean
-gst_souphttp_src_set_location (GstSouphttpSrc * src, const gchar * uri)
+static void
+gst_souphttp_src_session_unpause_message (GstSouphttpSrc *src)
 {
-  if (src->location) {
-    g_free (src->location);
-    src->location = NULL;
-  }
-  src->location = g_strdup (uri);
+  soup_session_unpause_message (src->session, src->msg);
+}
 
-  return TRUE;
+static void
+gst_souphttp_src_session_pause_message (GstSouphttpSrc *src)
+{
+  soup_session_pause_message (src->session, src->msg);
 }
 
 static void
-soup_got_headers (SoupMessage * msg, GstSouphttpSrc * src)
+gst_souphttp_src_session_close (GstSouphttpSrc *src)
+{
+  if (src->session) {
+    soup_session_abort (src->session);  /* This unrefs the message. */
+    g_object_unref (src->session);
+    src->session = NULL;
+    src->msg = NULL;
+  }
+}
+
+static void
+gst_souphttp_src_got_headers_cb (SoupMessage *msg, GstSouphttpSrc *src)
 {
   const char *value;
   GstTagList *tag_list;
@@ -563,14 +508,24 @@ soup_got_headers (SoupMessage * msg, Gst
 
   GST_DEBUG_OBJECT (src, "got headers");
 
+  if (src->automatic_redirect &&
+      SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
+    GST_DEBUG_OBJECT (src, "%u redirect to \"%s\"", msg->status_code,
+        soup_message_headers_get (msg->response_headers, "Location"));
+    return;
+  }
+
+  src->session_io_status = GST_SOUPHTTP_SRC_SESSION_IO_STATUS_RUNNING;
+
   /* Parse Content-Length. */
-  value = soup_message_get_header (msg->response_headers, "Content-Length");
-  if (value != NULL) {
-    newsize = src->request_position + g_ascii_strtoull (value, NULL, 10);
+  if (soup_message_headers_get_encoding (msg->response_headers) ==
+      SOUP_ENCODING_CONTENT_LENGTH) {
+    newsize = src->request_position + 
+        soup_message_headers_get_content_length (msg->response_headers);
     if (!src->have_size || (src->content_size != newsize)) {
       src->content_size = newsize;
       src->have_size = TRUE;
-      GST_DEBUG_OBJECT (src, "size = %llu", src->content_size);
+      GST_DEBUG_OBJECT (src, "size = %" G_GUINT64_FORMAT, src->content_size);
 
       basesrc = GST_BASE_SRC_CAST (src);
       gst_segment_set_duration (&basesrc->segment, GST_FORMAT_BYTES,
@@ -585,7 +540,7 @@ soup_got_headers (SoupMessage * msg, Gst
   tag_list = gst_tag_list_new ();
 
   if ((value =
-          soup_message_get_header (msg->response_headers,
+          soup_message_headers_get (msg->response_headers,
               "icy-metaint")) != NULL) {
     gint icy_metaint = atoi (value);
 
@@ -596,7 +551,7 @@ soup_got_headers (SoupMessage * msg, Gst
   }
 
   if ((value =
-          soup_message_get_header (msg->response_headers,
+          soup_message_headers_get (msg->response_headers,
               "icy-name")) != NULL) {
     g_free (src->iradio_name);
     src->iradio_name = gst_souphttp_src_unicodify (value);
@@ -607,7 +562,7 @@ soup_got_headers (SoupMessage * msg, Gst
     }
   }
   if ((value =
-          soup_message_get_header (msg->response_headers,
+          soup_message_headers_get (msg->response_headers,
               "icy-genre")) != NULL) {
     g_free (src->iradio_genre);
     src->iradio_genre = gst_souphttp_src_unicodify (value);
@@ -618,7 +573,8 @@ soup_got_headers (SoupMessage * msg, Gst
     }
   }
   if ((value =
-          soup_message_get_header (msg->response_headers, "icy-url")) != NULL) {
+          soup_message_headers_get (msg->response_headers, "icy-url"))
+              != NULL) {
     g_free (src->iradio_url);
     src->iradio_url = gst_souphttp_src_unicodify (value);
     if (src->iradio_url) {
@@ -636,7 +592,7 @@ soup_got_headers (SoupMessage * msg, Gst
   }
 
   /* Handle HTTP errors. */
-  soup_parse_status (msg, src);
+  gst_souphttp_src_parse_status (msg, src);
 
   /* Check if Range header was respected. */
   if (src->ret == GST_FLOW_CUSTOM_ERROR &&
@@ -651,27 +607,37 @@ soup_got_headers (SoupMessage * msg, Gst
 
 /* Have body. Signal EOS. */
 static void
-soup_got_body (SoupMessage * msg, GstSouphttpSrc * src)
+gst_souphttp_src_got_body_cb (SoupMessage *msg, GstSouphttpSrc *src)
 {
-  if (msg != src->msg) {
+  if (G_UNLIKELY (msg != src->msg)) {
     GST_DEBUG_OBJECT (src, "got body, but not for current message");
     return;
   }
+  if (G_UNLIKELY (src->session_io_status !=
+      GST_SOUPHTTP_SRC_SESSION_IO_STATUS_RUNNING)) {
+    /* Probably a redirect. */
+    return;
+  }
   GST_DEBUG_OBJECT (src, "got body");
   src->ret = GST_FLOW_UNEXPECTED;
   if (src->loop)
     g_main_loop_quit (src->loop);
-  soup_message_io_pause (msg);
+  gst_souphttp_src_session_pause_message (src);
 }
 
 /* Finished. Signal EOS. */
 static void
-soup_finished (SoupMessage * msg, GstSouphttpSrc * src)
+gst_souphttp_src_finished_cb (SoupMessage *msg, GstSouphttpSrc *src)
 {
-  if (msg != src->msg) {
+  if (G_UNLIKELY (msg != src->msg)) {
     GST_DEBUG_OBJECT (src, "finished, but not for current message");
     return;
   }
+  if (G_UNLIKELY (src->session_io_status !=
+      GST_SOUPHTTP_SRC_SESSION_IO_STATUS_RUNNING)) {
+    /* Probably a redirect. */
+    return;
+  }
   GST_DEBUG_OBJECT (src, "finished");
   src->ret = GST_FLOW_UNEXPECTED;
   if (src->loop)
@@ -679,53 +645,66 @@ soup_finished (SoupMessage * msg, GstSou
 }
 
 static void
-soup_got_chunk (SoupMessage * msg, GstSouphttpSrc * src)
+gst_souphttp_src_got_chunk_cb (SoupMessage *msg, SoupBuffer *chunk,
+    GstSouphttpSrc *src)
 {
   GstBaseSrc *basesrc;
   guint64 new_position;
+  const char *data;
+  gsize length;
 
   if (G_UNLIKELY (msg != src->msg)) {
     GST_DEBUG_OBJECT (src, "got chunk, but not for current message");
     return;
   }
+  if (G_UNLIKELY (src->session_io_status !=
+      GST_SOUPHTTP_SRC_SESSION_IO_STATUS_RUNNING)) {
+    /* Probably a redirect. */
+    return;
+  }
   basesrc = GST_BASE_SRC_CAST (src);
-  GST_DEBUG_OBJECT (src, "got chunk of %d bytes", msg->response.length);
+  data = chunk->data;
+  length = chunk->length;
+  GST_DEBUG_OBJECT (src, "got chunk of %d bytes", length);
 
   /* Create the buffer. */
   src->ret = gst_pad_alloc_buffer (GST_BASE_SRC_PAD (basesrc),
-      basesrc->segment.last_stop, msg->response.length,
+      basesrc->segment.last_stop, length,
       GST_PAD_CAPS (GST_BASE_SRC_PAD (basesrc)), src->outbuf);
   if (G_LIKELY (src->ret == GST_FLOW_OK)) {
-    memcpy (GST_BUFFER_DATA (*src->outbuf), msg->response.body,
-        msg->response.length);
-    new_position = src->read_position + msg->response.length;
+    memcpy (GST_BUFFER_DATA (*src->outbuf), data, length);
+    new_position = src->read_position + length;
     if (G_LIKELY (src->request_position == src->read_position))
       src->request_position = new_position;
     src->read_position = new_position;
   }
 
   g_main_loop_quit (src->loop);
-  soup_message_io_pause (msg);
+  gst_souphttp_src_session_pause_message (src);
 }
 
 static void
-soup_response (SoupMessage * msg, gpointer user_data)
+gst_souphttp_src_response_cb (SoupSession *session, SoupMessage *msg,
+    GstSouphttpSrc *src)
 {
-  GstSouphttpSrc *src = (GstSouphttpSrc *) user_data;
-
-  if (msg != src->msg) {
+  if (G_UNLIKELY (msg != src->msg)) {
     GST_DEBUG_OBJECT (src, "got response %d: %s, but not for current message",
         msg->status_code, msg->reason_phrase);
     return;
   }
+  if (G_UNLIKELY (src->session_io_status !=
+      GST_SOUPHTTP_SRC_SESSION_IO_STATUS_RUNNING)) {
+    /* Probably a redirect. */
+    return;
+  }
   GST_DEBUG_OBJECT (src, "got response %d: %s", msg->status_code,
       msg->reason_phrase);
-  soup_parse_status (msg, src);
+  gst_souphttp_src_parse_status (msg, src);
   g_main_loop_quit (src->loop);
 }
 
 static void
-soup_parse_status (SoupMessage * msg, GstSouphttpSrc * src)
+gst_souphttp_src_parse_status (SoupMessage *msg, GstSouphttpSrc *src)
 {
   if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
     switch (msg->status_code) {
@@ -761,6 +740,7 @@ soup_parse_status (SoupMessage * msg, Gs
         break;
     }
   } else if (SOUP_STATUS_IS_CLIENT_ERROR (msg->status_code) ||
+      SOUP_STATUS_IS_REDIRECTION (msg->status_code) ||
       SOUP_STATUS_IS_SERVER_ERROR (msg->status_code)) {
     /* Report HTTP error. */
     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
@@ -770,15 +750,246 @@ soup_parse_status (SoupMessage * msg, Gs
   }
 }
 
-static void
-soup_session_close (GstSouphttpSrc * src)
+static GstFlowReturn
+gst_souphttp_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
 {
-  if (src->session) {
-    soup_session_abort (src->session);  /* This unrefs the message. */
-    g_object_unref (src->session);
-    src->session = NULL;
-    src->msg = NULL;
+  GstSouphttpSrc *src;
+
+  src = GST_SOUPHTTP_SRC (psrc);
+
+  if (src->msg && (src->request_position != src->read_position)) {
+    if (src->session_io_status == GST_SOUPHTTP_SRC_SESSION_IO_STATUS_IDLE) {
+      gst_souphttp_src_add_range_header (src, src->request_position);
+    } else {
+      GST_DEBUG_OBJECT (src, "Seek from position %" G_GUINT64_FORMAT
+          " to %" G_GUINT64_FORMAT ": requeueing connection request",
+          src->read_position, src->request_position);
+      gst_souphttp_src_cancel_message (src);
+    }
+  }
+  if (!src->msg) {
+    src->msg = soup_message_new (SOUP_METHOD_GET, src->location);
+    if (!src->msg) {
+      GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+          (NULL), ("Error parsing URL \"%s\"", src->location));
+      return GST_FLOW_ERROR;
+    }
+    src->session_io_status = GST_SOUPHTTP_SRC_SESSION_IO_STATUS_IDLE;
+    soup_message_headers_append (src->msg->request_headers, "Connection",
+        "close");
+    if (src->user_agent) {
+      soup_message_headers_append (src->msg->request_headers, "User-Agent",
+          src->user_agent);
+    }
+    if (src->iradio_mode) {
+      soup_message_headers_append (src->msg->request_headers, "icy-metadata",
+          "1");
+    }
+
+    g_signal_connect (src->msg, "got_headers",
+        G_CALLBACK (gst_souphttp_src_got_headers_cb), src);
+    g_signal_connect (src->msg, "got_body",
+        G_CALLBACK (gst_souphttp_src_got_body_cb), src);
+    g_signal_connect (src->msg, "finished",
+        G_CALLBACK (gst_souphttp_src_finished_cb), src);
+    g_signal_connect (src->msg, "got_chunk",
+        G_CALLBACK (gst_souphttp_src_got_chunk_cb), src);
+    soup_message_set_flags (src->msg, SOUP_MESSAGE_OVERWRITE_CHUNKS |
+        src->automatic_redirect ? 0 : SOUP_MESSAGE_NO_REDIRECT);
+    gst_souphttp_src_add_range_header (src, src->request_position);
+  }
+
+  src->ret = GST_FLOW_CUSTOM_ERROR;
+  src->outbuf = outbuf;
+  do {
+    if (src->interrupted) {
+      gst_souphttp_src_cancel_message (src);
+      break;
+    }
+    if (!src->msg) {
+      GST_DEBUG_OBJECT (src, "EOS reached");
+      break;
+    }
+
+    switch (src->session_io_status)
+    {
+      case GST_SOUPHTTP_SRC_SESSION_IO_STATUS_IDLE:
+        GST_DEBUG_OBJECT (src, "Queueing connection request");
+        gst_souphttp_src_queue_message (src);
+        break;
+      case GST_SOUPHTTP_SRC_SESSION_IO_STATUS_FINISHED:
+        GST_DEBUG_OBJECT (src, "Connection closed");
+        gst_souphttp_src_cancel_message (src);
+        break;
+      case GST_SOUPHTTP_SRC_SESSION_IO_STATUS_QUEUED:
+        break;
+      case GST_SOUPHTTP_SRC_SESSION_IO_STATUS_RUNNING:
+        gst_souphttp_src_session_unpause_message (src);
+        break;
+    }
+
+    if (src->ret == GST_FLOW_CUSTOM_ERROR)
+      g_main_loop_run (src->loop);
+  } while (src->ret == GST_FLOW_CUSTOM_ERROR);
+
+  if (src->ret == GST_FLOW_CUSTOM_ERROR)
+    src->ret = GST_FLOW_UNEXPECTED;
+  return src->ret;
+}
+
+static gboolean
+gst_souphttp_src_start (GstBaseSrc * bsrc)
+{
+  GstSouphttpSrc *src = GST_SOUPHTTP_SRC (bsrc);
+
+  GST_DEBUG_OBJECT (src, "start(\"%s\")", src->location);
+
+  if (!src->location) {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+        (NULL), ("Missing location property"));
+    return FALSE;
+  }
+
+  src->context = g_main_context_new ();
+
+  src->loop = g_main_loop_new (src->context, TRUE);
+  if (!src->loop) {
+    GST_ELEMENT_ERROR (src, LIBRARY, INIT,
+        (NULL), ("Failed to start GMainLoop"));
+    g_main_context_unref (src->context);
+    return FALSE;
+  }
+
+  if (src->proxy == NULL)
+    src->session =
+        soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
+        src->context, NULL);
+  else
+    src->session =
+        soup_session_async_new_with_options (SOUP_SESSION_ASYNC_CONTEXT,
+        src->context, SOUP_SESSION_PROXY_URI, src->proxy, NULL);
+  if (!src->session) {
+    GST_ELEMENT_ERROR (src, LIBRARY, INIT,
+        (NULL), ("Failed to create async session"));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* Close the socket and associated resources
+ * used both to recover from errors and go to NULL state. */
+static gboolean
+gst_souphttp_src_stop (GstBaseSrc * bsrc)
+{
+  GstSouphttpSrc *src;
+
+  src = GST_SOUPHTTP_SRC (bsrc);
+  GST_DEBUG_OBJECT (src, "stop()");
+  gst_souphttp_src_session_close (src);
+  if (src->loop) {
+    g_main_loop_unref (src->loop);
+    g_main_context_unref (src->context);
+    src->loop = NULL;
+    src->context = NULL;
+  }
+
+  return TRUE;
+}
+
+/* Interrupt a blocking request. */
+static gboolean
+gst_souphttp_src_unlock (GstBaseSrc * bsrc)
+{
+  GstSouphttpSrc *src;
+
+  src = GST_SOUPHTTP_SRC (bsrc);
+  GST_DEBUG_OBJECT (src, "unlock()");
+
+  src->interrupted = TRUE;
+  if (src->loop)
+    g_main_loop_quit (src->loop);
+  return TRUE;
+}
+
+/* Interrupt interrupt. */
+static gboolean
+gst_souphttp_src_unlock_stop (GstBaseSrc * bsrc)
+{
+  GstSouphttpSrc *src;
+
+  src = GST_SOUPHTTP_SRC (bsrc);
+  GST_DEBUG_OBJECT (src, "unlock_stop()");
+
+  src->interrupted = FALSE;
+  return TRUE;
+}
+
+static gboolean
+gst_souphttp_src_get_size (GstBaseSrc * bsrc, guint64 * size)
+{
+  GstSouphttpSrc *src;
+
+  src = GST_SOUPHTTP_SRC (bsrc);
+
+  if (src->have_size) {
+    GST_DEBUG_OBJECT (src, "get_size() = %" G_GUINT64_FORMAT,
+        src->content_size);
+    *size = src->content_size;
+    return TRUE;
   }
+  GST_DEBUG_OBJECT (src, "get_size() = FALSE");
+  return FALSE;
+}
+
+static gboolean
+gst_souphttp_src_is_seekable (GstBaseSrc * bsrc)
+{
+  GstSouphttpSrc *src = GST_SOUPHTTP_SRC (bsrc);
+
+  return src->seekable;
+}
+
+static gboolean
+gst_souphttp_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
+{
+  GstSouphttpSrc *src = GST_SOUPHTTP_SRC (bsrc);
+
+  GST_DEBUG_OBJECT (src, "do_seek(%" G_GUINT64_FORMAT ")", segment->start);
+
+  if (src->read_position == segment->start)
+    return TRUE;
+
+  if (!src->seekable)
+    return FALSE;
+
+  /* Wait for create() to handle the jump in offset. */
+  src->request_position = segment->start;
+  return TRUE;
+}
+
+static gboolean
+gst_souphttp_src_set_location (GstSouphttpSrc * src, const gchar * uri)
+{
+  if (src->location) {
+    g_free (src->location);
+    src->location = NULL;
+  }
+  src->location = g_strdup (uri);
+
+  return TRUE;
+}
+
+static gboolean
+gst_souphttp_src_set_proxy (GstSouphttpSrc * src, const gchar * uri)
+{
+  if (src->proxy) {
+    soup_uri_free (src->proxy);
+    src->proxy = NULL;
+  }
+  src->proxy = soup_uri_new (uri);
+
+  return TRUE;
 }
 
 static guint
@@ -824,8 +1035,6 @@ gst_souphttp_src_uri_handler_init (gpoin
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-  /* note: do not upgrade rank before we depend on a libsoup version where
-   * icecast is supported properly out of the box */
   return gst_element_register (plugin, "souphttpsrc", GST_RANK_NONE,
       GST_TYPE_SOUPHTTP_SRC);
 }
diff -upNar gst-plugins-bad.orig/ext/soup/gstsouphttpsrc.h gst-plugins-bad.new/ext/soup/gstsouphttpsrc.h
--- gst-plugins-bad.orig/ext/soup/gstsouphttpsrc.h	2008-01-18 06:24:39.000000000 +0100
+++ gst-plugins-bad.new/ext/soup/gstsouphttpsrc.h	2008-01-29 22:22:23.000000000 +0100
@@ -37,14 +37,25 @@ G_BEGIN_DECLS
 typedef struct _GstSouphttpSrc GstSouphttpSrc;
 typedef struct _GstSouphttpSrcClass GstSouphttpSrcClass;
 
+typedef enum {
+  GST_SOUPHTTP_SRC_SESSION_IO_STATUS_IDLE,
+  GST_SOUPHTTP_SRC_SESSION_IO_STATUS_QUEUED,
+  GST_SOUPHTTP_SRC_SESSION_IO_STATUS_RUNNING,
+  GST_SOUPHTTP_SRC_SESSION_IO_STATUS_FINISHED,
+} GstSouphttpSrcSessionIOStatus;
+
 struct _GstSouphttpSrc {
   GstPushSrc element;
 
   gchar * location;                     /* Full URI. */
   gchar * user_agent;                   /* User-Agent HTTP header. */
+  gboolean automatic_redirect;          /* Follow redirects. */
+  SoupURI * proxy;                      /* HTTP proxy URI. */
   GMainContext * context;               /* I/O context. */
   GMainLoop * loop;                     /* Event loop. */
   SoupSession * session;                /* Async context. */
+  GstSouphttpSrcSessionIOStatus session_io_status;
+                                        /* Async I/O status. */
   SoupMessage * msg;                    /* Request message. */
   GstFlowReturn ret;                    /* Return code from callback. */
   GstBuffer ** outbuf;                  /* Return buffer allocated by callback. */
diff -upNar gst-plugins-bad.orig/tests/check/Makefile.am gst-plugins-bad.new/tests/check/Makefile.am
--- gst-plugins-bad.orig/tests/check/Makefile.am	2008-01-23 11:11:43.000000000 +0100
+++ gst-plugins-bad.new/tests/check/Makefile.am	2008-01-29 22:23:36.000000000 +0100
@@ -15,6 +15,8 @@ TESTS_ENVIRONMENT = \
         GST_PLUGIN_PATH=$(top_builddir)/gst:$(top_builddir)/sys:$(top_builddir)/ext:$(GSTPB_PLUGINS_DIR):$(GST_PLUGINS_DIR) \
         STATE_IGNORE_ELEMENTS="vcdsrc nassink glimagesink"
 
+EXTRA_DIST = test-cert.pem test-key.pem
+
 plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
 
 # override to _not_ install the test plugins
@@ -45,6 +47,12 @@ else
 check_neon = 
 endif
 
+if USE_SOUP
+check_soup = elements/souphttpsrc
+else
+check_soup = 
+endif
+
 if USE_TIMIDITY
 check_timidity=elements/timidity
 else
@@ -64,6 +72,7 @@ check_PROGRAMS = \
 	$(check_gio)  \
 	$(check_mpeg2enc)  \
 	$(check_neon)      \
+	$(check_soup)      \
 	$(check_timidity)  \
 	elements/bpwsinc  \
 	elements/equalizer  \
@@ -90,3 +99,5 @@ elements_timidity_LDADD = $(GST_BASE_LIB
 pipelines_gio_CFLAGS = $(GIO_CFLAGS) $(AM_CFLAGS)
 pipelines_gio_LDADD = $(GIO_LIBS) $(LDADD)
 
+elements_souphttpsrc_CFLAGS = $(SOUP_CFLAGS) $(AM_CFLAGS)
+elements_souphttpsrc_LDADD = $(SOUP_LIBS) $(LDADD)
diff -upNar gst-plugins-bad.orig/tests/check/elements/.cvsignore gst-plugins-bad.new/tests/check/elements/.cvsignore
--- gst-plugins-bad.orig/tests/check/elements/.cvsignore	2008-01-23 11:11:44.000000000 +0100
+++ gst-plugins-bad.new/tests/check/elements/.cvsignore	2008-01-29 22:23:36.000000000 +0100
@@ -8,6 +8,7 @@ interleave
 lpwsinc
 mpeg2enc
 neonhttpsrc
+souphttpsrc
 rganalysis
 rglimiter
 rgvolume
diff -upNar gst-plugins-bad.orig/tests/check/elements/souphttpsrc.c gst-plugins-bad.new/tests/check/elements/souphttpsrc.c
--- gst-plugins-bad.orig/tests/check/elements/souphttpsrc.c	1970-01-01 01:00:00.000000000 +0100
+++ gst-plugins-bad.new/tests/check/elements/souphttpsrc.c	2008-01-29 22:25:14.000000000 +0100
@@ -0,0 +1,405 @@
+/* GStreamer unit tests for the souphttpsrc element
+ * Copyright (C) 2006-2007 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2008 Wouter Cloetens <wouter@mind.be>
+ * Copyright (C) 2001-2003, Ximian, Inc.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <libsoup/soup-address.h>
+#include <libsoup/soup-message.h>
+#include <libsoup/soup-server.h>
+#include <gst/check/gstcheck.h>
+
+static int http_port = 0, https_port = 0;
+gboolean redirect = TRUE;
+
+static int run_server (int *http_port, int *https_port);
+
+
+static void
+handoff_cb (GstElement * fakesink, GstBuffer * buf, GstPad * pad,
+    GstBuffer ** p_outbuf)
+{
+  GST_LOG ("handoff, buf = %p", buf);
+  if (*p_outbuf == NULL)
+    *p_outbuf = gst_buffer_ref (buf);
+}
+
+int run_test (const char *format, ...)
+{
+  GstStateChangeReturn ret;
+  GstElement *pipe, *src, *sink;
+  GstBuffer *buf = NULL;
+  GstMessage *msg;
+  gchar *url;
+  va_list args;
+  int rc = -1;
+
+  pipe = gst_pipeline_new (NULL);
+
+  src = gst_element_factory_make ("souphttpsrc", NULL);
+  fail_unless (src != NULL);
+
+  sink = gst_element_factory_make ("fakesink", NULL);
+  fail_unless (sink != NULL);
+
+  gst_bin_add (GST_BIN (pipe), src);
+  gst_bin_add (GST_BIN (pipe), sink);
+  fail_unless (gst_element_link (src, sink));
+
+  if (http_port == 0) {
+    GST_DEBUG ("failed to start soup http server");
+  }
+  fail_unless (http_port != 0);
+  va_start(args, format);
+  g_vasprintf(&url, format, args);
+  va_end(args);
+  fail_unless (url != NULL);
+  g_object_set (src, "location", url, NULL);
+  g_free (url);
+
+  g_object_set (src, "automatic-redirect", redirect, NULL);
+  g_object_set (sink, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (sink, "preroll-handoff", G_CALLBACK (handoff_cb), &buf);
+
+  ret = gst_element_set_state (pipe, GST_STATE_PAUSED);
+  if (ret != GST_STATE_CHANGE_ASYNC) {
+    GST_DEBUG ("failed to start up soup http src, ret = %d", ret);
+    goto done;
+  }
+
+  gst_element_set_state (pipe, GST_STATE_PLAYING);
+  msg = gst_bus_poll (GST_ELEMENT_BUS (pipe),
+      GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    gchar *debug = NULL;
+    GError *err = NULL;
+
+    gst_message_parse_error (msg, &err, &debug);
+    GST_INFO ("error: %s", err->message);
+    if (g_str_has_suffix (err->message, "Not Found"))
+      rc = 404;
+    else if (g_str_has_suffix (err->message, "Forbidden"))
+      rc = 403;
+    else if (g_str_has_suffix (err->message, "Found"))
+      rc = 302;
+    GST_INFO ("debug: %s", debug);
+    g_error_free (err);
+    g_free(debug);
+    gst_message_unref (msg);
+    goto done;
+  }
+  gst_message_unref (msg);
+
+  /* don't wait for more than 10 seconds */
+  ret = gst_element_get_state (pipe, NULL, NULL, 10 * GST_SECOND);
+  GST_LOG ("ret = %u", ret);
+
+  if (buf == NULL) {
+    /* we want to test the buffer offset, nothing else; if there's a failure
+     * it might be for lots of reasons (no network connection, whatever), we're
+     * not interested in those */
+    GST_DEBUG ("didn't manage to get data within 10 seconds, skipping test");
+    goto done;
+  }
+
+  GST_DEBUG ("buffer offset = %" G_GUINT64_FORMAT, GST_BUFFER_OFFSET (buf));
+
+  /* first buffer should have a 0 offset */
+  fail_unless (GST_BUFFER_OFFSET (buf) == 0);
+  gst_buffer_unref (buf);
+  rc = 0;
+
+done:
+
+  gst_element_set_state (pipe, GST_STATE_NULL);
+  gst_object_unref (pipe);
+  return rc;
+}
+
+GST_START_TEST (test_first_buffer_has_offset)
+{
+  fail_unless (run_test("http://127.0.0.1:%d/", http_port) == 0);
+}
+GST_END_TEST;
+
+GST_START_TEST (test_not_found)
+{
+  fail_unless (run_test("http://127.0.0.1:%d/404", http_port) == 404);
+}
+GST_END_TEST;
+
+GST_START_TEST (test_forbidden)
+{
+  fail_unless (run_test("http://127.0.0.1:%d/403", http_port) == 403);
+}
+GST_END_TEST;
+
+GST_START_TEST (test_redirect_no)
+{
+  redirect = FALSE;
+  fail_unless (run_test("http://127.0.0.1:%d/302", http_port) == 302);
+}
+GST_END_TEST;
+
+GST_START_TEST (test_redirect_yes)
+{
+  redirect = TRUE;
+  fail_unless (run_test("http://127.0.0.1:%d/302", http_port) == 0);
+}
+GST_END_TEST;
+
+GST_START_TEST (test_https)
+{
+  if (!https_port)
+    GST_INFO ("Failed to start an HTTPS server; let's just skip this test.");
+  else
+    fail_unless (run_test("https://127.0.0.1:%d/", https_port) == 0);
+}
+GST_END_TEST;
+
+GST_START_TEST (test_icy_stream)
+{
+  GstElement *pipe, *src, *sink;
+  GstMessage *msg;
+
+  pipe = gst_pipeline_new (NULL);
+
+  src = gst_element_factory_make ("souphttpsrc", NULL);
+  fail_unless (src != NULL);
+
+  sink = gst_element_factory_make ("fakesink", NULL);
+  fail_unless (sink != NULL);
+
+  gst_bin_add (GST_BIN (pipe), src);
+  gst_bin_add (GST_BIN (pipe), sink);
+  fail_unless (gst_element_link (src, sink));
+
+  /* First try Virgin Radio Ogg stream, to see if there's connectivity and all
+   * (which is an attempt to work around the completely horrid error reporting
+   * and that we can't distinguish different types of failures here). */
+
+  g_object_set (src, "location", "http://ogg2.smgradio.com/vr32.ogg", NULL);
+  g_object_set (src, "num-buffers", 1, NULL);
+  gst_element_set_state (pipe, GST_STATE_PLAYING);
+
+  msg = gst_bus_poll (GST_ELEMENT_BUS (pipe),
+      GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+    GST_INFO ("looks like there's no net connectivity or sgmradio.com is "
+        "down. In any case, let's just skip this test");
+    gst_message_unref (msg);
+    goto done;
+  }
+  gst_message_unref (msg);
+  msg = NULL;
+  gst_element_set_state (pipe, GST_STATE_NULL);
+
+  /* Now, if the ogg stream works, the mp3 shoutcast stream should work as
+   * well (time will tell if that's true) */
+
+  /* Virgin Radio 32kbps mp3 shoutcast stream */
+  g_object_set (src, "location", "http://mp3-vr-32.smgradio.com:80/", NULL);
+
+
+  /* EOS after the first buffer */
+  g_object_set (src, "num-buffers", 1, NULL);
+
+  gst_element_set_state (pipe, GST_STATE_PLAYING);
+  msg = gst_bus_poll (GST_ELEMENT_BUS (pipe),
+      GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
+
+  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) {
+    GST_DEBUG ("success, we're done here");
+    gst_message_unref (msg);
+    goto done;
+  }
+
+  {
+    GError *err = NULL;
+
+    gst_message_parse_error (msg, &err, NULL);
+    gst_message_unref (msg);
+    g_error ("Error with ICY mp3 shoutcast stream: %s", err->message);
+    g_error_free (err);
+  }
+
+done:
+
+  gst_element_set_state (pipe, GST_STATE_NULL);
+  gst_object_unref (pipe);
+}
+
+GST_END_TEST;
+
+static Suite *
+souphttpsrc_suite (void)
+{
+  g_type_init ();
+  g_thread_init (NULL);
+
+  Suite *s = suite_create ("souphttpsrc");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  run_server (&http_port, &https_port);
+  tcase_add_test (tc_chain, test_first_buffer_has_offset);
+  tcase_add_test (tc_chain, test_https);
+  tcase_add_test (tc_chain, test_redirect_yes);
+  tcase_add_test (tc_chain, test_redirect_no);
+  tcase_add_test (tc_chain, test_not_found);
+  tcase_add_test (tc_chain, test_forbidden);
+  tcase_add_test (tc_chain, test_icy_stream);
+
+  return s;
+}
+
+GST_CHECK_MAIN (souphttpsrc);
+
+static void
+do_get (SoupMessage *msg, const char *path)
+{
+  char *uri;
+  int buflen = 4096;
+  SoupKnownStatusCode status = SOUP_STATUS_OK;
+  uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
+  GST_DEBUG ("request: \"%s\"", uri);
+
+  if (!strcmp (path, "/301"))
+      status = SOUP_STATUS_MOVED_PERMANENTLY;
+  else if (!strcmp (path, "/302"))
+      status = SOUP_STATUS_MOVED_TEMPORARILY;
+  else if (!strcmp (path, "/307"))
+    status = SOUP_STATUS_TEMPORARY_REDIRECT;
+  else if (!strcmp (path, "/403"))
+    status = SOUP_STATUS_FORBIDDEN;
+  else if (!strcmp (path, "/404"))
+    status = SOUP_STATUS_NOT_FOUND;
+
+  if (SOUP_STATUS_IS_REDIRECTION (status)) {
+      char *redir_uri;
+
+      redir_uri = g_strdup_printf ("%s-redirected", uri);
+      soup_message_headers_append (msg->response_headers,
+                                   "Location", redir_uri);
+      g_free (redir_uri);
+  }
+  if (status != SOUP_STATUS_OK)
+    goto leave;
+
+  if (msg->method == SOUP_METHOD_GET) {
+    char *buf;
+
+    buf = g_malloc (buflen);
+    memset (buf, 0, buflen);
+    soup_message_body_append (msg->response_body, SOUP_MEMORY_TAKE,
+        buf, buflen);
+  } else /* msg->method == SOUP_METHOD_HEAD */ {
+    char *length;
+
+    /* We could just use the same code for both GET and
+     * HEAD. But we'll optimize and avoid the extra
+     * malloc.
+     */
+    length = g_strdup_printf ("%lu", (gulong)buflen);
+    soup_message_headers_append (msg->response_headers,
+        "Content-Length", length);
+    g_free (length);
+  }
+
+leave:
+  soup_message_set_status (msg, status);
+  g_free (uri);
+}
+
+static void
+print_header (const char *name, const char *value, gpointer data)
+{
+  GST_DEBUG ("header: %s: %s", name, value);
+}
+
+static void
+server_callback (SoupServer *server, SoupMessage *msg,
+                 const char *path, GHashTable *query,
+                 SoupClientContext *context, gpointer data)
+{
+  GST_DEBUG ("%s %s HTTP/1.%d", msg->method, path,
+      soup_message_get_http_version (msg));
+  soup_message_headers_foreach (msg->request_headers, print_header, NULL);
+  if (msg->request_body->length)
+    GST_DEBUG ("%s", msg->request_body->data);
+
+  if (msg->method == SOUP_METHOD_GET || msg->method == SOUP_METHOD_HEAD)
+    do_get (msg, path);
+  else
+    soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
+
+  GST_DEBUG ("  -> %d %s", msg->status_code, msg->reason_phrase);
+}
+
+int
+run_server (int *http_port, int *https_port)
+{
+  SoupServer *server, *ssl_server;
+  int port = SOUP_ADDRESS_ANY_PORT;
+  int ssl_port = SOUP_ADDRESS_ANY_PORT;
+  const char *ssl_cert_file = "test-cert.pem", *ssl_key_file = "test-key.pem";
+  static int server_running = 0;
+
+  if (server_running)
+    return 0;
+  server_running = 1;
+
+  *http_port = *https_port = 0;
+
+  server = soup_server_new (SOUP_SERVER_PORT, port,
+                            NULL);
+  if (!server) {
+    GST_DEBUG ("Unable to bind to server port %d", port);
+    return 1;
+  }
+  *http_port = soup_server_get_port (server);
+  GST_INFO ("HTTP server listening on port %d", *http_port);
+  soup_server_add_handler (server, NULL,
+      server_callback, NULL, NULL);
+  soup_server_run_async (server);
+
+  if (ssl_cert_file && ssl_key_file) {
+    ssl_server = soup_server_new (
+        SOUP_SERVER_PORT, ssl_port,
+        SOUP_SERVER_SSL_CERT_FILE, ssl_cert_file,
+        SOUP_SERVER_SSL_KEY_FILE, ssl_key_file,
+        NULL);
+
+    if (!ssl_server) {
+      GST_DEBUG ("Unable to bind to SSL server port %d", ssl_port);
+      return 1;
+    }
+    *https_port = soup_server_get_port (ssl_server);
+    GST_INFO ("HTTPS server listening on port %d", *https_port);
+    soup_server_add_handler (ssl_server, NULL,
+        server_callback, NULL, NULL);
+    soup_server_run_async (ssl_server);
+  }
+
+  return 0;
+}
diff -upNar gst-plugins-bad.orig/tests/check/test-cert.pem gst-plugins-bad.new/tests/check/test-cert.pem
--- gst-plugins-bad.orig/tests/check/test-cert.pem	1970-01-01 01:00:00.000000000 +0100
+++ gst-plugins-bad.new/tests/check/test-cert.pem	2008-01-29 22:23:36.000000000 +0100
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDjzCCAvigAwIBAgIBADANBgkqhkiG9w0BAQQFADCBkjELMAkGA1UEBhMCVVMx
+FjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcTBkJvc3RvbjEPMA0GA1UE
+ChMGWGltaWFuMRUwEwYDVQQLEwxTb3VwIEtpdGNoZW4xEjAQBgNVBAMTCWxvY2Fs
+aG9zdDEeMBwGCSqGSIb3DQEJARYPc291cEB4aW1pYW4uY29tMB4XDTAzMDkyMzE4
+Mzc0MVoXDTEzMDkyMzE4Mzc0MVowgZIxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1N
+YXNzYWNodXNldHRzMQ8wDQYDVQQHEwZCb3N0b24xDzANBgNVBAoTBlhpbWlhbjEV
+MBMGA1UECxMMU291cCBLaXRjaGVuMRIwEAYDVQQDEwlsb2NhbGhvc3QxHjAcBgkq
+hkiG9w0BCQEWD3NvdXBAeGltaWFuLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEAwzT/WxfdXqb2hbyjQav3FtN7tLxj3UbZKCKDYlizBsNLxb9exfebhV4h
+CoAcaSNvLUnk3tAXnk+BDsIC1V4SbwqHYR17PnO3YZ8fkNwh5RGZwNx+zafdfFyu
++3Sh+mE03bljpDlTsgPL8CiFCd68MPRnuHoKt5iTpSyLC6Df0qcCAwEAAaOB8jCB
+7zAdBgNVHQ4EFgQU9A9omrgBK5Kkl6FRxrgJU2voj4Uwgb8GA1UdIwSBtzCBtIAU
+9A9omrgBK5Kkl6FRxrgJU2voj4WhgZikgZUwgZIxCzAJBgNVBAYTAlVTMRYwFAYD
+VQQIEw1NYXNzYWNodXNldHRzMQ8wDQYDVQQHEwZCb3N0b24xDzANBgNVBAoTBlhp
+bWlhbjEVMBMGA1UECxMMU291cCBLaXRjaGVuMRIwEAYDVQQDEwlsb2NhbGhvc3Qx
+HjAcBgkqhkiG9w0BCQEWD3NvdXBAeGltaWFuLmNvbYIBADAMBgNVHRMEBTADAQH/
+MA0GCSqGSIb3DQEBBAUAA4GBAGCV56N7bEDNdE76T8i68gS00NIVVosVQjS39Ojd
+ED+rvq0YYvuc2UXlzAonuCJfwFc73g4wSIjS0xijF5rnugZ+aay0LNv2y+Rf34CQ
+RNswrwurFjlxgTOO+Wx2IM64mAnBfj43M8uKEZFqAiGKrZZ0xIqyUMlku0FgXDH2
+Jvpg
+-----END CERTIFICATE-----
diff -upNar gst-plugins-bad.orig/tests/check/test-key.pem gst-plugins-bad.new/tests/check/test-key.pem
--- gst-plugins-bad.orig/tests/check/test-key.pem	1970-01-01 01:00:00.000000000 +0100
+++ gst-plugins-bad.new/tests/check/test-key.pem	2008-01-29 22:23:36.000000000 +0100
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDDNP9bF91epvaFvKNBq/cW03u0vGPdRtkoIoNiWLMGw0vFv17F
+95uFXiEKgBxpI28tSeTe0BeeT4EOwgLVXhJvCodhHXs+c7dhnx+Q3CHlEZnA3H7N
+p918XK77dKH6YTTduWOkOVOyA8vwKIUJ3rww9Ge4egq3mJOlLIsLoN/SpwIDAQAB
+AoGAOGAi6zzuKrrPcXo0L/ApEQeMr3rE4I/ogUXOaeWx9l8KkBafmU7UNGUl57Fu
+AxM/tXWkypCQcaEGZau0Q8jCS5wKgynNi72F4OzBqgjgW4vvtrjfC1LagnCd2ZMX
+V5XVECjO/sEDg0hJeOsXlKbECAgvHMU3dSCGO7DmuG9tIxkCQQDsth1VvVjOdfp6
+klOfYzbAM1p9HIcNPJMeuBFqq//UHX4aPqh/6G6W06TOTN+bjZBmitG9yjV958t2
+rPxl64f7AkEA0x0WOLm5S0LNsv7zwjXuTcj+NCHL36b3dK90oxX8Gq69PANL/EJY
+ItpHNLgzzo4DRmQy8q0WZlC9HYk1YljERQJAEN7+AkFnlfeErb3GJgMNQO+oEGi7
+G29o0PSvkRnHNxgPB9HVcqBfWXKmOWnzOgQB+b0FK/DAlUOzFbdImf8KhwJAFLty
+hzeV/tIcqUtoXNY3BOSMMkpvXxNikc75QVrTWzt10gLw32EUjreo7oB4dfx0TeFh
+L3vYC0w6hkAHQhU9kQJAPSEQ+Bqzlk6BrQNrNFEVzi1Rwpz7LOzhOjuYW6bsiAdX
+axA4r6Xh25x08ZU7cqX7gwVLHL6pgrEKuUs0Nc5Klg==
+-----END RSA PRIVATE KEY-----
