diff --git a/core/includes/Drupal/Context/Context.php b/core/includes/Drupal/Context/Context.php
new file mode 100644
index 0000000..519a058
--- /dev/null
+++ b/core/includes/Drupal/Context/Context.php
@@ -0,0 +1,259 @@
+<?php
+
+namespace Drupal\Context;
+
+use Closure;
+
+/**
+ * Default Drupal context object.
+ *
+ * It handles routing of context requests to handlers.
+ */
+class Context implements ContextInterface {
+
+  /**
+   * The query string for this page. This generally means the value of $_GET['q'].
+   *
+   * @var string
+   */
+  protected $queryString;
+
+  /**
+   * Index of registered handler creation closures.
+   *
+   * @var array
+   */
+  protected $handlerClosures = array();
+
+  /**
+   * Index of already-instantiated handler objects.
+   *
+   * @var array
+   */
+  protected $handlers = array();
+
+  /**
+   * Key/value store of already-derived context information.
+   *
+   * @var array
+   */
+  protected $contextValues = array();
+
+  /**
+   * An array of keys for all the values and objects in $context accessed in
+   * the current scope.
+   *
+   * @var array
+   */
+  protected $usedKeys = array();
+
+  /**
+   * Whether or not this object has been locked against further changes.
+   *
+   * @var boolean
+   */
+  protected $locked = FALSE;
+
+  /**
+   * The context stack to which this contect objec is bound.
+   *
+   * @var Stack
+   */
+  protected $stack = NULL;
+
+  /**
+   * The parent context object from which this object will inherit data.
+   *
+   * @var ContextInterface
+   */
+  protected $parent = NULL;
+
+  /**
+   * Implements ContextInterface::setStack().
+   */
+  public function setStack(Stack $stack) {
+    if ($this->locked) {
+      throw new LockedException("Cannot set the stack of a locked context.");
+    }
+    $this->stack = $stack;
+  }
+
+  /**
+   * Implements ContextInterface::getStack().
+   */
+  public function getStack() {
+    return $this->stack;
+  }
+
+  /**
+   * Implements ContextInterface::setParent().
+   */
+  public function setParent(ContextInterface $parent) {
+    if ($this->locked) {
+      throw new LockedException("Cannot set the parent of a locked context.");
+    }
+    $this->parent = $parent;
+    // For consistency reasons, this instance must belong to the same stack
+    // than its parent.
+    $this->stack = $this->parent->getStack();
+  }
+
+  /**
+   * Checks if this context has a parent.
+   *
+   * @return bool
+   *   TRUE if the context has a parent, FALSE otherwise.
+   */
+  public function hasParent() {
+    return isset($this->parent);
+  }
+
+  /**
+   * Implements ContextInterface::getParent().
+   */
+  public function getParent() {
+    return $this->parent;
+  }
+
+  /**
+   * Returns the handler at the given context key.
+   *
+   * @param string $context_key
+   *   The context key for which we want a handler object
+   *
+   * @return Drupal\Context\Handler\HandlerInterface
+   *   A valid handler object, or NULL if none found.
+   */
+  protected function getHandlerAt($context_key) {
+    if (!array_key_exists($context_key, $this->handlers)) {
+      if (isset($this->handlerClosures[$context_key])) {
+        $this->handlers[$context_key] = $this->handlerClosures[$context_key]();
+      }
+      else {
+        $this->handlers[$context_key] = NULL;
+      }
+    }
+
+    return $this->handlers[$context_key];
+  }
+
+  /**
+   * Implements ContextInterface::getValue().
+   */
+  public function getValue($context_key) {
+    if (!$this->locked) {
+      throw new NotLockedException(t('This context object has not been locked. It must be locked before it can be used.'));
+    }
+
+    // We do not have data for this offset yet: use array_key_exists() because
+    // the value can be NULL. We do not want to re-run all handlerClasses for a
+    // variable with data.
+    if (!array_key_exists($context_key, $this->contextValues)) {
+      $this->contextValues[$context_key] = $this->findValue($context_key, $this);
+    }
+
+    if (!isset($this->usedKeys[$context_key])) {
+      $this->usedKeys[$context_key] = $context_key;
+    }
+
+    return $this->contextValues[$context_key];
+  }
+
+  /**
+   * Implements ContextInterface::findValue().
+   */
+  public function findValue($context_key, ContextInterface $context) {
+    // Loop over the possible context keys.
+    $local_key = $context_key;
+    $key_elements = explode(':', $context_key);
+    $args = array();
+
+    while ($key_elements) {
+      $handler = $this->getHandlerAt($local_key);
+
+      if (isset($handler)) {
+        $handler_value = $handler->getValue($args, $context);
+
+        // NULL value here means the context pass, and let potential parent
+        // overrides happen.
+        if (NULL !== $handler_value) {
+          // The null object here means it's definitely a NULL and parent
+          // cannot override it.
+          if ($handler_value instanceof OffsetIsNull) {
+            return NULL;
+          }
+          else {
+            return $handler_value;
+          }
+        }
+      }
+
+      array_unshift($args, array_pop($key_elements));
+      $local_key = implode(':', $key_elements);
+    }
+
+    // If we did not found a value using local handlers, check for parents.
+    if ($this->hasParent()) {
+      return $this->getParent()->findValue($context_key, $context);
+    }
+
+    return NULL;
+  }
+
+  /**
+   * Implements ContextInterface::setValue().
+   */
+  public function setValue($context_key, $value) {
+    if ($this->locked) {
+      throw new LockedException(t('This context object has been locked. It no longer accepts new explicit context sets.'));
+    }
+    // Set an explicit override for a given context value.
+    $this->contextValues[$context_key] = $value;
+  }
+
+  /**
+   * Implements ContextInterface::setHandler().
+   */
+  public function setHandler($context_key, $closure) {
+    if ($this->locked) {
+      throw new LockedException(t('This context object has been locked. It no longer accepts new handler registrations.'));
+    }
+    $this->handlerClosures[$context_key] = $closure;
+  }
+
+  /**
+   * Implements ContextInterface::usedKeys().
+   */
+  function usedKeys() {
+    $key_list = array();
+
+    foreach ($this->usedKeys as $key) {
+      $value = $this->contextValues[$key];
+      if ($value instanceof ValueInterface) {
+        $key_list[$key] = $value->contextKey();
+      }
+      else {
+        $key_list[$key] = $value;
+      }
+    }
+
+    return $key_list;
+  }
+
+  /**
+   * Implements ContextInterface::lock().
+   */
+  public function lock() {
+    $this->locked = TRUE;
+    return new Tracker($this);
+  }
+
+  /**
+   * Implements ContextInterface::addLayer().
+   */
+  public function addLayer() {
+    $layer = new self();
+    $layer->setParent($this);
+    return $layer;
+  }
+}
diff --git a/core/includes/Drupal/Context/ContextException.php b/core/includes/Drupal/Context/ContextException.php
new file mode 100644
index 0000000..002e3db
--- /dev/null
+++ b/core/includes/Drupal/Context/ContextException.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Drupal\Context;
+
+/**
+ * Base class for Context-related exceptions.
+ */
+class ContextException extends \Exception {}
\ No newline at end of file
diff --git a/core/includes/Drupal/Context/ContextInterface.php b/core/includes/Drupal/Context/ContextInterface.php
new file mode 100644
index 0000000..a375444
--- /dev/null
+++ b/core/includes/Drupal/Context/ContextInterface.php
@@ -0,0 +1,146 @@
+<?php
+
+namespace Drupal\Context;
+
+use Closure;
+
+/**
+ * Interface definition for all context objects.
+ */
+interface ContextInterface {
+
+  /**
+   * Sets owner stack.
+   *
+   * @param ContextStack $stack
+   *   TODO needs a comment
+   *
+   * @throws LockedException
+   *   If the current context is locked.
+   */
+  public function setStack(Stack $stack);
+
+  /**
+   * Gets stack, if any.
+   *
+   * @return Stack $stack
+   *   TODO needs a comment
+   */
+  public function getStack();
+
+  /**
+   * Sets parent context.
+   *
+   * @param ContextInterface $parent
+   *   TODO needs comment
+   *
+   * @throws LockedException
+   *   If the current context is locked.
+   */
+  public function setParent(ContextInterface $parent);
+
+  /**
+   * Checks if this object has a parent context.
+   *
+   * @return bool
+   */
+  public function hasParent();
+
+  /**
+   * Gets parent context, if any.
+   *
+   * @return ContextInterface
+   *   Can be NULL if current instance has no parent.
+   */
+  public function getParent();
+
+  /**
+   * Registers a class as the handler for a given context.
+   *
+   * @param string $context_key
+   *   The context key to register for, such as "http:get".
+   * @param Closure $closure
+   *   An anonymous function that will be called to generate the handler
+   *   on-demand.  Alternately, an object that implements the __invoke() magic
+   *   method should work as well. The anonymous function or __invoke() method
+   *   must return an object that implements \Drupal\Context\Handler\HandlerInterface.
+   * @param array $params
+   *   An array of configuration options for the class.
+   */
+  public function setHandler($context_key, $closure);
+
+  /**
+   * Finds the value directly from handlers, proceeding to the full handler
+   * lookup algorithm, relatively to the given context. // TODO short summary needs to be on one line
+   *
+   * This method will not cache values inside the current instance but will
+   * return it instead as the data can vary depending on the given context.
+   *
+   * This method is part of the context inheritance feature and is to be for
+   * internal use only.
+   *
+   * @param string $context_key
+   *   The context key to retrieve.
+   * @param Context $context
+   *   The context object against which to run various handlers.
+   *
+   * @return mixed
+   *   The value that is associated with the context key. It may be a primitive
+   *   value or an instance of \Drupal\Context\ValueInterface.
+   */
+  public function findValue($context_key, ContextInterface $context);
+
+  /**
+   * Sets an explict value for a context key.
+   *
+   * @param string $context_key
+   *   The context key to set.
+   * @param mixed $value
+   *   The value to which to set the context key.  It may be any primitive value
+   *   or an instance of \Drupal\Context\ValueInterface.
+   */
+  public function setValue($context_key, $value);
+
+  /**
+   * Retrieves the value for the specified context key.
+   *
+   * The context key is a colon-delimited string.  If no literal value or
+   * handler has been set for that value, the right-most fragment of the key
+   * will be stripped off and used as a parameter to a handler on the remaining
+   * key.  That process continues until either a value is found or the key runs
+   * out.
+   *
+   * @param string $context_key
+   *   The context key to retrieve.
+   *
+   * @return mixed
+   *   The value that is associated with the context key. It may be a primitive
+   *   value or an instance of \Drupal\Context\ValueInterface.
+   */
+  public function getValue($context_key);
+
+  /**
+   * Returns a set of keys to objects used in the current context
+   *
+   * This converts any context values referenced in the current scope into
+   * a normalised array.
+   *
+   * @return an array of context keys and their corresponding values
+   */
+  public function usedKeys();
+
+  /**
+   * Locks this context object against futher modification.
+   *
+   * This allows us to setup a mocked context object very easily, and then
+   * make it immutable so we know that it won't change out from under us.
+   */
+  public function lock();
+
+  /**
+   * Spawns a new context object that is pushed to the context stack.
+   *
+   * @return DrualContextInterface
+   */
+  public function addLayer();
+}
diff --git a/core/includes/Drupal/Context/Handler/HandlerAbstract.php b/core/includes/Drupal/Context/Handler/HandlerAbstract.php
new file mode 100644
index 0000000..5f6bc0b
--- /dev/null
+++ b/core/includes/Drupal/Context/Handler/HandlerAbstract.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Drupal\Context\Handler;
+
+use \Drupal\Context\ContextInterface;
+
+/**
+ * Base implementation of a Context Handler.
+ *
+ * Other handlers may extend this class to make their job easier.
+ */
+abstract class HandlerAbstract implements HandlerInterface {
+
+  /**
+   * Parameters for the context handler.
+   *
+   * @var array
+   */
+  protected $params;
+
+  /**
+   * Constructs a HandlerAbstract object.
+   *
+   * @param array $params
+   *   // TODO
+   */
+  public function __construct(array $params = array()) {
+    $this->params = $params;
+  }
+}
diff --git a/core/includes/Drupal/Context/Handler/HandlerHttp.php b/core/includes/Drupal/Context/Handler/HandlerHttp.php
new file mode 100644
index 0000000..42ef85b
--- /dev/null
+++ b/core/includes/Drupal/Context/Handler/HandlerHttp.php
@@ -0,0 +1,126 @@
+<?php
+
+namespace Drupal\Context\Handler;
+
+use \Drupal\Context\ContextInterface;
+use \Symfony\Component\HttpFoundation\Request;
+
+/**
+ * HTTP Context Handler implementation.
+ */
+class HandlerHttp extends HandlerAbstract {
+
+  /**
+   * Symfony Request object.
+   *
+   * @var \Symfony\Component\HttpFoundation\Request
+   */
+  protected $request = NULL;
+
+  /**
+   * Constructs a HandlerHttp object.
+   *
+   * @param Request $request
+   *   // TODO
+   */
+  public function __construct(Request $request) {
+    $this->request = $request;
+  }
+
+  /**
+   * Implements HandlerInterface::getValue().
+   */
+  public function getValue(array $args = array(), ContextInterface $context = null) {
+    $property = $args[0];
+
+    switch ($property) {
+      case 'method':
+        $value = $this->request->getMethod();
+        break;
+      case 'uri':
+        $value = $this->request->getUri();
+        break;
+      case 'base_url':
+        $value = $this->request->getScheme() . '://' . $this->request->getHost() . $this->request->getBaseUrl();
+        break;
+      case 'base_path':
+        $value = $this->request->getBasePath() . '/';
+        break;
+      case 'request_uri':
+        $value = $this->request->getRequestUri();
+        break;
+      case 'script_name':
+        $value = $this->request->getScriptName();
+        break;
+      case 'php_self':
+        $value = $this->request->server->get('PHP_SELF');
+        break;
+      case 'accept_types':
+        $value = $this->request->getAcceptableContentTypes();
+        break;
+      case 'domain':
+        $value = $this->request->getHost();
+        break;
+      case 'request_args':
+        $value = $this->request->request->all();
+        break;
+      case 'query':
+        $value = $this->request->query->all();
+        break;
+      case 'languages':
+        // Although HttpFoundation has a getLanguages() method already, it
+        // does some case folding that is incompatible with Drupal's language
+        // string formats.
+        // @todo Revisit this after https://github.com/symfony/symfony/issues/2468
+        // is resolved
+        $value = $this->request->splitHttpAcceptHeader($this->request->headers->get('Accept-Language'));
+        break;
+      case 'files':
+        $value = $this->request->files->all();
+        break;
+      case 'cookies':
+        $value = $this->request->cookies->all();
+        break;
+      case 'headers':
+        $value = $this->request->headers->all();
+        // Cleanup from unnecessary nesting level.
+        foreach ($value as &$item) {
+          if (is_array($item)) {
+            $item = current($item);
+          }
+        }
+        break;
+      case 'server':
+        $value = $this->request->server->all();
+        break;
+      case 'request_body':
+        $value = $this->request->getContent();
+        break;
+      default:
+        return;
+    }
+
+    // Many of the properties of the HTTP handler are actually arrays that
+    // we never want directly, but want a specific element out of. For instance,
+    // http:query is an array of GET parameters.  The following routine lets us
+    // retrieve third-level properties consistently, so $_GET['foo'] would map
+    // to http:query:foo.  The same code also supports cookies, headers, and so
+    // forth.
+    // Only one level of nesting is supported.  If a GET parameter is itself an
+    // array, it will be returned as an array.
+    if (!is_array($value) || !isset($args[1])) {
+      return $value;
+    }
+    else {
+      // Return second nesting level value if it exists.
+      if (!empty($args[1]) && isset($value[$args[1]])) {
+        return $value[$args[1]];
+      }
+      else {
+        // We return empty string if there is no
+        // second argument key in $this->params[$property].
+        return '';
+      }
+    }
+  }
+}
diff --git a/core/includes/Drupal/Context/Handler/HandlerInterface.php b/core/includes/Drupal/Context/Handler/HandlerInterface.php
new file mode 100644
index 0000000..3804d9f
--- /dev/null
+++ b/core/includes/Drupal/Context/Handler/HandlerInterface.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\Context\Handler;
+
+use Drupal\Context\ContextInterface;
+
+/**
+ * Interface for context handler objects.
+ *
+ * Handlers are stateless object: they receive the context to work with at
+ * getValue() time.
+ */
+interface HandlerInterface {
+
+  /**
+   * Retrieves the value for this context key.
+   *
+   * This value must be assumed to be immutable within a given request.
+   *
+   * @param array $args
+   *   Arguments to pass into the context handler.  Arguments are derived from
+   *   the portion of the context key after the key fragment that led to this
+   *   handler.
+   * @param ContextInterface $context = null
+   *   The current context scope within this handler must fetch values.
+   *
+   * @return mixed
+   *   The corresponding value for this context. Return here an new instance of
+   *   ContextOffsetIsNull if you don't have any value corresponding to
+   *   the given arguments to provide: this will cause the context to stop
+   *   value lookup for this offset.
+   */
+  public function getValue(array $args = array(), ContextInterface $context = null);
+}
diff --git a/core/includes/Drupal/Context/Handler/HandlerPathRaw.php b/core/includes/Drupal/Context/Handler/HandlerPathRaw.php
new file mode 100644
index 0000000..af73737
--- /dev/null
+++ b/core/includes/Drupal/Context/Handler/HandlerPathRaw.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Drupal\Context\Handler;
+
+use \Drupal\Context\ContextInterface;
+
+/**
+ * Raw path Context Handler implementation.
+ *
+ * Examples:
+ * - http://example.com/node/306 returns "node/306".
+ * - http://example.com/drupalfolder/node/306 returns "node/306" while
+ *   base_path() returns "/drupalfolder/".
+ * - http://example.com/path/alias (which is a path alias for node/306) returns
+ *   "path/alias" as opposed to the internal path.
+ * - http://example.com/index.php returns an empty string (meaning: front page).
+ * - http://example.com/index.php?page=1 returns an empty string.
+ */
+class HandlerPathRaw extends HandlerAbstract {
+
+  /**
+   * Implements HandlerInterface::getValue().
+   */
+  public function getValue(array $args = array(), ContextInterface $context = null) {
+    $raw_path = '';
+
+    $q = $context->getValue('http:query:q');
+    if (!empty($q)) {
+      // This is a request with a ?q=foo/bar query string. $_GET['q'] is
+      // overwritten in drupal_path_initialize(), but path:system is called
+      // very early in the bootstrap process, so the original value is saved in
+      // $path and returned in later calls.
+      $raw_path = $q;
+    }
+    else {
+      // This request is either a clean URL, or 'index.php', or nonsense.
+      // Extract the path from REQUEST_URI.
+      $request_uri = $context->getValue('http:request_uri');
+      $request_path = strtok($request_uri, '?');
+      $script_name = $context->getValue('http:script_name');
+      $base_path_len = strlen(rtrim(dirname($script_name), '\/'));
+      // Unescape and strip $base_path prefix, leaving q without a leading slash.
+      $raw_path = substr(urldecode($request_path), $base_path_len + 1);
+      // If the path equals the script filename, either because 'index.php' was
+      // explicitly provided in the URL, or because the server added it to
+      // $_SERVER['REQUEST_URI'] even when it wasn't provided in the URL (some
+      // versions of Microsoft IIS do this), the front page should be served.
+      $php_self = $context->getValue('http:php_self');
+      if ($raw_path == basename($php_self)) {
+        $raw_path = '';
+      }
+    }
+
+    // Under certain conditions Apache's RewriteRule directive prepends the value
+    // assigned to $_GET['q'] with a slash. Moreover we can always have a trailing
+    // slash in place, hence we need to normalize $_GET['q'].
+    $raw_path = trim($raw_path, '/');
+
+    return $raw_path;
+  }
+
+}
diff --git a/core/includes/Drupal/Context/Handler/HandlerPathSystem.php b/core/includes/Drupal/Context/Handler/HandlerPathSystem.php
new file mode 100644
index 0000000..a27f0dd
--- /dev/null
+++ b/core/includes/Drupal/Context/Handler/HandlerPathSystem.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Context\Handler;
+
+use \Drupal\Context\ContextInterface;
+
+/**
+ * System path Context Handler implementation.
+ *
+ * This implementation is likely to change once the path system is no longer
+ * function based.
+ *
+ * Examples:
+ * - http://example.com/node/306 returns "node/306".
+ * - http://example.com/drupalfolder/node/306 returns "node/306" while
+ *   base_path() returns "/drupalfolder/".
+ * - http://example.com/path/alias (which is a path alias for node/306) returns
+ *   "node/306" as opposed to the path alias.
+ *
+ * This handler is not available in hook_boot() so use
+ * drupal_get_context()->getValue('path:raw') instead.
+ * However, be careful when doing that because in the case of Example #3
+ * drupal_get_context()->getValue('path:raw') will contain "path/alias". If
+ * "node/306" is needed, calling drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL)
+ * makes this function available.
+
+ * @todo Clean this up once the path system changes.
+ */
+class HandlerPathSystem extends HandlerAbstract {
+
+  /**
+   * Implements HandlerInterface::getValue().
+   */
+  public function getValue(array $args = array(), ContextInterface $context = null) {
+    $system_path = '';
+
+    $path = $context->getValue('path:raw');
+    if (!empty($path)) {
+      $system_path = drupal_get_normal_path($path);
+    }
+    else {
+      $system_path = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
+    }
+
+    return $system_path;
+  }
+}
diff --git a/core/includes/Drupal/Context/LockedException.php b/core/includes/Drupal/Context/LockedException.php
new file mode 100644
index 0000000..9cb6e26
--- /dev/null
+++ b/core/includes/Drupal/Context/LockedException.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Drupal\Context;
+
+/**
+ * Exception thrown when attempting to modify a locked context object.
+ */
+class LockedException extends ContextException {}
+
diff --git a/core/includes/Drupal/Context/NotLockedException.php b/core/includes/Drupal/Context/NotLockedException.php
new file mode 100644
index 0000000..39ee579
--- /dev/null
+++ b/core/includes/Drupal/Context/NotLockedException.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Drupal\Context;
+
+/**
+ * Exception thrown when attempting to use an unlocked context object.
+ */
+class NotLockedException extends ContextException {}
diff --git a/core/includes/Drupal/Context/OffsetIsNull.php b/core/includes/Drupal/Context/OffsetIsNull.php
new file mode 100644
index 0000000..9172beb
--- /dev/null
+++ b/core/includes/Drupal/Context/OffsetIsNull.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace Drupal\Context;
+
+
+/**
+ * Internal class that is meant for context values existence check optimization.
+ *
+ * Do not use elsewhere.
+ */
+class OffsetIsNull {}
diff --git a/core/includes/Drupal/Context/ParentContextNotExistsException.php b/core/includes/Drupal/Context/ParentContextNotExistsException.php
new file mode 100644
index 0000000..ddb7e00
--- /dev/null
+++ b/core/includes/Drupal/Context/ParentContextNotExistsException.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Drupal\Context;
+
+/**
+ * Exception thrown when attempting to fall through to a parent context object
+ * that already got garbage collected.
+ */
+class ParentContextNotExistsException extends ContextException {}
diff --git a/core/includes/Drupal/Context/Stack.php b/core/includes/Drupal/Context/Stack.php
new file mode 100644
index 0000000..f48cef8
--- /dev/null
+++ b/core/includes/Drupal/Context/Stack.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Drupal\Context;
+
+/**
+ * Needs a comment
+ */
+class Stack {
+
+  /**
+   * Internal context stack.
+   *
+   * @var array
+   */
+  protected $stack = array();
+
+  /**
+   * Pushes a new context on top of the stack, make it being the active context.
+   *
+   * @param ContextInterface $context
+   *   // TODO comment
+   */
+  public function push(ContextInterface $context) {
+    $this->stack[spl_object_hash($context)] = $context;
+  }
+
+  /**
+   * Removes the given context from the stack, if exists, and all its children.
+   *
+   * @param ContextInterface $context
+   *   // TODO comment
+   *
+   * @throws ContextException
+   */
+  public function pop(ContextInterface $context) {
+    $pos = array_search(spl_object_hash($context), array_keys($this->stack));
+    if (FALSE !== $pos && count($this->stack) > 1) {
+      $this->stack = array_slice($this->stack, 0, $pos, TRUE);
+    }
+    else {
+      // throw new ContextException("Attempting to pop a non existing context from the stack.");
+    }
+  }
+
+  /**
+   * Gets the top-most context object.
+   *
+   * The top most context object is the only one that any outside systems
+   * should ever access.
+   *
+   * @return Drupal\Context\ContextInterface
+   */
+  public function getActiveContext() {
+    return end($this->stack);
+  }
+}
diff --git a/core/includes/Drupal/Context/Tracker.php b/core/includes/Drupal/Context/Tracker.php
new file mode 100644
index 0000000..42d6956
--- /dev/null
+++ b/core/includes/Drupal/Context/Tracker.php
@@ -0,0 +1,59 @@
+<?php
+
+namespace Drupal\Context;
+
+/**
+ * Transaction-like class for the context stack.
+ *
+ * When this class is destroyed, so its its corresponding context object.
+ */
+class Tracker {
+
+  /**
+   * The context object we're tracking.
+   *
+   * @var ContextInterface
+   */
+  protected $context;
+
+  /**
+   * The stack object to which the context object we're tracking is bound.
+   *
+   * @var Stack
+   */
+  protected $stack;
+
+  /**
+   * Constructs a Tracker object.
+   *
+   * @param ContextInterface $context
+   *   The context object we should be tracking.
+   */
+  public function __construct(ContextInterface $context) {
+    $this->context = $context;
+
+    // If the context object has not been bound to a stack, it won't work
+    // properly.  Still, we shouldn't fatal.
+    $stack = $this->context->getStack();
+    if (isset($stack)) {
+      $stack->push($this->context);
+      $this->stack = $stack;
+    }
+  }
+
+  /**
+   * Destructs a Tracker object.
+   *
+   * When destroying this object, pop the associated context off the stack and
+   * everything above it.
+   *
+   * Note that this method does not actively destroy those context objects, it
+   * just pops them off the stack. PHP will delete them for us unless someone
+   * has one hanging around somewhere.
+   */
+  public function __destruct() {
+    if ($this->stack) {
+      $this->stack->pop($this->context);
+    }
+  }
+}
diff --git a/core/includes/Drupal/Context/ValueInterface.php b/core/includes/Drupal/Context/ValueInterface.php
new file mode 100644
index 0000000..c75f8d4
--- /dev/null
+++ b/core/includes/Drupal/Context/ValueInterface.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Drupal\Context;
+
+/**
+ * Interface for context value objects.
+ *
+ * ValueInterface includes a method - contextKey() - that will return a
+ * load key for that object. It is up to the object to return something
+ * meaningful. The load key is the value by which we can load that object later,
+ * such as nid, view machine name, etc.
+ */
+interface ValueInterface {
+
+  /**
+   * Retrieves the key for the object to be loaded
+   *
+   * @return mixed
+   *   A key for the object to be returned by the appropriate handler
+   */
+  public function contextKey();
+}
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 9b4667e..fb8fe5f 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -698,13 +698,6 @@ function drupal_environment_initialize() {
     $_SERVER['HTTP_HOST'] = '';
   }
 
-  // When clean URLs are enabled, emulate ?q=foo/bar using REQUEST_URI. It is
-  // not possible to append the query string using mod_rewrite without the B
-  // flag (this was added in Apache 2.2.8), because mod_rewrite unescapes the
-  // path before passing it on to PHP. This is a problem when the path contains
-  // e.g. "&" or "%" that have special meanings in URLs and must be encoded.
-  $_GET['q'] = request_path();
-
   // Enforce E_STRICT, but allow users to set levels not part of E_STRICT.
   error_reporting(E_STRICT | E_ALL | error_reporting());
 
@@ -1116,9 +1109,10 @@ function bootstrap_invoke_all($hook) {
   // first time during the bootstrap that module_list() is called, we want to
   // make sure that its internal cache is primed with the bootstrap modules
   // only.
+  $args = func_get_args();
   foreach (module_list(FALSE, TRUE) as $module) {
     drupal_load('module', $module);
-    module_invoke($module, $hook);
+    call_user_func_array('module_invoke', array_merge(array($module), $args));
   }
 }
 
@@ -1412,7 +1406,7 @@ function drupal_serve_page_from_cache(stdClass $cache) {
  * Define the critical hooks that force modules to always be loaded.
  */
 function bootstrap_hooks() {
-  return array('boot', 'exit', 'watchdog', 'language_init');
+  return array('boot', 'exit', 'watchdog', 'language_init', 'context_init');
 }
 
 /**
@@ -2243,12 +2237,6 @@ function _drupal_bootstrap_configuration() {
   set_error_handler('_drupal_error_handler');
   set_exception_handler('_drupal_exception_handler');
 
-  drupal_environment_initialize();
-  // Start a page timer:
-  timer_start('page');
-  // Initialize the configuration, including variables from settings.php.
-  drupal_settings_initialize();
-
   // Hook up the Symfony ClassLoader for loading PSR-0-compatible classes.
   require_once(DRUPAL_ROOT . '/core/includes/Symfony/Component/ClassLoader/UniversalClassLoader.php');
 
@@ -2282,6 +2270,12 @@ function _drupal_bootstrap_configuration() {
 
   // Activate the autoloader.
   $loader->register();
+
+  drupal_environment_initialize();
+  // Start a page timer:
+  timer_start('page');
+  // Initialize the configuration, including variables from settings.php.
+  drupal_settings_initialize();
 }
 
 /**
@@ -2407,6 +2401,66 @@ function _drupal_bootstrap_variables() {
   // Load bootstrap modules.
   require_once DRUPAL_ROOT . '/core/includes/module.inc';
   module_load_all(TRUE);
+
+  require_once DRUPAL_ROOT . '/core/includes/common.inc';
+
+  drupal_bootstrap_context();
+}
+
+/**
+ * Initialize the context system.
+ *
+ * This function should only ever be called by _drupal_bootstrap_variables()
+ * and the install system.  Calling it from anywhere else is a bug.
+ *
+ * @todo Refactor the install system so that we don't need an $install argument.
+ * @param boolean $install
+ *   Set this to TRUE to set up install-system-specific overrides.
+  *
+ * @return \Drupal\Context\Context
+ *   The context object just initialized.  It is safe to ignore this value
+ *   as it is the same that will be retrieved from drupal_get_context().
+ *
+ * @see drupal_get_context();
+ */
+function drupal_bootstrap_context($install = FALSE) {
+  // Initialize the context system (temporary version).
+  $stack = new \Drupal\Context\Stack;
+  drupal_get_context($stack);
+
+  $context = new \Drupal\Context\Context;
+  $context->setStack($stack);
+
+  // Assuming we're answering a web request, there are a number of handlers
+  // that we know we'll always want available. Don't bother with a hook for
+  // these.
+  // @todo Technically this is hard-coding a special case, which is bad. Once
+  // we have a better low-level "what environment are we running in" concept
+  // these should be moved over to the HTTP implementation of that.
+  if (!drupal_is_cli()) {
+    $context->setHandler('http', function() {
+      $request = \Symfony\Component\HttpFoundation\Request::createFromGlobals();
+      return new \Drupal\Context\Handler\HandlerHttp($request);
+    });
+    $context->setHandler('path:raw', function() {
+      return new \Drupal\Context\Handler\HandlerPathRaw();
+    });
+    $context->setHandler('path:system', function() {
+      return new \Drupal\Context\Handler\HandlerPathSystem();
+    });
+  }
+
+  bootstrap_invoke_all('context_init', $context);
+
+  if ($install) {
+    $context->setValue('path:system', '');
+  }
+
+  // We do not need to keep the tracker here, because the DrupalContext
+  // destructor will never remove the root item from the stack.
+  $context->lock();
+
+  return $context;
 }
 
 /**
@@ -2422,6 +2476,28 @@ function _drupal_bootstrap_page_header() {
 }
 
 /**
+ * Returns the currently active context object.
+ *
+ * The return value from this funciton should never be statically cached. Doing
+ * so could lead to strange behavior if it has been removed from the stack, as
+ * it may no longer be valid and the object may even have been deleted.
+ *
+ * @return DrupalContextInterface
+ */
+function drupal_get_context(\Drupal\Context\Stack $new_stack = NULL) {
+  // This static property is infamous, but it's better here than in the OOP
+  // code, at least it does not taints the API.
+  static $stack;
+  if ($new_stack) {
+    $stack = $new_stack;
+  }
+
+  if (isset($stack)) {
+    return $stack->getActiveContext();
+  }
+}
+
+/**
  * Returns the current bootstrap phase for this Drupal process.
  *
  * The current phase is the one most recently completed by drupal_bootstrap().
@@ -2517,9 +2593,10 @@ function drupal_maintenance_theme() {
  */
 function drupal_fast_404() {
   $exclude_paths = variable_get('404_fast_paths_exclude', FALSE);
-  if ($exclude_paths && !preg_match($exclude_paths, $_GET['q'])) {
+  $system_path = drupal_get_context()->getValue('path:system');
+  if ($exclude_paths && !preg_match($exclude_paths, $system_path)) {
     $fast_paths = variable_get('404_fast_paths', FALSE);
-    if ($fast_paths && preg_match($fast_paths, $_GET['q'])) {
+    if ($fast_paths && preg_match($fast_paths, $system_path)) {
       drupal_add_http_header('Status', '404 Not Found');
       $fast_404_html = variable_get('404_fast_html', '<html xmlns="http://www.w3.org/1999/xhtml"><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>');
       // Replace @path in the variable with the page path.
@@ -2704,65 +2781,6 @@ function language_default() {
 }
 
 /**
- * Returns the requested URL path of the page being viewed.
- *
- * Examples:
- * - http://example.com/node/306 returns "node/306".
- * - http://example.com/drupalfolder/node/306 returns "node/306" while
- *   base_path() returns "/drupalfolder/".
- * - http://example.com/path/alias (which is a path alias for node/306) returns
- *   "path/alias" as opposed to the internal path.
- * - http://example.com/index.php returns an empty string (meaning: front page).
- * - http://example.com/index.php?page=1 returns an empty string.
- *
- * @return
- *   The requested Drupal URL path.
- *
- * @see current_path()
- */
-function request_path() {
-  static $path;
-
-  if (isset($path)) {
-    return $path;
-  }
-
-  if (isset($_GET['q'])) {
-    // This is a request with a ?q=foo/bar query string. $_GET['q'] is
-    // overwritten in drupal_path_initialize(), but request_path() is called
-    // very early in the bootstrap process, so the original value is saved in
-    // $path and returned in later calls.
-    $path = $_GET['q'];
-  }
-  elseif (isset($_SERVER['REQUEST_URI'])) {
-    // This request is either a clean URL, or 'index.php', or nonsense.
-    // Extract the path from REQUEST_URI.
-    $request_path = strtok($_SERVER['REQUEST_URI'], '?');
-    $base_path_len = strlen(rtrim(dirname($_SERVER['SCRIPT_NAME']), '\/'));
-    // Unescape and strip $base_path prefix, leaving q without a leading slash.
-    $path = substr(urldecode($request_path), $base_path_len + 1);
-    // If the path equals the script filename, either because 'index.php' was
-    // explicitly provided in the URL, or because the server added it to
-    // $_SERVER['REQUEST_URI'] even when it wasn't provided in the URL (some
-    // versions of Microsoft IIS do this), the front page should be served.
-    if ($path == basename($_SERVER['PHP_SELF'])) {
-      $path = '';
-    }
-  }
-  else {
-    // This is the front page.
-    $path = '';
-  }
-
-  // Under certain conditions Apache's RewriteRule directive prepends the value
-  // assigned to $_GET['q'] with a slash. Moreover we can always have a trailing
-  // slash in place, hence we need to normalize $_GET['q'].
-  $path = trim($path, '/');
-
-  return $path;
-}
-
-/**
  * Return a component of the current Drupal path.
  *
  * When viewing a page at the path "admin/structure/types", for example, arg(0)
@@ -2798,7 +2816,7 @@ function arg($index = NULL, $path = NULL) {
   $arguments = &$drupal_static_fast['arguments'];
 
   if (!isset($path)) {
-    $path = $_GET['q'];
+    $path = drupal_get_context()->getValue('path:system');
   }
   if (!isset($arguments[$path])) {
     $arguments[$path] = explode('/', $path);
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 919bfb5..7d0a86b 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -501,7 +501,7 @@ function drupal_get_destination() {
     $destination = array('destination' => $_GET['destination']);
   }
   else {
-    $path = $_GET['q'];
+    $path = drupal_get_context()->getValue('path:system');
     $query = drupal_http_build_query(drupal_get_query_parameters());
     if ($query != '') {
       $path .= '?' . $query;
@@ -2281,7 +2281,7 @@ function l($text, $path, array $options = array()) {
   );
 
   // Append active class.
-  if (($path == $_GET['q'] || ($path == '<front>' && drupal_is_front_page())) &&
+  if (($path == drupal_get_context()->getValue('path:system') || ($path == '<front>' && drupal_is_front_page())) &&
       (empty($options['language']) || $options['language']->language == $language_url->language)) {
     $options['attributes']['class'][] = 'active';
   }
@@ -2407,7 +2407,7 @@ function drupal_deliver_page($page_callback_result, $default_delivery_callback =
     // If a delivery callback is specified, but doesn't exist as a function,
     // something is wrong, but don't print anything, since it's not known
     // what format the response needs to be in.
-    watchdog('delivery callback not found', 'callback %callback not found: %q.', array('%callback' => $delivery_callback, '%q' => $_GET['q']), WATCHDOG_ERROR);
+    watchdog('delivery callback not found', 'callback %callback not found: %q.', array('%callback' => $delivery_callback, '%q' => drupal_get_context()->getValue('path:system')), WATCHDOG_ERROR);
   }
 }
 
@@ -2438,24 +2438,25 @@ function drupal_deliver_html_page($page_callback_result) {
 
   // Menu status constants are integers; page content is a string or array.
   if (is_int($page_callback_result)) {
+    $system_path = drupal_get_context()->getValue('path:system');
     // @todo: Break these up into separate functions?
     switch ($page_callback_result) {
       case MENU_NOT_FOUND:
         // Print a 404 page.
         drupal_add_http_header('Status', '404 Not Found');
 
-        watchdog('page not found', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);
+        watchdog('page not found', check_plain($system_path), NULL, WATCHDOG_WARNING);
 
         // Check for and return a fast 404 page if configured.
         drupal_fast_404();
 
         // Keep old path for reference, and to allow forms to redirect to it.
         if (!isset($_GET['destination'])) {
-          $_GET['destination'] = $_GET['q'];
+          $_GET['destination'] = $system_path;
         }
 
         $path = drupal_get_normal_path(variable_get('site_404', ''));
-        if ($path && $path != $_GET['q']) {
+        if ($path && $path != $system_path) {
           // Custom 404 handler. Set the active item in case there are tabs to
           // display, or other dependencies on the path.
           menu_set_active_item($path);
@@ -2476,15 +2477,15 @@ function drupal_deliver_html_page($page_callback_result) {
       case MENU_ACCESS_DENIED:
         // Print a 403 page.
         drupal_add_http_header('Status', '403 Forbidden');
-        watchdog('access denied', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);
+        watchdog('access denied', check_plain($system_path), NULL, WATCHDOG_WARNING);
 
         // Keep old path for reference, and to allow forms to redirect to it.
         if (!isset($_GET['destination'])) {
-          $_GET['destination'] = $_GET['q'];
+          $_GET['destination'] = $system_path;
         }
 
         $path = drupal_get_normal_path(variable_get('site_403', ''));
-        if ($path && $path != $_GET['q']) {
+        if ($path && $path != $system_path) {
           // Custom 403 handler. Set the active item in case there are tabs to
           // display or other dependencies on the path.
           menu_set_active_item($path);
@@ -5030,9 +5031,6 @@ function _drupal_bootstrap_full() {
     ini_set('error_log', 'public://error.log');
   }
 
-  // Initialize $_GET['q'] prior to invoking hook_init().
-  drupal_path_initialize();
-
   // Let all modules take action before the menu system handles the request.
   // We do not want this while running update.php.
   if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
@@ -5069,7 +5067,7 @@ function drupal_page_set_cache() {
     $cache = (object) array(
       'cid' => $base_root . request_uri(),
       'data' => array(
-        'path' => $_GET['q'],
+        'path' => drupal_get_context()->getValue('path:system'),
         'body' => ob_get_clean(),
         'title' => drupal_get_title(),
         'headers' => array(),
diff --git a/core/includes/form.inc b/core/includes/form.inc
index a12fb34..586b3b6 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -1102,7 +1102,7 @@ function drupal_validate_form($form_id, &$form, &$form_state) {
   // matches the current user's session.
   if (isset($form['#token'])) {
     if (!drupal_valid_token($form_state['values']['form_token'], $form['#token'])) {
-      $path = current_path();
+      $path = drupal_get_context()->getValue('path:system');
       $query = drupal_get_query_parameters();
       $url = url($path, array('query' => $query));
 
@@ -1236,7 +1236,8 @@ function drupal_redirect_form($form_state) {
         $function($form_state['redirect']);
       }
     }
-    drupal_goto($_GET['q']);
+    $system_path = drupal_get_context()->getValue('path:system');
+    drupal_goto($system_path);
   }
 }
 
@@ -4317,7 +4318,7 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = 'd
       'progressive' => TRUE,
       'url' => $url,
       'url_options' => array(),
-      'source_url' => $_GET['q'],
+      'source_url' => drupal_get_context()->getValue('path:system'),
       'redirect' => $redirect,
       'theme' => $GLOBALS['theme_key'],
       'redirect_callback' => $redirect_callback,
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index fefa670..daf9af4 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -262,6 +262,11 @@ function install_begin_request(&$install_state) {
   drupal_load('module', 'entity');
   drupal_load('module', 'user');
 
+  // Initialize the context system.
+  // @todo Refactor the context system such that we don't need to pass a boolean
+  // here and can rely on the normal context stack.
+  $context = drupal_bootstrap_context(TRUE);
+
   // Load the cache infrastructure using a "fake" cache implementation that
   // does not attempt to write to the database. We need this during the initial
   // part of the installer because the database is not available yet. We
diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index f23eb0d..29a0a40 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -425,7 +425,7 @@ function menu_set_item($path, $router_item) {
 function menu_get_item($path = NULL, $router_item = NULL) {
   $router_items = &drupal_static(__FUNCTION__);
   if (!isset($path)) {
-    $path = $_GET['q'];
+    $path = drupal_get_context()->getValue('path:system');
   }
   if (isset($router_item)) {
     $router_items[$path] = $router_item;
@@ -490,7 +490,7 @@ function menu_execute_active_handler($path = NULL, $deliver = TRUE) {
   // Allow other modules to change the site status but not the path because that
   // would not change the global variable. hook_url_inbound_alter() can be used
   // to change the path. Code later will not use the $read_only_path variable.
-  $read_only_path = !empty($path) ? $path : $_GET['q'];
+  $read_only_path = !empty($path) ? $path : drupal_get_context()->getValue('path:system');
   drupal_alter('menu_site_status', $page_callback_result, $read_only_path);
 
   // Only continue if the site status is not set.
@@ -1035,11 +1035,11 @@ function menu_tree_output($tree) {
       $class[] = 'active-trail';
       $data['link']['localized_options']['attributes']['class'][] = 'active-trail';
     }
-    // Normally, l() compares the href of every link with $_GET['q'] and sets
-    // the active class accordingly. But local tasks do not appear in menu
+    // Normally, l() compares the href of every link with the system path and
+    // sets the active class accordingly. But local tasks do not appear in menu
     // trees, so if the current path is a local task, and this link is its
     // tab root, then we have to set the class manually.
-    if ($data['link']['href'] == $router_item['tab_root_href'] && $data['link']['href'] != $_GET['q']) {
+    if ($data['link']['href'] == $router_item['tab_root_href'] && $data['link']['href'] != drupal_get_context()->getValue('path:system')) {
       $data['link']['localized_options']['attributes']['class'][] = 'active';
     }
 
@@ -1824,11 +1824,11 @@ function menu_navigation_links($menu_name, $level = 0) {
         $class = ' active-trail';
         $l['attributes']['class'][] = 'active-trail';
       }
-      // Normally, l() compares the href of every link with $_GET['q'] and sets
-      // the active class accordingly. But local tasks do not appear in menu
+      // Normally, l() compares the href of every link with the system path and
+      // sets the active class accordingly. But local tasks do not appear in menu
       // trees, so if the current path is a local task, and this link is its
       // tab root, then we have to set the class manually.
-      if ($item['link']['href'] == $router_item['tab_root_href'] && $item['link']['href'] != $_GET['q']) {
+      if ($item['link']['href'] == $router_item['tab_root_href'] && $item['link']['href'] != drupal_get_context()->getValue('path:system')) {
         $l['attributes']['class'][] = 'active';
       }
       // Keyed with the unique mlid to generate classes in theme_links().
@@ -1942,8 +1942,8 @@ function menu_local_tasks($level = 0) {
             // local tasks link to their parent, but the path of default local
             // tasks can still be accessed directly, in which case this link
             // would not be marked as active, since l() only compares the href
-            // with $_GET['q'].
-            if ($link['href'] != $_GET['q']) {
+            // with the system path.
+            if ($link['href'] != drupal_get_context()->getValue('path:system')) {
               $link['localized_options']['attributes']['class'][] = 'active';
             }
             $tabs_current[] = array(
@@ -2018,8 +2018,8 @@ function menu_local_tasks($level = 0) {
             // Mark the link as active, if the current path is a (second-level)
             // local task of a default local task. Since this default local task
             // links to its parent, l() will not mark it as active, as it only
-            // compares the link's href to $_GET['q'].
-            if ($link['href'] != $_GET['q']) {
+            // compares the link's href to the system path.
+            if ($link['href'] != drupal_get_context()->getValue('path:system')) {
               $link['localized_options']['attributes']['class'][] = 'active';
             }
             $tabs_current[] = array(
@@ -2385,7 +2385,7 @@ function menu_link_get_preferred($path = NULL) {
   $preferred_links = &drupal_static(__FUNCTION__);
 
   if (!isset($path)) {
-    $path = $_GET['q'];
+    $path = drupal_get_context()->getValue('path:system');
   }
 
   if (!isset($preferred_links[$path])) {
@@ -3777,7 +3777,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 && drupal_get_context()->getValue('path:system') != 'admin/config/development/maintenance') {
         if (user_access('administer site configuration')) {
           drupal_set_message(t('Operating in maintenance mode. <a href="@url">Go online.</a>', array('@url' => url('admin/config/development/maintenance'))), 'status', FALSE);
         }
diff --git a/core/includes/pager.inc b/core/includes/pager.inc
index a5d3e6b..2168242 100644
--- a/core/includes/pager.inc
+++ b/core/includes/pager.inc
@@ -630,7 +630,7 @@ function theme_pager_link($variables) {
     }
   }
 
-  return l($text, $_GET['q'], array('attributes' => $attributes, 'query' => $query));
+  return l($text, drupal_get_context()->getValue('path:system'), array('attributes' => $attributes, 'query' => $query));
 }
 
 /**
diff --git a/core/includes/path.inc b/core/includes/path.inc
index 2c0568c..bc0b472 100644
--- a/core/includes/path.inc
+++ b/core/includes/path.inc
@@ -10,17 +10,6 @@
  */
 
 /**
- * Initialize the $_GET['q'] variable to the proper normal path.
- */
-function drupal_path_initialize() {
-  // Ensure $_GET['q'] is set before calling drupal_normal_path().
-  if (empty($_GET['q'])) {
-    $_GET['q'] = variable_get('site_frontpage', 'node');
-  }
-  $_GET['q'] = drupal_get_normal_path($_GET['q']);
-}
-
-/**
  * Given an alias, return its Drupal system URL if one exists. Given a Drupal
  * system URL return one of its aliases if such a one exists. Otherwise,
  * return FALSE.
@@ -88,7 +77,7 @@ function drupal_lookup_path($action, $path = '', $path_language = NULL) {
 
         $cache['map'][$path_language] = array();
         // Load system paths from cache.
-        $cid = current_path();
+        $cid = drupal_get_context()->getValue('path:system');
         if ($cached = cache('path')->get($cid)) {
           $cache['system_paths'] = $cached->data;
           // Now fetch the aliases corresponding to these system paths.
@@ -205,7 +194,7 @@ function drupal_cache_system_paths() {
   $cache = &drupal_static('drupal_lookup_path', array());
   if (empty($cache['system_paths']) && !empty($cache['map'])) {
     // Generate a cache ID (cid) specifically for this page.
-    $cid = current_path();
+    $cid = drupal_get_context()->getValue('path:system');
     // The static $map array used by drupal_lookup_path() includes all
     // system paths for the page request.
     if ($paths = current($cache['map'])) {
@@ -234,7 +223,7 @@ function drupal_cache_system_paths() {
 function drupal_get_path_alias($path = NULL, $path_language = NULL) {
   // If no path is specified, use the current page's path.
   if ($path == NULL) {
-    $path = $_GET['q'];
+    $path = drupal_get_context()->getValue('path:system');
   }
   $result = $path;
   if ($alias = drupal_lookup_path('alias', $path, $path_language)) {
@@ -289,9 +278,9 @@ function drupal_is_front_page() {
   $is_front_page = &$drupal_static_fast['is_front_page'];
 
   if (!isset($is_front_page)) {
-    // As drupal_path_initialize updates $_GET['q'] with the 'site_frontpage' path,
+    // As system path handler updates 'path:system' with the 'site_frontpage' path,
     // we can check it against the 'site_frontpage' variable.
-    $is_front_page = ($_GET['q'] == variable_get('site_frontpage', 'node'));
+    $is_front_page = (drupal_get_context()->getValue('path:system') == variable_get('site_frontpage', 'node'));
   }
 
   return $is_front_page;
@@ -331,30 +320,6 @@ function drupal_match_path($path, $patterns) {
 }
 
 /**
- * Return the current URL path of the page being viewed.
- *
- * Examples:
- * - http://example.com/node/306 returns "node/306".
- * - http://example.com/drupalfolder/node/306 returns "node/306" while
- *   base_path() returns "/drupalfolder/".
- * - http://example.com/path/alias (which is a path alias for node/306) returns
- *   "node/306" as opposed to the path alias.
- *
- * This function is not available in hook_boot() so use $_GET['q'] instead.
- * However, be careful when doing that because in the case of Example #3
- * $_GET['q'] will contain "path/alias". If "node/306" is needed, calling
- * drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL) makes this function available.
- *
- * @return
- *   The current Drupal URL path.
- *
- * @see request_path()
- */
-function current_path() {
-  return $_GET['q'];
-}
-
-/**
  * Rebuild the path alias white list.
  *
  * @param $source
diff --git a/core/includes/tablesort.inc b/core/includes/tablesort.inc
index 121a1b9..bdf2546 100644
--- a/core/includes/tablesort.inc
+++ b/core/includes/tablesort.inc
@@ -143,7 +143,7 @@ function tablesort_header($cell, $header, $ts) {
       $ts['sort'] = 'asc';
       $image = '';
     }
-    $cell['data'] = l($cell['data'] . $image, $_GET['q'], array('attributes' => array('title' => $title), 'query' => array_merge($ts['query'], array('sort' => $ts['sort'], 'order' => $cell['data'])), 'html' => TRUE));
+    $cell['data'] = l($cell['data'] . $image, drupal_get_context()->getValue('path:system'), array('attributes' => array('title' => $title), 'query' => array_merge($ts['query'], array('sort' => $ts['sort'], 'order' => $cell['data'])), 'html' => TRUE));
 
     unset($cell['field'], $cell['sort']);
   }
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 68dd70b..6e726af 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1601,7 +1601,7 @@ function theme_links($variables) {
       if ($i == $num_links) {
         $class[] = 'last';
       }
-      if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))
+      if (isset($link['href']) && ($link['href'] == drupal_get_context()->getValue('path:system') || ($link['href'] == '<front>' && drupal_is_front_page()))
           && (empty($link['language']) || $link['language']->language == $language_url->language)) {
         $class[] = 'active';
       }
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index b6ea373..ea6637d 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -833,11 +833,12 @@ function block_block_list_alter(&$blocks) {
       $pages = drupal_strtolower($block->pages);
       if ($block->visibility < BLOCK_VISIBILITY_PHP) {
         // Convert the Drupal path to lowercase
-        $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
+        $system_path = drupal_get_context()->getValue('path:system');
+        $path = drupal_strtolower(drupal_get_path_alias($system_path));
         // Compare the lowercase internal and lowercase path alias (if any).
         $page_match = drupal_match_path($path, $pages);
-        if ($path != $_GET['q']) {
-          $page_match = $page_match || drupal_match_path($_GET['q'], $pages);
+        if ($path != $system_path) {
+          $page_match = $page_match || drupal_match_path($system_path, $pages);
         }
         // When $block->visibility has a value of 0 (BLOCK_VISIBILITY_NOTLISTED),
         // the block is displayed on all pages except those listed in $block->pages.
diff --git a/core/modules/contact/contact.module b/core/modules/contact/contact.module
index 9388877..ec04bfa 100644
--- a/core/modules/contact/contact.module
+++ b/core/modules/contact/contact.module
@@ -173,7 +173,7 @@ function contact_mail($key, &$message, $params) {
     '!site-name' => variable_get('site_name', 'Drupal'),
     '!subject' => $params['subject'],
     '!category' => isset($params['category']['category']) ? $params['category']['category'] : '',
-    '!form-url' => url($_GET['q'], array('absolute' => TRUE, 'language' => $language)),
+    '!form-url' => url(drupal_get_context()->getValue('path:system'), array('absolute' => TRUE, 'language' => $language)),
     '!sender-name' => format_username($params['sender']),
     '!sender-url' => $params['sender']->uid ? url('user/' . $params['sender']->uid, array('absolute' => TRUE, 'language' => $language)) : $params['sender']->mail,
   );
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 103c284..9e8dbd1 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -230,7 +230,7 @@ function locale_init() {
   // in $conf. This should happen on all pages except the date and time formats
   // settings page, where we want to display the site default and not the
   // localized version.
-  if (strpos($_GET['q'], 'admin/config/regional/date-time/formats') !== 0) {
+  if (strpos(drupal_get_context()->getValue('path:system'), 'admin/config/regional/date-time/formats') !== 0) {
     $languages = array($language->language);
 
     // Setup appropriate date formats for this locale.
@@ -1008,7 +1008,7 @@ function locale_block_info() {
  */
 function locale_block_view($type) {
   if (drupal_multilingual()) {
-    $path = drupal_is_front_page() ? '<front>' : $_GET['q'];
+    $path = drupal_is_front_page() ? '<front>' : drupal_get_context()->getValue('path:system');
     $links = language_negotiation_get_switch_links($type, $path);
 
     if (isset($links->links)) {
diff --git a/core/modules/overlay/overlay.install b/core/modules/overlay/overlay.install
index 2fa7c84..89e5e4b 100644
--- a/core/modules/overlay/overlay.install
+++ b/core/modules/overlay/overlay.install
@@ -12,7 +12,7 @@
  * install profile, reopen the modules page in an overlay.
  */
 function overlay_enable() {
-  if (strpos(current_path(), 'admin/modules') === 0) {
+  if (strpos(drupal_get_context()->getValue('path:system'), 'admin/modules') === 0) {
     // Flag for a redirect to <front>#overlay=admin/modules on hook_init().
     $_SESSION['overlay_enable_redirect'] = 1;
   }
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index 5433d3e..9215259 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -125,7 +125,7 @@ function overlay_init() {
   // set. Other modules can also enable the overlay directly for other uses.
   $use_overlay = !isset($user->data['overlay']) || $user->data['overlay'];
   if (empty($mode) && user_access('access overlay') && $use_overlay) {
-    $current_path = current_path();
+    $current_path = drupal_get_context()->getValue('path:system');
     // After overlay is enabled on the modules page, redirect to
     // <front>#overlay=admin/modules to actually enable the overlay.
     if (isset($_SESSION['overlay_enable_redirect']) && $_SESSION['overlay_enable_redirect']) {
@@ -241,7 +241,7 @@ function overlay_drupal_goto_alter(&$path, &$options, &$http_response_code) {
     // overlay_init().
     if ($path == system_authorized_get_url() || $path == system_authorized_batch_processing_url()) {
       $_SESSION['overlay_close_dialog'] = array($path, $options);
-      $path = current_path();
+      $path = drupal_get_context()->getValue('path:system');
       $options = drupal_get_query_parameters();
     }
 
diff --git a/core/modules/shortcut/shortcut.admin.inc b/core/modules/shortcut/shortcut.admin.inc
index 75c12b4..93e95b4 100644
--- a/core/modules/shortcut/shortcut.admin.inc
+++ b/core/modules/shortcut/shortcut.admin.inc
@@ -137,7 +137,7 @@ function shortcut_set_switch_submit($form, &$form_state) {
     $replacements = array(
       '%user' => $account->name,
       '%set_name' => $set->title,
-      '@switch-url' => url(current_path()),
+      '@switch-url' => url(drupal_get_context()->getValue('path:system')),
     );
     if ($account->uid == $user->uid) {
       // Only administrators can create new shortcut sets, so we know they have
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index f8ddcc2..a3109cd 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -648,7 +648,7 @@ function shortcut_preprocess_page(&$variables) {
   // we do not want to display it on "access denied" or "page not found"
   // pages).
   if (shortcut_set_edit_access() && ($item = menu_get_item()) && $item['access']) {
-    $link = $_GET['q'];
+    $link = drupal_get_context()->getValue('path:system');
     $query_parameters = drupal_get_query_parameters();
     if (!empty($query_parameters)) {
      $link .= '?' . drupal_http_build_query($query_parameters);
diff --git a/core/modules/simpletest/simpletest.info b/core/modules/simpletest/simpletest.info
index fab7b5e..07835f9 100644
--- a/core/modules/simpletest/simpletest.info
+++ b/core/modules/simpletest/simpletest.info
@@ -14,6 +14,7 @@ files[] = tests/batch.test
 files[] = tests/bootstrap.test
 files[] = tests/cache.test
 files[] = tests/common.test
+files[] = tests/context.test
 files[] = tests/database_test.test
 files[] = tests/error.test
 files[] = tests/file.test
diff --git a/core/modules/simpletest/tests/common.test b/core/modules/simpletest/tests/common.test
index 6cc159b..cc7f2a7 100644
--- a/core/modules/simpletest/tests/common.test
+++ b/core/modules/simpletest/tests/common.test
@@ -97,7 +97,7 @@ class CommonURLUnitTest extends DrupalWebTestCase {
    * Tests for active class in l() function.
    */
   function testLActiveClass() {
-    $link = l($this->randomName(), $_GET['q']);
+    $link = l($this->randomName(), drupal_get_context()->getValue('path:system'));
     $this->assertTrue($this->hasClass($link, 'active'), t('Class @class is present on link to the current page', array('@class' => 'active')));
   }
 
@@ -106,7 +106,7 @@ class CommonURLUnitTest extends DrupalWebTestCase {
    */
   function testLCustomClass() {
     $class = $this->randomName();
-    $link = l($this->randomName(), $_GET['q'], array('attributes' => array('class' => array($class))));
+    $link = l($this->randomName(), drupal_get_context()->getValue('path:system'), array('attributes' => array('class' => array($class))));
     $this->assertTrue($this->hasClass($link, $class), t('Custom class @class is present on link when requested', array('@class' => $class)));
     $this->assertTrue($this->hasClass($link, 'active'), t('Class @class is present on link to the current page', array('@class' => 'active')));
   }
diff --git a/core/modules/simpletest/tests/context.test b/core/modules/simpletest/tests/context.test
new file mode 100644
index 0000000..af273a3
--- /dev/null
+++ b/core/modules/simpletest/tests/context.test
@@ -0,0 +1,782 @@
+<?php
+
+/**
+ * Unit tests for the context system.
+ *
+ * Note: This file is using full namespaced names for classes, but in practice
+ * most code would use a "use" directive and then just the short class name.
+ */
+
+class ContextTestCases extends DrupalUnitTestCase {
+  public function setUp() {
+    parent::setUp();
+
+    require_once(DRUPAL_ROOT . '/core/modules/simpletest/tests/context_test.module');
+
+    // This unfortunately necessary because Drupal's registry throws a database
+    // exception when testing class_exist on non-existent classes in unit tests.
+    // This is the point of one of our tests so we have to remove the registry
+    // prior to running our tests.
+    spl_autoload_unregister('drupal_autoload_class');
+    spl_autoload_unregister('drupal_autoload_interface');
+  }
+
+  public function tearDown() {
+    // Re-register drupal's autoload classes. See setUp for the reasoning.
+    spl_autoload_register('drupal_autoload_class');
+    spl_autoload_register('drupal_autoload_interface');
+
+    parent::tearDown();
+  }
+}
+
+class ContextTestCase extends ContextTestCases {
+  public static function getInfo() {
+    return array(
+      'name' => 'Context functionality',
+      'description' => 'Test the Context context object.',
+      'group' => 'Context',
+    );
+  }
+
+  /**
+   * Test simple handler registration.
+   */
+  function testSimpleRegistration() {
+    $butler = new \Drupal\Context\Context();
+
+    $butler->setHandler('http:get', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValue('foo', 'bar');
+      return $handler;
+    });
+    $butler->lock();
+
+    $param = $butler->getValue('http:get:foo');
+
+    $this->assertEqual($param, 'bar', t('Correct Http GET fragment found.'));
+  }
+
+  /**
+   * Test explicit specification of a context value.
+   */
+  function testExplicitContext() {
+    $butler = new \Drupal\Context\Context();
+
+    $butler->setValue('foo:bar', 'baz');
+
+    $butler->lock();
+
+    $this->assertEqual($butler->getValue('foo:bar'), 'baz', t('Explicit context set correctly.'));
+  }
+
+  /**
+   * Test explicit overriding of a context value.
+   */
+  function testExplicitContextOverride() {
+    $butler = new \Drupal\Context\Context();
+
+    // This handler would return "one".
+    $butler->setHandler('foo:bar', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValue('', 'one');
+      return $handler;
+    });
+
+    // But we override it to "two".
+    $butler->setValue('foo:bar', 'two');
+
+    $butler->lock();
+
+    $this->assertEqual($butler->getValue('foo:bar'), 'two', t('Explicit context overridden correctly.'));
+  }
+
+  /**
+   * Test that we can lock a context object against modification.
+   */
+  function testLockStatusExplcit() {
+    $butler = new \Drupal\Context\Context();
+
+    try {
+      $butler->lock();
+      // This should throw an exception.
+      $butler->setValue('foo:bar', 'baz');
+
+      $this->fail(t('Exception not thrown when setting context on a locked object.'));
+    }
+    catch (\Drupal\Context\LockedException $e) {
+      $this->pass(t('Proper exception thrown when setting context on a locked object.'));
+    }
+    catch (Exception $e) {
+      $this->fail(t('Incorrect exception thrown when modifying a locked object.'));
+    }
+  }
+
+  /**
+   * Test that we can lock a context object against modification.
+   */
+  function testLockStatusDerived() {
+    $butler = new \Drupal\Context\Context();
+
+    try {
+      $butler->lock();
+      // This should throw an exception.
+      $butler->setHandler('foo:bar', function() {
+        $handler = new ContextMockHandler();
+        $handler->setValue('', 'one');
+        return $handler;
+      });
+      $this->fail(t('Exception not thrown when setting context on a locked object.'));
+    }
+    catch (\Drupal\Context\LockedException $e) {
+      $this->pass(t('Proper exception thrown when setting context handler on a locked object.'));
+    }
+    catch (Exception $e) {
+      $this->fail(t('Incorrect exception thrown when modifying a locked object.'));
+    }
+  }
+
+  /**
+   * Test the result caching logic.
+   */
+  function testResultCaching() {
+    $butler = new \Drupal\Context\Context();
+
+    // This handler should return 1, then 2, then 3, each time it's called.
+    $butler->setHandler('foo:bar', function() {
+      $handler = new ContextMockHandler();
+      $counter = 1;
+      $handler->setValueClosure(function(array $args = array(), \Drupal\Context\ContextInterface $context) use (&$counter) {
+        // This increases every time it's called.  If we ever get back something
+        // other than 1, it means the result caching is broken because we were
+        // called a second time.
+        return $counter++;
+      });
+      return $handler;
+    });
+    $butler->lock();
+
+    // Calling the same context variable should always give the same value
+    // due to immutable caching.
+    $this->assertEqual($butler->getValue('foo:bar'), $butler->getValue('foo:bar'), t('Identical context keys always return the same value.'));
+    // Handlers should be cached. That is, the same handler object should be
+    // used for foo:bar and foo:bar:baz, but the value of foo:bar:baz has not
+    // been cached.  Therefore it should get called again and return an
+    // incremented value.
+    $this->assertNotEqual($butler->getValue('foo:bar'), $butler->getValue('foo:bar:baz'), t('Handler classes are cached.'));
+  }
+
+  /**
+   * Test that the priority order of keys at different levels is stable.
+   */
+  function testTraversingLogic() {
+    $butler = new \Drupal\Context\Context;
+    // This handler will be more specific than the child one, but should not be
+    // found because the less specialized child one will hide it.
+    $butler->setHandler('foo:bar', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValue('baz', 1);
+      return $handler;
+    });
+
+    $t1 = $butler->lock();
+    $this->assertEqual(1, $butler->getValue('foo:bar:baz'), t('Asking for specialized value in root context.'));
+
+    $b2 = $butler->addLayer();
+    // This handler is less specialized than the parent one, but working on the
+    // same context key path tree than its parent. It should hide the parent
+    // more specialized one.
+    $b2->setHandler('foo', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValue('bar:baz', 2);
+      return $handler;
+    });
+    $t2 = $b2->lock();
+
+    $this->assertEqual(2, $b2->getValue('foo:bar:baz'), t('Less specialized handler in the overriding context hides the root more specialized one.'));
+
+    $b3 = $b2->addLayer();
+    // Test the other way arround, local context handlers should always hide
+    // the parent one if on the same context key path.
+    $b3->setHandler('foo:bar', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValue('baz', 3);
+      return $handler;
+    });
+    $t3 = $b3->lock();
+
+    $this->assertEqual(3, $b3->getValue('foo:bar:baz'), t('More specialized handler in the overriding context hides the root less specialized one.'));
+
+    $b4 = $b2->addLayer();
+
+    // Set two handlers on the same context key tree, one less specialized
+    // and one more specialized, and ensures that everything is ok.
+    $b4->setHandler('foo', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValue('bar:baz', 5);
+      return $handler;
+    });
+    $b4->setHandler('foo:bar', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValue('baz', 7);
+      return $handler;
+    });
+    $t4 = $b4->lock();
+
+    $this->assertEqual(7, $b4->getValue('foo:bar:baz'), t('Generic handler is overridden by the more specialized one in the fourth layer.'));
+
+    $b5 = $b2->addLayer();
+
+    // Set one handler and one value on the same context key tree, handler will
+    // be more generic than the value.
+    $b5->setHandler('foo', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValue('bar:baz', 11);
+      return $handler;
+    });
+    $b5->setValue('foo:bar:baz', 13);
+    $t5 = $b5->lock();
+
+    $this->assertEqual(13, $b5->getValue('foo:bar:baz'), t('Value overrides the generic handler in fifth layer.'));
+  }
+}
+
+class ContextValueObjectTestCase extends ContextTestCases {
+  public static function getInfo() {
+    return array(
+      'name' => 'Context Value Object functionality',
+      'description' => 'Test the Context system\'s handling of objects.',
+      'group' => 'Context',
+    );
+  }
+
+  /**
+   * Test the retrieval of context values of objects.
+   */
+  function testContextValues() {
+    $butler = new \Drupal\Context\Context();
+
+    // Add a handler for this test to mimic to create an example (E.g. from url arguments)
+    $butler->setHandler('example', function() {
+      return new ContextHandlerExample(array('id' => 1));
+    });
+
+    $t1 = $butler->lock();
+
+    // Catch the id from the url.
+    $this->assertEqual($butler->getValue('example')->id, 1, t('ContextValueNode property id in context retrieved from request correctly.'));
+    $this->assertEqual($butler->getValue('example')->foo, 10, t('ContextValueNode property foo in context retrieved from request correctly.'));
+
+    // Add a context layer to the butler context.
+    $b2 = $butler->addLayer();
+    $b2->setValue('test', 'test');
+
+    // Override with another instance of ContextValueInterface.
+    $n1 = $this->createExampleObject(2);
+    $b2->setValue('example', $n1);
+    // This will cause the error, which needs to be fixed.
+    //$b2['example:id'] = 2;
+    $t2 = $b2->lock();
+
+    $this->assertEqual($b2->getValue('test'), 'test', t('Explicit context assigned correctly in layer 2.'));
+    $this->assertEqual($b2->getValue('example')->foo, 20, t('ContextValueNode property in in layer 2 overridden correctly.'));
+    //$this->assertEqual($b2->getValue('example:id'), 2, t('Explicit context (example:id) overridden correctly in layer 2.'));
+
+    // Add a context layer to the butler context.
+    $b3 = $butler->addLayer();
+    $b3->setValue('test', 'testischanged');
+    $b3->setValue('test:foo', 'newtest');
+    $n2 = $this->createExampleObject(3);
+    $b3->setValue('example', $n2);
+    // Setting the example:id as contextKey:offset will add that property to the context.
+    $b3->setValue('example:id', 3);
+    $t3 = $b3->lock();
+
+    $this->assertEqual($b3->getValue('test'), 'testischanged', t('Explicit context overridden correctly in layer 3.'));
+    $this->assertEqual($b3->getValue('test:foo'), 'newtest', t('Explicit context retrieved correctly in layer 3.'));
+    $this->assertEqual($b3->getValue('example')->foo, 30, t('ContextValueNode property in in layer overridden correctly.'));
+    $this->assertEqual($b3->getValue('example:id'), 3, t('Explicit context (example:id) overridden correctly in layer 3.'));
+  }
+
+  /**
+   * Test that we can track the keys we've used.
+   */
+  public function testUsedKeys() {
+    $butler = new \Drupal\Context\Context();
+
+    // Add a handler for this test to mimic to create an example (E.g. from url arguments)
+    $butler->setHandler('example', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValue('id', 1);
+      return $handler;
+    });
+
+    $butler->setValue('test', 'test');
+
+    $t1 = $butler->lock();
+
+    // Add a context layer to the butler context.
+    $b2 = $butler->addLayer();
+    $b2->setValue('test', 'test2');
+
+    // Override with another instance of ContextValueInterface.
+    $n1 = $this->createExampleObject(2);
+    $b2->setValue('example', $n1);
+    $t2 = $b2->lock();
+
+    // Now try using the context values.
+    $b2->getValue('example');
+    $b2->getValue('test');
+
+    $used = $b2->usedKeys();
+
+    $this->assertEqual(count($used), 2, t('Correct number of keys in used keys array.'));
+    $this->assertEqual($used['test'], 'test2', t('Used keys includes primitive key correctly.'));
+    $this->assertEqual($used['example'], 2, t('Used keys includes object key correctly.'));
+  }
+
+  /**
+   * Utility method for an example value object.
+   *
+   * The property values are predictable and can be used for testing.
+   */
+  protected function createExampleObject($id) {
+    $c = new ContextValueExample($id);
+    $c->foo = $id * 10;
+    $c->bar = 'Baz ' . $id;
+
+    return $c;
+  }
+}
+
+/**
+ * Test class for the mocking/overriding capability of the context system.
+ */
+class ContextMockTestCase extends ContextTestCases {
+  public static function getInfo() {
+    return array(
+      'name' => 'Context Mocking functionality',
+      'description' => 'Test the Context object\'s override capability.',
+      'group' => 'Context',
+    );
+  }
+
+  /**
+   * Test basic context overrides.
+   */
+  function testOverrides() {
+    $butler = new \Drupal\Context\Context();
+
+    $butler->setHandler('http:get', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValue('foo', 'bar');
+      return $handler;
+    });
+
+    $t1 = $butler->lock();
+
+    $foo1 = $butler->getValue('http:get:foo');
+
+    $this->assertEqual($foo1, 'bar', t('Correct Http GET fragment found.'));
+
+    // Now check cloning.
+    $b2 = $butler->addLayer();
+    $b2->setValue('test', 'test');
+    $t2 = $b2->lock();
+
+    $this->assertNotIdentical($butler, $b2, t('New context object created properly.'));
+
+    $this->assertEqual($b2->getValue('http:get:foo'), 'bar', t('Inherited property works.'));
+    $this->assertEqual($b2->getValue('test'), 'test', t('Explicit context property in mocked object is correct.'));
+
+    $b3 = $b2->addLayer();
+    $b3->setValue('test', 'test_again');
+    $t3 = $b3->lock();
+
+    $this->assertEqual($b3->getValue('test'), 'test_again', t('Explicitly overriden property works.'));
+  }
+
+  /**
+   * Test access to the "active" context.
+   */
+  public function testActiveContext() {
+    $stack = new \Drupal\Context\Stack;
+    $butler = new \Drupal\Context\Context;
+    $butler->setStack($stack);
+
+    $t1 = $butler->lock();
+    $b2 = $butler->addLayer();
+    $t2 = $b2->lock();
+
+    $this->assertEqual($b2, $stack->getActiveContext(), t('Active context is correct when adding context objects.'));
+
+    unset($t2);
+
+    $this->assertEqual($butler, $stack->getActiveContext(), t('Active context is correct when removing context objects.'));
+  }
+
+  /**
+   * Test access to the "active" context at the global level.
+   */
+  public function testGlobalActiveContext() {
+    $butler = drupal_get_context();
+
+    $t1 = $butler->lock();
+    $b2 = $butler->addLayer();
+    $t2 = $b2->lock();
+
+    $this->assertEqual($b2, drupal_get_context(), t('Active global context is correct when adding context objects.'));
+
+    unset($t2);
+
+    $this->assertEqual($butler, drupal_get_context(), t('Active global context is correct when removing context objects.'));
+  }
+
+  /**
+   * Test that cotext values are removed from the stack properly.
+   */
+  public function testGarbageCollection() {
+    // Create a simple butler object.
+    $butler = new \Drupal\Context\Context();
+    $butler->setHandler('foo', function() {
+      return new ContextTestCaseHelperThree(array('bar' => 'butler'));
+    });
+    $t1 = $butler->lock();
+
+    // Create a new layer on top of that, which overrides some information.
+    $b2 = $butler->addLayer();
+    $b2->setHandler('foo', function() {
+      return new ContextTestCaseHelperThree(array('bar' => 'b2'));
+    });
+    $t2 = $b2->lock();
+
+    // Create a new layer on top of that, which actually does nothing at all.
+    $b3 = $b2->addLayer();
+    $t3 = $b3->lock();
+
+    // Get rid of the tracker for b3.
+    unset($t3);
+
+    // Get rid of b2 entirely.
+    unset($t2);
+    unset($b2);
+
+    /*
+     * FIXME: This test is not needed anymore. Contextes will remain in memory
+     * even if removed from the stack as long as references remain.
+     *
+     * This makes sense, contextes could be referenced (even if it sounds bad)
+     * in render array's and result built at the very end of page build, for
+     * exemple.
+     *
+    try {
+      // This should throw an exception.
+      $b3->getValue('foo:bar');
+
+      $this->fail(t('Exception not thrown when getting data from a context that should have been destroyed.'));
+    }
+    catch (\Drupal\Context\ParentContextNotExistsException $e) {
+      $this->pass(t('Proper exception thrown when getting data from a context that should have been destroyed.'));
+    }
+    catch (Exception $e) {
+      $this->fail(t('Incorrect exception thrown when getting data from a context that should have been destroyed.'));
+    }
+     */
+  }
+
+  /**
+   * Test that later parts of the context key are passed to the handler.
+   */
+  public function testContextArguments() {
+    $butler = new \Drupal\Context\Context();
+    $butler->setHandler('foo', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValueClosure(function(array $args = array(), \Drupal\Context\ContextInterface $context) {
+        return $args;
+      });
+      return $handler;
+    });
+    $butler->lock();
+
+    $this->assertEqual($butler->getValue('foo:bar:baz'), array('bar', 'baz'), t('ContextHandler gets the correct arguments.'));
+  }
+
+  public function testInheritanceContexts() {
+    $butler = new \Drupal\Context\Context();
+    $butler->setHandler('foo:bar', function() {
+      return new ContextTestCaseHelperThree(array('baz' => 1));
+    });
+
+    $t1 = $butler->lock();
+
+    $b2 = $butler->addLayer();
+    $b2->setHandler('foo', function() {
+      return new ContextTestCaseHelperThree(array('bar' => 3));
+    });
+    $t2 = $b2->lock();
+
+    $this->assertEqual($b2->getValue('foo:bar:baz'), 3, t('Context overrides even when more generic.'));
+
+    unset($t2, $b2);
+
+    $b3 = $butler->addLayer();
+    $b3->setHandler('foo', function() {
+      return new ContextTestCaseHelperThree(array('baz' => 5));
+    });
+    $t3 = $b3->lock();
+    $this->assertEqual($b3->getValue('foo:bar:baz'), 1, t('If a context handler does not return data, the parent handler gets a chance to return data'));
+
+    unset($t3, $b3);
+
+    $b4 = $butler->addLayer();
+    $b4->setHandler('foo:bar:baz', function() {
+      return new ContextTestCaseHelperThree(array('bax' => 7));
+    });
+    $b4->setHandler('foo:bar', function() {
+      return new ContextTestCaseHelperThree(array('baz' => 9));
+    });
+    $t4 = $b4->lock();
+
+    $this->assertEqual($b4->getValue('foo:bar:baz:boo'), 9, t('A more generic handler in the same context should be called if the less generic handler does not return data.'));
+  }
+
+  /**
+   * Test the offsetExists() method behavior.
+   */
+  public function testOffsetExists() {
+    $butler = new \Drupal\Context\Context();
+    $butler->setHandler('foo', function() {
+      return new ContextTestCaseHelperThree(array('bar' => 3));
+    });
+    // B1: T1, B2: T2, Butler: Tutler :)
+    $tutler = $butler->lock();
+
+    // Normal behavior, with no derivation.
+    $this->assertNotNull($butler->getValue('foo:bar'), t("foo:bar exists"));
+    $this->assertNull($butler->getValue('I:Do:Not:Exist'), t("I:Do:Not:Exist does not exists"));
+    $this->assertNotNull($butler->getValue('foo:bar'), t("foo:bar exists (caching does not break anything)"));
+    $this->assertNull($butler->getValue('I:Do:Not:Exist'), t("I:Do:Not:Exist does not exists (caching does not break anything)"));
+  }
+
+  /**
+   * Test the offsetExists() method behavior after multiple context derivation
+   * (through multiple layers over the same root context).
+   */
+  public function testOffsetExistsWithDerivation() {
+    $butler = new \Drupal\Context\Context();
+    $butler->setHandler('foo', function() {
+      return new ContextTestCaseHelperThree(array('bar' => 3));
+    });
+    // B1: T1, B2: T2, Butler: Tutler :)
+    $tutler = $butler->lock();
+
+    // Derivate and test over the new layer. Results should be the exact same.
+    $b1 = $butler->addLayer();
+    $t1 = $b1->lock();
+    $this->assertNotNull($b1->getValue('foo:bar'), t("foo:bar exists in new layer"));
+    $this->assertNull($b1->getValue('I:Do:Not:Exist'), t("I:Do:Not:Exist does not exists in new layer"));
+    $this->assertNotNull($b1->getValue('foo:bar'), t("Value exists in new layer (caching does not break anything)"));
+    $this->assertNull($b1->getValue('I:Do:Not:Exist'), t("I:Do:Not:Exist does not exists in new layer (caching does not break anything)"));
+
+    unset($t1, $b1);
+
+    // Derivate again, add a new value, and test for all other existence.
+    $b2 = $butler->addLayer();
+    $b2->setHandler('May:I', function() {
+      return new ContextTestCaseHelperThree(array('Exist' => 5));
+    });
+    $t2 = $b2->lock();
+    $this->assertNotNull($b2->getValue('foo:bar'), t("foo:bar exists in new layer"));
+    $this->assertNull($b2->getValue('I:Do:Not:Exist'), t("I:Do:Not:Exist does not exists in new layer"));
+    $this->assertNotNull($b2->getValue('May:I:Exist'), t("May:I:Exist value exists in new layer"));
+
+    unset($t2, $tutler);
+  }
+}
+
+/**
+ * Test class for the HTTP Handler.
+ */
+class ContextHTTPTestCase extends ContextTestCases {
+  public static function getInfo() {
+    return array(
+      'name' => 'Context HTTP Handler',
+      'description' => 'Test the HTTP Handler.',
+      'group' => 'Context',
+    );
+  }
+
+  /**
+   * Get method HTTP property.
+   */
+  function testGetHttpProperty() {
+    // If we're running in a Drush/CLI environment, the default HTTP-related
+    // superglobals won't be available so this test will always fail. We're
+    // keeping it around, though, to ensure that the superglobals do get used
+    // when they should.
+    if (!isset($_SERVER['SERVER_SOFTWARE']) && (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0))) {
+      return;
+    }
+
+    $butler = new \Drupal\Context\Context();
+
+    $butler->setHandler('http', function() {
+      $request = \Symfony\Component\HttpFoundation\Request::createFromGlobals();
+      return new \Drupal\Context\Handler\HandlerHttp($request);
+    });
+    $butler->lock();
+
+    $this->assertEqual($butler->getValue('http:method'), 'POST', t('Correct Http method property found.'));
+
+    // Test headers and server properties.
+    $this->assertEqual($butler->getValue('http:headers:host'), $_SERVER['HTTP_HOST'], t('Host header fetched successfully.'));
+    $this->assertEqual($butler->getValue('http:server:HTTP_USER_AGENT'), $_SERVER['HTTP_USER_AGENT'], t('User agent server variable fetched successfully'));
+  }
+
+  /**
+   * Mock HTTP property.
+   */
+  function testMockHttpProperty() {
+    $butler = new \Drupal\Context\Context();
+
+    $butler->setHandler('http', function() {
+      $request = \Symfony\Component\HttpFoundation\Request::create('', 'POST');
+      return new \Drupal\Context\Handler\HandlerHttp($request);
+    });
+    $butler->lock();
+
+    $this->assertEqual($butler->getValue('http:method'), 'POST', t('Http method property mocked successfully.'));
+  }
+
+  /**
+   * Access array property.
+   */
+  function testArrayHttpProperty() {
+    $butler = new \Drupal\Context\Context();
+
+    $params = array('foo' => array('bar' => 'baz'));
+    $butler->setHandler('http', function() use ($params) {
+      $request = \Symfony\Component\HttpFoundation\Request::create('', 'GET', $params);
+      return new \Drupal\Context\Handler\HandlerHttp($request);
+    });
+    $butler->lock();
+
+    // Different nesting level values.
+    $this->assertEqual($butler->getValue('http:query'), $params, t('Query args fetched successfully.'));
+    $this->assertEqual($butler->getValue('http:query:foo'), $params['foo'], t('First level value from query_args fetched successfully.'));
+
+    // Non existing value.
+    $this->assertEqual($butler->getValue('http:query:baz'), '', t('Non existent value fetched as empty string'));
+  }
+}
+
+/**
+ * Test class for the HTTP Handler.
+ */
+class ContextPathTestCase extends ContextTestCases {
+  public static function getInfo() {
+    return array(
+      'name' => 'Context Path Handlers',
+      'description' => 'Test the Path Handlers.',
+      'group' => 'Context',
+    );
+  }
+
+  /**
+   * Test path:raw from http:query:q
+   */
+  function testPathRawFromGetQ() {
+    $butler = new \Drupal\Context\Context();
+    $path_alias = 'alias';
+
+    $butler->setHandler('path:raw', function() {
+      return new \Drupal\Context\Handler\HandlerPathRaw();
+    });
+
+    $butler->setValue('http:query:q', $path_alias);
+    $butler->lock();
+
+    // Comment needed to tell the raw path is based on http:query:q
+    $this->assertEqual($butler->getValue('path:raw'), $path_alias, t('Raw path is fetched successfully from GET query parameters.'));
+  }
+
+  /**
+   * Test path:raw from http:request_uri
+   */
+  function testPathRawPropertyFromRequestUri() {
+    $butler = new \Drupal\Context\Context();
+    $path_alias = 'alias';
+
+    $butler->setHandler('path:raw', function() {
+      return new \Drupal\Context\Handler\HandlerPathRaw();
+    });
+
+    $butler->setValue('http:request_uri', '/alias?page=1');
+    $butler->setValue('http:script_name', '/index.php');
+    $butler->setValue('http:php_self', '/index.php');
+    $butler->lock();
+
+    // Comment needed to tell the raw path is based on the request_uri
+    $this->assertEqual($butler->getValue('path:raw'), $path_alias, t('Raw path is fetched successfully from request uri.'));
+  }
+
+  /**
+   * Test path:raw from http:request_uri with index.php as request uri
+   */
+  function testPathRawPropertyFromRequestUriIndexPhp() {
+    $butler = new \Drupal\Context\Context();
+    $path_alias = '';
+
+    $butler->setHandler('path:raw', function() {
+      return new \Drupal\Context\Handler\HandlerPathRaw();
+    });
+
+    $butler->setValue('http:request_uri', '/index.php');
+    $butler->setValue('http:script_name', '/index.php');
+    $butler->setValue('http:php_self', '/index.php');
+    $butler->lock();
+
+    // Comment needed to tell the raw path is based on the request_uri with index.php as request uri
+    $this->assertEqual($butler->getValue('path:raw'), $path_alias, t('Raw path is fetched successfully from request uri.'));
+  }
+
+  /**
+   * Test that a derived context value will clear when its dependant values do.
+   */
+  public function testDerivedContextCaching() {
+    $butler = new \Drupal\Context\Context();
+    $butler->setHandler('base_value', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValue('val', 5);
+      return $handler;
+    });
+    $butler->setHandler('derived_value', function() {
+      $handler = new ContextMockHandler();
+      $handler->setValueClosure(function(array $args = array(), \Drupal\Context\ContextInterface $context) {
+        return 2 * $context->getValue('base_value:val');
+      });
+      return $handler;
+    });
+    $t1 = $butler->lock();
+
+    $this->derivedContextCachingInner($butler);
+
+    // Because we are out of the scope where base_value was overridden, we
+    // should get back 10 here, that is, the base value of 5 times 2.
+    $value = $butler->getValue('derived_value');
+    $this->assertEqual($value, 10, t('Correct value derived from original base value.'));
+  }
+
+  protected function derivedContextCachingInner(\Drupal\Context\ContextInterface $context) {
+    $c2 = $context->addLayer();
+    $c2->setValue('base_value:val', 6);
+    $t2 = $c2->lock();
+
+    // This should implicitly request base_value:val, which should have a
+    // value of 6.
+    $value = $c2->getValue('derived_value');
+    $this->assertEqual($value, 12, t('Correct value derived from overridden base value.'));
+
+    // $t2 goes out of scope here, so $c2 gets popped off the stack.
+  }
+}
diff --git a/core/modules/simpletest/tests/context_test.info b/core/modules/simpletest/tests/context_test.info
new file mode 100644
index 0000000..6b64908
--- /dev/null
+++ b/core/modules/simpletest/tests/context_test.info
@@ -0,0 +1,5 @@
+name = Context Tests
+description = Central context handling system for Drupal, unit test file
+core = 8.x
+files[] = context_test.module
+hidden = TRUE
diff --git a/core/modules/simpletest/tests/context_test.module b/core/modules/simpletest/tests/context_test.module
new file mode 100644
index 0000000..adffa97
--- /dev/null
+++ b/core/modules/simpletest/tests/context_test.module
@@ -0,0 +1,118 @@
+<?php
+
+use Drupal\Context\ContextInterface;
+use Drupal\Context\Handler\HandlerInterface;
+
+/**
+ * Mock handler for testing purposes.
+ *
+ * Return an instance of this object from the handler closure in a unit test,
+ * in order to tightly control what should be returned for testing purposes.
+ */
+class ContextMockHandler implements HandlerInterface {
+
+  /**
+   * Simple list of values to return for a given key.
+   *
+   * @var array
+   */
+  protected $values = array();
+
+  /**
+   * Set the closure that will be used for the getValue() method.
+   *
+   * @var Closure
+   */
+  protected $valueClosure = NULL;
+
+  /**
+   * Sets a specific value to a specific key for testing purposes.
+   *
+   * @param string $key
+   *   A colon-delimited string specifying the context key to which to set a value.
+   * @param mixed $value
+   *   The value to bind to the $key.
+   */
+  public function setValue($key, $value) {
+    $this->values[$key] = $value;
+  }
+
+  /**
+   * Sets a custom method body for the getValue() method for testing purposes.
+   *
+   * @param Closure $closure
+   *   The closure object that will get called as part of the getValue() method.
+   *   It should match the signature of getValue().
+   */
+  public function setValueClosure($closure) {
+    $this->valueClosure = $closure;
+  }
+
+  /**
+   * Implements HandlerInterface::getValue().
+   */
+  public function getValue(array $args = array(), ContextInterface $context = NULL) {
+    $key = implode(':', $args);
+    if (isset($this->values[$key])) {
+      return $this->values[$key];
+    }
+    $closure = $this->valueClosure;
+    return $closure($args, $context);
+  }
+}
+
+class ContextTestCaseHelperThree extends \Drupal\Context\Handler\HandlerAbstract {
+  public function getValue(array $args = array(), ContextInterface $context = null) {
+    $param = $args[0];
+    return isset($this->params[$param]) ? $this->params[$param] : NULL;
+  }
+}
+
+/**
+ * Basic implementation of a ContextValueInterface.
+ */
+class ContextValueExample implements \Drupal\Context\ValueInterface {
+
+  public $id = 0;
+  public $foo = 0;
+  public $bar = '';
+
+  public function __construct($id) {
+    $this->id = $id;
+  }
+
+  public function contextKey() {
+    return $this->id();
+  }
+
+  public function id() {
+    return $this->id;
+  }
+}
+
+/**
+ * ContextHandlerExample
+ */
+class ContextHandlerExample extends \Drupal\Context\Handler\HandlerAbstract {
+
+  public function getValue(array $args = array(), ContextInterface $context = null) {
+    if (isset($this->params['id'])) {
+      $contextValueExample =  $this->createExampleObject($this->params['id']);
+      $param = !empty($args) ? $args[0] : NULL;
+      return isset($contextValueExample->$param) ? $contextValueExample->$param : $contextValueExample;
+    }
+  }
+
+  /**
+   * Utility method for an example value object.
+   *
+   * The property values are predictable and can be used for testing.
+   */
+  protected function createExampleObject($id) {
+    $c = new ContextValueExample($id);
+    $c->foo = $id * 10;
+    $c->bar = 'Baz ' . $id;
+
+    return $c;
+  }
+}
diff --git a/core/modules/simpletest/tests/path.test b/core/modules/simpletest/tests/path.test
index 9406a65..6a5abbd 100644
--- a/core/modules/simpletest/tests/path.test
+++ b/core/modules/simpletest/tests/path.test
@@ -192,23 +192,6 @@ class UrlAlterFunctionalTest extends DrupalWebTestCase {
   }
 
   /**
-   * Test current_path() and request_path().
-   */
-  function testCurrentUrlRequestedPath() {
-    $this->drupalGet('url-alter-test/bar');
-    $this->assertRaw('request_path=url-alter-test/bar', t('request_path() returns the requested path.'));
-    $this->assertRaw('current_path=url-alter-test/foo', t('current_path() returns the internal path.'));
-  }
-
-  /**
-   * Tests that $_GET['q'] is initialized when the request path is empty.
-   */
-  function testGetQInitialized() {
-    $this->drupalGet('');
-    $this->assertText("\$_GET['q'] is non-empty with an empty request path.", "\$_GET['q'] is initialized with an empty request path.");
-  }
-
-  /**
    * Assert that an outbound path is altered to an expected value.
    *
    * @param $original
diff --git a/core/modules/simpletest/tests/theme.test b/core/modules/simpletest/tests/theme.test
index 7968cf7..11aae38 100644
--- a/core/modules/simpletest/tests/theme.test
+++ b/core/modules/simpletest/tests/theme.test
@@ -61,13 +61,15 @@ class ThemeUnitTest extends DrupalWebTestCase {
    * Ensure page-front template suggestion is added when on front page.
    */
   function testFrontPageThemeSuggestion() {
-    $q = $_GET['q'];
-    // Set $_GET['q'] to node because theme_get_suggestions() will query it to
+    $context = drupal_get_context();
+    $c2 = $context->addLayer();
+    // Set path:system to node because theme_get_suggestions() will query it to
     // see if we are on the front page.
-    $_GET['q'] = variable_get('site_frontpage', 'node');
-    $suggestions = theme_get_suggestions(explode('/', $_GET['q']), 'page');
-    // Set it back to not annoy the batch runner.
-    $_GET['q'] = $q;
+    $c2->setValue('path:system', variable_get('site_frontpage', 'node'));
+    $t2 = $c2->lock();
+
+    $suggestions = theme_get_suggestions(explode('/', $c2->getValue('path:system')), 'page');
+
     $this->assertTrue(in_array('page__front', $suggestions), t('Front page template was suggested.'));
   }
 
diff --git a/core/modules/simpletest/tests/url_alter_test.module b/core/modules/simpletest/tests/url_alter_test.module
index 9287ff5..5c6b017 100644
--- a/core/modules/simpletest/tests/url_alter_test.module
+++ b/core/modules/simpletest/tests/url_alter_test.module
@@ -22,7 +22,7 @@ function url_alter_test_menu() {
  * Menu callback.
  */
 function url_alter_test_foo() {
-  print 'current_path=' . current_path() . ' request_path=' . request_path();
+  print 'current_path=' . drupal_get_context()->getValue('path:system') . ' request_path=' . drupal_get_context()->getValue('path:raw');
   exit;
 }
 
diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module
index 4f72553..b14dc4e 100644
--- a/core/modules/statistics/statistics.module
+++ b/core/modules/statistics/statistics.module
@@ -82,7 +82,7 @@ function statistics_exit() {
     db_insert('accesslog')
       ->fields(array(
         'title' => truncate_utf8(strip_tags(drupal_get_title()), 255),
-        'path' => truncate_utf8($_GET['q'], 255),
+        'path' => truncate_utf8(drupal_get_context()->getValue('path:system'), 255),
         'url' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
         'hostname' => ip_address(),
         'uid' => $user->uid,
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 6088a87..a5c9e40 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -486,7 +486,7 @@ function hook_page_build(&$page) {
  */
 function hook_menu_get_item_alter(&$router_item, $path, $original_map) {
   // When retrieving the router item for the current path...
-  if ($path == $_GET['q']) {
+  if ($path == drupal_get_context()->getValue('path:system')) {
     // ...call a function that prepares something for this request.
     mymodule_prepare_something();
   }
@@ -4136,5 +4136,24 @@ function hook_filetransfer_info_alter(&$filetransfer_info) {
 }
 
 /**
+ * Register universal context handlers.
+ *
+ * This bootstrap-level hook allows modules to register handlers that will
+ * respond to various context key requests.  Handlers should be registered
+ * using the setHandler() method.
+ *
+ * @see \Drupal\Context\ContextInterface
+ *
+ * @param ContextInterface $context
+ *   The root context object for the system.
+ */
+function hook_context_init(\Drupal\Context\ContextInterface $context) {
+
+  $context->setHandler('http', function() {
+    return new \Drupal\Context\Handler\HandlerHttp();
+  });
+}
+
+/**
  * @} End of "addtogroup hooks".
  */
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index f16b73f..921424b 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -1898,7 +1898,7 @@ function system_init() {
   // Add the CSS for this module. These aren't in system.info, because they
   // need to be in the CSS_SYSTEM group rather than the CSS_DEFAULT group.
   drupal_add_css($path . '/system.base.css', array('group' => CSS_SYSTEM, 'every_page' => TRUE));
-  if (path_is_admin(current_path())) {
+  if (path_is_admin(drupal_get_context()->getValue('path:system'))) {
     drupal_add_css($path . '/system.admin.css', array('group' => CSS_SYSTEM));
   }
   drupal_add_css($path . '/system.theme.css', array('group' => CSS_SYSTEM, 'every_page' => TRUE));
@@ -1953,7 +1953,7 @@ function system_add_module_assets() {
  * Implements hook_custom_theme().
  */
 function system_custom_theme() {
-  if (user_access('view the administration theme') && path_is_admin(current_path())) {
+  if (user_access('view the administration theme') && path_is_admin(drupal_get_context()->getValue('path:system'))) {
     return variable_get('admin_theme');
   }
 }
diff --git a/core/modules/taxonomy/taxonomy.admin.inc b/core/modules/taxonomy/taxonomy.admin.inc
index 99114a6..2041c5c 100644
--- a/core/modules/taxonomy/taxonomy.admin.inc
+++ b/core/modules/taxonomy/taxonomy.admin.inc
@@ -412,7 +412,7 @@ function taxonomy_overview_terms($form, &$form_state, $vocabulary) {
       '#type' => 'submit',
       '#value' => t('Reset to alphabetical')
     );
-    $form_state['redirect'] = array($_GET['q'], (isset($_GET['page']) ? array('query' => array('page' => $_GET['page'])) : array()));
+    $form_state['redirect'] = array(drupal_get_context()->getValue('path:system'), (isset($_GET['page']) ? array('query' => array('page' => $_GET['page'])) : array()));
   }
 
   return $form;
@@ -772,7 +772,7 @@ function taxonomy_form_term($form, &$form_state, $edit = array(), $vocabulary =
     );
   }
   else {
-    $form_state['redirect'] = $_GET['q'];
+    $form_state['redirect'] = drupal_get_context()->getValue('path:system');
   }
 
   return $form;
diff --git a/core/modules/update/update.compare.inc b/core/modules/update/update.compare.inc
index 2ccd97c..69e075c 100644
--- a/core/modules/update/update.compare.inc
+++ b/core/modules/update/update.compare.inc
@@ -738,8 +738,7 @@ function update_project_cache($cid) {
   $projects = array();
 
   // On certain paths, we should clear the cache and recompute the projects for
-  // update status of the site to avoid presenting stale information.
-  $q = $_GET['q'];
+  // update status of the site to avoid presenting stale informatio
   $paths = array(
     'admin/modules',
     'admin/modules/update',
@@ -751,7 +750,7 @@ function update_project_cache($cid) {
     'admin/reports/status',
     'admin/reports/updates/check',
   );
-  if (in_array($q, $paths)) {
+  if (in_array(drupal_get_context()->getValue('path:system'), $paths)) {
     _update_cache_clear($cid);
   }
   else {
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index 6da47c0..43baebb 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -107,7 +107,7 @@ function update_help($path, $arg) {
  */
 function update_init() {
   if (arg(0) == 'admin' && user_access('administer site configuration')) {
-    switch ($_GET['q']) {
+    switch (drupal_get_context()->getValue('path:system')) {
       // These pages don't need additional nagging.
       case 'admin/appearance/update':
       case 'admin/appearance/install':
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 260124c..af40a5f 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1205,7 +1205,7 @@ function user_user_presave(&$edit, $account) {
 }
 
 function user_login_block($form) {
-  $form['#action'] = url($_GET['q'], array('query' => drupal_get_destination()));
+  $form['#action'] = url(drupal_get_context()->getValue('path:system'), array('query' => drupal_get_destination()));
   $form['#id'] = 'user-login-form';
   $form['#validate'] = user_login_default_validators();
   $form['#submit'][] = 'user_login_submit';
@@ -3697,7 +3697,7 @@ function user_register_form($form, &$form_state) {
   if ($admin) {
     // Redirect back to page which initiated the create request;
     // usually admin/people/create.
-    $form_state['redirect'] = $_GET['q'];
+    $form_state['redirect'] = drupal_get_context()->getValue('path:system');
   }
 
   $form['actions'] = array('#type' => 'actions');
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
old mode 100644
new mode 100755
