diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a65b417
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+lib
diff --git a/commands/core/runserver-drupal.inc b/commands/core/runserver-drupal.inc
new file mode 100644
index 0000000..385d362
--- /dev/null
+++ b/commands/core/runserver-drupal.inc
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * @file
+ *   Classes extending the httpserver library that provide Drupal specific
+ *   behaviours.
+ */
+
+/**
+ * Extends the HTTPServer class, handling request routing and environment.
+ */
+class DrupalServer extends HTTPServer {
+  public $http_host;
+
+  /**
+   * This is the equivalent of .htaccess, passing requests to files if they
+   * exist, and all other requests to index.php. We also set a number
+   * of CGI environment variables here.  
+   */
+  function route_request($request) {
+    $cgi_env = array();
+
+    // Handle static files and php scripts accessed directly
+    $uri = $request->uri;
+    $doc_root = DRUPAL_ROOT;
+    $path = $doc_root . $uri;
+    if (is_file(realpath($path))) {
+      if (preg_match('#\.php$#', $uri)) {
+        // SCRIPT_NAME is equal to uri if it does exist on disk
+        $cgi_env['SCRIPT_NAME'] = $uri;
+        return $this->get_php_response($request, $path, $cgi_env);
+      }
+      return $this->get_static_response($request, $path);
+    }
+
+    // We pass in the effective base_url to our auto_prepend_script via the cgi
+    // environment. This allows Drupal to generate working URLs to this http
+    // server, whilst finding the correct multisite from the HTTP_HOST header.
+    $cgi_env['RUNSERVER_BASE_URL'] = 'http://localhost:' . $this->port;
+    
+    // We pass in an array of $conf overrides using the same approach.
+    // By default we set drupal_http_request_fails to FALSE, as the httpserver
+    // is unable to process simultanious requests on some systems.
+    // This is available as an option for developers to pass in their own
+    // favorite $conf overrides (e.g. disabling css aggregation). 
+    $conf_inject = drush_get_option('conf-inject', array('drupal_http_request_fails' => FALSE));
+    $cgi_env['RUNSERVER_CONF'] = urlencode(serialize($conf_inject));
+
+    // Rewrite clean-urls
+    $cgi_env['QUERY_STRING'] = 'q=' . ltrim($uri, '/');
+    if ($request->query_string != "") {
+      $cgi_env['QUERY_STRING'] .= '&' . $request->query_string;
+    }
+
+    $cgi_env['SCRIPT_NAME'] = '/index.php';
+    $cgi_env['HTTP_HOST'] = $cgi_env['SERVER_NAME'] = $this->http_host;
+
+    return $this->get_php_response($request, $doc_root . '/index.php', $cgi_env);
+  }
+}
diff --git a/commands/core/runserver-prepend.php b/commands/core/runserver-prepend.php
new file mode 100644
index 0000000..8f89d94
--- /dev/null
+++ b/commands/core/runserver-prepend.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * @file
+ * This file is included using the php "auto_prepend_file" option whenever
+ * Drupal is used with runserver.
+ * We use this to inject some specific changes so Drupal works correctly in
+ * this environment.
+ */
+
+// We set the base_url so that Drupal generates correct URLs for runserver
+// (e.g. http://localhost:8888/...), but can still select and serve a specific
+// site in a multisite configuration (e.g. http://mysite.com/...).
+$base_url = $_SERVER['RUNSERVER_BASE_URL'];
+
+/**
+ * Configuration added here will apply to all sites.
+ * This can be a useful place to apply generic development settings.
+ * We hijack system_boot (which core system module does not implement) as
+ * a convenient place to inject values into the $conf array.
+ */
+if (!function_exists('system_boot')) {
+  // Check function_exists as a safety net in case it is added in future.
+  function system_boot() {
+    global $conf;
+    $conf_inject = unserialize(urldecode($_SERVER['RUNSERVER_CONF']));
+    // Merge in the injected conf, overriding existing items.
+    $conf = array_merge($conf, $conf_inject);
+  }
+}
\ No newline at end of file
diff --git a/commands/core/runserver.drush.inc b/commands/core/runserver.drush.inc
new file mode 100644
index 0000000..61dc7ca
--- /dev/null
+++ b/commands/core/runserver.drush.inc
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * @file
+ *   Built in http server commands.
+ *   
+ *   This uses an excellent php http server library developed by Jesse Young
+ *   with support from the Envaya project.
+ *   See https://github.com/youngj/httpserver/ and http://envaya.org/.
+ */
+
+/**
+ * Supported version of httpserver. This is displayed in the manual install help.
+ */
+define('DRUSH_HTTPSERVER_VERSION', '9fa27f503c79308dedd5eb4667b38130ebdd2bb8');
+
+/**
+ * URL for automatic checkout of supported version of httpserver.
+ */
+define('DRUSH_HTTPSERVER_URL', 'https://github.com/youngj/httpserver.git');
+
+/**
+ * Implementation of hook_drush_help().
+ */
+function runserver_drush_help($section) {
+  switch ($section) {
+    case 'drush:runserver':
+      return dt("Runs a lightweight built in http server for development. Don't use this for production.");
+  }
+}
+
+/**
+ * Implementation of hook_drush_command().
+ */
+function runserver_drush_command() {
+  $items = array();
+
+  $items['runserver'] = array(
+    'description' => 'Runs a lightweight built in http server for development.',
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_SITE,
+    'arguments' => array(
+      'addr:port' => 'Host IP address and port number to bind to (default 0.0.0.0:8888). The IP is optional, in which case just pass in the numeric port.',
+    ),
+    'options' => array(
+      'php-cgi' => 'Name of the php-cgi binary. If it is not on your current $PATH you should include the full path. You can include command line parameters to pass into php-cgi.',
+      'conf-inject' => 'Key-value array of variables to override in the $conf array for the running site. By default disables drupal_http_request_fails to avoid errors on Windows (which supports only one connection at a time). Note that as this is a key-value array, it can only be specified in a drushrc or alias file, and not on the command line.',
+    ),
+    'aliases' => array('rs'),
+  );
+  return $items;
+}
+
+/**
+ * Validate callback for runserver command.
+ */
+function drush_core_runserver_validate() {
+  if (version_compare(PHP_VERSION, '5.3.0') < 0) {
+    return drush_set_error('RUNSERVER_PHP_VERSION', dt('The runserver command requires php 5.3, which could not be found.'));
+  }
+  if (!drush_shell_exec('which ' . drush_get_option('php-cgi', 'php-cgi'))) {
+    return drush_set_error('RUNSERVER_PHP_CGI', dt('The runserver command requires the php-cgi binary, which could not be found.'));
+  }
+}
+
+/**
+ * Callback for runserver command.
+ */
+function drush_core_runserver($addrport = '8888') {
+  // Clone httpserver to our /lib directory, if needed.
+  $httpserverfile = drush_get_option('lib', DRUSH_BASE_PATH . '/lib') . '/httpserver/httpserver.php';
+  $targetpath = dirname($httpserverfile);
+  if (!file_exists($httpserverfile)) {
+    drush_shell_exec('git clone ' . DRUSH_HTTPSERVER_URL . ' ' . $targetpath);
+  }
+  // Check the version and upgrade, if needed.
+  $git = 'git --work-tree=' . $targetpath . ' --git-dir=' . $targetpath . '/.git';
+  drush_shell_exec($git .' rev-parse --verify HEAD');
+  $version = drush_shell_exec_output();
+  if (isset($version[0]) && $version[0] !== DRUSH_HTTPSERVER_VERSION) {
+    if ((drush_shell_exec($git .' fetch') && drush_shell_exec($git .' checkout -f ' . DRUSH_HTTPSERVER_VERSION)) === FALSE) {
+      return drush_set_error('RUNSERVER_HTTPSERVER_UPGRADE', dt('The runserver command requires version !version of the httpserver library, but was unable to upgrade to this version. Please clone the httpserver project from !url to the !dir directory (if it does not already exist) and checkout the !version commit.', array('!version' => DRUSH_HTTPSERVER_VERSION, '!url' => DRUSH_HTTPSERVER_URL, '!dir' => $targetpath)));
+    }
+  }
+  if (!file_exists($httpserverfile)) {
+    // Something went wrong - the library is still not present.
+    return drush_set_error('RUNSERVER_HTTPSERVER_NOT_EXIST', dt('The runserver command requires version !version of the httpserver library, but was unable to source this version. Please clone the httpserver project from !url to the !dir directory and checkout the !version commit.', array('!version' => DRUSH_HTTPSERVER_VERSION, '!url' => DRUSH_HTTPSERVER_URL, '!dir' => $targetpath)));
+  }
+  
+  require_once $httpserverfile;
+  require_once 'runserver-drupal.inc';
+  
+  // Determine configuration.
+  if (is_numeric($addrport)) {
+    $addr = '0.0.0.0';
+    $port = $addrport;
+  }
+  else {
+    $addrport = explode(':', $addrport);
+    if (count($addrport) !== 2 && is_numeric($addrport[1])) {
+      return drush_set_error('RUNSERVER_INVALID_ADDRPORT', dt('Invalid address/port argument - should be either numeric (port only), or in the "host:port" format..'));
+    }
+    $addr = $addrport[0];
+    $port = $addrport[1];
+  }
+  
+  // Create a new server instance and start it running.
+  $server = new DrupalServer(array(
+    'addr' => $addr,
+    'port' => $port,
+    'serverid' => 'Drush runserver',
+    'php_cgi' => drush_get_option('php-cgi', 'php-cgi') . ' --define auto_prepend_file="' . DRUSH_BASE_PATH . '/commands/core/runserver-prepend.php"',
+  ));
+  $server->run_forever();
+}
diff --git a/commands/pm/pm.drush.inc b/commands/pm/pm.drush.inc
index 1a4a18a..436d49e 100644
--- a/commands/pm/pm.drush.inc
+++ b/commands/pm/pm.drush.inc
@@ -1322,7 +1322,7 @@ function _drush_pm_releasenotes($requests, $print_status = TRUE, $tmpfile = NULL
         @$dom = DOMDocument::loadHTML($data->data);
       }
       else {
-        $filename = _drush_download_file($release_page_url);
+        $filename = drush_download_file($release_page_url);
         @$dom = DOMDocument::loadHTMLFile($filename);
         @unlink($filename);
         if ($dom === FALSE) {
@@ -1712,7 +1712,7 @@ function _drush_pm_get_release_history_xml($request) {
   drush_log('Downloading release history from ' . $url);
   // Some hosts have allow_url_fopen disabled.
   if (!$xml = @simplexml_load_file($url)) {
-    $filename = _drush_download_file($url);
+    $filename = drush_download_file($url);
     $xml = simplexml_load_file($filename);
     drush_op('unlink', $filename);
   }
diff --git a/includes/drush.inc b/includes/drush.inc
index 3cf9751..da8a764 100644
--- a/includes/drush.inc
+++ b/includes/drush.inc
@@ -348,6 +348,7 @@ function drush_get_global_options($brief = FALSE) {
     $options['user']             = array('short-form' => 'u', 'description' => dt("Specify a Drupal user to login with. May be a name or a number."));
     $options['backend']          = array('short-form' => 'b', 'description' => dt("Hide all output and return structured data (internal use only)."));
     $options['choice']           = dt("Provide an answer to a multiple-choice prompt.");
+    $options['lib']              = dt("Location of directory where 3rd party libraries are available, or where Drush can downloaded them to if they are not found.");
     $options['no-label']         = dt("Remove the site label that drush includes in multi-site command output(e.g. `drush @site1,@site2 status`).");
     $options['nocolor']          = dt("Suppress color highlighting on log messages.");
     $options['show-passwords']   = dt("Show database passwords in commands that display connection information.");
@@ -703,26 +704,41 @@ function drush_op($function) {
 }
 
 /**
- * Download a file using wget or curl.
+ * Download a file using file_get_contents, wget or curl.
  *
  * @param string $url
  *   The path to the file to download
+ * @param string $filename
+ *   The name of the file to be saved. Optional, if omitted the filename will be
+ *   extracted from the url.
  *
  * @return string
- *   The filename that was downloaded,
- *   or NULL if the file could not be
+ *   The filename that was downloaded, or NULL if the file could not be
  *   downloaded.
  */
-function _drush_download_file($url) {
-  $filename = explode('/', $url);
-  $filename = array_pop($filename);
+function drush_download_file($url, $filename = NULL) {
+  if (!$filename) {
+    $filename = explode('/', $url);
+    $filename = array_pop($filename);
+  }
 
-  if (!drush_shell_exec("wget %s", $url)) {
-    if(!drush_shell_exec("curl -O %s", $url)) {
-      return NULL;
+  if (!file_exists($filename) && $file = @file_get_contents($url)) {
+    @file_put_contents($filename, $file);
+  }
+  if (!file_exists($filename)) {
+    drush_shell_exec("wget -q --timeout=30 -O $filename " . $url);
+    // wget creates an empty file on timeout. We remove it here.
+    if (file_exists($filename) && !drush_file_not_empty($filename)) {
+      unlink($filename);
     }
   }
-
+  if (!file_exists($filename)) {
+    drush_shell_exec("curl -s  --connect-timeout 30 -o $filename " . $url);
+  }
+  if (!file_exists($filename)) {
+    return NULL;
+  }
+  
   return $filename;
 }
 
diff --git a/includes/environment.inc b/includes/environment.inc
index e18e1ce..d5c7a2a 100644
--- a/includes/environment.inc
+++ b/includes/environment.inc
@@ -504,6 +504,10 @@ function _drush_bootstrap_drush_validate() {
     return $return;
   }
 
+  if (drush_environment_lib() === FALSE) {
+    return FALSE;
+  }
+
   if (drush_environment_table_inc() === FALSE) {
     return FALSE;
   }
@@ -522,35 +526,38 @@ function drush_environment_check_os() {
   }
 }
 
+/*
+ * Check for the existence of the specified lib directory, and create if needed.
+ */
+function drush_environment_lib() {
+  $lib = drush_get_option('lib', DRUSH_BASE_PATH . '/lib');
+  drush_mkdir($lib);
+  if (!is_dir($lib)) {
+    return FALSE;
+  }
+}
+
 function drush_environment_table_inc() {
-  // try using the PEAR installed version of Console_Table
+  // Try using the PEAR installed version of Console_Table.
   $tablefile = 'Console/Table.php';
   if (@file_get_contents($tablefile, FILE_USE_INCLUDE_PATH) === FALSE) {
-    $tablefile = DRUSH_BASE_PATH . '/includes/table.inc';
-
+    $tablefile = drush_get_option('lib', DRUSH_BASE_PATH . '/lib') . '/Console_Table-' . DRUSH_TABLE_VERSION . '/Table.inc';
+    $targetpath = dirname($tablefile);
+    drush_mkdir($targetpath);
     // Attempt to download Console Table, via various methods.
     if (!drush_file_not_empty($tablefile)) {
-      $targetpath = dirname($tablefile);
-      // not point continuing if we can't write to the target path
+      // No point continuing if we can't write to the target path.
       if (!is_writable($targetpath)) {
         return drush_bootstrap_error('DRUSH_TABLES_INC', dt("Drush needs a copy of the PEAR Console_Table library in order to function, and the attempt to download this file automatically failed because you do not have permission to write files in !path. To continue you will need to download the !version package from http://pear.php.net/package/Console_Table, extract it, and copy the Table.php file into Drush's directory as !tablefile.", array('!path' => $targetpath, '!version' => DRUSH_TABLE_VERSION ,'!tablefile' => $tablefile)));
       }
-
-      if ($file = @file_get_contents(DRUSH_TABLE_URL)) {
-        @file_put_contents($tablefile, $file);
+      // Attempt to move Console Table, from the legacy location to new.
+      // TODO: Remove this (and associated .git.ignore) in Drush 6.x.
+      $tablefile_legacy = DRUSH_BASE_PATH . '/includes/table.inc';
+      if (drush_file_not_empty($tablefile_legacy)) {
+        drush_op('rename', $tablefile_legacy, $tablefile);
       }
-      if (!file_exists($tablefile)) {
-        drush_shell_exec("wget -q --timeout=30 -O $tablefile " . DRUSH_TABLE_URL);
-        // wget creates an empty file on timeout. We remove it here.
-        if (file_exists($tablefile) && !drush_file_not_empty($tablefile)) {
-          unlink($tablefile);
-        }
-        if (!file_exists($tablefile)) {
-          drush_shell_exec("curl -s  --connect-timeout 30 -o $tablefile " . DRUSH_TABLE_URL);
-          if (!file_exists($tablefile)) {
-            return drush_bootstrap_error('DRUSH_TABLES_INC', dt("Drush needs a copy of the PEAR Console_Table library in order to function, and the attempt to download this file automatically failed. To continue you will need to download the !version package from http://pear.php.net/package/Console_Table, extract it, and copy the Table.php file into Drush's directory as !tablefile.", array('!version' => DRUSH_TABLE_VERSION ,'!tablefile' => $tablefile)));
-          }
-        }
+      if (!drush_download_file(DRUSH_TABLE_URL,  $tablefile)) {
+        return drush_bootstrap_error('DRUSH_TABLES_INC', dt("Drush needs a copy of the PEAR Console_Table library in order to function, and the attempt to download this file automatically failed. To continue you will need to download the !version package from http://pear.php.net/package/Console_Table, extract it, and copy the Table.php file into Drush's directory as !tablefile.", array('!version' => DRUSH_TABLE_VERSION ,'!tablefile' => $tablefile)));
       }
     }
   }
