souphttpsrc: Remove cookie_jar patch
[platform/upstream/gst-plugins-good.git] / ext / soup / gstsouphttpsrc.c
index f6b8fb4..09d3828 100644 (file)
@@ -86,6 +86,8 @@
 GST_DEBUG_CATEGORY_STATIC (souphttpsrc_debug);
 #define GST_CAT_DEFAULT souphttpsrc_debug
 
+#define GST_SOUP_SESSION_CONTEXT "gst.soup.session"
+
 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
@@ -123,7 +125,7 @@ enum
 #define DEFAULT_IRADIO_MODE          TRUE
 #define DEFAULT_SOUP_LOG_LEVEL       SOUP_LOGGER_LOG_HEADERS
 #define DEFAULT_COMPRESS             FALSE
-#define DEFAULT_KEEP_ALIVE           FALSE
+#define DEFAULT_KEEP_ALIVE           TRUE
 #define DEFAULT_SSL_STRICT           TRUE
 #define DEFAULT_SSL_CA_FILE          NULL
 #define DEFAULT_SSL_USE_SYSTEM_CA_FILE TRUE
@@ -139,6 +141,12 @@ enum
 #define REDUCE_BLOCKSIZE_LIMIT 0.20
 #define REDUCE_BLOCKSIZE_COUNT 2
 #define REDUCE_BLOCKSIZE_FACTOR 0.5
+#define GROW_TIME_LIMIT (1 * GST_SECOND)
+
+#ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+#define DLNA_OP_TIMED_SEEK  0x02
+#define DLNA_OP_BYTE_SEEK   0x01
+#endif
 
 static void gst_soup_http_src_uri_handler_init (gpointer g_iface,
     gpointer iface_data);
@@ -152,6 +160,8 @@ static void gst_soup_http_src_get_property (GObject * object, guint prop_id,
 
 static GstStateChangeReturn gst_soup_http_src_change_state (GstElement *
     element, GstStateChange transition);
+static void gst_soup_http_src_set_context (GstElement * element,
+    GstContext * context);
 static GstFlowReturn gst_soup_http_src_create (GstPushSrc * psrc,
     GstBuffer ** outbuf);
 static gboolean gst_soup_http_src_start (GstBaseSrc * bsrc);
@@ -413,6 +423,8 @@ gst_soup_http_src_class_init (GstSoupHTTPSrcClass * klass)
       "Wouter Cloetens <wouter@mind.be>");
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_soup_http_src_change_state);
+  gstelement_class->set_context =
+      GST_DEBUG_FUNCPTR (gst_soup_http_src_set_context);
 
   gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_soup_http_src_start);
   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_soup_http_src_stop);
@@ -446,6 +458,7 @@ gst_soup_http_src_reset (GstSoupHTTPSrc * src)
 
   src->reduce_blocksize_count = 0;
   src->increase_blocksize_count = 0;
+  src->last_socket_read_time = 0;
 
 #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
   if (src->dash_oldest_segment) {
@@ -456,13 +469,16 @@ gst_soup_http_src_reset (GstSoupHTTPSrc * src)
     g_free (src->dash_newest_segment);
     src->dash_newest_segment = NULL;
   }
+  src->dlna_opt = 0;
 #endif
 
   g_cancellable_reset (src->cancellable);
+  g_mutex_lock (&src->mutex);
   if (src->input_stream) {
     g_object_unref (src->input_stream);
     src->input_stream = NULL;
   }
+  g_mutex_unlock (&src->mutex);
 
   gst_caps_replace (&src->src_caps, NULL);
   g_free (src->iradio_name);
@@ -492,9 +508,13 @@ gst_soup_http_src_init (GstSoupHTTPSrc * src)
   src->cookies = NULL;
   src->iradio_mode = DEFAULT_IRADIO_MODE;
   src->session = NULL;
+  src->external_session = NULL;
+  src->forced_external_session = FALSE;
   src->msg = NULL;
   src->timeout = DEFAULT_TIMEOUT;
   src->log_level = DEFAULT_SOUP_LOG_LEVEL;
+  src->compress = DEFAULT_COMPRESS;
+  src->keep_alive = DEFAULT_KEEP_ALIVE;
   src->ssl_strict = DEFAULT_SSL_STRICT;
   src->ssl_use_system_ca_file = DEFAULT_SSL_USE_SYSTEM_CA_FILE;
   src->tls_database = DEFAULT_TLS_DATABASE;
@@ -505,6 +525,8 @@ gst_soup_http_src_init (GstSoupHTTPSrc * src)
 #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
   src->dash_oldest_segment = NULL;
   src->dash_newest_segment = NULL;
+  src->received_total = 0;
+  src->dlna_opt = 0;
 #endif
   proxy = g_getenv ("http_proxy");
   if (!gst_soup_http_src_set_proxy (src, proxy)) {
@@ -512,9 +534,7 @@ gst_soup_http_src_init (GstSoupHTTPSrc * src)
         "The proxy in the http_proxy env var (\"%s\") cannot be parsed.",
         proxy);
   }
-#ifdef TIZEN_FEATURE_SOUP_MODIFICATION
-  src->cookie_jar  = NULL;
-#endif
+
   gst_base_src_set_automatic_eos (GST_BASE_SRC (src), FALSE);
 
   gst_soup_http_src_reset (src);
@@ -529,6 +549,11 @@ gst_soup_http_src_dispose (GObject * gobject)
 
   gst_soup_http_src_session_close (src);
 
+  if (src->external_session) {
+    g_object_unref (src->external_session);
+    src->external_session = NULL;
+  }
+
   G_OBJECT_CLASS (parent_class)->dispose (gobject);
 }
 
@@ -616,29 +641,8 @@ gst_soup_http_src_set_property (GObject * object, guint prop_id,
       break;
     }
     case PROP_COOKIES:
-#ifdef TIZEN_FEATURE_SOUP_MODIFICATION
-    {
-      char **array;
-      SoupURI *base_uri;
       g_strfreev (src->cookies);
       src->cookies = g_strdupv (g_value_get_boxed (value));
-
-      if (src->cookie_jar && ((array = src->cookies) != NULL)) {
-        base_uri = soup_uri_new (src->location);
-        GST_INFO_OBJECT (src, "request to set cookies...");
-        while (*array != NULL) {
-          soup_cookie_jar_add_cookie (src->cookie_jar,
-              soup_cookie_parse (*array++, base_uri));
-        }
-        soup_uri_free (base_uri);
-      } else {
-        GST_INFO_OBJECT (src, "set cookies after session creation");
-      }
-    }
-#else
-      g_strfreev (src->cookies);
-      src->cookies = g_strdupv (g_value_get_boxed (value));
-#endif
       break;
     case PROP_IS_LIVE:
       gst_base_src_set_live (GST_BASE_SRC (src), g_value_get_boolean (value));
@@ -734,32 +738,12 @@ gst_soup_http_src_get_property (GObject * object, guint prop_id,
         g_value_set_static_string (value, "");
       else {
         char *proxy = soup_uri_to_string (src->proxy, FALSE);
-
         g_value_set_string (value, proxy);
         g_free (proxy);
       }
       break;
     case PROP_COOKIES:
-#ifdef TIZEN_FEATURE_SOUP_MODIFICATION
-    {
-        GSList *cookie_list, *c;
-        gchar **cookies, **array;
-
-        cookies = NULL;
-        if ((src->cookie_jar) &&
-            ((cookie_list = soup_cookie_jar_all_cookies (src->cookie_jar)) != NULL)) {
-          cookies = g_new0 (gchar *, g_slist_length(cookie_list) + 1);
-          array = cookies;
-          for (c = cookie_list; c; c = c->next) {
-            *array++ = soup_cookie_to_set_cookie_header ((SoupCookie *)(c->data));
-          }
-          soup_cookies_free (cookie_list);
-        }
-        g_value_set_boxed (value, cookies);
-    }
-#else
-        g_value_set_boxed (value, g_strdupv (src->cookies));
-#endif
+      g_value_set_boxed (value, g_strdupv (src->cookies));
       break;
     case PROP_IS_LIVE:
       g_value_set_boolean (value, gst_base_src_is_live (GST_BASE_SRC (src)));
@@ -862,13 +846,12 @@ gst_soup_http_src_add_range_header (GstSoupHTTPSrc * src, guint64 offset,
           stop_offset);
     } else {
       rc = g_snprintf (buf, sizeof (buf), "bytes=%" G_GUINT64_FORMAT "-",
-                offset);
+          offset);
     }
     if (rc > sizeof (buf) || rc < 0)
       return FALSE;
     soup_message_headers_append (src->msg->request_headers, "Range", buf);
   }
-
   src->read_position = offset;
   return TRUE;
 }
@@ -902,35 +885,6 @@ _append_extra_header (GQuark field_id, const GValue * value, gpointer user_data)
   soup_message_headers_append (src->msg->request_headers, field_name,
       field_content);
 
-#ifdef TIZEN_FEATURE_SOUP_MODIFICATION
-  if (!g_ascii_strcasecmp(field_name, "Cookie")) {
-    SoupURI *uri = NULL;
-    SoupCookie *cookie_parsed = NULL;
-    gchar *saveptr = NULL;
-
-    if (strlen(field_content) > 0) {
-      gchar *tmp_field = NULL;
-
-      uri = soup_uri_new (src->location);
-
-      tmp_field = strtok_r (field_content, ";", &saveptr);
-
-      while (tmp_field != NULL) {
-        GST_DEBUG_OBJECT (src, "field_content = %s", tmp_field);
-
-        cookie_parsed = soup_cookie_parse(tmp_field, uri);
-        GST_DEBUG_OBJECT (src, "cookie parsed = %p", cookie_parsed);
-
-        if (src->cookie_jar)
-          soup_cookie_jar_add_cookie (src->cookie_jar, cookie_parsed);
-
-        tmp_field = strtok_r (NULL, ";", &saveptr);
-      }
-      soup_uri_free (uri);
-    }
-  }
-#endif
-
   g_free (field_content);
 
   return TRUE;
@@ -992,72 +946,119 @@ gst_soup_http_src_session_open (GstSoupHTTPSrc * src)
   }
 
   if (!src->session) {
-    GST_DEBUG_OBJECT (src, "Creating session");
-    if (src->proxy == NULL) {
-      src->session =
-          soup_session_new_with_options (SOUP_SESSION_USER_AGENT,
-          src->user_agent, SOUP_SESSION_TIMEOUT, src->timeout,
-          SOUP_SESSION_SSL_STRICT, src->ssl_strict, NULL);
-//          SOUP_SESSION_TLS_INTERACTION, src->tls_interaction, NULL);
+    GstQuery *query;
+    gboolean can_share = (src->timeout == DEFAULT_TIMEOUT)
+        && (src->ssl_strict == DEFAULT_SSL_STRICT)
+        && (src->tls_interaction == NULL) && (src->proxy == NULL)
+        && (src->tls_database == DEFAULT_TLS_DATABASE)
+        && (src->ssl_ca_file == DEFAULT_SSL_CA_FILE)
+        && (src->ssl_use_system_ca_file == DEFAULT_SSL_USE_SYSTEM_CA_FILE);
+
+    query = gst_query_new_context (GST_SOUP_SESSION_CONTEXT);
+    if (gst_pad_peer_query (GST_BASE_SRC_PAD (src), query)) {
+      GstContext *context;
+
+      gst_query_parse_context (query, &context);
+      gst_element_set_context (GST_ELEMENT_CAST (src), context);
     } else {
-      src->session =
-          soup_session_new_with_options (SOUP_SESSION_PROXY_URI, src->proxy,
-          SOUP_SESSION_TIMEOUT, src->timeout,
-          SOUP_SESSION_SSL_STRICT, src->ssl_strict,
-          SOUP_SESSION_USER_AGENT, src->user_agent, NULL);
-//          SOUP_SESSION_TLS_INTERACTION, src->tls_interaction, NULL);
-    }
+      GstMessage *message;
 
-    if (!src->session) {
-      GST_ELEMENT_ERROR (src, LIBRARY, INIT,
-          (NULL), ("Failed to create async session"));
-      return FALSE;
+      message =
+          gst_message_new_need_context (GST_OBJECT_CAST (src),
+          GST_SOUP_SESSION_CONTEXT);
+      gst_element_post_message (GST_ELEMENT_CAST (src), message);
     }
+    gst_query_unref (query);
+
+    GST_OBJECT_LOCK (src);
+    if (src->external_session && (can_share || src->forced_external_session)) {
+      GST_DEBUG_OBJECT (src, "Using external session %p",
+          src->external_session);
+      src->session = g_object_ref (src->external_session);
+      src->session_is_shared = TRUE;
+    } else {
+      GST_DEBUG_OBJECT (src, "Creating session (can share %d)", can_share);
+
+      /* We explicitly set User-Agent to NULL here and overwrite it per message
+       * to be able to have the same session with different User-Agents per
+       * source */
+      if (src->proxy == NULL) {
+        src->session =
+            soup_session_new_with_options (SOUP_SESSION_USER_AGENT,
+            NULL, SOUP_SESSION_TIMEOUT, src->timeout,
+            SOUP_SESSION_SSL_STRICT, src->ssl_strict,
+            SOUP_SESSION_TLS_INTERACTION, src->tls_interaction, NULL);
+      } else {
+        src->session =
+            soup_session_new_with_options (SOUP_SESSION_PROXY_URI, src->proxy,
+            SOUP_SESSION_TIMEOUT, src->timeout,
+            SOUP_SESSION_SSL_STRICT, src->ssl_strict,
+            SOUP_SESSION_USER_AGENT, NULL,
+            SOUP_SESSION_TLS_INTERACTION, src->tls_interaction, NULL);
+      }
 
-#ifdef TIZEN_FEATURE_SOUP_MODIFICATION
-    {
-      char **array = NULL;
-      SoupURI *base_uri;
-      SoupCookie *soup_cookie = NULL;
-
-      soup_session_add_feature_by_type (src->session, SOUP_TYPE_COOKIE_JAR);
-      src->cookie_jar = SOUP_COOKIE_JAR (soup_session_get_feature (src->session, SOUP_TYPE_COOKIE_JAR));
-      if ((array = src->cookies) != NULL) {
-        base_uri = soup_uri_new (src->location);
-        while (*array != NULL) {
-          soup_cookie = soup_cookie_parse (*array++, base_uri);
-          if (soup_cookie != NULL) {
-            GST_INFO_OBJECT (src, "adding cookies..");
-            soup_cookie_jar_add_cookie (src->cookie_jar, soup_cookie);
-          }
+      if (src->session) {
+        gst_soup_util_log_setup (src->session, src->log_level,
+            GST_ELEMENT (src));
+        soup_session_add_feature_by_type (src->session,
+            SOUP_TYPE_CONTENT_DECODER);
+        soup_session_add_feature_by_type (src->session, SOUP_TYPE_COOKIE_JAR);
+
+        if (can_share) {
+          GstContext *context;
+          GstMessage *message;
+          GstStructure *s;
+
+          GST_DEBUG_OBJECT (src, "Sharing session %p", src->session);
+          src->session_is_shared = TRUE;
+
+          /* Unset the limit the number of maximum allowed connection */
+          g_object_set (src->session, SOUP_SESSION_MAX_CONNS, G_MAXINT,
+              SOUP_SESSION_MAX_CONNS_PER_HOST, G_MAXINT, NULL);
+
+          context = gst_context_new (GST_SOUP_SESSION_CONTEXT, TRUE);
+          s = gst_context_writable_structure (context);
+          gst_structure_set (s, "session", SOUP_TYPE_SESSION, src->session,
+              "force", G_TYPE_BOOLEAN, FALSE, NULL);
+
+          gst_object_ref (src->session);
+          GST_OBJECT_UNLOCK (src);
+          gst_element_set_context (GST_ELEMENT_CAST (src), context);
+          message =
+              gst_message_new_have_context (GST_OBJECT_CAST (src), context);
+          gst_element_post_message (GST_ELEMENT_CAST (src), message);
+          GST_OBJECT_LOCK (src);
+          gst_object_unref (src->session);
+        } else {
+          src->session_is_shared = FALSE;
         }
-        soup_uri_free (base_uri);
       }
     }
-#endif
+
+    if (!src->session) {
+      GST_ELEMENT_ERROR (src, LIBRARY, INIT,
+          (NULL), ("Failed to create session"));
+      GST_OBJECT_UNLOCK (src);
+      return FALSE;
+    }
 
     g_signal_connect (src->session, "authenticate",
         G_CALLBACK (gst_soup_http_src_authenticate_cb), src);
 
-    /* Set up logging */
-    gst_soup_util_log_setup (src->session, src->log_level, GST_ELEMENT (src));
-    if (src->tls_database)
-      g_object_set (src->session, "tls-database", src->tls_database, NULL);
-    else if (src->ssl_ca_file)
-      g_object_set (src->session, "ssl-ca-file", src->ssl_ca_file, NULL);
-    else
-      g_object_set (src->session, "ssl-use-system-ca-file",
-          src->ssl_use_system_ca_file, NULL);
+    if (!src->session_is_shared) {
+      if (src->tls_database)
+        g_object_set (src->session, "tls-database", src->tls_database, NULL);
+      else if (src->ssl_ca_file)
+        g_object_set (src->session, "ssl-ca-file", src->ssl_ca_file, NULL);
+      else
+        g_object_set (src->session, "ssl-use-system-ca-file",
+            src->ssl_use_system_ca_file, NULL);
+    }
+    GST_OBJECT_UNLOCK (src);
   } else {
     GST_DEBUG_OBJECT (src, "Re-using session");
   }
 
-  if (src->compress)
-    soup_session_add_feature_by_type (src->session, SOUP_TYPE_CONTENT_DECODER);
-  else
-    soup_session_remove_feature_by_type (src->session,
-        SOUP_TYPE_CONTENT_DECODER);
-
   return TRUE;
 }
 
@@ -1074,18 +1075,14 @@ gst_soup_http_src_session_close (GstSoupHTTPSrc * src)
   }
 
   if (src->session) {
-#ifdef TIZEN_FEATURE_SOUP_MODIFICATION
-/* When Playback is ongoing and Browser is moved to background ( Pressing Menu or Home Key ), The Session gets destroyed.
-   But the cookie_jar property remains unfreed. This results in garbage pointer and causes crash.
-   Removing the cookie_jar feature during close session of browser to handle the issue. */
-    GST_DEBUG_OBJECT (src, "Removing Cookie Jar instance");
-    soup_session_remove_feature_by_type(src->session, SOUP_TYPE_COOKIE_JAR);
-    src->cookie_jar = NULL;
-#endif
-    soup_session_abort (src->session);
+    if (!src->session_is_shared)
+      soup_session_abort (src->session);
+    g_signal_handlers_disconnect_by_func (src->session,
+        G_CALLBACK (gst_soup_http_src_authenticate_cb), src);
     g_object_unref (src->session);
     src->session = NULL;
   }
+
   g_mutex_unlock (&src->mutex);
 }
 
@@ -1093,6 +1090,10 @@ static void
 gst_soup_http_src_authenticate_cb (SoupSession * session, SoupMessage * msg,
     SoupAuth * auth, gboolean retrying, GstSoupHTTPSrc * src)
 {
+  /* Might be from another user of the shared session */
+  if (!GST_IS_SOUP_HTTP_SRC (src) || msg != src->msg)
+    return;
+
   if (!retrying) {
     /* First time authentication only, if we fail and are called again with retry true fall through */
     if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
@@ -1149,41 +1150,14 @@ gst_soup_http_src_headers_foreach (const gchar * name, const gchar * val,
 {
   GST_INFO_OBJECT (src, " %s: %s", name, val);
 
-  if (g_ascii_strcasecmp (name, "Set-Cookie") == 0)
-  {
-    if (val)
-    {
-      gboolean bret = FALSE;
-      GstStructure *s = NULL;
-      GstSoupHTTPSrc * tmp = src;
-      SoupURI *uri;
-
-      uri =  soup_uri_new (tmp->location);
-
-      /* post current bandwith & uri to application */
-      s = gst_structure_new ("cookies",
-            "updated-cookie", G_TYPE_STRING, val,
-            "updated-url", G_TYPE_STRING, tmp->location, NULL);
-      bret = gst_element_post_message (GST_ELEMENT_CAST (src), gst_message_new_element (GST_OBJECT_CAST (src), s));
-      soup_cookie_jar_set_cookie (tmp->cookie_jar,  uri, val);
-      soup_uri_free (uri);
-
-      GST_INFO_OBJECT (src, "request url [%s], posted cookies [%s] msg and returned = %d", tmp->location, val, bret);
-    }
-  }
-  else if (g_ascii_strcasecmp (name, "Dash-Oldest-Segment") == 0)
-  {
-    if (val)
-    {
+  if (g_ascii_strcasecmp (name, "Dash-Oldest-Segment") == 0) {
+    if (val) {
       GstSoupHTTPSrc * tmp = src;
       tmp->dash_oldest_segment = g_strdup (val);
       GST_INFO_OBJECT (src, "Dash-Oldest-Segment set as %s ", tmp->dash_oldest_segment);
     }
-  }
-  else if (g_ascii_strcasecmp (name, "Dash-Newest-Segment") == 0)
-  {
-    if (val)
-    {
+  } else if (g_ascii_strcasecmp (name, "Dash-Newest-Segment") == 0) {
+    if (val) {
       GstSoupHTTPSrc * tmp = src;
       tmp->dash_newest_segment = g_strdup (val);
       GST_INFO_OBJECT (src, "Dash-Newest-Segment set as %s ", tmp->dash_newest_segment);
@@ -1218,16 +1192,9 @@ gst_soup_http_src_got_headers (GstSoupHTTPSrc * src, SoupMessage * msg)
     return GST_FLOW_OK;
   }
 
-  if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
-    /* force an error */
-    return gst_soup_http_src_parse_status (msg, src);
-  }
-
-  src->got_headers = TRUE;
-  g_cond_broadcast (&src->have_headers_cond);
-
   http_headers = gst_structure_new_empty ("http-headers");
-  gst_structure_set (http_headers, "uri", G_TYPE_STRING, src->location, NULL);
+  gst_structure_set (http_headers, "uri", G_TYPE_STRING, src->location,
+      "http-status-code", G_TYPE_UINT, msg->status_code, NULL);
   if (src->redirection_uri)
     gst_structure_set (http_headers, "redirection-uri", G_TYPE_STRING,
         src->redirection_uri, NULL);
@@ -1244,11 +1211,62 @@ gst_soup_http_src_got_headers (GstSoupHTTPSrc * src, SoupMessage * msg)
       headers, NULL);
   gst_structure_free (headers);
 
+  gst_element_post_message (GST_ELEMENT_CAST (src),
+      gst_message_new_element (GST_OBJECT_CAST (src),
+          gst_structure_copy (http_headers)));
+
+  if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
+    /* force an error */
+    gst_structure_free (http_headers);
+    return gst_soup_http_src_parse_status (msg, src);
+  }
+
+  src->got_headers = TRUE;
+  g_cond_broadcast (&src->have_headers_cond);
+
   http_headers_event =
       gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_STICKY, http_headers);
   gst_event_replace (&src->http_headers_event, http_headers_event);
   gst_event_unref (http_headers_event);
 
+#ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+  /* Parse DLNA OP CODE */
+  if ((value = soup_message_headers_get_one
+        (msg->response_headers, "contentFeatures.dlna.org")) != NULL) {
+    gchar **token = NULL;
+    gchar **ptr = NULL;
+
+    GST_DEBUG_OBJECT (src, "DLNA server response");
+
+    token = g_strsplit (value, ";", 0);
+    for (ptr = token ; *ptr ; ptr++) {
+      gchar *tmp = NULL;
+      gchar *op_code = NULL;
+
+      if (!strlen (*ptr))
+        continue;
+
+      tmp = g_ascii_strup (*ptr, strlen (*ptr));
+      if (!strstr (tmp, "DLNA.ORG_OP")) {
+        g_free (tmp);
+        continue;
+      }
+
+      g_free (tmp);
+
+      op_code = strchr (*ptr, '=');
+      if (op_code) {
+        op_code++;
+
+        src->dlna_opt = (atoi (op_code) / 10 << 1) | (atoi (op_code) % 10);
+        GST_DEBUG_OBJECT (src, "dlna op code: %s (0x%X)", op_code, src->dlna_opt);
+        break;
+      }
+    }
+    g_strfreev (token);
+  }
+#endif
+
   /* Parse Content-Length. */
   if (soup_message_headers_get_encoding (msg->response_headers) ==
       SOUP_ENCODING_CONTENT_LENGTH) {
@@ -1296,10 +1314,16 @@ gst_soup_http_src_got_headers (GstSoupHTTPSrc * src, SoupMessage * msg)
       src->seekable = FALSE;
   }
 #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+  else if (src->dlna_opt & DLNA_OP_BYTE_SEEK) {
+    if (src->have_size) {
+      GST_DEBUG_OBJECT (src, "DLNA server is seekable");
+      src->seekable = TRUE;
+    }
+  }
   /* The Range request header is always included.
    * @ref gst_soup_http_src_add_range_header() */
   else if ((msg->status_code == SOUP_STATUS_OK) &&
-    (soup_message_headers_get_content_range(msg->response_headers, &start, &stop, &total) == FALSE)) {
+    (soup_message_headers_get_content_range (msg->response_headers, &start, &stop, &total) == FALSE)) {
     GST_DEBUG_OBJECT (src, "there is no accept range header");
     src->seekable = FALSE;
   }
@@ -1580,6 +1604,29 @@ gst_soup_http_src_build_message (GstSoupHTTPSrc * src, const gchar * method)
         ("Error parsing URL."), ("URL: %s", src->location));
     return FALSE;
   }
+
+  /* Duplicating the defaults of libsoup here. We don't want to set a
+   * User-Agent in the session as each source might have its own User-Agent
+   * set */
+  if (!src->user_agent || !*src->user_agent) {
+    gchar *user_agent =
+        g_strdup_printf ("libsoup/%u.%u.%u", soup_get_major_version (),
+        soup_get_minor_version (), soup_get_micro_version ());
+    soup_message_headers_append (src->msg->request_headers, "User-Agent",
+        user_agent);
+    g_free (user_agent);
+  } else if (g_str_has_suffix (src->user_agent, " ")) {
+    gchar *user_agent = g_strdup_printf ("%slibsoup/%u.%u.%u", src->user_agent,
+        soup_get_major_version (),
+        soup_get_minor_version (), soup_get_micro_version ());
+    soup_message_headers_append (src->msg->request_headers, "User-Agent",
+        user_agent);
+    g_free (user_agent);
+  } else {
+    soup_message_headers_append (src->msg->request_headers, "User-Agent",
+        src->user_agent);
+  }
+
   if (!src->keep_alive) {
     soup_message_headers_append (src->msg->request_headers, "Connection",
         "close");
@@ -1590,33 +1637,12 @@ gst_soup_http_src_build_message (GstSoupHTTPSrc * src, const gchar * method)
   }
 
 #ifdef TIZEN_FEATURE_SOUP_MODIFICATION
-/* This changes are needed to enable Seekable Contents from server.
+  /* This changes are needed to enable Seekable Contents from server.
    We have observed that , for few specific networks ( VODAFONE ) , without theabove headers ,
    Youtube is sending non-seekable contents to the Client. */
   soup_message_headers_append (src->msg->request_headers, "Accept-Ranges","bytes");
+#endif
 
-  if (src->cookie_jar) {
-    GSList *cookie_list, *c;
-    gchar *header;
-
-    SoupURI *uri = NULL;
-    SoupCookie *cookie;
-    uri = soup_uri_new (src->location);
-
-    if ((cookie_list = soup_cookie_jar_all_cookies (src->cookie_jar)) != NULL) {
-      for (c = cookie_list; c; c = c->next) {
-        cookie = (SoupCookie *)c->data;
-        if (soup_cookie_applies_to_uri(cookie, uri)) {
-          header = soup_cookie_to_cookie_header (cookie);
-          soup_message_headers_append (src->msg->request_headers, "Cookie", header);
-          g_free (header);
-        }
-      }
-    }
-    soup_cookies_free (cookie_list);
-    soup_uri_free (uri);
-  }
-#else
   if (src->cookies) {
     gchar **cookie;
 
@@ -1625,7 +1651,9 @@ gst_soup_http_src_build_message (GstSoupHTTPSrc * src, const gchar * method)
           *cookie);
     }
   }
-#endif
+
+  if (!src->compress)
+    soup_message_disable_feature (src->msg, SOUP_TYPE_CONTENT_DECODER);
 
   soup_message_set_flags (src->msg, SOUP_MESSAGE_OVERWRITE_CHUNKS |
       (src->automatic_redirect ? 0 : SOUP_MESSAGE_NO_REDIRECT));
@@ -1648,6 +1676,7 @@ gst_soup_http_src_build_message (GstSoupHTTPSrc * src, const gchar * method)
   return TRUE;
 }
 
+/* Lock taken */
 static GstFlowReturn
 gst_soup_http_src_send_message (GstSoupHTTPSrc * src)
 {
@@ -1655,6 +1684,7 @@ gst_soup_http_src_send_message (GstSoupHTTPSrc * src)
   GError *error = NULL;
 
   g_return_val_if_fail (src->msg != NULL, GST_FLOW_ERROR);
+  g_assert (src->input_stream == NULL);
 
   src->input_stream =
       soup_session_send (src->session, src->msg, src->cancellable, &error);
@@ -1709,7 +1739,14 @@ gst_soup_http_src_do_request (GstSoupHTTPSrc * src, const gchar * method)
   if (src->msg && src->request_position > 0) {
     gst_soup_http_src_add_range_header (src, src->request_position,
         src->stop_position);
-  }
+  } else if (src->msg && src->request_position == 0)
+    soup_message_headers_remove (src->msg->request_headers, "Range");
+
+  /* add_range_header() has the side effect of setting read_position to
+   * the requested position. This *needs* to be set regardless of having
+   * a message or not. Failure to do so would result in calculation being
+   * done with stale/wrong read position */
+  src->read_position = src->request_position;
 
   if (!src->msg) {
     if (!gst_soup_http_src_build_message (src, method)) {
@@ -1758,10 +1795,15 @@ gst_soup_http_src_check_update_blocksize (GstSoupHTTPSrc * src,
 {
   guint blocksize = gst_base_src_get_blocksize (GST_BASE_SRC_CAST (src));
 
-  GST_LOG_OBJECT (src, "Checking to update blocksize. Read:%" G_GINT64_FORMAT
-      " blocksize:%u", bytes_read, blocksize);
+  gint64 time_since_last_read =
+      g_get_monotonic_time () * GST_USECOND - src->last_socket_read_time;
+
+  GST_LOG_OBJECT (src, "Checking to update blocksize. Read: %" G_GINT64_FORMAT
+      " bytes, blocksize: %u bytes, time since last read: %" GST_TIME_FORMAT,
+      bytes_read, blocksize, GST_TIME_ARGS (time_since_last_read));
 
-  if (bytes_read >= blocksize * GROW_BLOCKSIZE_LIMIT) {
+  if (bytes_read >= blocksize * GROW_BLOCKSIZE_LIMIT
+      && time_since_last_read <= GROW_TIME_LIMIT) {
     src->reduce_blocksize_count = 0;
     src->increase_blocksize_count++;
 
@@ -1771,7 +1813,8 @@ gst_soup_http_src_check_update_blocksize (GstSoupHTTPSrc * src,
       gst_base_src_set_blocksize (GST_BASE_SRC_CAST (src), blocksize);
       src->increase_blocksize_count = 0;
     }
-  } else if (bytes_read < blocksize * REDUCE_BLOCKSIZE_LIMIT) {
+  } else if (bytes_read < blocksize * REDUCE_BLOCKSIZE_LIMIT
+      || time_since_last_read > GROW_TIME_LIMIT) {
     src->reduce_blocksize_count++;
     src->increase_blocksize_count = 0;
 
@@ -1854,12 +1897,17 @@ gst_soup_http_src_read_buffer (GstSoupHTTPSrc * src, GstBuffer ** outbuf)
     GST_BUFFER_OFFSET (*outbuf) = bsrc->segment.position;
     ret = GST_FLOW_OK;
     gst_soup_http_src_update_position (src, read_bytes);
+#ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+    src->received_total += read_bytes;
+#endif
 
     /* Got some data, reset retry counter */
     src->retry_count = 0;
 
     gst_soup_http_src_check_update_blocksize (src, read_bytes);
 
+    src->last_socket_read_time = g_get_monotonic_time () * GST_USECOND;
+
     /* If we're at the end of a range request, read again to let libsoup
      * finalize the request. This allows to reuse the connection again later,
      * otherwise we would have to cancel the message and close the connection
@@ -1963,6 +2011,13 @@ done:
       goto retry;
     }
   }
+
+  if (ret == GST_FLOW_FLUSHING) {
+    g_mutex_lock (&src->mutex);
+    src->retry_count = 0;
+    g_mutex_unlock (&src->mutex);
+  }
+
   return ret;
 }
 
@@ -1993,7 +2048,7 @@ gst_soup_http_src_stop (GstBaseSrc * bsrc)
 
   src = GST_SOUP_HTTP_SRC (bsrc);
   GST_DEBUG_OBJECT (src, "stop()");
-  if (src->keep_alive && !src->msg)
+  if (src->keep_alive && !src->msg && !src->session_is_shared)
     gst_soup_http_src_cancel_message (src);
   else
     gst_soup_http_src_session_close (src);
@@ -2011,6 +2066,13 @@ gst_soup_http_src_change_state (GstElement * element, GstStateChange transition)
   src = GST_SOUP_HTTP_SRC (element);
 
   switch (transition) {
+#ifdef TIZEN_FEATURE_SOUP_MODIFICATION
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      GST_WARNING_OBJECT (src, "Last read pos"
+            ": %" G_GINT64_FORMAT ", received total : %" G_GINT64_FORMAT,
+            src->read_position, src->received_total);
+      break;
+#endif
     case GST_STATE_CHANGE_READY_TO_NULL:
       gst_soup_http_src_session_close (src);
       break;
@@ -2023,6 +2085,33 @@ gst_soup_http_src_change_state (GstElement * element, GstStateChange transition)
   return ret;
 }
 
+static void
+gst_soup_http_src_set_context (GstElement * element, GstContext * context)
+{
+  GstSoupHTTPSrc *src = GST_SOUP_HTTP_SRC (element);
+
+  if (g_strcmp0 (gst_context_get_context_type (context),
+          GST_SOUP_SESSION_CONTEXT) == 0) {
+    const GstStructure *s = gst_context_get_structure (context);
+
+    GST_OBJECT_LOCK (src);
+    if (src->external_session)
+      g_object_unref (src->external_session);
+    src->external_session = NULL;
+    gst_structure_get (s, "session", SOUP_TYPE_SESSION, &src->external_session,
+        NULL);
+    src->forced_external_session = FALSE;
+    gst_structure_get (s, "force", G_TYPE_BOOLEAN,
+        &src->forced_external_session, NULL);
+
+    GST_DEBUG_OBJECT (src, "Setting external session %p (force: %d)",
+        src->external_session, src->forced_external_session);
+    GST_OBJECT_UNLOCK (src);
+  }
+
+  GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
+}
+
 /* Interrupt a blocking request. */
 static gboolean
 gst_soup_http_src_unlock (GstBaseSrc * bsrc)
@@ -2171,7 +2260,6 @@ gst_soup_http_src_query (GstBaseSrc * bsrc, GstQuery * query)
 
   switch (GST_QUERY_TYPE (query)) {
     case GST_QUERY_SCHEDULING:
-
       gst_query_parse_scheduling (query, &flags, &minsize, &maxsize, &align);
       flags |= GST_SCHEDULING_FLAG_BANDWIDTH_LIMITED;
 
@@ -2182,7 +2270,6 @@ gst_soup_http_src_query (GstBaseSrc * bsrc, GstQuery * query)
       }
 #endif
       gst_query_set_scheduling (query, flags, minsize, maxsize, align);
-
       break;
     default:
       break;
@@ -2235,7 +2322,7 @@ gst_soup_http_src_set_proxy (GstSoupHTTPSrc * src, const gchar * uri)
   if (uri == NULL || *uri == '\0')
     return TRUE;
 
-  if (g_str_has_prefix (uri, "http://")) {
+  if (g_strstr_len (uri, -1, "://")) {
     src->proxy = soup_uri_new (uri);
   } else {
     gchar *new_uri = g_strconcat ("http://", uri, NULL);
@@ -2247,7 +2334,7 @@ gst_soup_http_src_set_proxy (GstSoupHTTPSrc * src, const gchar * uri)
   return (src->proxy != NULL);
 }
 
-static guint
+static GstURIType
 gst_soup_http_src_uri_get_type (GType type)
 {
   return GST_URI_SRC;