diff --git a/.htaccess b/.htaccess
index a69bdd4..725897e 100644
--- a/.htaccess
+++ b/.htaccess
@@ -109,7 +109,7 @@ DirectoryIndex index.php index.html index.htm
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
- RewriteRule ^ index.php [L]
+ RewriteRule ^(.*)$ index.php [L]
# Rules to correctly serve gzip compressed CSS and JS files.
# Requires both mod_rewrite and mod_headers to be enabled.
diff --git a/core/includes/batch.inc b/core/includes/batch.inc
index 83ddd30..0b07d8e 100644
--- a/core/includes/batch.inc
+++ b/core/includes/batch.inc
@@ -14,6 +14,8 @@
* @see batch_get()
*/
+use \Symfony\Component\HttpFoundation\JsonResponse;
+
/**
* Loads a batch from the database.
*
@@ -77,7 +79,7 @@ function _batch_page() {
case 'do':
// JavaScript-based progress page callback.
- _batch_do();
+ $output = _batch_do();
break;
case 'do_nojs':
@@ -160,7 +162,7 @@ function _batch_do() {
// Perform actual processing.
list($percentage, $message) = _batch_process();
- drupal_json_output(array('status' => TRUE, 'percentage' => $percentage, 'message' => $message));
+ return new JsonResponse(array('status' => TRUE, 'percentage' => $percentage, 'message' => $message));
}
/**
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 12b1d80..d76ca4c 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -3,6 +3,7 @@
use Drupal\Core\Database\Database;
use Symfony\Component\ClassLoader\UniversalClassLoader;
use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
+use Symfony\Component\HttpFoundation\Request;
/**
* @file
@@ -1511,6 +1512,27 @@ function request_uri() {
}
/**
+ * Returns the current global reuqest object.
+ *
+ * @todo Replace this function with a proper dependency injection container.
+ *
+ * @staticvar Request $request
+ * @param Request $new_request
+ * The new request object to store. If you are not index.php, you probably
+ * should not be using this parameter.
+ * @return Request
+ * The current request object.
+ */
+function request(Request $new_request = NULL) {
+ static $request;
+
+ if ($new_request) {
+ $request = $new_request;
+ }
+ return $request;
+}
+
+/**
* Logs an exception.
*
* This is a wrapper function for watchdog() which automatically decodes an
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 5ff6167..cd21512 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -1,5 +1,7 @@
$base_root . request_uri(),
'data' => array(
'path' => $_GET['q'],
- 'body' => ob_get_clean(),
+ 'body' => $response_body,
'title' => drupal_get_title(),
'headers' => array(),
),
diff --git a/core/includes/file.inc b/core/includes/file.inc
index eaff634..fa6670d 100644
--- a/core/includes/file.inc
+++ b/core/includes/file.inc
@@ -5,6 +5,9 @@
* API for handling file uploads and server file management.
*/
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpFoundation\StreamedResponse;
use Drupal\Core\StreamWrapper\LocalStream;
/**
@@ -2046,18 +2049,27 @@ function file_download() {
$function = $module . '_file_download';
$result = $function($uri);
if ($result == -1) {
- return drupal_access_denied();
+ throw new AccessDeniedHttpException();
}
if (isset($result) && is_array($result)) {
$headers = array_merge($headers, $result);
}
}
if (count($headers)) {
- file_transfer($uri, $headers);
+ return new StreamedResponse(function() use ($uri) {
+ $scheme = file_uri_scheme($uri);
+ // Transfer file in 1024 byte chunks to save memory usage.
+ if ($scheme && file_stream_wrapper_valid_scheme($scheme) && $fd = fopen($uri, 'rb')) {
+ while (!feof($fd)) {
+ print fread($fd, 1024);
+ }
+ fclose($fd);
+ }
+ }, 200, $headers);
}
- return drupal_access_denied();
+ throw new AccessDeniedHttpException();
}
- return drupal_not_found();
+ throw new NotFoundHttpException();
}
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 37b3281..e7bf3f8 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -3,6 +3,9 @@
use Drupal\Core\Database\Database;
use Drupal\Core\Database\Install\TaskException;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
/**
* @file
* API functions for installing Drupal.
@@ -261,6 +264,14 @@ function install_begin_request(&$install_state) {
drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+ // A request object from the HTTPFoundation to tell us about the request.
+ $request = Request::createFromGlobals();
+
+ // Set the global $request object. This is a temporary measure to
+ // keep legacy utility functions working. It should be moved to a dependency
+ // injection container at some point.
+ request($request);
+
// This must go after drupal_bootstrap(), which unsets globals!
global $conf;
@@ -488,6 +499,15 @@ function install_run_task($task, &$install_state) {
elseif ($current_batch == $function) {
include_once DRUPAL_ROOT . '/core/includes/batch.inc';
$output = _batch_page();
+ // Because Batch API now returns a JSON response for intermediary steps,
+ // but the installer doesn't handle Response objects yet, we will just
+ // send the output here and emulate the old model.
+ // @todo: Replace this when we refactor the installer to use a
+ // Request/Response workflow.
+ if ($output instanceof Response) {
+ $output->send();
+ $output = NULL;
+ }
// The task is complete when we try to access the batch page and receive
// FALSE in return, since this means we are at a URL where we are no
// longer requesting a batch ID.
diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index fecd158..5f0cf25 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -3807,7 +3807,7 @@ function _menu_site_is_offline($check_only = FALSE) {
// Ensure that the maintenance mode message is displayed only once
// (allowing for page redirects) and specifically suppress its display on
// the maintenance mode settings page.
- if (!$check_only && $_GET['q'] != 'admin/config/development/maintenance') {
+ if (!$check_only && request()->attributes->get('system_path') != 'admin/config/development/maintenance') {
if (user_access('administer site configuration')) {
drupal_set_message(t('Operating in maintenance mode. Go online.', array('@url' => url('admin/config/development/maintenance'))), 'status', FALSE);
}
diff --git a/core/lib/Drupal/Core/ContentNegotiation.php b/core/lib/Drupal/Core/ContentNegotiation.php
new file mode 100644
index 0000000..e19d950
--- /dev/null
+++ b/core/lib/Drupal/Core/ContentNegotiation.php
@@ -0,0 +1,55 @@
+getAcceptableContentTypes();
+
+ // AJAX iframe uploads need special handling, because they contain a json
+ // response wrapped in