bossan 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +6 -14
- data/.travis.yml +2 -1
- data/CHANGELOG.md +16 -0
- data/README.md +5 -3
- data/examples/fork_sample.rb +1 -1
- data/examples/hello.rb +11 -11
- data/examples/uploads.rb +7 -11
- data/ext/bossan/bossan.h +33 -32
- data/ext/bossan/bossan_ext.c +1260 -679
- data/ext/bossan/buffer.c +8 -8
- data/ext/bossan/buffer.h +12 -7
- data/ext/bossan/client.h +9 -10
- data/ext/bossan/http_parser.c +1252 -677
- data/ext/bossan/http_parser.h +200 -46
- data/ext/bossan/request.c +46 -37
- data/ext/bossan/request.h +26 -15
- data/ext/bossan/time_cache.h +1 -0
- data/lib/bossan/version.rb +1 -1
- data/test/test_rack_bad_http_method.rb +75 -63
- data/test/test_rack_chunk_response.rb +76 -0
- data/test/test_rack_long_url.rb +53 -47
- data/test/test_rack_spec.rb +55 -48
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
OTUxMWUwMGIxYmM0ZWUwODNjYzNlMTVlYjk5MmE2YTJjMmQ0YzMxMmQ1N2Uz
|
10
|
-
NjM5ZjA3MmE4NTAzM2JmNjNmZWQxYjY5MTdiYWMxZjUzYzE5NGNkODRhODlm
|
11
|
-
NzhlZjVkNDAwYjhkMDE2MTRiNzdiMzJmMWRkMGVhMjY1YzMwMDM=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ZjNhZjE4ZDgxZmNmOWQ5M2UyMWVjOTI3OGZiNWU1ZmUyYzg1ZGMxMzQ4OWRk
|
14
|
-
ODg4OGE1YWQ1YzU0YmE3Y2FhOTkxZWNhY2YxYzcxYTAzYjFiNTA1NTMwNDYw
|
15
|
-
MTU5YTk5MWQ3Y2ZiNzUwOGFlMzRjM2I5NzgyY2FlYjBjMmVmZDg=
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a6c9a88db061e6810d579b2bbd96d1883353e0dc
|
4
|
+
data.tar.gz: 2b24f8d88a989cf4f6bb388297f7aca5d79d93bf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dbe2c03e817dae7af733fbd451e211a5ec04288a4a472c4cc3782844145f344640c9f6752ca594c5be7aa285fe96c5072c37818c3dabc62c04f59e2975fec600
|
7
|
+
data.tar.gz: 825ce88118370976ef9ca6c3f1161ee402a3c3fcf2e5faa6d2b513285f84f35da6bf708a49e4b433abaf954d2209049351a2393ee42a06f3a9a494ebdb8c164f
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
### v0.4.0
|
4
|
+
|
5
|
+
(New Feature release. release 2013-0X-XX)
|
6
|
+
|
7
|
+
* Support RFC2616(HTTP/1.1)
|
8
|
+
|
9
|
+
* fix reason phrase
|
10
|
+
|
11
|
+
### v0.3.0
|
12
|
+
|
13
|
+
(New Feature release. release 2013-06-28)
|
14
|
+
|
15
|
+
* Add Bossan.listen method, for supporting pre-fork server
|
16
|
+
|
17
|
+
* change API Bossan.run
|
18
|
+
|
3
19
|
### v0.2.0
|
4
20
|
|
5
21
|
(New Feature release. release 2013-05-22)
|
data/README.md
CHANGED
@@ -31,14 +31,16 @@ simple rack app:
|
|
31
31
|
``` ruby
|
32
32
|
require 'bossan'
|
33
33
|
|
34
|
-
Bossan.
|
34
|
+
Bossan.listen('127.0.0.1', 8000)
|
35
|
+
Bossan.run(proc {|env|
|
36
|
+
body = ['hello, world!'] # Response body
|
35
37
|
[
|
36
38
|
200, # Status code
|
37
39
|
{ # Response headers
|
38
40
|
'Content-Type' => 'text/html',
|
39
|
-
'Content-Length' =>
|
41
|
+
'Content-Length' => body.join.size.to_s,
|
40
42
|
},
|
41
|
-
|
43
|
+
body
|
42
44
|
]
|
43
45
|
})
|
44
46
|
```
|
data/examples/fork_sample.rb
CHANGED
data/examples/hello.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
require_relative '../lib/bossan'
|
2
2
|
|
3
3
|
Bossan.listen('127.0.0.1', 8000)
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
4
|
+
Bossan.run(proc {|env|
|
5
|
+
body = ['hello, world!']
|
6
|
+
[
|
7
|
+
200, # Status code
|
8
|
+
{ # Response headers
|
9
|
+
'Content-Type' => 'text/html',
|
10
|
+
'Content-Length' => body.join.size.to_s,
|
11
|
+
},
|
12
|
+
body # Response body
|
13
|
+
]
|
14
|
+
})
|
data/examples/uploads.rb
CHANGED
@@ -4,9 +4,6 @@ require 'tempfile'
|
|
4
4
|
|
5
5
|
|
6
6
|
def view_file req
|
7
|
-
# p req
|
8
|
-
# p req.env['rack.input']
|
9
|
-
|
10
7
|
tempfile = Tempfile.new('raw-upload.')
|
11
8
|
req.env['rack.input'].each do |chunk|
|
12
9
|
if chunk.respond_to?(:force_encoding)
|
@@ -21,11 +18,10 @@ def view_file req
|
|
21
18
|
tempfile.flush
|
22
19
|
tempfile.rewind
|
23
20
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
# {"Content-Type" => req.content_type})
|
21
|
+
return Rack::Response.new(tempfile,
|
22
|
+
200,
|
23
|
+
{ "Content-Length" => req.env["CONTENT_LENGTH"],
|
24
|
+
"Content-Type" => 'image/jpeg'})
|
29
25
|
end
|
30
26
|
|
31
27
|
|
@@ -38,7 +34,7 @@ def upload_file req
|
|
38
34
|
EOF
|
39
35
|
],
|
40
36
|
200,
|
41
|
-
)
|
37
|
+
)
|
42
38
|
end
|
43
39
|
|
44
40
|
|
@@ -55,5 +51,5 @@ app = ->(env) {
|
|
55
51
|
|
56
52
|
|
57
53
|
Bossan.set_max_content_length(1024 * 1024 * 1024)
|
58
|
-
Bossan.
|
59
|
-
Bossan.
|
54
|
+
Bossan.listen('localhost', 8000)
|
55
|
+
Bossan.run(app)
|
data/ext/bossan/bossan.h
CHANGED
@@ -3,8 +3,9 @@
|
|
3
3
|
|
4
4
|
#include "ruby.h"
|
5
5
|
#include <assert.h>
|
6
|
-
#include <fcntl.h>
|
7
|
-
#include <stddef.h>
|
6
|
+
#include <fcntl.h>
|
7
|
+
#include <stddef.h>
|
8
|
+
#include <stdlib.h>
|
8
9
|
#include <unistd.h>
|
9
10
|
#include <errno.h>
|
10
11
|
#include <arpa/inet.h>
|
@@ -26,36 +27,36 @@
|
|
26
27
|
/* #define DEVELOP */
|
27
28
|
|
28
29
|
#ifdef DEVELOP
|
29
|
-
#define DEBUG(...)
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
#define RDEBUG(...)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
#define GDEBUG(...)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
#define BDEBUG(...)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
#define YDEBUG(...)
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
30
|
+
#define DEBUG(...) \
|
31
|
+
do { \
|
32
|
+
printf("%-40s %-26s%4u: ", __FILE__, __func__, __LINE__); \
|
33
|
+
printf(__VA_ARGS__); \
|
34
|
+
printf("\n"); \
|
35
|
+
} while(0)
|
36
|
+
#define RDEBUG(...) \
|
37
|
+
do { \
|
38
|
+
printf("\x1B[31m%-40s %-26s%4u: ", __FILE__, __func__, __LINE__); \
|
39
|
+
printf(__VA_ARGS__); \
|
40
|
+
printf("\x1B[0m\n"); \
|
41
|
+
} while(0)
|
42
|
+
#define GDEBUG(...) \
|
43
|
+
do { \
|
44
|
+
printf("\x1B[32m%-40s %-26s%4u: ", __FILE__, __func__, __LINE__); \
|
45
|
+
printf(__VA_ARGS__); \
|
46
|
+
printf("\x1B[0m\n"); \
|
47
|
+
} while(0)
|
48
|
+
#define BDEBUG(...) \
|
49
|
+
do { \
|
50
|
+
printf("\x1B[1;34m%-40s %-26s%4u: ", __FILE__, __func__, __LINE__); \
|
51
|
+
printf(__VA_ARGS__); \
|
52
|
+
printf("\x1B[0m\n"); \
|
53
|
+
} while(0)
|
54
|
+
#define YDEBUG(...) \
|
55
|
+
do { \
|
56
|
+
printf("\x1B[1;33m%-40s %-26s%4u: ", __FILE__, __func__, __LINE__); \
|
57
|
+
printf(__VA_ARGS__); \
|
58
|
+
printf("\x1B[0m\n"); \
|
59
|
+
} while(0)
|
59
60
|
#else
|
60
61
|
#define DEBUG(...) do{}while(0)
|
61
62
|
#define RDEBUG(...) do{}while(0)
|
data/ext/bossan/bossan_ext.c
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
#include "buffer.h"
|
7
7
|
#include "client.h"
|
8
8
|
|
9
|
+
|
9
10
|
#define ACCEPT_TIMEOUT_SECS 1
|
10
11
|
#define SHORT_TIMEOUT_SECS 2
|
11
12
|
#define WRITE_TIMEOUT_SECS 5
|
@@ -16,18 +17,42 @@
|
|
16
17
|
|
17
18
|
#define LIMIT_SIZE 1024 * 512
|
18
19
|
|
20
|
+
#define READ_TIMEOUT_SECS 30
|
21
|
+
#define READ_BUF_SIZE 1024 * 64
|
22
|
+
|
19
23
|
#define CRLF "\r\n"
|
20
24
|
#define DELIM ": "
|
21
25
|
|
22
|
-
#define
|
26
|
+
#define SERVER "bossan/0.4.0"
|
27
|
+
|
28
|
+
#define H_MSG_500 "HTTP/1.0 500 Internal Server Error\r\nContent-Type: text/html\r\nServer: " SERVER "\r\n\r\n"
|
29
|
+
|
30
|
+
#define H_MSG_503 "HTTP/1.0 503 Service Unavailable\r\nContent-Type: text/html\r\nServer: " SERVER "\r\n\r\n"
|
31
|
+
|
32
|
+
#define H_MSG_400 "HTTP/1.0 400 Bad Request\r\nContent-Type: text/html\r\nServer: " SERVER "\r\n\r\n"
|
33
|
+
|
34
|
+
#define H_MSG_408 "HTTP/1.0 408 Request Timeout\r\nContent-Type: text/html\r\nServer: " SERVER "\r\n\r\n"
|
35
|
+
|
36
|
+
#define H_MSG_411 "HTTP/1.0 411 Length Required\r\nContent-Type: text/html\r\nServer: " SERVER "\r\n\r\n"
|
37
|
+
|
38
|
+
#define H_MSG_413 "HTTP/1.0 413 Request Entity Too Large\r\nContent-Type: text/html\r\nServer: " SERVER "\r\n\r\n"
|
39
|
+
|
40
|
+
#define H_MSG_417 "HTTP/1.1 417 Expectation Failed\r\nContent-Type: text/html\r\nServer: " SERVER "\r\n\r\n"
|
41
|
+
|
42
|
+
|
43
|
+
#define MSG_500 H_MSG_500 "<html><head><title>500 Internal Server Error</title></head><body><h1>Internal Server Error</h1><p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p></body></html>"
|
23
44
|
|
24
|
-
#define
|
45
|
+
#define MSG_503 H_MSG_503 "<html><head><title>Service Unavailable</title></head><body><p>Service Unavailable.</p></body></html>"
|
25
46
|
|
26
|
-
#define
|
47
|
+
#define MSG_400 H_MSG_400 "<html><head><title>Bad Request</title></head><body><p>Bad Request.</p></body></html>"
|
27
48
|
|
28
|
-
#define
|
49
|
+
#define MSG_408 H_MSG_408 "<html><head><title>Request Timeout</title></head><body><p>Request Timeout.</p></body></html>"
|
29
50
|
|
30
|
-
#define
|
51
|
+
#define MSG_411 H_MSG_411 "<html><head><title>Length Required</title></head><body><p>Length Required.</p></body></html>"
|
52
|
+
|
53
|
+
#define MSG_413 H_MSG_413 "<html><head><title>Request Entity Too Large</title></head><body><p>Request Entity Too Large.</p></body></html>"
|
54
|
+
|
55
|
+
#define MSG_417 H_MSG_417 "<html><head><title>Expectation Failed</title></head><body><p>Expectation Failed.</p></body></html>"
|
31
56
|
|
32
57
|
VALUE server; // Bossan
|
33
58
|
|
@@ -62,23 +87,60 @@ static VALUE rb_remote_port;
|
|
62
87
|
static VALUE rack_input;
|
63
88
|
static VALUE http_connection;
|
64
89
|
|
90
|
+
static VALUE content_type;
|
91
|
+
static VALUE content_length;
|
92
|
+
|
93
|
+
static VALUE h_content_type;
|
94
|
+
static VALUE h_content_length;
|
95
|
+
|
65
96
|
static VALUE empty_string;
|
66
97
|
|
98
|
+
static VALUE http_10;
|
99
|
+
static VALUE http_11;
|
100
|
+
|
101
|
+
static VALUE http_delete;
|
102
|
+
static VALUE http_get;
|
103
|
+
static VALUE http_head;
|
104
|
+
static VALUE http_post;
|
105
|
+
static VALUE http_put;
|
106
|
+
static VALUE http_connect;
|
107
|
+
static VALUE http_options;
|
108
|
+
static VALUE http_trace;
|
109
|
+
static VALUE http_copy;
|
110
|
+
static VALUE http_lock;
|
111
|
+
static VALUE http_mkcol;
|
112
|
+
static VALUE http_move;
|
113
|
+
static VALUE http_propfind;
|
114
|
+
static VALUE http_proppatch;
|
115
|
+
static VALUE http_unlock;
|
116
|
+
static VALUE http_report;
|
117
|
+
static VALUE http_mkactivity;
|
118
|
+
static VALUE http_checkout;
|
119
|
+
static VALUE http_merge;
|
120
|
+
|
67
121
|
static VALUE http_user_agent;
|
68
122
|
static VALUE http_referer;
|
69
123
|
|
70
|
-
static VALUE
|
71
|
-
|
72
|
-
static
|
73
|
-
static
|
74
|
-
static
|
75
|
-
static
|
76
|
-
static
|
77
|
-
static
|
124
|
+
static VALUE http_expect;
|
125
|
+
|
126
|
+
static ID i_keys;
|
127
|
+
static ID i_call;
|
128
|
+
static ID i_new;
|
129
|
+
static ID i_each;
|
130
|
+
static ID i_toenum;
|
131
|
+
static ID i_close;
|
132
|
+
static ID i_write;
|
133
|
+
static ID i_seek;
|
134
|
+
static ID i_toa;
|
135
|
+
static ID i_next;
|
136
|
+
|
137
|
+
static VALUE default_path_string;
|
78
138
|
|
79
139
|
static const char *server_name = "127.0.0.1";
|
80
140
|
static short server_port = 8000;
|
81
141
|
|
142
|
+
static int prefix_len = 0;
|
143
|
+
|
82
144
|
static int listen_sock; // listen socket
|
83
145
|
|
84
146
|
static char *unix_sock_name = NULL;
|
@@ -89,8 +151,6 @@ static VALUE rack_app; //rack app
|
|
89
151
|
|
90
152
|
static char *log_path = NULL; //access log path
|
91
153
|
static int log_fd = -1; //access log
|
92
|
-
/* static char *error_log_path = NULL; //error log path */
|
93
|
-
/* static int err_log_fd = -1; //error log */
|
94
154
|
|
95
155
|
static int is_keep_alive = 0; //keep alive support
|
96
156
|
static int keep_alive_timeout = 5;
|
@@ -110,15 +170,30 @@ typedef struct {
|
|
110
170
|
uint32_t iov_size;
|
111
171
|
uint32_t total;
|
112
172
|
uint32_t total_size;
|
173
|
+
uint8_t sended;
|
174
|
+
VALUE temp1; //keep origin pointer
|
175
|
+
VALUE chunk_data; //keep chunk_data origin pointer
|
113
176
|
} write_bucket;
|
114
177
|
|
115
178
|
|
179
|
+
typedef enum {
|
180
|
+
STATUS_OK = 0,
|
181
|
+
STATUS_SUSPEND,
|
182
|
+
STATUS_ERROR
|
183
|
+
} response_status;
|
184
|
+
|
185
|
+
|
116
186
|
static void
|
117
187
|
r_callback(picoev_loop* loop, int fd, int events, void* cb_arg);
|
118
188
|
|
119
189
|
static void
|
120
190
|
w_callback(picoev_loop* loop, int fd, int events, void* cb_arg);
|
121
191
|
|
192
|
+
static void
|
193
|
+
call_rack_app(client_t *client);
|
194
|
+
|
195
|
+
static void
|
196
|
+
prepare_call_rack(client_t *client);
|
122
197
|
|
123
198
|
int
|
124
199
|
open_log_file(const char *path)
|
@@ -176,43 +251,45 @@ write_log(const char *new_path, int fd, const char *data, size_t len)
|
|
176
251
|
}
|
177
252
|
|
178
253
|
|
179
|
-
int
|
254
|
+
static int
|
180
255
|
write_access_log(client_t *cli, int log_fd, const char *log_path)
|
181
256
|
{
|
257
|
+
request *req = (cli);
|
258
|
+
|
182
259
|
char buf[1024*4];
|
183
260
|
if(log_fd > 0){
|
184
261
|
VALUE obj;
|
185
262
|
char *method, *path, *version, *ua, *referer;
|
186
263
|
|
187
|
-
obj = rb_hash_aref(
|
264
|
+
obj = rb_hash_aref(req->environ, request_method);
|
188
265
|
if(obj != Qnil){
|
189
266
|
method = StringValuePtr(obj);
|
190
267
|
}else{
|
191
268
|
method = "-";
|
192
269
|
}
|
193
270
|
|
194
|
-
obj = rb_hash_aref(
|
271
|
+
obj = rb_hash_aref(req->environ, path_info);
|
195
272
|
if(obj != Qnil){
|
196
273
|
path = StringValuePtr(obj);
|
197
274
|
}else{
|
198
275
|
path = "-";
|
199
276
|
}
|
200
277
|
|
201
|
-
obj = rb_hash_aref(
|
278
|
+
obj = rb_hash_aref(req->environ, server_protocol);
|
202
279
|
if(obj != Qnil){
|
203
280
|
version = StringValuePtr(obj);
|
204
281
|
}else{
|
205
282
|
version = "-";
|
206
283
|
}
|
207
284
|
|
208
|
-
obj = rb_hash_aref(
|
285
|
+
obj = rb_hash_aref(req->environ, http_user_agent);
|
209
286
|
if(obj != Qnil){
|
210
287
|
ua = StringValuePtr(obj);
|
211
288
|
}else{
|
212
289
|
ua = "-";
|
213
290
|
}
|
214
291
|
|
215
|
-
obj = rb_hash_aref(
|
292
|
+
obj = rb_hash_aref(req->environ, http_referer);
|
216
293
|
if(obj != Qnil){
|
217
294
|
referer = StringValuePtr(obj);
|
218
295
|
}else{
|
@@ -278,38 +355,52 @@ blocking_write(client_t *client, char *data, size_t len)
|
|
278
355
|
default:
|
279
356
|
data += (int)r;
|
280
357
|
len -= r;
|
281
|
-
client->
|
358
|
+
client->write_bytes += r;
|
282
359
|
}
|
283
360
|
}
|
284
361
|
return 1;
|
285
362
|
}
|
286
363
|
|
287
364
|
|
288
|
-
void
|
365
|
+
static void
|
289
366
|
send_error_page(client_t *client)
|
290
367
|
{
|
291
368
|
shutdown(client->fd, SHUT_RD);
|
292
|
-
if(client->header_done){
|
369
|
+
if(client->header_done || client->response_closed){
|
293
370
|
//already sended response data
|
294
371
|
//close connection
|
295
372
|
return;
|
296
373
|
}
|
297
|
-
|
298
|
-
|
299
|
-
client->status_code = r;
|
300
|
-
switch(r){
|
374
|
+
|
375
|
+
switch(client->status_code){
|
301
376
|
case 400:
|
302
377
|
blocking_write(client, MSG_400, sizeof(MSG_400) -1);
|
378
|
+
client->write_bytes -= sizeof(H_MSG_400) -1;
|
379
|
+
break;
|
380
|
+
case 408:
|
381
|
+
blocking_write(client, MSG_408, sizeof(MSG_408) -1);
|
382
|
+
client->write_bytes -= sizeof(H_MSG_408) -1;
|
303
383
|
break;
|
304
384
|
case 411:
|
305
385
|
blocking_write(client, MSG_411, sizeof(MSG_411) -1);
|
386
|
+
client->write_bytes -= sizeof(H_MSG_411) -1;
|
306
387
|
break;
|
307
388
|
case 413:
|
308
389
|
blocking_write(client, MSG_413, sizeof(MSG_413) -1);
|
390
|
+
client->write_bytes -= sizeof(H_MSG_413) -1;
|
391
|
+
break;
|
392
|
+
case 417:
|
393
|
+
blocking_write(client, MSG_417, sizeof(MSG_417) -1);
|
394
|
+
client->write_bytes -= sizeof(H_MSG_417) -1;
|
395
|
+
break;
|
396
|
+
case 503:
|
397
|
+
blocking_write(client, MSG_503, sizeof(MSG_503) -1);
|
398
|
+
client->write_bytes -= sizeof(H_MSG_503) -1;
|
309
399
|
break;
|
310
400
|
default:
|
311
401
|
//Internal Server Error
|
312
402
|
blocking_write(client, MSG_500, sizeof(MSG_500) -1);
|
403
|
+
client->write_bytes -= sizeof(H_MSG_500) -1;
|
313
404
|
break;
|
314
405
|
}
|
315
406
|
client->keep_alive = 0;
|
@@ -318,29 +409,21 @@ send_error_page(client_t *client)
|
|
318
409
|
}
|
319
410
|
|
320
411
|
|
321
|
-
static void
|
322
|
-
enable_cork(client_t *client)
|
323
|
-
{
|
324
|
-
int on = 1, r;
|
325
|
-
#ifdef linux
|
326
|
-
r = setsockopt(client->fd, IPPROTO_TCP, TCP_CORK, &on, sizeof(on));
|
327
|
-
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
328
|
-
r = setsockopt(client->fd, IPPROTO_TCP, TCP_NOPUSH, &on, sizeof(on));
|
329
|
-
#endif
|
330
|
-
assert(r == 0);
|
331
|
-
}
|
332
|
-
|
333
|
-
|
334
412
|
static write_bucket *
|
335
413
|
new_write_bucket(int fd, int cnt)
|
336
414
|
{
|
337
415
|
write_bucket *bucket;
|
416
|
+
iovec_t *iov;
|
417
|
+
|
338
418
|
bucket = ruby_xmalloc(sizeof(write_bucket));
|
339
419
|
memset(bucket, 0, sizeof(write_bucket));
|
340
420
|
|
341
421
|
bucket->fd = fd;
|
342
|
-
|
422
|
+
iov = (iovec_t *)ruby_xmalloc(sizeof(iovec_t) * cnt);
|
423
|
+
memset(iov, 0, sizeof(iovec_t));
|
424
|
+
bucket->iov = iov;
|
343
425
|
bucket->iov_size = cnt;
|
426
|
+
GDEBUG("allocate %p", bucket);
|
344
427
|
return bucket;
|
345
428
|
}
|
346
429
|
|
@@ -348,6 +431,7 @@ new_write_bucket(int fd, int cnt)
|
|
348
431
|
static void
|
349
432
|
free_write_bucket(write_bucket *bucket)
|
350
433
|
{
|
434
|
+
GDEBUG("free %p", bucket);
|
351
435
|
ruby_xfree(bucket->iov);
|
352
436
|
ruby_xfree(bucket);
|
353
437
|
}
|
@@ -364,6 +448,25 @@ set2bucket(write_bucket *bucket, char *buf, size_t len)
|
|
364
448
|
}
|
365
449
|
|
366
450
|
|
451
|
+
static void
|
452
|
+
set_chunked_data(write_bucket *bucket, char *lendata, size_t lenlen, char *data, size_t datalen)
|
453
|
+
{
|
454
|
+
set2bucket(bucket, lendata, lenlen);
|
455
|
+
set2bucket(bucket, CRLF, 2);
|
456
|
+
set2bucket(bucket, data, datalen);
|
457
|
+
set2bucket(bucket, CRLF, 2);
|
458
|
+
}
|
459
|
+
|
460
|
+
|
461
|
+
static void
|
462
|
+
set_last_chunked_data(write_bucket *bucket)
|
463
|
+
{
|
464
|
+
set2bucket(bucket, "0", 1);
|
465
|
+
set2bucket(bucket, CRLF, 2);
|
466
|
+
set2bucket(bucket, CRLF, 2);
|
467
|
+
}
|
468
|
+
|
469
|
+
|
367
470
|
static void
|
368
471
|
add_header(write_bucket *bucket, char *key, size_t keylen, char *val, size_t vallen)
|
369
472
|
{
|
@@ -374,28 +477,50 @@ add_header(write_bucket *bucket, char *key, size_t keylen, char *val, size_t val
|
|
374
477
|
}
|
375
478
|
|
376
479
|
|
377
|
-
|
480
|
+
#ifdef DEVELOP
|
481
|
+
static void
|
482
|
+
writev_log(write_bucket *data)
|
483
|
+
{
|
484
|
+
int i = 0;
|
485
|
+
char *c;
|
486
|
+
size_t len;
|
487
|
+
for(; i < data->iov_cnt; i++){
|
488
|
+
c = data->iov[i].iov_base;
|
489
|
+
len = data->iov[i].iov_len;
|
490
|
+
printf("%.*s", (int)len, c);
|
491
|
+
}
|
492
|
+
}
|
493
|
+
#endif
|
494
|
+
|
495
|
+
|
496
|
+
static response_status
|
378
497
|
writev_bucket(write_bucket *data)
|
379
498
|
{
|
380
|
-
|
499
|
+
size_t w;
|
381
500
|
int i = 0;
|
501
|
+
#ifdef DEVELOP
|
502
|
+
BDEBUG("\nwritev_bucket fd:%d", data->fd);
|
503
|
+
printf("\x1B[34m");
|
504
|
+
writev_log(data);
|
505
|
+
printf("\x1B[0m\n");
|
506
|
+
#endif
|
382
507
|
w = writev(data->fd, data->iov, data->iov_cnt);
|
508
|
+
BDEBUG("writev fd:%d ret:%d total_size:%d", data->fd, (int)w, data->total);
|
383
509
|
if(w == -1){
|
384
510
|
//error
|
385
511
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
386
512
|
// try again later
|
387
|
-
return
|
513
|
+
return STATUS_SUSPEND;
|
388
514
|
}else{
|
389
515
|
//ERROR
|
390
516
|
|
391
517
|
// TODO:
|
392
|
-
|
393
|
-
|
394
|
-
write_error_log(__FILE__, __LINE__);
|
395
|
-
return -1;
|
518
|
+
/* write_error_log(__FILE__, __LINE__); */
|
519
|
+
return STATUS_ERROR;
|
396
520
|
}
|
397
521
|
}if(w == 0){
|
398
|
-
|
522
|
+
data->sended = 1;
|
523
|
+
return STATUS_OK;
|
399
524
|
}else{
|
400
525
|
if(data->total > w){
|
401
526
|
for(; i < data->iov_cnt;i++){
|
@@ -409,23 +534,54 @@ writev_bucket(write_bucket *data)
|
|
409
534
|
break;
|
410
535
|
}
|
411
536
|
}
|
412
|
-
data->total = data->total -w;
|
537
|
+
data->total = data->total - w;
|
413
538
|
DEBUG("writev_bucket write %d progeress %d/%d \n", w, data->total, data->total_size);
|
414
539
|
//resume
|
415
540
|
// again later
|
416
541
|
return writev_bucket(data);
|
417
542
|
}
|
418
543
|
}
|
419
|
-
|
544
|
+
data->sended = 1;
|
545
|
+
return STATUS_OK;
|
420
546
|
}
|
421
547
|
|
422
548
|
|
423
|
-
static
|
424
|
-
|
549
|
+
static VALUE
|
550
|
+
get_chunk_data(size_t datalen)
|
425
551
|
{
|
426
|
-
|
427
|
-
|
552
|
+
char lendata[32];
|
553
|
+
int i = 0;
|
554
|
+
i = snprintf(lendata, 32, "%zx", datalen);
|
555
|
+
DEBUG("Transfer-Encoding chunk_size %s", lendata);
|
556
|
+
return rb_str_new(lendata, i);
|
557
|
+
}
|
558
|
+
|
559
|
+
|
560
|
+
static void
|
561
|
+
set_first_body_data(client_t *client, char *data, size_t datalen)
|
562
|
+
{
|
563
|
+
write_bucket *bucket = client->bucket;
|
564
|
+
if(data){
|
565
|
+
if(client->chunked_response){
|
566
|
+
char *lendata = NULL;
|
567
|
+
ssize_t len = 0;
|
568
|
+
|
569
|
+
VALUE chunk_data = get_chunk_data(datalen);
|
570
|
+
//TODO CHECK ERROR
|
571
|
+
lendata = StringValuePtr(chunk_data);
|
572
|
+
len = RSTRING_LEN(chunk_data);
|
573
|
+
set_chunked_data(bucket, lendata, len, data, datalen);
|
574
|
+
bucket->chunk_data = chunk_data;
|
575
|
+
}else{
|
576
|
+
set2bucket(bucket, data, datalen);
|
577
|
+
}
|
428
578
|
}
|
579
|
+
}
|
580
|
+
|
581
|
+
|
582
|
+
static response_status
|
583
|
+
write_headers(client_t *client, char *data, size_t datalen)
|
584
|
+
{
|
429
585
|
write_bucket *bucket;
|
430
586
|
uint32_t i = 0, hlen = 0;
|
431
587
|
|
@@ -435,22 +591,24 @@ write_headers(client_t *client)
|
|
435
591
|
ssize_t namelen;
|
436
592
|
char *value = NULL;
|
437
593
|
long valuelen;
|
594
|
+
response_status ret;
|
438
595
|
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
}
|
443
|
-
arr = rb_funcall(client->headers, i_keys, 0);
|
444
|
-
hlen = RARRAY_LEN(arr);
|
596
|
+
DEBUG("header write? %d", client->header_done);
|
597
|
+
if(client->header_done){
|
598
|
+
return STATUS_OK;
|
445
599
|
}
|
600
|
+
|
601
|
+
if (TYPE(client->headers) != T_HASH) {
|
602
|
+
return STATUS_ERROR;
|
603
|
+
}
|
604
|
+
|
605
|
+
arr = rb_funcall(client->headers, i_keys, 0);
|
606
|
+
hlen = RARRAY_LEN(arr);
|
607
|
+
|
446
608
|
bucket = new_write_bucket(client->fd, ( hlen * 4 * 2) + 32 );
|
447
609
|
|
448
610
|
object = client->http_status;
|
449
611
|
|
450
|
-
if(TYPE(object) != T_STRING){
|
451
|
-
return -1;
|
452
|
-
}
|
453
|
-
|
454
612
|
if(object){
|
455
613
|
value = StringValuePtr(object);
|
456
614
|
valuelen = RSTRING_LEN(object);
|
@@ -458,71 +616,77 @@ write_headers(client_t *client)
|
|
458
616
|
set2bucket(bucket, value, valuelen);
|
459
617
|
|
460
618
|
add_header(bucket, "Server", 6, SERVER, sizeof(SERVER) -1);
|
461
|
-
cache_time_update();
|
462
619
|
add_header(bucket, "Date", 4, (char *)http_time, 29);
|
463
|
-
if(client->keep_alive == 1){
|
464
|
-
// Keep-Alive
|
465
|
-
add_header(bucket, "Connection", 10, "Keep-Alive", 10);
|
466
|
-
} else {
|
467
|
-
add_header(bucket, "Connection", 10, "close", 5);
|
468
|
-
}
|
469
620
|
}
|
470
621
|
|
471
622
|
VALUE object1, object2;
|
472
623
|
|
473
624
|
//write header
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
Check_Type(object1, T_STRING);
|
478
|
-
|
479
|
-
if (TYPE(client->headers)!=T_HASH){
|
480
|
-
goto error;
|
481
|
-
}
|
482
|
-
VALUE tmp = rb_funcall(client->headers, i_key, 1, object1);
|
483
|
-
if (tmp == Qfalse){
|
484
|
-
goto error;
|
485
|
-
}
|
486
|
-
object2 = rb_hash_aref(client->headers, object1);
|
625
|
+
for(i=0; i < hlen; i++){
|
626
|
+
object1 = rb_ary_entry(arr, i);
|
627
|
+
/* Check_Type(object1, T_STRING); */
|
487
628
|
|
488
|
-
|
629
|
+
object2 = rb_hash_aref(client->headers, object1);
|
630
|
+
/* Check_Type(object2, T_STRING); */
|
489
631
|
|
490
|
-
|
491
|
-
|
632
|
+
name = StringValuePtr(object1);
|
633
|
+
namelen = RSTRING_LEN(object1);
|
492
634
|
|
493
|
-
|
494
|
-
|
635
|
+
value = StringValuePtr(object2);
|
636
|
+
valuelen = RSTRING_LEN(object2);
|
495
637
|
|
496
|
-
|
497
|
-
|
498
|
-
|
638
|
+
if (strchr(name, ':') != 0) {
|
639
|
+
goto error;
|
640
|
+
}
|
641
|
+
|
642
|
+
if (strchr(name, '\n') != 0 || strchr(value, '\n') != 0) {
|
643
|
+
goto error;
|
644
|
+
}
|
499
645
|
|
500
|
-
|
501
|
-
|
502
|
-
|
646
|
+
if (!strcasecmp(name, "Server") || !strcasecmp(name, "Date")) {
|
647
|
+
continue;
|
648
|
+
}
|
503
649
|
|
504
|
-
|
505
|
-
|
506
|
-
|
650
|
+
if (client->content_length_set != 1 && !strcasecmp(name, "Content-Length")) {
|
651
|
+
char *v = value;
|
652
|
+
long l = 0;
|
507
653
|
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
goto error;
|
513
|
-
}
|
514
|
-
client->content_length_set = 1;
|
515
|
-
client->content_length = l;
|
654
|
+
errno = 0;
|
655
|
+
l = strtol(v, &v, 10);
|
656
|
+
if (*v || errno == ERANGE || l < 0) {
|
657
|
+
goto error;
|
516
658
|
}
|
517
|
-
|
659
|
+
client->content_length_set = 1;
|
660
|
+
client->content_length = l;
|
518
661
|
}
|
662
|
+
add_header(bucket, name, namelen, value, valuelen);
|
663
|
+
}
|
664
|
+
|
665
|
+
// check content_length_set
|
666
|
+
if(data && !client->content_length_set && client->http_parser->http_minor == 1){
|
667
|
+
//Transfer-Encoding chunked
|
668
|
+
add_header(bucket, "Transfer-Encoding", 17, "chunked", 7);
|
669
|
+
client->chunked_response = 1;
|
670
|
+
}
|
671
|
+
|
672
|
+
if(client->keep_alive == 1){
|
673
|
+
// Keep-Alive
|
674
|
+
add_header(bucket, "Connection", 10, "Keep-Alive", 10);
|
675
|
+
} else {
|
676
|
+
add_header(bucket, "Connection", 10, "close", 5);
|
519
677
|
}
|
520
678
|
set2bucket(bucket, CRLF, 2);
|
521
679
|
|
680
|
+
// write_body
|
522
681
|
client->bucket = bucket;
|
523
|
-
|
524
|
-
|
682
|
+
set_first_body_data(client, data, datalen);
|
683
|
+
|
684
|
+
ret = writev_bucket(bucket);
|
685
|
+
if(ret != STATUS_SUSPEND){
|
525
686
|
client->header_done = 1;
|
687
|
+
if(ret == STATUS_OK && data){
|
688
|
+
client->write_bytes += datalen;
|
689
|
+
}
|
526
690
|
// clear
|
527
691
|
free_write_bucket(bucket);
|
528
692
|
client->bucket = NULL;
|
@@ -534,9 +698,9 @@ write_headers(client_t *client)
|
|
534
698
|
free_write_bucket(bucket);
|
535
699
|
client->bucket = NULL;
|
536
700
|
}
|
537
|
-
return
|
701
|
+
return STATUS_ERROR;
|
538
702
|
}
|
539
|
-
|
703
|
+
|
540
704
|
|
541
705
|
static void
|
542
706
|
close_response(client_t *client)
|
@@ -548,21 +712,23 @@ close_response(client_t *client)
|
|
548
712
|
|
549
713
|
|
550
714
|
static VALUE
|
551
|
-
|
715
|
+
rb_body_iterator(VALUE iterator)
|
716
|
+
{
|
717
|
+
return rb_funcall(iterator, i_next, 0);
|
718
|
+
}
|
719
|
+
|
720
|
+
|
721
|
+
static VALUE
|
722
|
+
ret_qnil(void)
|
552
723
|
{
|
553
|
-
if(argc < 1) {
|
554
|
-
return Qnil;
|
555
|
-
}
|
556
|
-
rb_str_concat(str, argv[0]);
|
557
724
|
return Qnil;
|
558
725
|
}
|
559
726
|
|
560
727
|
|
561
|
-
static
|
728
|
+
static response_status
|
562
729
|
processs_write(client_t *client)
|
563
730
|
{
|
564
731
|
VALUE iterator;
|
565
|
-
VALUE v_body;
|
566
732
|
VALUE item;
|
567
733
|
char *buf;
|
568
734
|
size_t buflen;
|
@@ -570,112 +736,132 @@ processs_write(client_t *client)
|
|
570
736
|
int ret;
|
571
737
|
|
572
738
|
// body
|
739
|
+
DEBUG("process_write start");
|
573
740
|
iterator = client->response_iter;
|
574
741
|
|
575
|
-
|
576
|
-
if (TYPE(iterator) != T_ARRAY || RARRAY_LEN(iterator) != 3){
|
577
|
-
return -1;
|
578
|
-
}
|
742
|
+
while ( (item = rb_rescue(rb_body_iterator, iterator, ret_qnil, NULL)) != Qnil ) {
|
579
743
|
|
580
|
-
|
744
|
+
buf = StringValuePtr(item);
|
745
|
+
buflen = RSTRING_LEN(item);
|
581
746
|
|
582
|
-
|
583
|
-
|
584
|
-
|
747
|
+
//write
|
748
|
+
if(client->chunked_response){
|
749
|
+
bucket = new_write_bucket(client->fd, 4);
|
750
|
+
if(bucket == NULL){
|
751
|
+
return STATUS_ERROR;
|
752
|
+
}
|
753
|
+
char *lendata = NULL;
|
754
|
+
ssize_t len = 0;
|
585
755
|
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
}
|
756
|
+
VALUE chunk_data = get_chunk_data(buflen);
|
757
|
+
//TODO CHECK ERROR
|
758
|
+
lendata = StringValuePtr(chunk_data);
|
759
|
+
len = RSTRING_LEN(chunk_data);
|
591
760
|
|
592
|
-
|
593
|
-
|
761
|
+
set_chunked_data(bucket, lendata, len, buf, buflen);
|
762
|
+
bucket->chunk_data = chunk_data;
|
763
|
+
} else {
|
764
|
+
bucket = new_write_bucket(client->fd, 1);
|
765
|
+
if(bucket == NULL){
|
766
|
+
return STATUS_ERROR;
|
767
|
+
}
|
768
|
+
set2bucket(bucket, buf, buflen);
|
769
|
+
}
|
770
|
+
bucket->temp1 = item;
|
594
771
|
|
595
|
-
bucket = new_write_bucket(client->fd, 1);
|
596
|
-
set2bucket(bucket, buf, buflen);
|
597
772
|
ret = writev_bucket(bucket);
|
598
|
-
if(ret
|
773
|
+
if(ret != STATUS_OK){
|
774
|
+
client->bucket = bucket;
|
599
775
|
return ret;
|
600
776
|
}
|
777
|
+
|
778
|
+
free_write_bucket(bucket);
|
601
779
|
//mark
|
602
780
|
client->write_bytes += buflen;
|
603
781
|
//check write_bytes/content_length
|
604
782
|
if(client->content_length_set){
|
605
783
|
if(client->content_length <= client->write_bytes){
|
606
784
|
// all done
|
607
|
-
|
785
|
+
break;
|
608
786
|
}
|
609
787
|
}
|
788
|
+
|
789
|
+
if(client->chunked_response){
|
790
|
+
DEBUG("write last chunk");
|
791
|
+
//last packet
|
792
|
+
bucket = new_write_bucket(client->fd, 3);
|
793
|
+
if(bucket == NULL){
|
794
|
+
return STATUS_ERROR;
|
795
|
+
}
|
796
|
+
set_last_chunked_data(bucket);
|
797
|
+
writev_bucket(bucket);
|
798
|
+
free_write_bucket(bucket);
|
799
|
+
}
|
610
800
|
close_response(client);
|
611
801
|
}
|
612
|
-
return
|
802
|
+
return STATUS_OK;
|
613
803
|
}
|
614
804
|
|
615
805
|
|
616
|
-
|
806
|
+
static response_status
|
617
807
|
process_body(client_t *client)
|
618
808
|
{
|
619
|
-
|
809
|
+
response_status ret;
|
620
810
|
write_bucket *bucket;
|
621
811
|
if(client->bucket){
|
622
812
|
bucket = (write_bucket *)client->bucket;
|
623
813
|
//retry send
|
624
814
|
ret = writev_bucket(bucket);
|
625
815
|
|
626
|
-
if(ret
|
816
|
+
if(ret == STATUS_OK){
|
627
817
|
client->write_bytes += bucket->total_size;
|
628
818
|
//free
|
629
819
|
free_write_bucket(bucket);
|
630
820
|
client->bucket = NULL;
|
821
|
+
}else if(ret == STATUS_ERROR){
|
822
|
+
free_write_bucket(bucket);
|
823
|
+
client->bucket = NULL;
|
824
|
+
return ret;
|
631
825
|
}else{
|
632
|
-
return
|
826
|
+
return ret;
|
633
827
|
}
|
634
828
|
}
|
635
|
-
|
636
|
-
return ret;
|
829
|
+
return processs_write(client);
|
637
830
|
}
|
638
831
|
|
639
832
|
|
640
|
-
static
|
833
|
+
static response_status
|
641
834
|
start_response_write(client_t *client)
|
642
835
|
{
|
643
|
-
VALUE iterator;
|
644
|
-
VALUE dict;
|
645
836
|
VALUE item;
|
646
837
|
char *buf;
|
647
838
|
ssize_t buflen;
|
648
839
|
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
if (TYPE(iterator) != T_ARRAY){
|
653
|
-
return -1;
|
654
|
-
}
|
655
|
-
assert(3 == RARRAY_LEN(iterator));
|
840
|
+
item = rb_funcall(client->response_iter, i_next, 0);
|
841
|
+
/* Check_Type(item, T_STRING); */
|
842
|
+
DEBUG("client %p :fd %d", client, client->fd);
|
656
843
|
|
657
|
-
|
844
|
+
//write string only
|
845
|
+
buf = StringValuePtr(item);
|
846
|
+
buflen = RSTRING_LEN(item);
|
658
847
|
|
659
|
-
|
660
|
-
|
661
|
-
}
|
662
|
-
|
663
|
-
/* DEBUG("start_response_write buflen %d \n", buflen); */
|
664
|
-
return write_headers(client);
|
848
|
+
/* DEBUG("status_code %d body:%.*s", client->status_code, (int)buflen, buf); */
|
849
|
+
return write_headers(client, buf, buflen);
|
665
850
|
}
|
666
851
|
|
667
852
|
|
668
|
-
|
853
|
+
response_status
|
669
854
|
response_start(client_t *client)
|
670
855
|
{
|
671
|
-
|
672
|
-
|
856
|
+
response_status ret;
|
857
|
+
|
673
858
|
if(client->status_code == 304){
|
674
|
-
return write_headers(client);
|
859
|
+
return write_headers(client, NULL, 0);
|
675
860
|
}
|
676
861
|
ret = start_response_write(client);
|
677
|
-
DEBUG("start_response_write ret = %d \n", ret);
|
678
|
-
|
862
|
+
DEBUG("start_response_write ret = %d :fd = %d\n", ret, client->fd);
|
863
|
+
|
864
|
+
if(ret == STATUS_OK){
|
679
865
|
// sended header
|
680
866
|
ret = processs_write(client);
|
681
867
|
}
|
@@ -704,259 +890,342 @@ key_upper(char *s, const char *key, size_t len)
|
|
704
890
|
|
705
891
|
|
706
892
|
static int
|
707
|
-
write_body2mem(
|
893
|
+
write_body2mem(request *req, const char *buffer, size_t buf_len)
|
708
894
|
{
|
709
|
-
VALUE
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
DEBUG("write_body2mem %d bytes \n", buffer_len);
|
714
|
-
return client->body_readed;
|
895
|
+
rb_funcall((VALUE)req->body, i_write, 1, rb_str_new(buffer, buf_len));
|
896
|
+
req->body_readed += buf_len;
|
897
|
+
DEBUG("write_body2mem %d bytes \n", buf_len);
|
898
|
+
return req->body_readed;
|
715
899
|
}
|
716
900
|
|
717
901
|
|
718
902
|
static int
|
719
|
-
write_body(
|
903
|
+
write_body(request *req, const char *buffer, size_t buffer_len)
|
720
904
|
{
|
721
|
-
return write_body2mem(
|
905
|
+
return write_body2mem(req, buffer, buffer_len);
|
722
906
|
}
|
723
907
|
|
724
908
|
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
}
|
909
|
+
static client_t *
|
910
|
+
get_client(http_parser *p)
|
911
|
+
{
|
912
|
+
return (client_t *)p->data;
|
913
|
+
}
|
730
914
|
|
731
915
|
|
732
|
-
static
|
733
|
-
|
916
|
+
static request *
|
917
|
+
get_current_request(http_parser *p)
|
734
918
|
{
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
919
|
+
client_t *client = (client_t *)p->data;
|
920
|
+
return client->current_req;
|
921
|
+
}
|
922
|
+
|
923
|
+
|
924
|
+
static VALUE
|
925
|
+
new_environ(client_t *client)
|
926
|
+
{
|
927
|
+
VALUE object, environ;
|
928
|
+
char r_port[7];
|
929
|
+
|
930
|
+
environ = rb_hash_new();
|
931
|
+
|
932
|
+
rb_hash_aset(environ, version_key, version_val);
|
933
|
+
rb_hash_aset(environ, scheme_key, scheme_val);
|
934
|
+
rb_hash_aset(environ, errors_key, errors_val);
|
935
|
+
rb_hash_aset(environ, multithread_key, multithread_val);
|
936
|
+
rb_hash_aset(environ, multiprocess_key, multiprocess_val);
|
937
|
+
rb_hash_aset(environ, run_once_key, run_once_val);
|
938
|
+
rb_hash_aset(environ, script_key, empty_string);
|
939
|
+
rb_hash_aset(environ, server_name_key, server_name_val);
|
940
|
+
rb_hash_aset(environ, server_port_key, server_port_val);
|
941
|
+
|
942
|
+
object = rb_str_new2(client->remote_addr);
|
943
|
+
rb_hash_aset(environ, rb_remote_addr, object);
|
944
|
+
|
945
|
+
sprintf(r_port, "%d", client->remote_port);
|
946
|
+
object = rb_str_new2(r_port);
|
947
|
+
rb_hash_aset(environ, rb_remote_port, object);
|
948
|
+
return environ;
|
949
|
+
}
|
950
|
+
|
951
|
+
|
952
|
+
static int
|
953
|
+
hex2int(int i)
|
954
|
+
{
|
955
|
+
i = toupper(i);
|
956
|
+
i = i - '0';
|
957
|
+
if(i > 9){
|
958
|
+
i = i - 'A' + '9' + 1;
|
758
959
|
}
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
960
|
+
return i;
|
961
|
+
}
|
962
|
+
|
963
|
+
|
964
|
+
static int
|
965
|
+
urldecode(char *buf, int len)
|
966
|
+
{
|
967
|
+
int c, c1;
|
968
|
+
char *s0, *t;
|
969
|
+
t = s0 = buf;
|
970
|
+
while(len >0){
|
971
|
+
c = *buf++;
|
972
|
+
if(c == '%' && len > 2){
|
973
|
+
c = *buf++;
|
974
|
+
c1 = c;
|
975
|
+
c = *buf++;
|
976
|
+
c = hex2int(c1) * 16 + hex2int(c);
|
977
|
+
len -= 2;
|
978
|
+
}
|
979
|
+
*t++ = c;
|
980
|
+
len--;
|
764
981
|
}
|
765
|
-
|
982
|
+
*t = 0;
|
983
|
+
return t - s0;
|
766
984
|
}
|
767
985
|
|
768
986
|
|
769
|
-
static
|
770
|
-
|
987
|
+
static VALUE
|
988
|
+
concat_string(VALUE o, const char *buf, size_t len)
|
771
989
|
{
|
772
|
-
|
990
|
+
VALUE ret;
|
991
|
+
size_t l;
|
992
|
+
char *dest, *origin;
|
993
|
+
|
994
|
+
l = RSTRING_LEN(o);
|
995
|
+
|
996
|
+
ret = rb_str_new((char*)0, l + len);
|
997
|
+
if(ret == NULL){
|
998
|
+
return ret;
|
999
|
+
}
|
1000
|
+
dest = StringValuePtr(ret);
|
1001
|
+
origin = StringValuePtr(o);
|
1002
|
+
memcpy(dest, origin, l);
|
1003
|
+
memcpy(dest + l, buf, len);
|
1004
|
+
return ret;
|
773
1005
|
}
|
774
1006
|
|
775
1007
|
|
776
|
-
int
|
777
|
-
|
1008
|
+
static int
|
1009
|
+
replace_env_key(VALUE dict, VALUE old_key, VALUE new_key)
|
778
1010
|
{
|
779
|
-
|
1011
|
+
int ret = 1;
|
1012
|
+
|
1013
|
+
VALUE value = rb_hash_aref(dict, old_key);
|
1014
|
+
if(value != Qnil) {
|
1015
|
+
rb_hash_aset(dict, old_key, Qnil);
|
1016
|
+
ret = rb_hash_aset(dict, new_key, value);
|
1017
|
+
}
|
1018
|
+
return ret;
|
780
1019
|
}
|
781
1020
|
|
782
1021
|
|
783
|
-
int
|
784
|
-
|
1022
|
+
static int
|
1023
|
+
set_query(VALUE env, char *buf, int len)
|
785
1024
|
{
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
return -1;
|
1025
|
+
int c, slen = 0;
|
1026
|
+
char *s0;
|
1027
|
+
VALUE obj;
|
1028
|
+
|
1029
|
+
s0 = buf;
|
1030
|
+
while(len > 0){
|
1031
|
+
c = *buf++;
|
1032
|
+
if(c == '#'){
|
1033
|
+
slen++;
|
1034
|
+
break;
|
797
1035
|
}
|
798
|
-
|
1036
|
+
len--;
|
1037
|
+
slen++;
|
799
1038
|
}
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
1039
|
+
|
1040
|
+
if(slen > 1){
|
1041
|
+
obj = rb_str_new(s0, slen-1);
|
1042
|
+
rb_hash_aset(env, query_string, obj);
|
1043
|
+
}
|
1044
|
+
return 1;
|
1045
|
+
}
|
1046
|
+
|
1047
|
+
|
1048
|
+
static int
|
1049
|
+
set_path(VALUE env, char *buf, int len)
|
1050
|
+
{
|
1051
|
+
int c, c1, slen;
|
1052
|
+
char *s0, *t;
|
1053
|
+
VALUE obj;
|
1054
|
+
|
1055
|
+
t = s0 = buf;
|
1056
|
+
while(len > 0){
|
1057
|
+
c = *buf++;
|
1058
|
+
if(c == '%' && len > 2){
|
1059
|
+
c = *buf++;
|
1060
|
+
c1 = c;
|
1061
|
+
c = *buf++;
|
1062
|
+
c = hex2int(c1) * 16 + hex2int(c);
|
1063
|
+
len -= 2;
|
1064
|
+
}else if(c == '?'){
|
1065
|
+
//stop
|
1066
|
+
if(set_query(env, buf, len) == -1){
|
1067
|
+
//Error
|
1068
|
+
return -1;
|
1069
|
+
}
|
1070
|
+
break;
|
1071
|
+
}else if(c == '#'){
|
1072
|
+
//stop
|
1073
|
+
//ignore fragment
|
1074
|
+
break;
|
811
1075
|
}
|
812
|
-
|
813
|
-
|
1076
|
+
*t++ = c;
|
1077
|
+
len--;
|
814
1078
|
}
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
1079
|
+
slen = t - s0;
|
1080
|
+
slen = urldecode(s0, slen);
|
1081
|
+
|
1082
|
+
obj = rb_str_new(s0, slen);
|
1083
|
+
|
1084
|
+
rb_hash_aset(env, path_info, obj);
|
1085
|
+
|
1086
|
+
if (rb_hash_aref(env, query_string) == Qnil) {
|
1087
|
+
rb_hash_aset(env, query_string, empty_string);
|
824
1088
|
}
|
825
|
-
|
826
|
-
return 0;
|
1089
|
+
return slen;
|
827
1090
|
}
|
828
1091
|
|
829
1092
|
|
830
|
-
|
831
|
-
|
1093
|
+
static VALUE
|
1094
|
+
get_http_header_key(const char *s, int len)
|
832
1095
|
{
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
1096
|
+
VALUE obj;
|
1097
|
+
char *dest;
|
1098
|
+
char c;
|
1099
|
+
|
1100
|
+
obj = rb_str_new("", len + prefix_len);
|
1101
|
+
dest = (char*)StringValuePtr(obj);
|
1102
|
+
|
1103
|
+
*dest++ = 'H';
|
1104
|
+
*dest++ = 'T';
|
1105
|
+
*dest++ = 'T';
|
1106
|
+
*dest++ = 'P';
|
1107
|
+
*dest++ = '_';
|
1108
|
+
|
1109
|
+
while(len--) {
|
1110
|
+
c = *s++;
|
1111
|
+
if(c == '-'){
|
1112
|
+
*dest++ = '_';
|
1113
|
+
}else if(c >= 'a' && c <= 'z'){
|
1114
|
+
*dest++ = c - ('a'-'A');
|
1115
|
+
}else{
|
1116
|
+
*dest++ = c;
|
1117
|
+
}
|
854
1118
|
}
|
855
|
-
|
856
|
-
return 0;
|
1119
|
+
return obj;
|
857
1120
|
}
|
858
1121
|
|
859
1122
|
|
860
|
-
int
|
861
|
-
|
1123
|
+
static int
|
1124
|
+
message_begin_cb(http_parser *p)
|
862
1125
|
{
|
1126
|
+
request *req;
|
1127
|
+
|
1128
|
+
DEBUG("message_begin_cb");
|
1129
|
+
|
863
1130
|
client_t *client = get_client(p);
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
}
|
873
|
-
switch(ret){
|
874
|
-
case MEMORY_ERROR:
|
875
|
-
client->bad_request_code = 500;
|
876
|
-
return -1;
|
877
|
-
case LIMIT_OVER:
|
878
|
-
client->bad_request_code = 400;
|
879
|
-
return -1;
|
880
|
-
default:
|
881
|
-
break;
|
882
|
-
}
|
1131
|
+
|
1132
|
+
req = new_request();
|
1133
|
+
req->start_msec = current_msec;
|
1134
|
+
client->current_req = req;
|
1135
|
+
client->complete = 0;
|
1136
|
+
req->environ = new_environ(client);
|
1137
|
+
rb_gc_register_address(&req->environ);
|
1138
|
+
push_request(client->request_queue, client->current_req);
|
883
1139
|
return 0;
|
884
1140
|
}
|
885
1141
|
|
886
1142
|
|
887
|
-
int
|
888
|
-
|
1143
|
+
static int
|
1144
|
+
header_field_cb(http_parser *p, const char *buf, size_t len)
|
889
1145
|
{
|
890
|
-
|
891
|
-
request *req =
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
1146
|
+
VALUE env, obj;
|
1147
|
+
request *req = get_current_request(p);
|
1148
|
+
|
1149
|
+
if (req->last_header_element != FIELD){
|
1150
|
+
env = req->environ;
|
1151
|
+
if(LIMIT_REQUEST_FIELDS <= req->num_headers){
|
1152
|
+
req->bad_request_code = 400;
|
1153
|
+
return -1;
|
1154
|
+
}
|
1155
|
+
rb_hash_aset(env, req->field, req->value);
|
1156
|
+
req->field = NULL;
|
1157
|
+
req->value = NULL;
|
1158
|
+
req->num_headers++;
|
1159
|
+
}
|
1160
|
+
|
1161
|
+
if(likely(req->field == NULL)){
|
1162
|
+
obj = get_http_header_key(buf, len);
|
896
1163
|
}else{
|
897
|
-
|
898
|
-
|
1164
|
+
char temp[len];
|
1165
|
+
key_upper(temp, buf, len);
|
1166
|
+
obj = concat_string(req->field, temp, len);
|
899
1167
|
}
|
900
|
-
|
901
|
-
|
902
|
-
|
1168
|
+
|
1169
|
+
if(unlikely(obj == NULL)){
|
1170
|
+
req->bad_request_code = 500;
|
903
1171
|
return -1;
|
904
|
-
|
905
|
-
|
1172
|
+
}
|
1173
|
+
|
1174
|
+
if(unlikely(RSTRING_LEN(obj) > LIMIT_REQUEST_FIELD_SIZE)){
|
1175
|
+
req->bad_request_code = 400;
|
906
1176
|
return -1;
|
907
|
-
default:
|
908
|
-
break;
|
909
1177
|
}
|
1178
|
+
|
1179
|
+
req->field = obj;
|
1180
|
+
req->last_header_element = FIELD;
|
910
1181
|
return 0;
|
911
1182
|
}
|
912
1183
|
|
913
|
-
|
914
|
-
int
|
915
|
-
|
916
|
-
{
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
ret = write2buf(req->query_string, buf, len);
|
1184
|
+
|
1185
|
+
static int
|
1186
|
+
header_value_cb(http_parser *p, const char *buf, size_t len)
|
1187
|
+
{
|
1188
|
+
request *req = get_current_request(p);
|
1189
|
+
VALUE obj;
|
1190
|
+
|
1191
|
+
if(likely(req->value == NULL)){
|
1192
|
+
obj = rb_str_new(buf, len);
|
923
1193
|
}else{
|
924
|
-
|
925
|
-
ret = write2buf(req->query_string, buf, len);
|
1194
|
+
obj = concat_string(req->value, buf, len);
|
926
1195
|
}
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
return -1;
|
931
|
-
|
932
|
-
|
1196
|
+
|
1197
|
+
if(unlikely(obj == NULL)){
|
1198
|
+
req->bad_request_code = 500;
|
1199
|
+
return -1;
|
1200
|
+
}
|
1201
|
+
if(unlikely(RSTRING_LEN(obj) > LIMIT_REQUEST_FIELD_SIZE)){
|
1202
|
+
req->bad_request_code = 400;
|
933
1203
|
return -1;
|
934
|
-
default:
|
935
|
-
break;
|
936
1204
|
}
|
1205
|
+
req->value = obj;
|
1206
|
+
req->last_header_element = VAL;
|
937
1207
|
return 0;
|
938
1208
|
}
|
939
1209
|
|
940
1210
|
|
941
|
-
int
|
942
|
-
|
1211
|
+
static int
|
1212
|
+
request_uri_cb(http_parser *p, const char *buf, size_t len)
|
943
1213
|
{
|
944
|
-
|
945
|
-
request *req = client->req;
|
1214
|
+
request *req = get_current_request(p);
|
946
1215
|
buffer_result ret = MEMORY_ERROR;
|
947
|
-
|
948
|
-
if(req->
|
949
|
-
ret = write2buf(req->
|
1216
|
+
|
1217
|
+
if(req->path){
|
1218
|
+
ret = write2buf(req->path, buf, len);
|
950
1219
|
}else{
|
951
|
-
req->
|
952
|
-
ret = write2buf(req->
|
1220
|
+
req->path = new_buffer(1024, LIMIT_URI);
|
1221
|
+
ret = write2buf(req->path, buf, len);
|
953
1222
|
}
|
954
1223
|
switch(ret){
|
955
1224
|
case MEMORY_ERROR:
|
956
|
-
|
1225
|
+
req->bad_request_code = 500;
|
957
1226
|
return -1;
|
958
1227
|
case LIMIT_OVER:
|
959
|
-
|
1228
|
+
req->bad_request_code = 400;
|
960
1229
|
return -1;
|
961
1230
|
default:
|
962
1231
|
break;
|
@@ -965,27 +1234,28 @@ fragment_cb (http_parser *p, const char *buf, size_t len, char partial)
|
|
965
1234
|
}
|
966
1235
|
|
967
1236
|
|
968
|
-
int
|
969
|
-
body_cb
|
1237
|
+
static int
|
1238
|
+
body_cb(http_parser *p, const char *buf, size_t len)
|
970
1239
|
{
|
971
|
-
|
972
|
-
|
973
|
-
|
1240
|
+
request *req = get_current_request(p);
|
1241
|
+
|
1242
|
+
if(max_content_length <= req->body_readed + len){
|
1243
|
+
req->bad_request_code = 413;
|
974
1244
|
return -1;
|
975
1245
|
}
|
976
|
-
if(
|
977
|
-
if(
|
1246
|
+
if(req->body_type == BODY_TYPE_NONE){
|
1247
|
+
if(req->body_length == 0){
|
978
1248
|
//Length Required
|
979
|
-
|
1249
|
+
req->bad_request_code = 411;
|
980
1250
|
return -1;
|
981
1251
|
}
|
982
1252
|
//default memory stream
|
983
|
-
DEBUG("client->body_length %d \n",
|
984
|
-
|
985
|
-
|
1253
|
+
DEBUG("client->body_length %d \n", req->body_length);
|
1254
|
+
req->body = rb_funcall(StringIO, i_new, 1, rb_str_new2(""));
|
1255
|
+
req->body_type = BODY_TYPE_BUFFER;
|
986
1256
|
DEBUG("BODY_TYPE_BUFFER \n");
|
987
1257
|
}
|
988
|
-
write_body(
|
1258
|
+
write_body(req, buf, len);
|
989
1259
|
return 0;
|
990
1260
|
}
|
991
1261
|
|
@@ -993,129 +1263,134 @@ body_cb (http_parser *p, const char *buf, size_t len, char partial)
|
|
993
1263
|
int
|
994
1264
|
headers_complete_cb(http_parser *p)
|
995
1265
|
{
|
996
|
-
VALUE obj
|
1266
|
+
VALUE obj = NULL;
|
997
1267
|
client_t *client = get_client(p);
|
998
|
-
request *req = client->
|
999
|
-
VALUE env =
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1268
|
+
request *req = client->current_req;
|
1269
|
+
VALUE env = req->environ;
|
1270
|
+
int ret;
|
1271
|
+
uint64_t content_length = 0;
|
1272
|
+
|
1273
|
+
DEBUG("should keep alive %d", http_should_keep_alive(p));
|
1274
|
+
client->keep_alive = http_should_keep_alive(p);
|
1275
|
+
|
1276
|
+
if(p->content_length != ULLONG_MAX){
|
1277
|
+
content_length = p->content_length;
|
1278
|
+
if(max_content_length < p->content_length){
|
1279
|
+
RDEBUG("max_content_length over %d/%d", (int)content_length, (int)max_content_length);
|
1280
|
+
DEBUG("set request code %d", 413);
|
1281
|
+
req->bad_request_code = 413;
|
1282
|
+
return -1;
|
1283
|
+
}
|
1006
1284
|
}
|
1007
1285
|
|
1008
1286
|
if (p->http_minor == 1) {
|
1009
|
-
obj =
|
1287
|
+
obj = http_11;
|
1010
1288
|
} else {
|
1011
|
-
obj =
|
1012
|
-
}
|
1289
|
+
obj = http_10;
|
1290
|
+
}
|
1013
1291
|
rb_hash_aset(env, server_protocol, obj);
|
1014
|
-
|
1015
|
-
if(req->path){
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1292
|
+
|
1293
|
+
if(likely(req->path)){
|
1294
|
+
ret = set_path(env, req->path->buf, req->path->len);
|
1295
|
+
free_buffer(req->path);
|
1296
|
+
if(unlikely(ret == -1)){
|
1297
|
+
//TODO Error
|
1298
|
+
return -1;
|
1299
|
+
}
|
1300
|
+
}else{
|
1301
|
+
rb_hash_aset(env, path_info, default_path_string);
|
1019
1302
|
}
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1303
|
+
req->path = NULL;
|
1304
|
+
|
1305
|
+
//Last header
|
1306
|
+
if(likely(req->field && req->value)){
|
1307
|
+
rb_hash_aset(env, req->field, req->value);
|
1308
|
+
|
1309
|
+
req->field = NULL;
|
1310
|
+
req->value = NULL;
|
1024
1311
|
}
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
}
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
req->fragment = NULL;
|
1034
|
-
}
|
1035
|
-
for(i = 0; i < req->num_headers+1; i++){
|
1036
|
-
h = req->headers[i];
|
1037
|
-
if(h){
|
1038
|
-
key = getRbString(h->field);
|
1039
|
-
obj = getRbString(h->value);
|
1040
|
-
rb_hash_aset(env, key, obj);
|
1041
|
-
free_header(h);
|
1042
|
-
req->headers[i] = NULL;
|
1043
|
-
}
|
1312
|
+
|
1313
|
+
ret = replace_env_key(env, h_content_type, content_type);
|
1314
|
+
if(unlikely(ret == -1)){
|
1315
|
+
return -1;
|
1316
|
+
}
|
1317
|
+
ret = replace_env_key(env, h_content_length, content_length);
|
1318
|
+
if(unlikely(ret == -1)){
|
1319
|
+
return -1;
|
1044
1320
|
}
|
1045
1321
|
|
1046
1322
|
switch(p->method){
|
1047
1323
|
case HTTP_DELETE:
|
1048
|
-
obj =
|
1324
|
+
obj = http_delete;
|
1049
1325
|
break;
|
1050
1326
|
case HTTP_GET:
|
1051
|
-
obj =
|
1327
|
+
obj = http_get;
|
1052
1328
|
break;
|
1053
1329
|
case HTTP_HEAD:
|
1054
|
-
obj =
|
1330
|
+
obj = http_head;
|
1055
1331
|
break;
|
1056
1332
|
case HTTP_POST:
|
1057
|
-
obj =
|
1333
|
+
obj = http_post;
|
1058
1334
|
break;
|
1059
1335
|
case HTTP_PUT:
|
1060
|
-
obj =
|
1336
|
+
obj = http_put;
|
1061
1337
|
break;
|
1062
1338
|
case HTTP_CONNECT:
|
1063
|
-
obj =
|
1339
|
+
obj = http_connect;
|
1064
1340
|
break;
|
1065
1341
|
case HTTP_OPTIONS:
|
1066
|
-
obj =
|
1342
|
+
obj = http_options;
|
1067
1343
|
break;
|
1068
1344
|
case HTTP_TRACE:
|
1069
|
-
obj =
|
1345
|
+
obj = http_trace;
|
1070
1346
|
break;
|
1071
1347
|
case HTTP_COPY:
|
1072
|
-
obj =
|
1348
|
+
obj = http_copy;
|
1073
1349
|
break;
|
1074
1350
|
case HTTP_LOCK:
|
1075
|
-
obj =
|
1351
|
+
obj = http_lock;
|
1076
1352
|
break;
|
1077
1353
|
case HTTP_MKCOL:
|
1078
|
-
obj =
|
1354
|
+
obj = http_mkcol;
|
1079
1355
|
break;
|
1080
1356
|
case HTTP_MOVE:
|
1081
|
-
obj =
|
1357
|
+
obj = http_move;
|
1082
1358
|
break;
|
1083
1359
|
case HTTP_PROPFIND:
|
1084
|
-
obj =
|
1360
|
+
obj = http_propfind;
|
1085
1361
|
break;
|
1086
1362
|
case HTTP_PROPPATCH:
|
1087
|
-
obj =
|
1363
|
+
obj = http_proppatch;
|
1088
1364
|
break;
|
1089
1365
|
case HTTP_UNLOCK:
|
1090
|
-
obj =
|
1366
|
+
obj = http_unlock;
|
1091
1367
|
break;
|
1092
1368
|
case HTTP_REPORT:
|
1093
|
-
obj =
|
1369
|
+
obj = http_report;
|
1094
1370
|
break;
|
1095
1371
|
case HTTP_MKACTIVITY:
|
1096
|
-
obj =
|
1372
|
+
obj = http_mkactivity;
|
1097
1373
|
break;
|
1098
1374
|
case HTTP_CHECKOUT:
|
1099
|
-
obj =
|
1375
|
+
obj = http_checkout;
|
1100
1376
|
break;
|
1101
1377
|
case HTTP_MERGE:
|
1102
|
-
obj =
|
1378
|
+
obj = http_merge;
|
1103
1379
|
break;
|
1104
1380
|
default:
|
1105
|
-
obj =
|
1381
|
+
obj = http_get;
|
1106
1382
|
break;
|
1107
1383
|
}
|
1108
1384
|
|
1109
1385
|
rb_hash_aset(env, request_method, obj);
|
1386
|
+
req->body_length = p->content_length;
|
1110
1387
|
|
1111
|
-
|
1112
|
-
client->req = NULL;
|
1113
|
-
client->body_length = p->content_length;
|
1388
|
+
DEBUG("fin headers_complete_cb");
|
1114
1389
|
return 0;
|
1115
1390
|
}
|
1116
1391
|
|
1117
1392
|
|
1118
|
-
int
|
1393
|
+
static int
|
1119
1394
|
message_complete_cb (http_parser *p)
|
1120
1395
|
{
|
1121
1396
|
client_t *client = get_client(p);
|
@@ -1128,73 +1403,46 @@ static http_parser_settings settings =
|
|
1128
1403
|
{.on_message_begin = message_begin_cb
|
1129
1404
|
,.on_header_field = header_field_cb
|
1130
1405
|
,.on_header_value = header_value_cb
|
1131
|
-
,.on_path = request_path_cb
|
1132
1406
|
,.on_url = request_uri_cb
|
1133
|
-
,.on_fragment = fragment_cb
|
1134
|
-
,.on_query_string = query_string_cb
|
1135
1407
|
,.on_body = body_cb
|
1136
1408
|
,.on_headers_complete = headers_complete_cb
|
1137
1409
|
,.on_message_complete = message_complete_cb
|
1138
1410
|
};
|
1139
1411
|
|
1140
1412
|
|
1141
|
-
int
|
1413
|
+
static int
|
1142
1414
|
init_parser(client_t *cli, const char *name, const short port)
|
1143
1415
|
{
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
cli->
|
1148
|
-
memset(cli->http, 0, sizeof(http_parser));
|
1149
|
-
|
1150
|
-
cli->environ = rb_hash_new();
|
1151
|
-
|
1152
|
-
rb_hash_aset(cli->environ, version_key, version_val);
|
1153
|
-
rb_hash_aset(cli->environ, scheme_key, scheme_val);
|
1154
|
-
rb_hash_aset(cli->environ, errors_key, errors_val);
|
1155
|
-
rb_hash_aset(cli->environ, multithread_key, multithread_val);
|
1156
|
-
rb_hash_aset(cli->environ, multiprocess_key, multiprocess_val);
|
1157
|
-
rb_hash_aset(cli->environ, run_once_key, run_once_val);
|
1158
|
-
rb_hash_aset(cli->environ, script_key, script_val);
|
1159
|
-
rb_hash_aset(cli->environ, server_name_key, server_name_val);
|
1160
|
-
rb_hash_aset(cli->environ, server_port_key, server_port_val);
|
1161
|
-
|
1162
|
-
// query_string
|
1163
|
-
rb_hash_aset(cli->environ, query_string, empty_string);
|
1164
|
-
|
1165
|
-
object = rb_str_new2(cli->remote_addr);
|
1166
|
-
rb_hash_aset(cli->environ, rb_remote_addr, object);
|
1167
|
-
|
1168
|
-
sprintf(r_port, "%d", cli->remote_port);
|
1169
|
-
object = rb_str_new2(r_port);
|
1170
|
-
rb_hash_aset(cli->environ, rb_remote_port, object);
|
1171
|
-
|
1172
|
-
http_parser_init(cli->http, HTTP_REQUEST);
|
1173
|
-
cli->http->data = cli;
|
1416
|
+
cli->http_parser = (http_parser*)ruby_xmalloc(sizeof(http_parser));
|
1417
|
+
memset(cli->http_parser, 0, sizeof(http_parser));
|
1418
|
+
http_parser_init(cli->http_parser, HTTP_REQUEST);
|
1419
|
+
cli->http_parser->data = cli;
|
1174
1420
|
|
1175
1421
|
return 0;
|
1176
1422
|
}
|
1177
1423
|
|
1178
1424
|
|
1179
|
-
size_t
|
1425
|
+
static size_t
|
1180
1426
|
execute_parse(client_t *cli, const char *data, size_t len)
|
1181
1427
|
{
|
1182
|
-
return http_parser_execute(cli->
|
1428
|
+
return http_parser_execute(cli->http_parser, &settings, data, len);
|
1183
1429
|
}
|
1184
1430
|
|
1185
1431
|
|
1186
|
-
int
|
1432
|
+
static int
|
1187
1433
|
parser_finish(client_t *cli)
|
1188
1434
|
{
|
1189
1435
|
return cli->complete;
|
1190
1436
|
}
|
1191
1437
|
|
1192
1438
|
|
1193
|
-
void
|
1439
|
+
static void
|
1194
1440
|
setup_static_env(char *name, int port)
|
1195
1441
|
{
|
1196
1442
|
char vport[7];
|
1197
1443
|
|
1444
|
+
prefix_len = strlen("HTTP_");
|
1445
|
+
|
1198
1446
|
version_val = rb_obj_freeze(rb_ary_new3(2, INT2FIX(1), INT2FIX(1)));
|
1199
1447
|
version_key = rb_obj_freeze(rb_str_new2("rack.version"));
|
1200
1448
|
|
@@ -1234,8 +1482,39 @@ setup_static_env(char *name, int port)
|
|
1234
1482
|
rack_input = rb_obj_freeze(rb_str_new2("rack.input"));
|
1235
1483
|
http_connection = rb_obj_freeze(rb_str_new2("HTTP_CONNECTION"));
|
1236
1484
|
|
1485
|
+
content_type = rb_obj_freeze(rb_str_new2("CONTENT_TYPE"));
|
1486
|
+
content_length = rb_obj_freeze(rb_str_new2("CONTENT_LENGTH"));
|
1487
|
+
|
1488
|
+
h_content_type = rb_obj_freeze(rb_str_new2("HTTP_CONTENT_TYPE"));
|
1489
|
+
h_content_length = rb_obj_freeze(rb_str_new2("HTTP_CONTENT_LENGTH"));
|
1490
|
+
|
1491
|
+
http_10 = rb_obj_freeze(rb_str_new2("HTTP/1.0"));
|
1492
|
+
http_11 = rb_obj_freeze(rb_str_new2("HTTP/1.1"));
|
1493
|
+
|
1494
|
+
http_delete = rb_obj_freeze(rb_str_new2("DELETE"));
|
1495
|
+
http_get = rb_obj_freeze(rb_str_new2("GET"));
|
1496
|
+
http_head = rb_obj_freeze(rb_str_new2("HEAD"));
|
1497
|
+
http_post = rb_obj_freeze(rb_str_new2("POST"));
|
1498
|
+
http_put = rb_obj_freeze(rb_str_new2("PUT"));
|
1499
|
+
http_connect = rb_obj_freeze(rb_str_new2("CONNECT"));
|
1500
|
+
http_options = rb_obj_freeze(rb_str_new2("OPTIONS"));
|
1501
|
+
http_trace = rb_obj_freeze(rb_str_new2("TRACE"));
|
1502
|
+
http_copy = rb_obj_freeze(rb_str_new2("COPY"));
|
1503
|
+
http_lock = rb_obj_freeze(rb_str_new2("LOCK"));
|
1504
|
+
http_mkcol = rb_obj_freeze(rb_str_new2("MKCOL"));
|
1505
|
+
http_move = rb_obj_freeze(rb_str_new2("MOVE"));
|
1506
|
+
http_propfind= rb_obj_freeze(rb_str_new2("PROPFIND"));
|
1507
|
+
http_proppatch = rb_obj_freeze(rb_str_new2("PROPPATCH"));
|
1508
|
+
http_unlock = rb_obj_freeze(rb_str_new2("UNLOCK"));
|
1509
|
+
http_report = rb_obj_freeze(rb_str_new2("REPORT"));
|
1510
|
+
http_mkactivity = rb_obj_freeze(rb_str_new2("MKACTIVITY"));
|
1511
|
+
http_checkout = rb_obj_freeze(rb_str_new2("CHECKOUT"));
|
1512
|
+
http_merge = rb_obj_freeze(rb_str_new2("MERGE"));
|
1513
|
+
|
1237
1514
|
http_user_agent = rb_obj_freeze(rb_str_new2("HTTP_USER_AGENT"));
|
1238
1515
|
http_referer = rb_obj_freeze(rb_str_new2("HTTP_REFERER"));
|
1516
|
+
|
1517
|
+
http_expect = rb_obj_freeze(rb_str_new2("HTTP_EXPECT"));
|
1239
1518
|
}
|
1240
1519
|
|
1241
1520
|
|
@@ -1250,10 +1529,10 @@ setsig(int sig, void* handler)
|
|
1250
1529
|
}
|
1251
1530
|
|
1252
1531
|
|
1253
|
-
void
|
1532
|
+
static void
|
1254
1533
|
setup_listen_sock(int fd)
|
1255
1534
|
{
|
1256
|
-
int on = 1, r;
|
1535
|
+
int on = 1, r = -1;
|
1257
1536
|
r = setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &on, sizeof(on));
|
1258
1537
|
assert(r == 0);
|
1259
1538
|
r = fcntl(fd, F_SETFL, O_NONBLOCK);
|
@@ -1261,42 +1540,30 @@ setup_listen_sock(int fd)
|
|
1261
1540
|
}
|
1262
1541
|
|
1263
1542
|
|
1264
|
-
static
|
1543
|
+
static int
|
1265
1544
|
setup_sock(int fd)
|
1266
1545
|
{
|
1267
|
-
int
|
1546
|
+
int r;
|
1547
|
+
int on = 1;
|
1268
1548
|
r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
|
1269
|
-
assert(r == 0);
|
1270
1549
|
|
1271
1550
|
// 60 + 30 * 4
|
1272
|
-
on = 300;
|
1273
|
-
r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &on, sizeof(on));
|
1274
|
-
assert(r == 0);
|
1275
|
-
on = 30;
|
1276
|
-
r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &on, sizeof(on));
|
1277
|
-
assert(r == 0);
|
1278
|
-
on = 4;
|
1279
|
-
r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &on, sizeof(on));
|
1280
|
-
assert(r == 0);
|
1281
|
-
|
1551
|
+
/* on = 300; */
|
1552
|
+
/* r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &on, sizeof(on)); */
|
1553
|
+
/* assert(r == 0); */
|
1554
|
+
/* on = 30; */
|
1555
|
+
/* r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &on, sizeof(on)); */
|
1556
|
+
/* assert(r == 0); */
|
1557
|
+
/* on = 4; */
|
1558
|
+
/* r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &on, sizeof(on)); */
|
1559
|
+
/* assert(r == 0); */
|
1560
|
+
#if linux
|
1561
|
+
r = 0; // Use accept4() on Linux
|
1562
|
+
#else
|
1282
1563
|
r = fcntl(fd, F_SETFL, O_NONBLOCK);
|
1283
1564
|
assert(r == 0);
|
1284
|
-
}
|
1285
|
-
|
1286
|
-
|
1287
|
-
static void
|
1288
|
-
disable_cork(client_t *client)
|
1289
|
-
{
|
1290
|
-
int off = 0;
|
1291
|
-
int on = 1, r;
|
1292
|
-
#ifdef linux
|
1293
|
-
r = setsockopt(client->fd, IPPROTO_TCP, TCP_CORK, &off, sizeof(off));
|
1294
|
-
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
1295
|
-
r = setsockopt(client->fd, IPPROTO_TCP, TCP_NOPUSH, &off, sizeof(off));
|
1296
1565
|
#endif
|
1297
|
-
|
1298
|
-
r = setsockopt(client->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
|
1299
|
-
assert(r == 0);
|
1566
|
+
return r;
|
1300
1567
|
}
|
1301
1568
|
|
1302
1569
|
|
@@ -1311,98 +1578,255 @@ new_client_t(int client_fd, char *remote_addr, uint32_t remote_port)
|
|
1311
1578
|
client->fd = client_fd;
|
1312
1579
|
client->remote_addr = remote_addr;
|
1313
1580
|
client->remote_port = remote_port;
|
1314
|
-
client->
|
1315
|
-
client->body_type = BODY_TYPE_NONE;
|
1581
|
+
client->request_queue = new_request_queue();
|
1316
1582
|
return client;
|
1317
1583
|
}
|
1318
1584
|
|
1319
1585
|
|
1320
1586
|
static void
|
1321
|
-
|
1587
|
+
clean_client(client_t *client)
|
1322
1588
|
{
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1589
|
+
VALUE environ;
|
1590
|
+
uintptr_t end, delta_msec = 0;
|
1591
|
+
|
1592
|
+
request *req = client->current_req;
|
1593
|
+
|
1594
|
+
if(log_fd) {
|
1595
|
+
write_access_log(client, log_fd, log_path);
|
1596
|
+
if(req){
|
1597
|
+
environ = req->environ;
|
1598
|
+
end = current_msec;
|
1599
|
+
if (req->start_msec > 0){
|
1600
|
+
delta_msec = end - req->start_msec;
|
1601
|
+
}
|
1602
|
+
} else {
|
1603
|
+
if (client->status_code != 408) {
|
1604
|
+
environ = new_environ(client);
|
1605
|
+
}
|
1606
|
+
}
|
1327
1607
|
}
|
1328
|
-
DEBUG("close environ %p \n", client->environ);
|
1329
1608
|
|
1330
|
-
|
1331
|
-
|
1609
|
+
if (req == NULL) {
|
1610
|
+
goto init;
|
1611
|
+
}
|
1332
1612
|
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1613
|
+
DEBUG("status_code:%d env:%p", client->status_code, req->environ);
|
1614
|
+
if (req->body) {
|
1615
|
+
req->body = NULL;
|
1336
1616
|
}
|
1617
|
+
free_request(req);
|
1618
|
+
init:
|
1619
|
+
client->current_req = NULL;
|
1620
|
+
client->header_done = 0;
|
1621
|
+
client->response_closed = 0;
|
1622
|
+
client->chunked_response = 0;
|
1623
|
+
client->content_length_set = 0;
|
1624
|
+
client->content_length = 0;
|
1625
|
+
client->write_bytes = 0;
|
1337
1626
|
}
|
1338
1627
|
|
1339
1628
|
|
1340
1629
|
static void
|
1341
|
-
|
1630
|
+
close_client(client_t *client)
|
1342
1631
|
{
|
1343
|
-
client_t *new_client;
|
1344
|
-
|
1345
|
-
|
1632
|
+
client_t *new_client = NULL;
|
1633
|
+
|
1634
|
+
if (!client->response_closed) {
|
1635
|
+
close_response(client);
|
1346
1636
|
}
|
1347
|
-
|
1637
|
+
DEBUG("start close client:%p fd:%d status_code %d", client, client->fd, client->status_code);
|
1348
1638
|
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1639
|
+
if (picoev_is_active(main_loop, client->fd)) {
|
1640
|
+
picoev_del(main_loop, client->fd);
|
1641
|
+
DEBUG("picoev_del client:%p fd:%d", client, client->fd);
|
1642
|
+
}
|
1643
|
+
|
1644
|
+
clean_client(client);
|
1645
|
+
|
1646
|
+
DEBUG("remain http pipeline size :%d", client->request_queue->size);
|
1647
|
+
if (client->request_queue->size > 0) {
|
1648
|
+
/* if (check_status_code(client) > 0) { */
|
1649
|
+
//process pipeline
|
1650
|
+
prepare_call_rack(client);
|
1651
|
+
call_rack_app(client);
|
1652
|
+
/* } */
|
1653
|
+
return;
|
1654
|
+
}
|
1655
|
+
|
1656
|
+
if (client->http_parser != NULL) {
|
1657
|
+
ruby_xfree(client->http_parser);
|
1658
|
+
}
|
1659
|
+
|
1660
|
+
free_request_queue(client->request_queue);
|
1661
|
+
if (!client->keep_alive) {
|
1662
|
+
close(client->fd);
|
1663
|
+
BDEBUG("close client:%p fd:%d", client, client->fd);
|
1664
|
+
} else {
|
1665
|
+
BDEBUG("keep alive client:%p fd:%d", client, client->fd);
|
1666
|
+
new_client = new_client_t(client->fd, client->remote_addr, client->remote_port);
|
1358
1667
|
new_client->keep_alive = 1;
|
1359
1668
|
init_parser(new_client, server_name, server_port);
|
1360
1669
|
picoev_add(main_loop, new_client->fd, PICOEV_READ, keep_alive_timeout, r_callback, (void *)new_client);
|
1361
1670
|
}
|
1362
|
-
|
1671
|
+
//clear old client
|
1672
|
+
ruby_xfree(client);
|
1673
|
+
}
|
1674
|
+
|
1675
|
+
|
1676
|
+
static void
|
1677
|
+
init_main_loop(void)
|
1678
|
+
{
|
1679
|
+
if (main_loop == NULL) {
|
1680
|
+
/* init picoev */
|
1681
|
+
picoev_init(max_fd);
|
1682
|
+
/* create loop */
|
1683
|
+
main_loop = picoev_create_loop(60);
|
1684
|
+
}
|
1685
|
+
}
|
1686
|
+
|
1687
|
+
static char*
|
1688
|
+
get_reason_phrase(int status_code)
|
1689
|
+
{
|
1690
|
+
if (status_code == 200) {
|
1691
|
+
return "OK";
|
1692
|
+
} else if (status_code == 201) {
|
1693
|
+
return "Created";
|
1694
|
+
} else if (status_code == 202) {
|
1695
|
+
return "Accepted";
|
1696
|
+
} else if (status_code == 203) {
|
1697
|
+
return "Non-Authoritative Information";
|
1698
|
+
} else if (status_code == 204) {
|
1699
|
+
return "No Content";
|
1700
|
+
} else if (status_code == 205) {
|
1701
|
+
return "Reset Content";
|
1702
|
+
} else if (status_code == 206) {
|
1703
|
+
return "Partial Content";
|
1704
|
+
} else if (status_code == 300) {
|
1705
|
+
return "Multiple Choices";
|
1706
|
+
} else if (status_code == 301) {
|
1707
|
+
return "Moved Permanently";
|
1708
|
+
} else if (status_code == 302) {
|
1709
|
+
return "Found";
|
1710
|
+
} else if (status_code == 303) {
|
1711
|
+
return "See Other";
|
1712
|
+
} else if (status_code == 304) {
|
1713
|
+
return "Not Modified";
|
1714
|
+
} else if (status_code == 305) {
|
1715
|
+
return "Use Proxy";
|
1716
|
+
} else if (status_code == 307) {
|
1717
|
+
return "Temporary Redirect";
|
1718
|
+
} else if (status_code == 400) {
|
1719
|
+
return "Bad Request";
|
1720
|
+
} else if (status_code == 401) {
|
1721
|
+
return "Unauthorized";
|
1722
|
+
} else if (status_code == 402) {
|
1723
|
+
return "Payment Required";
|
1724
|
+
} else if (status_code == 403) {
|
1725
|
+
return "Forbidden";
|
1726
|
+
} else if (status_code == 404) {
|
1727
|
+
return "Not Found";
|
1728
|
+
} else if (status_code == 405) {
|
1729
|
+
return "Method Not Allowed";
|
1730
|
+
} else if (status_code == 406) {
|
1731
|
+
return "Not Acceptable";
|
1732
|
+
} else if (status_code == 407) {
|
1733
|
+
return "Proxy Authentication Required";
|
1734
|
+
} else if (status_code == 408) {
|
1735
|
+
return "Request Time-out";
|
1736
|
+
} else if (status_code == 409) {
|
1737
|
+
return "Conflict";
|
1738
|
+
} else if (status_code == 410) {
|
1739
|
+
return "Gone";
|
1740
|
+
} else if (status_code == 411) {
|
1741
|
+
return "Length Required";
|
1742
|
+
} else if (status_code == 412) {
|
1743
|
+
return "Precondition Failed";
|
1744
|
+
} else if (status_code == 413) {
|
1745
|
+
return " Request Entity Too Large";
|
1746
|
+
} else if (status_code == 414) {
|
1747
|
+
return "Request-URI Too Large";
|
1748
|
+
} else if (status_code == 415) {
|
1749
|
+
return "Unsupported Media Type";
|
1750
|
+
} else if (status_code == 416) {
|
1751
|
+
return "Requested range not satisfiable";
|
1752
|
+
} else if (status_code == 417) {
|
1753
|
+
return "Expectation Failed";
|
1754
|
+
} else if (status_code == 500) {
|
1755
|
+
return "Internal Server Error";
|
1756
|
+
} else if (status_code == 501) {
|
1757
|
+
return "Not Implemented";
|
1758
|
+
} else if (status_code == 502) {
|
1759
|
+
return "Bad Gateway";
|
1760
|
+
} else if (status_code == 503) {
|
1761
|
+
return "Service Unavailable";
|
1762
|
+
} else if (status_code == 504) {
|
1763
|
+
return "Gateway Time-out";
|
1764
|
+
} else if (status_code == 505) {
|
1765
|
+
return "HTTP Version not supported";
|
1766
|
+
} else {
|
1767
|
+
return "Unknown";
|
1768
|
+
}
|
1363
1769
|
}
|
1364
1770
|
|
1365
1771
|
|
1366
1772
|
static int
|
1367
1773
|
process_rack_app(client_t *cli)
|
1368
1774
|
{
|
1369
|
-
VALUE
|
1370
|
-
|
1775
|
+
VALUE env, response_arr, status_code, headers, response_body;
|
1776
|
+
request *req = cli->current_req;
|
1371
1777
|
|
1372
|
-
|
1778
|
+
env = req->environ;
|
1373
1779
|
|
1374
1780
|
// cli->response = [200, {}, []]
|
1375
|
-
|
1781
|
+
response_arr = rb_funcall(rack_app, i_call, 1, env);
|
1782
|
+
|
1783
|
+
// to_arr
|
1784
|
+
if (TYPE(response_arr) != T_ARRAY) {
|
1785
|
+
response_arr = rb_funcall(response_arr, i_toa, 0);
|
1786
|
+
}
|
1376
1787
|
|
1377
|
-
if(
|
1788
|
+
if(RARRAY_LEN(response_arr) < 3) {
|
1378
1789
|
return 0;
|
1379
1790
|
}
|
1380
1791
|
|
1381
|
-
|
1382
|
-
|
1383
|
-
|
1792
|
+
status_code = rb_ary_entry(response_arr, 0);
|
1793
|
+
headers = rb_ary_entry(response_arr, 1);
|
1794
|
+
response_body = rb_ary_entry(response_arr, 2);
|
1384
1795
|
|
1385
|
-
if (TYPE(
|
1386
|
-
TYPE(
|
1796
|
+
if (TYPE(status_code) != T_FIXNUM ||
|
1797
|
+
TYPE(headers) != T_HASH ||
|
1798
|
+
rb_respond_to(response_body, i_each) == 0) {
|
1387
1799
|
return 0;
|
1388
1800
|
}
|
1389
1801
|
|
1390
|
-
cli->status_code = NUM2INT(
|
1391
|
-
cli->headers =
|
1802
|
+
cli->status_code = NUM2INT(status_code);
|
1803
|
+
cli->headers = headers;
|
1804
|
+
cli->response_iter = rb_funcall(response_body, i_toenum, 0);
|
1805
|
+
|
1806
|
+
rb_gc_register_address(&cli->headers);
|
1807
|
+
rb_gc_register_address(&cli->response_iter);
|
1808
|
+
|
1809
|
+
if (cli->response_closed) {
|
1810
|
+
//closed
|
1811
|
+
close_client(cli);
|
1812
|
+
return 1;
|
1813
|
+
}
|
1392
1814
|
|
1393
1815
|
errno = 0;
|
1394
1816
|
/* printf("status code: %d\n", cli->status_code); */
|
1395
1817
|
|
1818
|
+
char* reason_phrase;
|
1819
|
+
reason_phrase = get_reason_phrase(cli->status_code);
|
1820
|
+
|
1396
1821
|
char buff[256];
|
1397
|
-
sprintf(buff, "HTTP/1
|
1822
|
+
sprintf(buff, "HTTP/1.%d %d %s\r\n", cli->http_parser->http_minor, cli->status_code, reason_phrase);
|
1398
1823
|
cli->http_status = rb_str_new(buff, strlen(buff));
|
1399
1824
|
|
1400
1825
|
//check response
|
1401
1826
|
if(cli->response && cli->response == Qnil){
|
1402
1827
|
write_error_log(__FILE__, __LINE__);
|
1403
|
-
|
1828
|
+
return 0;
|
1404
1829
|
}
|
1405
|
-
|
1406
1830
|
return 1;
|
1407
1831
|
}
|
1408
1832
|
|
@@ -1417,85 +1841,256 @@ w_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
|
|
1417
1841
|
YDEBUG("** w_callback timeout ** \n");
|
1418
1842
|
//timeout
|
1419
1843
|
client->keep_alive = 0;
|
1420
|
-
|
1844
|
+
close_client(client);
|
1421
1845
|
|
1422
1846
|
} else if ((events & PICOEV_WRITE) != 0) {
|
1423
1847
|
ret = process_body(client);
|
1424
|
-
picoev_set_timeout(loop, client->fd, WRITE_TIMEOUT_SECS);
|
1848
|
+
/* picoev_set_timeout(loop, client->fd, WRITE_TIMEOUT_SECS); */
|
1425
1849
|
DEBUG("process_body ret %d \n", ret);
|
1426
1850
|
if(ret != 0){
|
1427
1851
|
//ok or die
|
1428
|
-
|
1852
|
+
close_client(client);
|
1429
1853
|
}
|
1430
1854
|
}
|
1431
1855
|
}
|
1432
1856
|
|
1433
1857
|
|
1434
|
-
static
|
1435
|
-
|
1858
|
+
static int
|
1859
|
+
check_http_expect(client_t *client)
|
1436
1860
|
{
|
1861
|
+
VALUE c;
|
1862
|
+
char *val = NULL;
|
1437
1863
|
int ret;
|
1864
|
+
request *req = client->current_req;
|
1865
|
+
|
1866
|
+
if (client->http_parser->http_minor == 1) {
|
1867
|
+
///TODO CHECK
|
1868
|
+
c = rb_hash_aref(req->environ, http_expect);
|
1869
|
+
if (c != Qnil) {
|
1870
|
+
val = StringValuePtr(c);
|
1871
|
+
if (!strncasecmp(val, "100-continue", 12)) {
|
1872
|
+
ret = write(client->fd, "HTTP/1.1 100 Continue\r\n\r\n", 25);
|
1873
|
+
if (ret < 0) {
|
1874
|
+
//fail
|
1875
|
+
client->keep_alive = 0;
|
1876
|
+
client->status_code = 500;
|
1877
|
+
send_error_page(client);
|
1878
|
+
close_client(client);
|
1879
|
+
return -1;
|
1880
|
+
}
|
1881
|
+
} else {
|
1882
|
+
//417
|
1883
|
+
client->keep_alive = 0;
|
1884
|
+
client->status_code = 417;
|
1885
|
+
send_error_page(client);
|
1886
|
+
close_client(client);
|
1887
|
+
return -1;
|
1888
|
+
}
|
1889
|
+
}
|
1890
|
+
return 1;
|
1891
|
+
}
|
1892
|
+
return 0;
|
1893
|
+
}
|
1894
|
+
|
1895
|
+
|
1896
|
+
static void
|
1897
|
+
call_rack_app(client_t *client)
|
1898
|
+
{
|
1899
|
+
response_status ret;
|
1900
|
+
request *req = client->current_req;
|
1901
|
+
|
1438
1902
|
if(!process_rack_app(client)){
|
1439
1903
|
//Internal Server Error
|
1440
|
-
|
1904
|
+
req->bad_request_code = 500;
|
1441
1905
|
send_error_page(client);
|
1442
|
-
|
1906
|
+
close_client(client);
|
1443
1907
|
return;
|
1444
1908
|
}
|
1445
1909
|
|
1446
1910
|
ret = response_start(client);
|
1447
1911
|
switch(ret){
|
1448
|
-
case
|
1912
|
+
case STATUS_ERROR:
|
1449
1913
|
// Internal Server Error
|
1450
|
-
client->
|
1914
|
+
client->status_code = 500;
|
1451
1915
|
send_error_page(client);
|
1452
|
-
|
1916
|
+
close_client(client);
|
1453
1917
|
return;
|
1454
|
-
case
|
1918
|
+
case STATUS_SUSPEND:
|
1455
1919
|
// continue
|
1456
1920
|
// set callback
|
1457
1921
|
DEBUG("set write callback %d \n", ret);
|
1458
1922
|
//clear event
|
1459
|
-
picoev_del(
|
1460
|
-
picoev_add(
|
1923
|
+
picoev_del(main_loop, client->fd);
|
1924
|
+
picoev_add(main_loop, client->fd, PICOEV_WRITE, WRITE_TIMEOUT_SECS, w_callback, (void *)client);
|
1461
1925
|
return;
|
1462
1926
|
default:
|
1463
1927
|
// send OK
|
1464
|
-
|
1928
|
+
close_client(client);
|
1465
1929
|
}
|
1466
1930
|
}
|
1467
1931
|
|
1468
1932
|
|
1933
|
+
static inline void
|
1934
|
+
set_current_request(client_t *client)
|
1935
|
+
{
|
1936
|
+
request *req;
|
1937
|
+
req = shift_request(client->request_queue);
|
1938
|
+
client->current_req = req;
|
1939
|
+
}
|
1940
|
+
|
1941
|
+
|
1469
1942
|
static void
|
1470
1943
|
prepare_call_rack(client_t *client)
|
1471
1944
|
{
|
1472
|
-
|
1473
|
-
|
1945
|
+
request *req = NULL;
|
1946
|
+
VALUE input, object;
|
1947
|
+
|
1948
|
+
set_current_request(client);
|
1949
|
+
req = client->current_req;
|
1950
|
+
|
1951
|
+
//check Expect
|
1952
|
+
if (check_http_expect(client) < 0) {
|
1953
|
+
return;
|
1954
|
+
}
|
1474
1955
|
|
1475
|
-
if(
|
1476
|
-
rb_funcall((VALUE)
|
1477
|
-
rb_hash_aset(
|
1956
|
+
if(req->body_type == BODY_TYPE_BUFFER) {
|
1957
|
+
rb_funcall((VALUE)req->body, i_seek, 1, INT2NUM(0));
|
1958
|
+
rb_hash_aset(req->environ, rack_input, (VALUE)req->body);
|
1478
1959
|
} else {
|
1479
1960
|
object = rb_str_new2("");
|
1480
1961
|
input = rb_funcall(StringIO, i_new, 1, object);
|
1481
1962
|
rb_gc_register_address(&input);
|
1482
|
-
rb_hash_aset(
|
1483
|
-
|
1963
|
+
rb_hash_aset(req->environ, rack_input, input);
|
1964
|
+
req->body = input;
|
1484
1965
|
}
|
1485
1966
|
|
1486
|
-
if(is_keep_alive){
|
1487
|
-
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1967
|
+
if(!is_keep_alive){
|
1968
|
+
client->keep_alive = 0;
|
1969
|
+
}
|
1970
|
+
}
|
1971
|
+
|
1972
|
+
|
1973
|
+
static void
|
1974
|
+
set_bad_request_code(client_t *client, int status_code)
|
1975
|
+
{
|
1976
|
+
request *req;
|
1977
|
+
req = client->request_queue->tail;
|
1978
|
+
req->bad_request_code = status_code;
|
1979
|
+
DEBUG("set bad request code %d", status_code);
|
1980
|
+
}
|
1981
|
+
|
1982
|
+
|
1983
|
+
static int
|
1984
|
+
check_status_code(client_t *client)
|
1985
|
+
{
|
1986
|
+
request *req;
|
1987
|
+
req = client->request_queue->head;
|
1988
|
+
if (req && req->bad_request_code > 200) {
|
1989
|
+
//error
|
1990
|
+
//shift
|
1991
|
+
DEBUG("bad status code %d", req->bad_request_code);
|
1992
|
+
set_current_request(client);
|
1993
|
+
client->status_code = req->bad_request_code;
|
1994
|
+
send_error_page(client);
|
1995
|
+
close_client(client);
|
1996
|
+
return -1;
|
1997
|
+
}
|
1998
|
+
return 1;
|
1999
|
+
}
|
2000
|
+
|
2001
|
+
|
2002
|
+
static int
|
2003
|
+
set_read_error(client_t *client, int status_code)
|
2004
|
+
{
|
2005
|
+
client->keep_alive = 0;
|
2006
|
+
if (status_code == 0) {
|
2007
|
+
// bad request
|
2008
|
+
status_code = 400;
|
2009
|
+
}
|
2010
|
+
if (client->request_queue->size > 0) {
|
2011
|
+
//piplining
|
2012
|
+
set_bad_request_code(client, status_code);
|
2013
|
+
return 1;
|
2014
|
+
} else {
|
2015
|
+
client->status_code = status_code;
|
2016
|
+
send_error_page(client);
|
2017
|
+
close_client(client);
|
2018
|
+
return -1;
|
2019
|
+
}
|
2020
|
+
}
|
2021
|
+
|
2022
|
+
|
2023
|
+
static int
|
2024
|
+
read_timeout(int fd, client_t *client)
|
2025
|
+
{
|
2026
|
+
RDEBUG("** read timeout fd:%d", fd);
|
2027
|
+
//timeout
|
2028
|
+
return set_read_error(client, 408);
|
2029
|
+
}
|
2030
|
+
|
2031
|
+
|
2032
|
+
static int
|
2033
|
+
parse_http_request(int fd, client_t *client, char *buf, ssize_t r)
|
2034
|
+
{
|
2035
|
+
int nread = 0;
|
2036
|
+
request *req = NULL;
|
2037
|
+
|
2038
|
+
BDEBUG("fd:%d \n%.*s", fd, (int)r, buf);
|
2039
|
+
nread = execute_parse(client, buf, r);
|
2040
|
+
BDEBUG("read request fd %d readed %d nread %d", fd, (int)r, nread);
|
2041
|
+
|
2042
|
+
req = client->current_req;
|
2043
|
+
|
2044
|
+
if (nread != r || req->bad_request_code > 0) {
|
2045
|
+
if (req == NULL) {
|
2046
|
+
DEBUG("fd %d bad_request code 400", fd);
|
2047
|
+
return set_read_error(client, 400);
|
2048
|
+
} else {
|
2049
|
+
DEBUG("fd %d bad_request code %d", fd, req->bad_request_code);
|
2050
|
+
return set_read_error(client, req->bad_request_code);
|
2051
|
+
}
|
2052
|
+
}
|
2053
|
+
|
2054
|
+
if (parser_finish(client) > 0) {
|
2055
|
+
return 1;
|
2056
|
+
}
|
2057
|
+
return 0;
|
2058
|
+
}
|
2059
|
+
|
2060
|
+
|
2061
|
+
static int
|
2062
|
+
read_request(picoev_loop *loop, int fd, client_t *client, char call_time_update)
|
2063
|
+
{
|
2064
|
+
char buf[READ_BUF_SIZE];
|
2065
|
+
ssize_t r;
|
2066
|
+
|
2067
|
+
if (!client->keep_alive) {
|
2068
|
+
picoev_set_timeout(loop, fd, READ_TIMEOUT_SECS);
|
2069
|
+
}
|
2070
|
+
|
2071
|
+
r = read(client->fd, buf, sizeof(buf));
|
2072
|
+
switch (r) {
|
2073
|
+
case 0:
|
2074
|
+
return set_read_error(client, 503);
|
2075
|
+
case -1:
|
2076
|
+
// Error
|
2077
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
2078
|
+
// try again later
|
2079
|
+
return 0;
|
2080
|
+
} else {
|
2081
|
+
// Fatal error
|
1497
2082
|
client->keep_alive = 0;
|
2083
|
+
if (errno == ECONNRESET) {
|
2084
|
+
client->header_done = 1;
|
2085
|
+
client->response_closed = 1;
|
2086
|
+
}
|
2087
|
+
return set_read_error(client, 500);
|
2088
|
+
}
|
2089
|
+
default:
|
2090
|
+
if (call_time_update) {
|
2091
|
+
cache_time_update();
|
1498
2092
|
}
|
2093
|
+
return parse_http_request(fd, client, buf, r);
|
1499
2094
|
}
|
1500
2095
|
}
|
1501
2096
|
|
@@ -1504,85 +2099,22 @@ static void
|
|
1504
2099
|
r_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
|
1505
2100
|
{
|
1506
2101
|
client_t *cli = ( client_t *)(cb_arg);
|
2102
|
+
int finish = 0;
|
2103
|
+
|
1507
2104
|
if ((events & PICOEV_TIMEOUT) != 0) {
|
1508
|
-
|
1509
|
-
//timeout
|
1510
|
-
cli->keep_alive = 0;
|
1511
|
-
close_conn(cli, loop);
|
1512
|
-
} else if ((events & PICOEV_READ) != 0) {
|
1513
|
-
RDEBUG("ready read \n");
|
1514
|
-
/* update timeout, and read */
|
1515
|
-
int finish = 0, nread;
|
1516
|
-
char buf[INPUT_BUF_SIZE];
|
1517
|
-
ssize_t r;
|
1518
|
-
if(!cli->keep_alive){
|
1519
|
-
picoev_set_timeout(loop, cli->fd, SHORT_TIMEOUT_SECS);
|
1520
|
-
}
|
1521
|
-
r = read(cli->fd, buf, sizeof(buf));
|
1522
|
-
switch (r) {
|
1523
|
-
case 0:
|
1524
|
-
cli->keep_alive = 0;
|
1525
|
-
cli->status_code = 500; // ??? 503 ??
|
1526
|
-
send_error_page(cli);
|
1527
|
-
close_conn(cli, loop);
|
1528
|
-
return;
|
1529
|
-
case -1: /* error */
|
1530
|
-
if (errno == EAGAIN || errno == EWOULDBLOCK) { /* try again later */
|
1531
|
-
break;
|
1532
|
-
} else { /* fatal error */
|
1533
|
-
if (cli->keep_alive && errno == ECONNRESET) {
|
1534
|
-
cli->keep_alive = 0;
|
1535
|
-
cli->status_code = 500;
|
1536
|
-
cli->header_done = 1;
|
1537
|
-
cli->response_closed = 1;
|
1538
|
-
} else {
|
1539
|
-
/* rb_raise(rb_eException, "fatal error"); */
|
1540
|
-
write_error_log(__FILE__, __LINE__);
|
1541
|
-
cli->keep_alive = 0;
|
1542
|
-
cli->status_code = 500;
|
1543
|
-
if(errno != ECONNRESET){
|
1544
|
-
send_error_page(cli);
|
1545
|
-
}else{
|
1546
|
-
cli->header_done = 1;
|
1547
|
-
cli->response_closed = 1;
|
1548
|
-
}
|
1549
|
-
}
|
1550
|
-
close_conn(cli, loop);
|
1551
|
-
return;
|
1552
|
-
}
|
1553
|
-
break;
|
1554
|
-
default:
|
1555
|
-
RDEBUG("read request fd %d bufsize %d \n", cli->fd, r);
|
1556
|
-
nread = execute_parse(cli, buf, r);
|
1557
|
-
|
1558
|
-
if(cli->bad_request_code > 0){
|
1559
|
-
RDEBUG("fd %d bad_request code %d \n", cli->fd, cli->bad_request_code);
|
1560
|
-
send_error_page(cli);
|
1561
|
-
close_conn(cli, loop);
|
1562
|
-
return;
|
1563
|
-
}
|
1564
|
-
if( nread != r ){
|
1565
|
-
// parse error
|
1566
|
-
DEBUG("fd %d parse error %d \n", cli->fd, cli->bad_request_code);
|
1567
|
-
cli->bad_request_code = 400;
|
1568
|
-
send_error_page(cli);
|
1569
|
-
close_conn(cli, loop);
|
1570
|
-
return;
|
1571
|
-
}
|
1572
|
-
RDEBUG("parse ok, fd %d %d nread \n", cli->fd, nread);
|
2105
|
+
finish = read_timeout(fd, cli);
|
1573
2106
|
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
if(
|
1581
|
-
/* picoev_del(loop, cli->fd); */
|
2107
|
+
} else if ((events & PICOEV_READ) != 0) {
|
2108
|
+
finish = read_request(loop, fd, cli, 0);
|
2109
|
+
}
|
2110
|
+
if(finish == 1){
|
2111
|
+
picoev_del(loop, cli->fd);
|
2112
|
+
RDEBUG("del fd: %d", cli->fd);
|
2113
|
+
if (check_status_code(cli) > 0) {
|
1582
2114
|
prepare_call_rack(cli);
|
1583
|
-
call_rack_app(cli
|
1584
|
-
return;
|
2115
|
+
call_rack_app(cli);
|
1585
2116
|
}
|
2117
|
+
return;
|
1586
2118
|
}
|
1587
2119
|
}
|
1588
2120
|
|
@@ -1595,6 +2127,7 @@ accept_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
|
|
1595
2127
|
struct sockaddr_in client_addr;
|
1596
2128
|
char *remote_addr;
|
1597
2129
|
uint32_t remote_port;
|
2130
|
+
int finish = 0;
|
1598
2131
|
|
1599
2132
|
if ((events & PICOEV_TIMEOUT) != 0) {
|
1600
2133
|
// time out
|
@@ -1602,25 +2135,44 @@ accept_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
|
|
1602
2135
|
return;
|
1603
2136
|
}else if ((events & PICOEV_READ) != 0) {
|
1604
2137
|
socklen_t client_len = sizeof(client_addr);
|
2138
|
+
for(;;) {
|
1605
2139
|
#ifdef linux
|
1606
|
-
|
2140
|
+
client_fd = accept4(fd, (struct sockaddr *)&client_addr, &client_len, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
1607
2141
|
#else
|
1608
|
-
|
2142
|
+
client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);
|
1609
2143
|
#endif
|
1610
|
-
|
1611
|
-
|
1612
|
-
|
1613
|
-
|
1614
|
-
|
1615
|
-
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1620
|
-
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
2144
|
+
if (client_fd != -1) {
|
2145
|
+
DEBUG("accept fd %d \n", client_fd);
|
2146
|
+
|
2147
|
+
if (setup_sock(client_fd) == -1) {
|
2148
|
+
write_error_log(__FILE__, __LINE__);
|
2149
|
+
// die
|
2150
|
+
loop_done = 0;
|
2151
|
+
return;
|
2152
|
+
}
|
2153
|
+
|
2154
|
+
remote_addr = inet_ntoa(client_addr.sin_addr);
|
2155
|
+
remote_port = ntohs(client_addr.sin_port);
|
2156
|
+
client = new_client_t(client_fd, remote_addr, remote_port);
|
2157
|
+
init_parser(client, server_name, server_port);
|
2158
|
+
|
2159
|
+
finish = read_request(loop, fd, client, 1);
|
2160
|
+
if (finish == 1) {
|
2161
|
+
if (check_status_code(client) > 0) {
|
2162
|
+
//current request ok
|
2163
|
+
prepare_call_rack(client);
|
2164
|
+
call_rack_app(client);
|
2165
|
+
}
|
2166
|
+
} else if (finish == 0) {
|
2167
|
+
picoev_add(loop, client_fd, PICOEV_READ, keep_alive_timeout, r_callback, (void *)client);
|
2168
|
+
}
|
2169
|
+
} else {
|
2170
|
+
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
2171
|
+
write_error_log(__FILE__, __LINE__);
|
2172
|
+
// die
|
2173
|
+
loop_done = 0;
|
2174
|
+
}
|
2175
|
+
break;
|
1624
2176
|
}
|
1625
2177
|
}
|
1626
2178
|
}
|
@@ -1660,7 +2212,6 @@ inet_listen(void)
|
|
1660
2212
|
for(p = servinfo; p != NULL; p = p->ai_next) {
|
1661
2213
|
if ((listen_sock = socket(p->ai_family, p->ai_socktype,
|
1662
2214
|
p->ai_protocol)) == -1) {
|
1663
|
-
//perror("server: socket");
|
1664
2215
|
continue;
|
1665
2216
|
}
|
1666
2217
|
|
@@ -1677,10 +2228,9 @@ inet_listen(void)
|
|
1677
2228
|
break;
|
1678
2229
|
}
|
1679
2230
|
|
1680
|
-
if (p == NULL)
|
2231
|
+
if (p == NULL) {
|
1681
2232
|
close(listen_sock);
|
1682
2233
|
rb_raise(rb_eIOError, "server: failed to bind\n");
|
1683
|
-
return -1;
|
1684
2234
|
}
|
1685
2235
|
|
1686
2236
|
freeaddrinfo(servinfo); // all done with this structure
|
@@ -1848,9 +2398,7 @@ bossan_run_loop(VALUE self, VALUE args)
|
|
1848
2398
|
rack_app = args;
|
1849
2399
|
|
1850
2400
|
/* init picoev */
|
1851
|
-
|
1852
|
-
/* create loop */
|
1853
|
-
main_loop = picoev_create_loop(60);
|
2401
|
+
init_main_loop();
|
1854
2402
|
loop_done = 1;
|
1855
2403
|
|
1856
2404
|
setsig(SIGPIPE, sigpipe_cb);
|
@@ -1863,6 +2411,7 @@ bossan_run_loop(VALUE self, VALUE args)
|
|
1863
2411
|
while (loop_done) {
|
1864
2412
|
picoev_loop_once(main_loop, 10);
|
1865
2413
|
}
|
2414
|
+
|
1866
2415
|
picoev_destroy_loop(main_loop);
|
1867
2416
|
picoev_deinit();
|
1868
2417
|
|
@@ -1874,7 +2423,7 @@ bossan_run_loop(VALUE self, VALUE args)
|
|
1874
2423
|
}
|
1875
2424
|
|
1876
2425
|
|
1877
|
-
VALUE
|
2426
|
+
static VALUE
|
1878
2427
|
bossan_set_max_content_length(VALUE self, VALUE args)
|
1879
2428
|
{
|
1880
2429
|
max_content_length = NUM2INT(args);
|
@@ -1882,21 +2431,21 @@ bossan_set_max_content_length(VALUE self, VALUE args)
|
|
1882
2431
|
}
|
1883
2432
|
|
1884
2433
|
|
1885
|
-
VALUE
|
2434
|
+
static VALUE
|
1886
2435
|
bossan_get_max_content_length(VALUE self)
|
1887
2436
|
{
|
1888
2437
|
return INT2NUM(max_content_length);
|
1889
2438
|
}
|
1890
2439
|
|
1891
2440
|
|
1892
|
-
VALUE
|
2441
|
+
static VALUE
|
1893
2442
|
bossan_set_keepalive(VALUE self, VALUE args)
|
1894
2443
|
{
|
1895
2444
|
int on;
|
1896
2445
|
|
1897
2446
|
on = NUM2INT(args);
|
1898
2447
|
if(on < 0){
|
1899
|
-
|
2448
|
+
printf("keep alive value out of range.\n");
|
1900
2449
|
return Qfalse;
|
1901
2450
|
}
|
1902
2451
|
|
@@ -1911,14 +2460,14 @@ bossan_set_keepalive(VALUE self, VALUE args)
|
|
1911
2460
|
}
|
1912
2461
|
|
1913
2462
|
|
1914
|
-
VALUE
|
2463
|
+
static VALUE
|
1915
2464
|
bossan_get_keepalive(VALUE self)
|
1916
2465
|
{
|
1917
2466
|
return INT2NUM(is_keep_alive);
|
1918
2467
|
}
|
1919
2468
|
|
1920
2469
|
|
1921
|
-
VALUE
|
2470
|
+
static VALUE
|
1922
2471
|
bossan_set_picoev_max_fd(VALUE self, VALUE args)
|
1923
2472
|
{
|
1924
2473
|
int temp;
|
@@ -1931,14 +2480,14 @@ bossan_set_picoev_max_fd(VALUE self, VALUE args)
|
|
1931
2480
|
}
|
1932
2481
|
|
1933
2482
|
|
1934
|
-
VALUE
|
2483
|
+
static VALUE
|
1935
2484
|
bossan_get_picoev_max_fd(VALUE self)
|
1936
2485
|
{
|
1937
2486
|
return INT2NUM(max_fd);
|
1938
2487
|
}
|
1939
2488
|
|
1940
2489
|
|
1941
|
-
VALUE
|
2490
|
+
static VALUE
|
1942
2491
|
bossan_set_backlog(VALUE self, VALUE args)
|
1943
2492
|
{
|
1944
2493
|
int temp;
|
@@ -1951,7 +2500,7 @@ bossan_set_backlog(VALUE self, VALUE args)
|
|
1951
2500
|
}
|
1952
2501
|
|
1953
2502
|
|
1954
|
-
VALUE
|
2503
|
+
static VALUE
|
1955
2504
|
bossan_get_backlog(VALUE self)
|
1956
2505
|
{
|
1957
2506
|
return INT2NUM(backlog);
|
@@ -1992,17 +2541,47 @@ Init_bossan_ext(void)
|
|
1992
2541
|
rb_gc_register_address(&rack_input);
|
1993
2542
|
rb_gc_register_address(&http_connection);
|
1994
2543
|
|
2544
|
+
rb_gc_register_address(&h_content_type);
|
2545
|
+
rb_gc_register_address(&h_content_length);
|
2546
|
+
rb_gc_register_address(&content_type);
|
2547
|
+
rb_gc_register_address(&content_length);
|
2548
|
+
|
2549
|
+
rb_gc_register_address(&http_10);
|
2550
|
+
rb_gc_register_address(&http_11);
|
2551
|
+
|
2552
|
+
rb_gc_register_address(&http_delete);
|
2553
|
+
rb_gc_register_address(&http_get);
|
2554
|
+
rb_gc_register_address(&http_head);
|
2555
|
+
rb_gc_register_address(&http_post);
|
2556
|
+
rb_gc_register_address(&http_put);
|
2557
|
+
rb_gc_register_address(&http_connect);
|
2558
|
+
rb_gc_register_address(&http_options);
|
2559
|
+
rb_gc_register_address(&http_trace);
|
2560
|
+
rb_gc_register_address(&http_copy);
|
2561
|
+
rb_gc_register_address(&http_lock);
|
2562
|
+
rb_gc_register_address(&http_mkcol);
|
2563
|
+
rb_gc_register_address(&http_move);
|
2564
|
+
rb_gc_register_address(&http_propfind);
|
2565
|
+
rb_gc_register_address(&http_proppatch);
|
2566
|
+
rb_gc_register_address(&http_unlock);
|
2567
|
+
rb_gc_register_address(&http_report);
|
2568
|
+
rb_gc_register_address(&http_mkactivity);
|
2569
|
+
rb_gc_register_address(&http_checkout);
|
2570
|
+
rb_gc_register_address(&http_merge);
|
2571
|
+
|
1995
2572
|
rb_gc_register_address(&http_user_agent);
|
1996
2573
|
rb_gc_register_address(&http_referer);
|
1997
2574
|
|
2575
|
+
rb_gc_register_address(&http_expect);
|
2576
|
+
|
1998
2577
|
empty_string = rb_obj_freeze(rb_str_new2(""));
|
1999
2578
|
rb_gc_register_address(&empty_string);
|
2000
2579
|
|
2001
2580
|
rb_gc_register_address(&i_keys);
|
2002
2581
|
rb_gc_register_address(&i_call);
|
2003
2582
|
rb_gc_register_address(&i_new);
|
2004
|
-
rb_gc_register_address(&i_key);
|
2005
2583
|
rb_gc_register_address(&i_each);
|
2584
|
+
rb_gc_register_address(&i_toenum);
|
2006
2585
|
rb_gc_register_address(&i_close);
|
2007
2586
|
rb_gc_register_address(&i_write);
|
2008
2587
|
rb_gc_register_address(&i_seek);
|
@@ -2012,11 +2591,13 @@ Init_bossan_ext(void)
|
|
2012
2591
|
i_new = rb_intern("new");
|
2013
2592
|
i_call = rb_intern("call");
|
2014
2593
|
i_keys = rb_intern("keys");
|
2015
|
-
i_key = rb_intern("key?");
|
2016
2594
|
i_each = rb_intern("each");
|
2595
|
+
i_toenum = rb_intern("to_enum");
|
2017
2596
|
i_close = rb_intern("close");
|
2018
2597
|
i_write = rb_intern("write");
|
2019
2598
|
i_seek = rb_intern("seek");
|
2599
|
+
i_toa = rb_intern("to_a");
|
2600
|
+
i_next = rb_intern("next");
|
2020
2601
|
|
2021
2602
|
server = rb_define_module("Bossan");
|
2022
2603
|
rb_gc_register_address(&server);
|