From 949ac40c5b10daa8ed8a5bbe62c2d76b02a774c5 Mon Sep 17 00:00:00 2001
From: Alex Barth <alex_b@53995.no-reply.drupal.org>
Date: Wed, 4 Nov 2009 17:20:36 +0000
Subject: [PATCH] Block curl to download from anything else than http or https.
 Throw exception when download fails.

---
 libraries/http_request.inc   | 74 +++++++++++++++++++++---------------
 plugins/FeedsHTTPFetcher.inc |  3 ++
 2 files changed, 46 insertions(+), 31 deletions(-)

diff --git a/libraries/http_request.inc b/libraries/http_request.inc
index b4ed90c8..c6f037ee 100644
--- a/libraries/http_request.inc
+++ b/libraries/http_request.inc
@@ -150,41 +150,53 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
   if ($curl) {
     $headers[] = 'User-Agent: Drupal (+http://drupal.org/)';
     $result = new stdClass();
-    $download = curl_init($url);
-    curl_setopt($download, CURLOPT_FOLLOWLOCATION, TRUE);
-    if (!empty($username)) {
-      curl_setopt($download, CURLOPT_USERPWD, "{$username}:{$password}");
-    }
-    curl_setopt($download, CURLOPT_HTTPHEADER, $headers);
-    curl_setopt($download, CURLOPT_HEADER, TRUE);
-    curl_setopt($download, CURLOPT_RETURNTRANSFER, TRUE);
-    curl_setopt($download, CURLOPT_ENCODING, '');
-    if ($accept_invalid_cert) {
-      curl_setopt($download, CURLOPT_SSL_VERIFYPEER, 0);
+
+    // Only download via cURL if we can validate the scheme to be either http or
+    // https.
+    // Validate in PHP, CURLOPT_PROTOCOLS is only supported with cURL 7.19.4
+    $uri = parse_url($url);
+    if ($uri['scheme'] != 'http' && $uri['scheme'] != 'https') {
+      $result->error = 'invalid schema '. $uri['scheme'];
+      $result->code = -1003; // This corresponds to drupal_http_request()
     }
-    $header = '';
-    $data = curl_exec($download);
-    $header_size = curl_getinfo($download, CURLINFO_HEADER_SIZE);
-    $header = substr($data, 0, $header_size - 1);
-    $result->data = substr($data, $header_size);
-    $header_lines = preg_split("/\r\n|\n|\r/", $header);
-
-    $result->headers = array();
-    array_shift($header_lines); // skip HTTP response status
-    while ($line = trim(array_shift($header_lines))) {
-      list($header, $value) = explode(':', $line, 2);
-      if (isset($result->headers[$header]) && $header == 'Set-Cookie') {
-        // RFC 2109: the Set-Cookie response header comprises the token Set-
-        // Cookie:, followed by a comma-separated list of one or more cookies.
-        $result->headers[$header] .= ','. trim($value);
+    else {
+
+      $download = curl_init($url);
+      curl_setopt($download, CURLOPT_FOLLOWLOCATION, TRUE);
+      if (!empty($username)) {
+        curl_setopt($download, CURLOPT_USERPWD, "{$username}:{$password}");
       }
-      else {
-        $result->headers[$header] = trim($value);
+      curl_setopt($download, CURLOPT_HTTPHEADER, $headers);
+      curl_setopt($download, CURLOPT_HEADER, TRUE);
+      curl_setopt($download, CURLOPT_RETURNTRANSFER, TRUE);
+      curl_setopt($download, CURLOPT_ENCODING, '');
+      if ($accept_invalid_cert) {
+        curl_setopt($download, CURLOPT_SSL_VERIFYPEER, 0);
       }
-    }
-    $result->code = curl_getinfo($download, CURLINFO_HTTP_CODE);
+      $header = '';
+      $data = curl_exec($download);
+      $header_size = curl_getinfo($download, CURLINFO_HEADER_SIZE);
+      $header = substr($data, 0, $header_size - 1);
+      $result->data = substr($data, $header_size);
+      $header_lines = preg_split("/\r\n|\n|\r/", $header);
+
+      $result->headers = array();
+      array_shift($header_lines); // skip HTTP response status
+      while ($line = trim(array_shift($header_lines))) {
+        list($header, $value) = explode(':', $line, 2);
+        if (isset($result->headers[$header]) && $header == 'Set-Cookie') {
+          // RFC 2109: the Set-Cookie response header comprises the token Set-
+          // Cookie:, followed by a comma-separated list of one or more cookies.
+          $result->headers[$header] .= ','. trim($value);
+        }
+        else {
+          $result->headers[$header] = trim($value);
+        }
+      }
+      $result->code = curl_getinfo($download, CURLINFO_HTTP_CODE);
 
-    curl_close($download);
+      curl_close($download);
+    }
   }
   else {
     $result = drupal_http_request($url, $headers);
diff --git a/plugins/FeedsHTTPFetcher.inc b/plugins/FeedsHTTPFetcher.inc
index d139abd5..78ad0f11 100644
--- a/plugins/FeedsHTTPFetcher.inc
+++ b/plugins/FeedsHTTPFetcher.inc
@@ -31,6 +31,9 @@ class FeedsHTTPFetcher extends FeedsFetcher {
     else {
       $result = http_request_get($url);
     }
+    if ($result->code != 200) {
+      throw new Exception(t('Download of @url failed with code !code.', array('@url' => $url, '!code' => $result->code)));
+    }
     return new FeedsFetcherResult($result->data, 'text/xml');
   }
 
-- 
GitLab