[GStreamer] don't send transferMode HTTP header
[WebKit-https.git] / Source / WebCore / platform / graphics / gstreamer / WebKitWebSourceGStreamer.cpp
index af78ae0..7c7741b 100644 (file)
 #include "CachedResourceHandle.h"
 #include "CachedResourceLoader.h"
 #include "CachedResourceRequest.h"
+#include "CrossOriginAccessControl.h"
 #include "GRefPtrGStreamer.h"
 #include "GStreamerUtilities.h"
+#include "HTTPHeaderNames.h"
 #include "MediaPlayer.h"
 #include "NotImplemented.h"
 #include "ResourceHandle.h"
 #include "ResourceHandleClient.h"
 #include "ResourceRequest.h"
 #include "ResourceResponse.h"
+#include "SecurityOrigin.h"
+#include "SharedBuffer.h"
 #include <gst/app/gstappsrc.h>
 #include <gst/gst.h>
 #include <gst/pbutils/missing-plugins.h>
 #include <wtf/Noncopyable.h>
+#include <wtf/gobject/GMainLoopSource.h>
 #include <wtf/gobject/GMutexLocker.h>
-#include <wtf/gobject/GOwnPtr.h>
 #include <wtf/gobject/GRefPtr.h>
+#include <wtf/gobject/GUniquePtr.h>
 #include <wtf/text/CString.h>
 
 using namespace WebCore;
 
+enum CORSAccessCheckResult {
+    CORSNoCheck,
+    CORSSuccess,
+    CORSFailure
+};
+
 class StreamingClient {
     public:
         StreamingClient(WebKitWebSrc*);
@@ -56,17 +67,17 @@ class StreamingClient {
 
     protected:
         char* createReadBuffer(size_t requestedSize, size_t& actualSize);
-        void handleResponseReceived(const ResourceResponse&);
+        void handleResponseReceived(const ResourceResponse&, CORSAccessCheckResult);
         void handleDataReceived(const char*, int);
         void handleNotifyFinished();
 
-        GRefPtr<GstElement> m_src;
+        GstElement* m_src;
 };
 
 class CachedResourceStreamingClient : public CachedRawResourceClient, public StreamingClient {
     WTF_MAKE_NONCOPYABLE(CachedResourceStreamingClient); WTF_MAKE_FAST_ALLOCATED;
     public:
-        CachedResourceStreamingClient(WebKitWebSrc*, CachedResourceLoader*, const ResourceRequest&);
+        CachedResourceStreamingClient(WebKitWebSrc*, CachedResourceLoader*, const ResourceRequest&, MediaPlayerClient::CORSMode);
         virtual ~CachedResourceStreamingClient();
 
         // StreamingClient virtual methods.
@@ -81,6 +92,7 @@ class CachedResourceStreamingClient : public CachedRawResourceClient, public Str
         virtual void notifyFinished(CachedResource*);
 
         CachedResourceHandle<CachedRawResource> m_resource;
+        RefPtr<SecurityOrigin> m_origin;
 };
 
 class ResourceHandleStreamingClient : public ResourceHandleClient, public StreamingClient {
@@ -98,7 +110,8 @@ class ResourceHandleStreamingClient : public ResourceHandleClient, public Stream
         virtual char* getOrCreateReadBuffer(size_t requestedSize, size_t& actualSize);
         virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&);
         virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
-        virtual void didReceiveData(ResourceHandle*, const char*, int, int);
+        virtual void didReceiveData(ResourceHandle*, const char*, unsigned, int);
+        virtual void didReceiveBuffer(ResourceHandle*, PassRefPtr<SharedBuffer>, int encodedLength);
         virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/);
         virtual void didFail(ResourceHandle*, const ResourceError&);
         virtual void wasBlocked(ResourceHandle*);
@@ -117,6 +130,8 @@ struct _WebKitWebSrcPrivate {
 
     StreamingClient* client;
 
+    CORSAccessCheckResult corsAccessCheck;
+
     guint64 offset;
     guint64 size;
     gboolean seekable;
@@ -124,16 +139,15 @@ struct _WebKitWebSrcPrivate {
 
     guint64 requestedOffset;
 
-    guint startID;
-    guint stopID;
-    guint needDataID;
-    guint enoughDataID;
-    guint seekID;
+    GMainLoopSource startSource;
+    GMainLoopSource stopSource;
+    GMainLoopSource needDataSource;
+    GMainLoopSource enoughDataSource;
+    GMainLoopSource seekSource;
 
     GRefPtr<GstBuffer> buffer;
 
     // icecast stuff
-    gboolean iradioMode;
     gchar* iradioName;
     gchar* iradioGenre;
     gchar* iradioUrl;
@@ -141,8 +155,7 @@ struct _WebKitWebSrcPrivate {
 };
 
 enum {
-    PROP_IRADIO_MODE = 1,
-    PROP_IRADIO_NAME,
+    PROP_IRADIO_NAME = 1,
     PROP_IRADIO_GENRE,
     PROP_IRADIO_URL,
     PROP_IRADIO_TITLE,
@@ -202,14 +215,6 @@ static void webkit_web_src_class_init(WebKitWebSrcClass* klass)
 
     // icecast stuff
     g_object_class_install_property(oklass,
-                                    PROP_IRADIO_MODE,
-                                    g_param_spec_boolean("iradio-mode",
-                                                         "iradio-mode",
-                                                         "Enable internet radio mode (extraction of shoutcast/icecast metadata)",
-                                                         FALSE,
-                                                         (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
-
-    g_object_class_install_property(oklass,
                                     PROP_IRADIO_NAME,
                                     g_param_spec_string("iradio-name",
                                                         "iradio-name",
@@ -261,6 +266,7 @@ static void webkit_web_src_init(WebKitWebSrc* src)
     WebKitWebSrcPrivate* priv = WEBKIT_WEB_SRC_GET_PRIVATE(src);
 
     src->priv = priv;
+    new (priv) WebKitWebSrcPrivate();
 
     priv->appsrc = GST_APP_SRC(gst_element_factory_make("appsrc", 0));
     if (!priv->appsrc) {
@@ -322,6 +328,7 @@ static void webKitWebSrcFinalize(GObject* object)
     WebKitWebSrcPrivate* priv = src->priv;
 
     g_free(priv->uri);
+    priv->~WebKitWebSrcPrivate();
 
     GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
 }
@@ -329,14 +336,8 @@ static void webKitWebSrcFinalize(GObject* object)
 static void webKitWebSrcSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* pspec)
 {
     WebKitWebSrc* src = WEBKIT_WEB_SRC(object);
-    WebKitWebSrcPrivate* priv = src->priv;
 
     switch (propID) {
-    case PROP_IRADIO_MODE: {
-        GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
-        priv->iradioMode = g_value_get_boolean(value);
-        break;
-    }
     case PROP_LOCATION:
         gst_uri_handler_set_uri(reinterpret_cast<GstURIHandler*>(src), g_value_get_string(value), 0);
         break;
@@ -351,11 +352,8 @@ static void webKitWebSrcGetProperty(GObject* object, guint propID, GValue* value
     WebKitWebSrc* src = WEBKIT_WEB_SRC(object);
     WebKitWebSrcPrivate* priv = src->priv;
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
     switch (propID) {
-    case PROP_IRADIO_MODE:
-        g_value_set_boolean(value, priv->iradioMode);
-        break;
     case PROP_IRADIO_NAME:
         g_value_set_string(value, priv->iradioName);
         break;
@@ -381,35 +379,23 @@ static void removeTimeoutSources(WebKitWebSrc* src)
 {
     WebKitWebSrcPrivate* priv = src->priv;
 
-    if (priv->startID)
-        g_source_remove(priv->startID);
-    priv->startID = 0;
-
-    if (priv->needDataID)
-        g_source_remove(priv->needDataID);
-    priv->needDataID = 0;
-
-    if (priv->enoughDataID)
-        g_source_remove(priv->enoughDataID);
-    priv->enoughDataID = 0;
-
-    if (priv->seekID)
-        g_source_remove(priv->seekID);
-    priv->seekID = 0;
+    priv->startSource.cancel();
+    priv->needDataSource.cancel();
+    priv->enoughDataSource.cancel();
+    priv->seekSource.cancel();
 }
 
-static gboolean webKitWebSrcStop(WebKitWebSrc* src)
+static void webKitWebSrcStop(WebKitWebSrc* src)
 {
     WebKitWebSrcPrivate* priv = src->priv;
 
     ASSERT(isMainThread());
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
 
-    bool seeking = priv->seekID;
+    bool seeking = priv->seekSource.isActive();
 
     removeTimeoutSources(src);
-    priv->stopID = 0;
 
     if (priv->client) {
         delete priv->client;
@@ -453,25 +439,23 @@ static gboolean webKitWebSrcStop(WebKitWebSrc* src)
     }
 
     GST_DEBUG_OBJECT(src, "Stopped request");
-
-    return FALSE;
 }
 
-static gboolean webKitWebSrcStart(WebKitWebSrc* src)
+static void webKitWebSrcStart(WebKitWebSrc* src)
 {
     WebKitWebSrcPrivate* priv = src->priv;
 
     ASSERT(isMainThread());
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
 
-    priv->startID = 0;
+    priv->corsAccessCheck = CORSNoCheck;
 
     if (!priv->uri) {
         GST_ERROR_OBJECT(src, "No URI provided");
         locker.unlock();
         webKitWebSrcStop(src);
-        return FALSE;
+        return;
     }
 
     ASSERT(!priv->client);
@@ -500,22 +484,17 @@ static gboolean webKitWebSrcStart(WebKitWebSrc* src)
         request.setHTTPUserAgent("Quicktime/7.6.6");
 
     if (priv->requestedOffset) {
-        GOwnPtr<gchar> val;
-
-        val.set(g_strdup_printf("bytes=%" G_GUINT64_FORMAT "-", priv->requestedOffset));
-        request.setHTTPHeaderField("Range", val.get());
+        GUniquePtr<gchar> val(g_strdup_printf("bytes=%" G_GUINT64_FORMAT "-", priv->requestedOffset));
+        request.setHTTPHeaderField(HTTPHeaderName::Range, val.get());
     }
     priv->offset = priv->requestedOffset;
 
-    if (priv->iradioMode)
-        request.setHTTPHeaderField("icy-metadata", "1");
-
-    // Needed to use DLNA streaming servers
-    request.setHTTPHeaderField("transferMode.dlna", "Streaming");
+    // We always request Icecast/Shoutcast metadata, just in case ...
+    request.setHTTPHeaderField(HTTPHeaderName::IcyMetadata, "1");
 
     if (priv->player) {
         if (CachedResourceLoader* loader = priv->player->cachedResourceLoader())
-            priv->client = new CachedResourceStreamingClient(src, loader, request);
+            priv->client = new CachedResourceStreamingClient(src, loader, request, priv->player->mediaPlayerClient()->mediaPlayerCORSMode());
     }
 
     if (!priv->client)
@@ -529,10 +508,9 @@ static gboolean webKitWebSrcStart(WebKitWebSrc* src)
         }
         locker.unlock();
         webKitWebSrcStop(src);
-        return FALSE;
+        return;
     }
     GST_DEBUG_OBJECT(src, "Started request");
-    return FALSE;
 }
 
 static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStateChange transition)
@@ -560,17 +538,21 @@ static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStat
         return ret;
     }
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
     switch (transition) {
     case GST_STATE_CHANGE_READY_TO_PAUSED:
         GST_DEBUG_OBJECT(src, "READY->PAUSED");
-        priv->startID = g_idle_add_full(G_PRIORITY_DEFAULT, (GSourceFunc) webKitWebSrcStart, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
+        gst_object_ref(src);
+        priv->startSource.schedule("[WebKit] webKitWebSrcStart", std::function<void()>(std::bind(webKitWebSrcStart, src)), G_PRIORITY_DEFAULT,
+            [src] { gst_object_unref(src); });
         break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
         GST_DEBUG_OBJECT(src, "PAUSED->READY");
         // cancel pending sources
         removeTimeoutSources(src);
-        priv->stopID = g_idle_add_full(G_PRIORITY_DEFAULT, (GSourceFunc) webKitWebSrcStop, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
+        gst_object_ref(src);
+        priv->stopSource.schedule("[WebKit] webKitWebSrcStop", std::function<void()>(std::bind(webKitWebSrcStop, src)), G_PRIORITY_DEFAULT,
+            [src] { gst_object_unref(src); });
         break;
     default:
         break;
@@ -591,7 +573,7 @@ static gboolean webKitWebSrcQueryWithParent(GstPad* pad, GstObject* parent, GstQ
         gst_query_parse_duration(query, &format, NULL);
 
         GST_DEBUG_OBJECT(src, "duration query in format %s", gst_format_get_name(format));
-        GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+        GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
         if (format == GST_FORMAT_BYTES && src->priv->size > 0) {
             gst_query_set_duration(query, format, src->priv->size);
             result = TRUE;
@@ -599,7 +581,7 @@ static gboolean webKitWebSrcQueryWithParent(GstPad* pad, GstObject* parent, GstQ
         break;
     }
     case GST_QUERY_URI: {
-        GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+        GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
         gst_query_set_uri(query, src->priv->uri);
         result = TRUE;
         break;
@@ -640,7 +622,7 @@ static gchar* webKitWebSrcGetUri(GstURIHandler* handler)
     WebKitWebSrc* src = WEBKIT_WEB_SRC(handler);
     gchar* ret;
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
     ret = g_strdup(src->priv->uri);
     return ret;
 }
@@ -655,7 +637,7 @@ static gboolean webKitWebSrcSetUri(GstURIHandler* handler, const gchar* uri, GEr
         return FALSE;
     }
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
 
     g_free(priv->uri);
     priv->uri = 0;
@@ -685,24 +667,18 @@ static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer)
 
 // appsrc callbacks
 
-static gboolean webKitWebSrcNeedDataMainCb(WebKitWebSrc* src)
+static void webKitWebSrcNeedDataMainCb(WebKitWebSrc* src)
 {
     WebKitWebSrcPrivate* priv = src->priv;
 
     ASSERT(isMainThread());
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
-    // already stopped
-    if (!priv->needDataID)
-        return FALSE;
-
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
     priv->paused = FALSE;
-    priv->needDataID = 0;
     locker.unlock();
 
     if (priv->client)
         priv->client->setDefersLoading(false);
-    return FALSE;
 }
 
 static void webKitWebSrcNeedDataCb(GstAppSrc*, guint length, gpointer userData)
@@ -712,32 +688,27 @@ static void webKitWebSrcNeedDataCb(GstAppSrc*, guint length, gpointer userData)
 
     GST_DEBUG_OBJECT(src, "Need more data: %u", length);
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
-    if (priv->needDataID || !priv->paused) {
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
+    if (priv->needDataSource.isScheduled() || !priv->paused)
         return;
-    }
 
-    priv->needDataID = g_idle_add_full(G_PRIORITY_DEFAULT, (GSourceFunc) webKitWebSrcNeedDataMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
+    gst_object_ref(src);
+    priv->needDataSource.schedule("[WebKit] webKitWebSrcNeedDataMainCb", std::function<void()>(std::bind(webKitWebSrcNeedDataMainCb, src)), G_PRIORITY_DEFAULT,
+        [src] { gst_object_unref(src); });
 }
 
-static gboolean webKitWebSrcEnoughDataMainCb(WebKitWebSrc* src)
+static void webKitWebSrcEnoughDataMainCb(WebKitWebSrc* src)
 {
     WebKitWebSrcPrivate* priv = src->priv;
 
     ASSERT(isMainThread());
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
-    // already stopped
-    if (!priv->enoughDataID)
-        return FALSE;
-
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
     priv->paused = TRUE;
-    priv->enoughDataID = 0;
     locker.unlock();
 
     if (priv->client)
         priv->client->setDefersLoading(true);
-    return FALSE;
 }
 
 static void webKitWebSrcEnoughDataCb(GstAppSrc*, gpointer userData)
@@ -747,30 +718,21 @@ static void webKitWebSrcEnoughDataCb(GstAppSrc*, gpointer userData)
 
     GST_DEBUG_OBJECT(src, "Have enough data");
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
-    if (priv->enoughDataID || priv->paused) {
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
+    if (priv->enoughDataSource.isScheduled() || priv->paused)
         return;
-    }
 
-    priv->enoughDataID = g_idle_add_full(G_PRIORITY_DEFAULT, (GSourceFunc) webKitWebSrcEnoughDataMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
+    gst_object_ref(src);
+    priv->enoughDataSource.schedule("[WebKit] webKitWebSrcEnoughDataMainCb", std::function<void()>(std::bind(webKitWebSrcEnoughDataMainCb, src)), G_PRIORITY_DEFAULT,
+        [src] { gst_object_unref(src); });
 }
 
-static gboolean webKitWebSrcSeekMainCb(WebKitWebSrc* src)
+static void webKitWebSrcSeekMainCb(WebKitWebSrc* src)
 {
-    WebKitWebSrcPrivate* priv = src->priv;
-
     ASSERT(isMainThread());
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
-    // already stopped
-    if (!priv->seekID)
-        return FALSE;
-    locker.unlock();
-
     webKitWebSrcStop(src);
     webKitWebSrcStart(src);
-
-    return FALSE;
 }
 
 static gboolean webKitWebSrcSeekDataCb(GstAppSrc*, guint64 offset, gpointer userData)
@@ -779,7 +741,7 @@ static gboolean webKitWebSrcSeekDataCb(GstAppSrc*, guint64 offset, gpointer user
     WebKitWebSrcPrivate* priv = src->priv;
 
     GST_DEBUG_OBJECT(src, "Seeking to offset: %" G_GUINT64_FORMAT, offset);
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
     if (offset == priv->offset && priv->requestedOffset == priv->offset)
         return TRUE;
 
@@ -789,31 +751,37 @@ static gboolean webKitWebSrcSeekDataCb(GstAppSrc*, guint64 offset, gpointer user
     GST_DEBUG_OBJECT(src, "Doing range-request seek");
     priv->requestedOffset = offset;
 
-    if (priv->seekID)
-        g_source_remove(priv->seekID);
-    priv->seekID = g_idle_add_full(G_PRIORITY_DEFAULT, (GSourceFunc) webKitWebSrcSeekMainCb, gst_object_ref(src), (GDestroyNotify) gst_object_unref);
+    gst_object_ref(src);
+    priv->seekSource.schedule("[WebKit] webKitWebSrcSeekMainCb", std::function<void()>(std::bind(webKitWebSrcSeekMainCb, src)), G_PRIORITY_DEFAULT,
+        [src] { gst_object_unref(src); });
     return TRUE;
 }
 
 void webKitWebSrcSetMediaPlayer(WebKitWebSrc* src, WebCore::MediaPlayer* player)
 {
     ASSERT(player);
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
     src->priv->player = player;
 }
 
+bool webKitSrcPassedCORSAccessCheck(WebKitWebSrc* src)
+{
+    return src->priv->corsAccessCheck == CORSSuccess;
+}
+
 StreamingClient::StreamingClient(WebKitWebSrc* src)
-    : m_src(adoptGRef(static_cast<GstElement*>(gst_object_ref(src))))
+    : m_src(static_cast<GstElement*>(gst_object_ref(src)))
 {
 }
 
 StreamingClient::~StreamingClient()
 {
+    gst_object_unref(m_src);
 }
 
 char* StreamingClient::createReadBuffer(size_t requestedSize, size_t& actualSize)
 {
-    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
+    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
     WebKitWebSrcPrivate* priv = src->priv;
 
     ASSERT(!priv->buffer);
@@ -822,7 +790,7 @@ char* StreamingClient::createReadBuffer(size_t requestedSize, size_t& actualSize
 
     mapGstBuffer(buffer);
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
     priv->buffer = adoptGRef(buffer);
     locker.unlock();
 
@@ -830,24 +798,29 @@ char* StreamingClient::createReadBuffer(size_t requestedSize, size_t& actualSize
     return getGstBufferDataPointer(buffer);
 }
 
-void StreamingClient::handleResponseReceived(const ResourceResponse& response)
+void StreamingClient::handleResponseReceived(const ResourceResponse& response, CORSAccessCheckResult corsAccessCheck)
 {
-    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
+    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
     WebKitWebSrcPrivate* priv = src->priv;
 
     GST_DEBUG_OBJECT(src, "Received response: %d", response.httpStatusCode());
 
-    if (response.httpStatusCode() >= 400) {
-        // Received error code
-        GST_ELEMENT_ERROR(src, RESOURCE, READ, ("Received %d HTTP error code", response.httpStatusCode()), (0));
+    if (response.httpStatusCode() >= 400 || corsAccessCheck == CORSFailure) {
+        // Received error code or CORS check failed
+        if (corsAccessCheck == CORSFailure)
+            GST_ELEMENT_ERROR(src, RESOURCE, READ, ("Cross-origin stream load denied by Cross-Origin Resource Sharing policy."), (nullptr));
+        else
+            GST_ELEMENT_ERROR(src, RESOURCE, READ, ("Received %d HTTP error code", response.httpStatusCode()), (nullptr));
         gst_app_src_end_of_stream(priv->appsrc);
         webKitWebSrcStop(src);
         return;
     }
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
 
-    if (priv->seekID) {
+    priv->corsAccessCheck = corsAccessCheck;
+
+    if (priv->seekSource.isActive()) {
         GST_DEBUG_OBJECT(src, "Seek in progress, ignoring response");
         return;
     }
@@ -860,7 +833,7 @@ void StreamingClient::handleResponseReceived(const ResourceResponse& response)
         } else if (response.httpStatusCode() != 206) {
             // Range request completely failed.
             locker.unlock();
-            GST_ELEMENT_ERROR(src, RESOURCE, READ, ("Received unexpected %d HTTP status code", response.httpStatusCode()), (0));
+            GST_ELEMENT_ERROR(src, RESOURCE, READ, ("Received unexpected %d HTTP status code", response.httpStatusCode()), (nullptr));
             gst_app_src_end_of_stream(priv->appsrc);
             webKitWebSrcStop(src);
             return;
@@ -872,31 +845,34 @@ void StreamingClient::handleResponseReceived(const ResourceResponse& response)
         length += priv->requestedOffset;
 
     priv->size = length >= 0 ? length : 0;
-    priv->seekable = length > 0 && g_ascii_strcasecmp("none", response.httpHeaderField("Accept-Ranges").utf8().data());
+    priv->seekable = length > 0 && g_ascii_strcasecmp("none", response.httpHeaderField(HTTPHeaderName::AcceptRanges).utf8().data());
+
+    // Wait until we unlock to send notifications
+    g_object_freeze_notify(G_OBJECT(src));
 
     GstTagList* tags = gst_tag_list_new_empty();
-    String value = response.httpHeaderField("icy-name");
+    String value = response.httpHeaderField(HTTPHeaderName::IcyName);
     if (!value.isEmpty()) {
         g_free(priv->iradioName);
         priv->iradioName = g_strdup(value.utf8().data());
         g_object_notify(G_OBJECT(src), "iradio-name");
         gst_tag_list_add(tags, GST_TAG_MERGE_REPLACE, GST_TAG_ORGANIZATION, priv->iradioName, NULL);
     }
-    value = response.httpHeaderField("icy-genre");
+    value = response.httpHeaderField(HTTPHeaderName::IcyGenre);
     if (!value.isEmpty()) {
         g_free(priv->iradioGenre);
         priv->iradioGenre = g_strdup(value.utf8().data());
         g_object_notify(G_OBJECT(src), "iradio-genre");
         gst_tag_list_add(tags, GST_TAG_MERGE_REPLACE, GST_TAG_GENRE, priv->iradioGenre, NULL);
     }
-    value = response.httpHeaderField("icy-url");
+    value = response.httpHeaderField(HTTPHeaderName::IcyURL);
     if (!value.isEmpty()) {
         g_free(priv->iradioUrl);
         priv->iradioUrl = g_strdup(value.utf8().data());
         g_object_notify(G_OBJECT(src), "iradio-url");
         gst_tag_list_add(tags, GST_TAG_MERGE_REPLACE, GST_TAG_LOCATION, priv->iradioUrl, NULL);
     }
-    value = response.httpHeaderField("icy-title");
+    value = response.httpHeaderField(HTTPHeaderName::IcyTitle);
     if (!value.isEmpty()) {
         g_free(priv->iradioTitle);
         priv->iradioTitle = g_strdup(value.utf8().data());
@@ -905,6 +881,7 @@ void StreamingClient::handleResponseReceived(const ResourceResponse& response)
     }
 
     locker.unlock();
+    g_object_thaw_notify(G_OBJECT(src));
 
     // notify size/duration
     if (length > 0) {
@@ -913,7 +890,7 @@ void StreamingClient::handleResponseReceived(const ResourceResponse& response)
         gst_app_src_set_size(priv->appsrc, -1);
 
     // icecast stuff
-    value = response.httpHeaderField("icy-metaint");
+    value = response.httpHeaderField(HTTPHeaderName::IcyMetaInt);
     if (!value.isEmpty()) {
         gchar* endptr = 0;
         gint64 icyMetaInt = g_ascii_strtoll(value.utf8().data(), &endptr, 10);
@@ -935,19 +912,19 @@ void StreamingClient::handleResponseReceived(const ResourceResponse& response)
 
 void StreamingClient::handleDataReceived(const char* data, int length)
 {
-    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
+    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
     WebKitWebSrcPrivate* priv = src->priv;
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
 
-    GST_LOG_OBJECT(src, "Have %ld bytes of data", priv->buffer ? gst_buffer_get_size(priv->buffer.get()) : length);
+    GST_LOG_OBJECT(src, "Have %lld bytes of data", priv->buffer ? static_cast<long long>(gst_buffer_get_size(priv->buffer.get())) : length);
 
     ASSERT(!priv->buffer || data == getGstBufferDataPointer(priv->buffer.get()));
 
     if (priv->buffer)
         unmapGstBuffer(priv->buffer.get());
 
-    if (priv->seekID) {
+    if (priv->seekSource.isActive()) {
         GST_DEBUG_OBJECT(src, "Seek in progress, ignoring data");
         priv->buffer.clear();
         return;
@@ -1002,23 +979,34 @@ void StreamingClient::handleDataReceived(const char* data, int length)
 
 void StreamingClient::handleNotifyFinished()
 {
-    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
+    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
     WebKitWebSrcPrivate* priv = src->priv;
 
     GST_DEBUG_OBJECT(src, "Have EOS");
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
-    if (!priv->seekID) {
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
+    if (!priv->seekSource.isActive()) {
         locker.unlock();
         gst_app_src_end_of_stream(priv->appsrc);
     }
 }
 
-CachedResourceStreamingClient::CachedResourceStreamingClient(WebKitWebSrc* src, CachedResourceLoader* resourceLoader, const ResourceRequest& request)
+CachedResourceStreamingClient::CachedResourceStreamingClient(WebKitWebSrc* src, CachedResourceLoader* resourceLoader, const ResourceRequest& request, MediaPlayerClient::CORSMode corsMode)
     : StreamingClient(src)
 {
     DataBufferingPolicy bufferingPolicy = request.url().protocolIs("blob") ? BufferData : DoNotBufferData;
-    CachedResourceRequest cacheRequest(request, ResourceLoaderOptions(SendCallbacks, DoNotSniffContent, bufferingPolicy, DoNotAllowStoredCredentials, DoNotAskClientForCrossOriginCredentials, DoSecurityCheck, UseDefaultOriginRestrictionsForType));
+    RequestOriginPolicy corsPolicy = corsMode != MediaPlayerClient::Unspecified ? PotentiallyCrossOriginEnabled : UseDefaultOriginRestrictionsForType;
+    StoredCredentials allowCredentials = corsMode == MediaPlayerClient::UseCredentials ? AllowStoredCredentials : DoNotAllowStoredCredentials;
+    ResourceLoaderOptions options(SendCallbacks, DoNotSniffContent, bufferingPolicy, allowCredentials, DoNotAskClientForCrossOriginCredentials, DoSecurityCheck, corsPolicy, DoNotIncludeCertificateInfo);
+
+    CachedResourceRequest cacheRequest(request, options);
+
+    if (corsMode != MediaPlayerClient::Unspecified) {
+        m_origin = resourceLoader->document() ? resourceLoader->document()->securityOrigin() : nullptr;
+        updateRequestForAccessControl(cacheRequest.mutableResourceRequest(), m_origin.get(), allowCredentials);
+    }
+
+    // TODO: Decide whether to use preflight mode for cross-origin requests (see http://wkbug.com/131484).
     m_resource = resourceLoader->requestRawResource(cacheRequest);
     if (m_resource)
         m_resource->addClient(this);
@@ -1048,9 +1036,12 @@ char* CachedResourceStreamingClient::getOrCreateReadBuffer(CachedResource*, size
     return createReadBuffer(requestedSize, actualSize);
 }
 
-void CachedResourceStreamingClient::responseReceived(CachedResource*, const ResourceResponse& response)
+void CachedResourceStreamingClient::responseReceived(CachedResource* resource, const ResourceResponse& response)
 {
-    handleResponseReceived(response);
+    CORSAccessCheckResult corsAccessCheck = CORSNoCheck;
+    if (m_origin)
+        corsAccessCheck = (m_origin->canRequest(response.url()) || resource->passesAccessControlCheck(m_origin.get())) ? CORSSuccess : CORSFailure;
+    handleResponseReceived(response, corsAccessCheck);
 }
 
 void CachedResourceStreamingClient::dataReceived(CachedResource*, const char* data, int length)
@@ -1061,7 +1052,7 @@ void CachedResourceStreamingClient::dataReceived(CachedResource*, const char* da
 void CachedResourceStreamingClient::notifyFinished(CachedResource* resource)
 {
     if (resource->loadFailedOrCanceled()) {
-        WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
+        WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
 
         if (!resource->wasCanceled()) {
             const ResourceError& error = resource->resourceError();
@@ -1112,12 +1103,23 @@ void ResourceHandleStreamingClient::willSendRequest(ResourceHandle*, ResourceReq
 
 void ResourceHandleStreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
 {
-    handleResponseReceived(response);
+    handleResponseReceived(response, CORSNoCheck);
 }
 
-void ResourceHandleStreamingClient::didReceiveData(ResourceHandle*, const char* data, int length, int)
+void ResourceHandleStreamingClient::didReceiveData(ResourceHandle*, const char* /* data */, unsigned /* length */, int)
 {
-    handleDataReceived(data, length);
+    ASSERT_NOT_REACHED();
+}
+
+void ResourceHandleStreamingClient::didReceiveBuffer(ResourceHandle*, PassRefPtr<SharedBuffer> buffer, int /* encodedLength */)
+{
+    // This pattern is suggested by SharedBuffer.h.
+    const char* segment;
+    unsigned position = 0;
+    while (unsigned length = buffer->getSomeData(segment, position)) {
+        handleDataReceived(segment, length);
+        position += length;
+    }
 }
 
 void ResourceHandleStreamingClient::didFinishLoading(ResourceHandle*, double)
@@ -1127,7 +1129,7 @@ void ResourceHandleStreamingClient::didFinishLoading(ResourceHandle*, double)
 
 void ResourceHandleStreamingClient::didFail(ResourceHandle*, const ResourceError& error)
 {
-    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
+    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
 
     GST_ERROR_OBJECT(src, "Have failure: %s", error.localizedDescription().utf8().data());
     GST_ELEMENT_ERROR(src, RESOURCE, FAILED, ("%s", error.localizedDescription().utf8().data()), (0));
@@ -1136,13 +1138,13 @@ void ResourceHandleStreamingClient::didFail(ResourceHandle*, const ResourceError
 
 void ResourceHandleStreamingClient::wasBlocked(ResourceHandle*)
 {
-    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
-    GOwnPtr<gchar> uri;
+    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
+    GUniquePtr<gchar> uri;
 
     GST_ERROR_OBJECT(src, "Request was blocked");
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
-    uri.set(g_strdup(src->priv->uri));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
+    uri.reset(g_strdup(src->priv->uri));
     locker.unlock();
 
     GST_ELEMENT_ERROR(src, RESOURCE, OPEN_READ, ("Access to \"%s\" was blocked", uri.get()), (0));
@@ -1150,13 +1152,13 @@ void ResourceHandleStreamingClient::wasBlocked(ResourceHandle*)
 
 void ResourceHandleStreamingClient::cannotShowURL(ResourceHandle*)
 {
-    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src.get());
-    GOwnPtr<gchar> uri;
+    WebKitWebSrc* src = WEBKIT_WEB_SRC(m_src);
+    GUniquePtr<gchar> uri;
 
     GST_ERROR_OBJECT(src, "Cannot show URL");
 
-    GMutexLocker locker(GST_OBJECT_GET_LOCK(src));
-    uri.set(g_strdup(src->priv->uri));
+    GMutexLocker locker(*GST_OBJECT_GET_LOCK(src));
+    uri.reset(g_strdup(src->priv->uri));
     locker.unlock();
 
     GST_ELEMENT_ERROR(src, RESOURCE, OPEN_READ, ("Can't show \"%s\"", uri.get()), (0));