-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
RunserverCommands.php
161 lines (149 loc) · 6.58 KB
/
RunserverCommands.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<?php
namespace Drush\Commands\core;
use Consolidation\SiteProcess\Util\Tty;
use Drush\Drush;
use Drupal\Core\Url;
use Drush\Commands\DrushCommands;
use Drush\Exec\ExecTrait;
use Webmozart\PathUtil\Path;
class RunserverCommands extends DrushCommands
{
use ExecTrait;
protected $uri;
/**
* Runs PHP's built-in http server for development.
*
* - Don't use this for production, it is neither scalable nor secure for this use.
* - If you run multiple servers simultaneously, you will need to assign each a unique port.
* - Use Ctrl-C or equivalent to stop the server when complete.
*
* @command runserver
* @param $uri Host IP address and port number to bind to and path to open in web browser. Format is addr:port/path. Only opens a browser if a path is specified.
* @option default-server A default addr:port/path to use for any values not specified as an argument.
* @option browser Open the URL in the default browser. Use --no-browser to avoid opening a browser.
* @option dns Resolve hostnames/IPs using DNS/rDNS (if possible) to determine binding IPs and/or human friendly hostnames for URLs and browser.
* @bootstrap full
* @aliases rs,serve
* @usage drush rs 8080
* Start a web server on 127.0.0.1, port 8080.
* @usage drush rs 10.0.0.28:80
* Start runserver on 10.0.0.28, port 80.
* @usage drush rs [::1]:80
* Start runserver on IPv6 localhost ::1, port 80.
* @usage drush rs --dns localhost:8888/user
* Start runserver on localhost (using rDNS to determine binding IP), port 8888, and open /user in browser.
* @usage drush rs /
* Start runserver on default IP/port (127.0.0.1, port 8888), and open / in browser.
* @usage drush rs :9000/admin
* Start runserver on 127.0.0.1, port 9000, and open /admin in browser. Note that you need a colon when you specify port and path, but no IP.
* @usage drush --quiet rs
* Silence logging the printing of web requests to the console.
*/
public function runserver($uri = null, $options = ['default-server' => self::REQ, 'browser' => true, 'dns' => false])
{
// Determine active configuration.
$uri = $this->uri($uri, $options);
if (!$uri) {
return false;
}
// Remove any leading slashes from the path, since that is what url() expects.
$path = ltrim($uri['path'], '/');
// $uri['addr'] is a special field set by runserver_uri()
$hostname = $uri['host'];
$addr = $uri['addr'];
$this->uri = 'http://' . $hostname . ':' . $uri['port'];
// We delete any registered files here, since they are not caught by Ctrl-C.
_drush_delete_registered_files();
$link = Url::fromUserInput('/' . $path, ['absolute' => true])->toString();
$this->logger()->notice(dt('HTTP server listening on !addr, port !port (see http://!hostname:!port/!path), serving site, !site', ['!addr' => $addr, '!hostname' => $hostname, '!port' => $uri['port'], '!path' => $path, '!site' => \Drupal::service('kernel')->getSitePath()]));
// Start php built-in server.
if (!empty($path)) {
// Start a browser if desired. Include a 2 second delay to allow the server to come up.
$this->startBrowser($link, 2);
}
// Start the server using 'php -S'.
$router = Path::join(DRUSH_BASE_PATH, '/misc/d8-rs-router.php');
$php = $this->getConfig()->get('php', 'php');
$process = $this->processManager()->process([$php, '-S', $addr . ':' . $uri['port'], $router]);
$process->setTimeout(null);
$process->setWorkingDirectory(Drush::bootstrapManager()->getRoot());
$process->setTty(Tty::isTtySupported());
if ($options['quiet']) {
$process->disableOutput();
}
$process->mustRun();
}
/**
* Determine the URI to use for this server.
*/
public function uri($uri, $options): array
{
$drush_default = [
'host' => '127.0.0.1',
'port' => '8888',
'path' => '',
];
$user_default = $this->parseUri($options['default-server']);
$site_default = $this->parseUri($uri);
$uri = $this->parseUri($uri);
if (is_array($uri)) {
// Populate defaults.
$uri = $uri + $user_default + $site_default + $drush_default;
if (ltrim($uri['path'], '/') == '-') {
// Allow a path of a single hyphen to clear a default path.
$uri['path'] = '';
}
// Determine and set the new URI.
$uri['addr'] = $uri['host'];
if ($options['dns']) {
if (ip2long($uri['host'])) {
$uri['host'] = gethostbyaddr($uri['host']);
} else {
$uri['addr'] = gethostbyname($uri['host']);
}
}
}
return $uri;
}
/**
* Parse a URI or partial URI (including just a port, host IP or path).
*
* @param $uri
* String that can contain partial URI.
*
* URI array as returned by parse_url.
*/
public function parseUri(?string $uri): array
{
if (empty($uri)) {
return [];
}
if ($uri[0] == ':') {
// ':port/path' shorthand, insert a placeholder hostname to allow parsing.
$uri = 'placeholder-hostname' . $uri;
}
// FILTER_VALIDATE_IP expects '[' and ']' to be removed from IPv6 addresses.
// We check for colon from the right, since IPv6 addresses contain colons.
$to_path = trim(substr($uri, 0, strpos($uri, '/')), '[]');
$to_port = trim(substr($uri, 0, strrpos($uri, ':')), '[]');
if (filter_var(trim($uri, '[]'), FILTER_VALIDATE_IP) || filter_var($to_path, FILTER_VALIDATE_IP) || filter_var($to_port, FILTER_VALIDATE_IP)) {
// 'IP', 'IP/path' or 'IP:port' shorthand, insert a schema to allow parsing.
$uri = 'http://' . $uri;
}
$uri = parse_url($uri);
if (empty($uri)) {
throw new \Exception(dt('Invalid argument - should be in the "host:port/path" format, numeric (port only) or non-numeric (path only).'));
}
if (count($uri) == 1 && isset($uri['path'])) {
if (is_numeric($uri['path'])) {
// Port only shorthand.
$uri['port'] = $uri['path'];
unset($uri['path']);
}
}
if (isset($uri['host']) && $uri['host'] == 'placeholder-hostname') {
unset($uri['host']);
}
return $uri;
}
}