Skip to content

Commit 9fa87e0

Browse files
committed
fixed issues where responses would finish without writing all of their
body.
1 parent 30872e0 commit 9fa87e0

File tree

2 files changed

+316
-327
lines changed

2 files changed

+316
-327
lines changed

Diff for: lib/Rackem/Server.php

+137-153
Original file line numberDiff line numberDiff line change
@@ -5,192 +5,176 @@
55

66
class Server
77
{
8-
public $app, $reload = true;
9-
private $host, $port, $running, $in, $out;
10-
11-
public function __construct($host = '0.0.0.0', $port = 9393, $app = 'config.php')
12-
{
13-
declare(ticks=1);
14-
$this->host = $host;
15-
$this->port = $port;
16-
$this->app = $app;
17-
$this->in = array();
18-
$this->out = array();
19-
20-
\Rackem::$handler = new \Rackem\Handler\Rackem();
21-
}
22-
23-
public function start()
24-
{
25-
$this->init();
26-
$this->running = true;
27-
28-
while($this->step())
29-
{
30-
31-
}
32-
}
8+
public $app, $reload = true;
9+
private $host, $port, $running, $in, $out;
3310

34-
public function step()
35-
{
36-
$read = array();
37-
$write = array();
38-
$except = null;
39-
40-
foreach($this->in as $id => $conn)
11+
public function __construct($host = '0.0.0.0', $port = 9393, $app = 'config.php')
4112
{
42-
if(!$conn->is_request_complete())
43-
{
44-
$read[] = $conn->socket;
45-
}else
46-
{
47-
if(strlen($conn->buffer) || $conn->is_response_complete()) $write[] = $conn->socket;
48-
else $read[] = $conn->stream;
49-
}
13+
declare(ticks=1);
14+
$this->host = $host;
15+
$this->port = $port;
16+
$this->app = $app;
17+
$this->in = array();
18+
$this->out = array();
5019
}
51-
$read[] = $this->master;
52-
53-
if(@stream_select($read, $write, $except, null) < 1) return $this->running;
5420

55-
if(in_array($this->master, $read))
21+
public function start()
5622
{
57-
$client = stream_socket_accept($this->master);
58-
$this->in[(int)$client] = new Connection($client);
23+
$this->init();
24+
$this->running = true;
5925

60-
$key = array_search($this->master, $read);
61-
unset($read[$key]);
26+
while($this->step()) { /*BOOM*/ }
6227
}
6328

64-
foreach($read as $stream)
29+
public function step()
6530
{
66-
if(isset($this->out[(int)$stream])) $this->out[(int)$stream]->read();
67-
else $this->read_request($stream);
31+
$read = array();
32+
$write = array();
33+
$except = null;
34+
35+
foreach($this->in as $id => $conn) {
36+
if(!$conn->is_request_complete()) {
37+
$read[] = $conn->socket;
38+
} else {
39+
if($conn->socket) $write[] = $conn->socket;
40+
if(!$conn->is_response_complete()) $read[] = $conn->stream;
41+
}
42+
}
43+
$read[] = $this->master;
44+
45+
if(@stream_select($read, $write, $except, null) < 1) return $this->running;
46+
47+
if(in_array($this->master, $read)) {
48+
$client = stream_socket_accept($this->master);
49+
$this->in[(int)$client] = new Connection($client);
50+
51+
$key = array_search($this->master, $read);
52+
unset($read[$key]);
53+
}
54+
55+
foreach($read as $stream) {
56+
if(isset($this->out[(int)$stream])) $this->out[(int)$stream]->read();
57+
else $this->read_request($stream);
58+
}
59+
60+
foreach($write as $client) $this->write($client);
61+
62+
return $this->running;
6863
}
6964

70-
foreach($write as $client) $this->write($client);
71-
72-
return $this->running;
73-
}
65+
public function read_request($socket)
66+
{
67+
$conn = $this->in[(int)$socket];
68+
$data = @fread($socket, 30000);
7469

75-
public function read_request($socket)
76-
{
77-
$conn = $this->in[(int)$socket];
78-
$data = @fread($socket, 30000);
70+
if($data === false || $data == '') return $this->close_connection($conn);
7971

80-
if($data === false || $data == '') return $this->close_connection($conn);
72+
$conn->data($data);
73+
if($conn->is_request_complete()) {
74+
$conn->process($this->app);
75+
$this->out[(int)$conn->stream] = $conn;
76+
}
77+
}
8178

82-
$conn->data($data);
83-
if($conn->is_request_complete())
79+
public function write($socket)
8480
{
85-
$stream = $conn->process($this->app);
86-
$this->out[(int)$stream] = $conn;
81+
$conn = $this->in[(int)$socket];
82+
83+
$bytes = @fwrite($socket, $conn->buffer);
84+
if($bytes === false) return $this->close_connection($conn);
85+
86+
$conn->bytes_written += $bytes;
87+
$conn->buffer = substr($conn->buffer, $bytes);
88+
if($conn->bytes_written < $conn->response_length) return;
89+
if($conn->is_response_complete()) $this->complete_response($conn);
8790
}
88-
}
8991

90-
public function write($socket)
91-
{
92-
$conn = $this->in[(int)$socket];
92+
public function complete_response($conn)
93+
{
94+
fwrite(STDERR, $this->log_request($conn));
95+
if($conn->get_header('Connection') === 'close' || $conn->version !== 'HTTP/1.1') {
96+
$this->close_connection($conn);
97+
} else {
98+
$conn->cleanup();
99+
$this->close_response($conn);
100+
$this->in[(int)$conn->socket] = new Connection($conn->socket);
101+
}
102+
}
93103

94-
$bytes = @fwrite($socket, $conn->buffer);
95-
if($bytes === false) return $this->close_connection($conn);
104+
public function close_connection($conn)
105+
{
106+
$conn->cleanup();
107+
@fclose($conn->socket);
108+
unset($this->in[(int)$conn->socket]);
109+
$conn->socket = null;
96110

97-
$conn->bytes_written += $bytes;
98-
$conn->buffer = substr($conn->buffer, $bytes);
111+
$this->close_response($conn);
112+
}
99113

100-
if($conn->is_response_complete()) $this->complete_response($conn);
101-
}
114+
public function close_response($conn)
115+
{
116+
if(!$conn->stream) return;
117+
@fclose($conn->stream);
118+
unset($this->out[(int)$conn->stream]);
119+
$conn->stream = null;
120+
if($conn->proc) {
121+
proc_close($conn->proc);
122+
$conn->proc = null;
123+
}
124+
}
102125

103-
public function complete_response($conn)
104-
{
105-
fwrite(STDERR, $this->log_request($conn));
106-
if($conn->get_header('Connection') === 'close' || $conn->version !== 'HTTP/1.1')
126+
public function stop()
107127
{
108-
$this->close_connection($conn);
109-
}else
128+
$this->running = false;
129+
fclose($this->master);
130+
echo ">> Stopping...\n";
131+
exit(0);
132+
}
133+
134+
public function help()
110135
{
111-
$conn->cleanup();
112-
$this->close_response($conn);
113-
$this->in[(int)$conn->socket] = new Connection($conn->socket);
136+
echo "Usage:\n";
137+
echo "rackem [options] [config]\n\n";
138+
echo "Options:\n";
139+
echo " --basic run a basic HTTP server\n";
140+
echo " --host HOST listen on HOST (default: 127.0.0.1)\n";
141+
echo " --port PORT use PORT (default: 9393)\n";
142+
echo " -h show this message\n";
143+
echo " -v, --version show version.\n";
114144
}
115-
}
116-
117-
public function close_connection($conn)
118-
{
119-
$conn->cleanup();
120-
@fclose($conn->socket);
121-
unset($this->in[(int)$conn->socket]);
122-
$conn->socket = null;
123-
124-
$this->close_response($conn);
125-
}
126-
127-
public function close_response($conn)
128-
{
129-
if(!$conn->stream) return;
130-
@fclose($conn->stream);
131-
unset($this->out[(int)$conn->stream]);
132-
$conn->stream = null;
133-
if($conn->proc)
145+
146+
public function version()
134147
{
135-
proc_close($conn->proc);
136-
$conn->proc = null;
148+
echo explode(".", \Rackem::version()) ."\n";
137149
}
138-
}
139-
140-
public function stop()
141-
{
142-
$this->running = false;
143-
fclose($this->master);
144-
echo ">> Stopping...\n";
145-
exit(0);
146-
}
147-
148-
public function help()
149-
{
150-
echo "Usage:\n";
151-
echo "rackem [options] [config]\n\n";
152-
echo "Options:\n";
153-
echo " --basic run a basic HTTP server\n";
154-
echo " --host HOST listen on HOST (default: 127.0.0.1)\n";
155-
echo " --port PORT use PORT (default: 9393)\n";
156-
echo " -h show this message\n";
157-
echo " -v, --version show version.\n";
158-
}
159-
160-
public function version()
161-
{
162-
echo explode(".", \Rackem::version()) ."\n";
163-
}
164150

165151
/* private */
166152

167-
protected function init()
168-
{
169-
set_time_limit(0);
170-
$this->master = @stream_socket_server("tcp://{$this->host}:{$this->port}", $errno, $errstr);
171-
if($this->master === false)
153+
protected function init()
172154
{
173-
echo ">> Failed to bind socket.\n", $errno, " - ", $errstr, "\n";
174-
exit(2);
155+
set_time_limit(0);
156+
$this->master = @stream_socket_server("tcp://{$this->host}:{$this->port}", $errno, $errstr);
157+
if($this->master === false) {
158+
echo ">> Failed to bind socket.\n", $errno, " - ", $errstr, "\n";
159+
exit(2);
160+
}
161+
stream_set_blocking($this->master, 0);
162+
163+
echo "== Rack'em on http://{$this->host}:{$this->port}\n";
164+
echo ">> Rack'em web server\n";
165+
echo ">> Listening on {$this->host}:{$this->port}, CTRL+C to stop\n";
166+
if(function_exists('pcntl_signal')) {
167+
pcntl_signal(SIGINT, array($this, "stop"));
168+
pcntl_signal(SIGTERM, array($this, "stop"));
169+
}
175170
}
176-
stream_set_blocking($this->master, 0);
177171

178-
echo "== Rack'em on http://{$this->host}:{$this->port}\n";
179-
echo ">> Rack'em web server\n";
180-
echo ">> Listening on {$this->host}:{$this->port}, CTRL+C to stop\n";
181-
if(function_exists('pcntl_signal'))
172+
protected function log_request($conn)
182173
{
183-
pcntl_signal(SIGINT, array($this, "stop"));
184-
pcntl_signal(SIGTERM, array($this, "stop"));
185-
}
186-
}
174+
$date = @date("d/M/Y H:i:s");
175+
$time = sprintf('%.4f', microtime(true) - $conn->start_time);
187176

188-
protected function log_request($conn)
189-
{
190-
$date = @date("d/M/Y H:i:s");
191-
$time = sprintf('%.4f', microtime(true) - $conn->start_time);
192-
193-
return "{$conn->client} - - [{$date}] \"{$conn->request}\" {$conn->status} - {$time}\n";
194-
}
177+
return "{$conn->client} - - [{$date}] \"{$conn->request}\" {$conn->status} - {$time}\n";
178+
}
195179

196180
}

0 commit comments

Comments
 (0)