unicorn 4.8.0 → 6.1.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 +7 -0
- data/.document +0 -1
- data/.gitattributes +5 -0
- data/.gitignore +2 -2
- data/.manifest +17 -21
- data/.olddoc.yml +25 -0
- data/Application_Timeouts +7 -7
- data/CONTRIBUTORS +6 -2
- data/DESIGN +2 -4
- data/Documentation/.gitignore +1 -3
- data/Documentation/unicorn.1 +222 -0
- data/Documentation/unicorn_rails.1 +207 -0
- data/FAQ +23 -6
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +138 -92
- data/HACKING +10 -32
- data/ISSUES +80 -19
- data/KNOWN_ISSUES +18 -18
- data/LATEST +23 -27
- data/LICENSE +2 -2
- data/Links +24 -22
- data/NEWS +823 -0
- data/PHILOSOPHY +0 -6
- data/README +49 -48
- data/Rakefile +0 -44
- data/SIGNALS +2 -2
- data/Sandbox +11 -10
- data/TODO +0 -2
- data/TUNING +30 -9
- data/archive/.gitignore +3 -0
- data/archive/slrnpull.conf +4 -0
- data/bin/unicorn +4 -2
- data/bin/unicorn_rails +3 -3
- data/examples/big_app_gc.rb +1 -1
- data/examples/init.sh +36 -8
- data/examples/logrotate.conf +17 -2
- data/examples/nginx.conf +14 -14
- data/examples/unicorn.conf.minimal.rb +2 -2
- data/examples/unicorn.conf.rb +14 -6
- data/examples/unicorn.socket +11 -0
- data/examples/unicorn@.service +40 -0
- data/ext/unicorn_http/c_util.h +5 -13
- data/ext/unicorn_http/common_field_optimization.h +22 -5
- data/ext/unicorn_http/epollexclusive.h +124 -0
- data/ext/unicorn_http/ext_help.h +0 -44
- data/ext/unicorn_http/extconf.rb +32 -5
- data/ext/unicorn_http/global_variables.h +2 -2
- data/ext/unicorn_http/httpdate.c +3 -2
- data/ext/unicorn_http/unicorn_http.c +926 -638
- data/ext/unicorn_http/unicorn_http.rl +159 -170
- data/ext/unicorn_http/unicorn_http_common.rl +1 -1
- data/lib/unicorn/configurator.rb +110 -46
- data/lib/unicorn/const.rb +2 -25
- data/lib/unicorn/http_request.rb +110 -31
- data/lib/unicorn/http_response.rb +17 -31
- data/lib/unicorn/http_server.rb +272 -180
- data/lib/unicorn/launcher.rb +1 -1
- data/lib/unicorn/oob_gc.rb +16 -6
- data/lib/unicorn/select_waiter.rb +6 -0
- data/lib/unicorn/socket_helper.rb +58 -78
- data/lib/unicorn/stream_input.rb +8 -7
- data/lib/unicorn/tee_input.rb +16 -11
- data/lib/unicorn/tmpio.rb +10 -6
- data/lib/unicorn/util.rb +5 -4
- data/lib/unicorn/version.rb +1 -1
- data/lib/unicorn/worker.rb +36 -23
- data/lib/unicorn.rb +64 -44
- data/man/man1/unicorn.1 +124 -122
- data/man/man1/unicorn_rails.1 +113 -127
- data/t/.gitignore +0 -1
- data/t/GNUmakefile +3 -80
- data/t/README +4 -4
- data/t/t0002-parser-error.sh +3 -3
- data/t/t0011-active-unix-socket.sh +1 -1
- data/t/t0012-reload-empty-config.sh +2 -1
- data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
- data/t/t0301.ru +13 -0
- data/t/test-lib.sh +4 -3
- data/test/benchmark/README +14 -4
- data/test/benchmark/ddstream.ru +50 -0
- data/test/benchmark/readinput.ru +40 -0
- data/test/benchmark/uconnect.perl +66 -0
- data/test/exec/test_exec.rb +74 -20
- data/test/test_helper.rb +42 -33
- data/test/unit/test_ccc.rb +91 -0
- data/test/unit/test_droplet.rb +1 -1
- data/test/unit/test_http_parser.rb +49 -19
- data/test/unit/test_http_parser_ng.rb +98 -115
- data/test/unit/test_request.rb +11 -11
- data/test/unit/test_response.rb +31 -19
- data/test/unit/test_server.rb +89 -15
- data/test/unit/test_signals.rb +9 -9
- data/test/unit/test_socket_helper.rb +16 -12
- data/test/unit/test_tee_input.rb +10 -0
- data/test/unit/test_upload.rb +10 -15
- data/test/unit/test_util.rb +32 -6
- data/test/unit/test_waiter.rb +34 -0
- data/unicorn.gemspec +28 -23
- data/unicorn_1 +1 -0
- data/unicorn_rails_1 +1 -0
- metadata +68 -134
- data/.wrongdoc.yml +0 -10
- data/ChangeLog +0 -4861
- data/Documentation/GNUmakefile +0 -30
- data/Documentation/unicorn.1.txt +0 -178
- data/Documentation/unicorn_rails.1.txt +0 -175
- data/examples/git.ru +0 -13
- data/lib/unicorn/app/exec_cgi.rb +0 -154
- data/lib/unicorn/app/inetd.rb +0 -109
- data/lib/unicorn/ssl_client.rb +0 -11
- data/lib/unicorn/ssl_configurator.rb +0 -104
- data/lib/unicorn/ssl_server.rb +0 -42
- data/local.mk.sample +0 -59
- data/script/isolate_for_tests +0 -32
- data/t/hijack.ru +0 -42
- data/t/sslgen.sh +0 -71
- data/t/t0016-trust-x-forwarded-false.sh +0 -30
- data/t/t0017-trust-x-forwarded-true.sh +0 -30
- data/t/t0200-rack-hijack.sh +0 -27
- data/t/t0600-https-server-basic.sh +0 -48
- data/test/unit/test_http_parser_xftrust.rb +0 -38
- data/test/unit/test_sni_hostnames.rb +0 -47
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
#include "common_field_optimization.h"
|
|
13
13
|
#include "global_variables.h"
|
|
14
14
|
#include "c_util.h"
|
|
15
|
+
#include "epollexclusive.h"
|
|
15
16
|
|
|
16
17
|
void init_unicorn_httpdate(void);
|
|
17
18
|
|
|
@@ -25,86 +26,33 @@ void init_unicorn_httpdate(void);
|
|
|
25
26
|
#define UH_FL_KAVERSION 0x80
|
|
26
27
|
#define UH_FL_HASHEADER 0x100
|
|
27
28
|
#define UH_FL_TO_CLEAR 0x200
|
|
29
|
+
#define UH_FL_RESSTART 0x400 /* for check_client_connection */
|
|
30
|
+
#define UH_FL_HIJACK 0x800
|
|
28
31
|
|
|
29
32
|
/* all of these flags need to be set for keepalive to be supported */
|
|
30
33
|
#define UH_FL_KEEPALIVE (UH_FL_KAVERSION | UH_FL_REQEOF | UH_FL_HASHEADER)
|
|
31
34
|
|
|
32
|
-
/*
|
|
33
|
-
* whether or not to trust X-Forwarded-Proto and X-Forwarded-SSL when
|
|
34
|
-
* setting rack.url_scheme
|
|
35
|
-
*/
|
|
36
|
-
static VALUE trust_x_forward = Qtrue;
|
|
37
|
-
|
|
38
|
-
static unsigned long keepalive_requests = 100; /* same as nginx */
|
|
39
|
-
|
|
40
|
-
/*
|
|
41
|
-
* Returns the maximum number of keepalive requests a client may make
|
|
42
|
-
* before the parser refuses to continue.
|
|
43
|
-
*/
|
|
44
|
-
static VALUE ka_req(VALUE self)
|
|
45
|
-
{
|
|
46
|
-
return ULONG2NUM(keepalive_requests);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/*
|
|
50
|
-
* Sets the maximum number of keepalive requests a client may make.
|
|
51
|
-
* A special value of +nil+ causes this to be the maximum value
|
|
52
|
-
* possible (this is architecture-dependent).
|
|
53
|
-
*/
|
|
54
|
-
static VALUE set_ka_req(VALUE self, VALUE val)
|
|
55
|
-
{
|
|
56
|
-
keepalive_requests = NIL_P(val) ? ULONG_MAX : NUM2ULONG(val);
|
|
57
|
-
|
|
58
|
-
return ka_req(self);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/*
|
|
62
|
-
* Sets whether or not the parser will trust X-Forwarded-Proto and
|
|
63
|
-
* X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly.
|
|
64
|
-
* Rainbows!/Zbatery installations facing untrusted clients directly
|
|
65
|
-
* should set this to +false+
|
|
66
|
-
*/
|
|
67
|
-
static VALUE set_xftrust(VALUE self, VALUE val)
|
|
68
|
-
{
|
|
69
|
-
if (Qtrue == val || Qfalse == val)
|
|
70
|
-
trust_x_forward = val;
|
|
71
|
-
else
|
|
72
|
-
rb_raise(rb_eTypeError, "must be true or false");
|
|
73
|
-
|
|
74
|
-
return val;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/*
|
|
78
|
-
* returns whether or not the parser will trust X-Forwarded-Proto and
|
|
79
|
-
* X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly
|
|
80
|
-
*/
|
|
81
|
-
static VALUE xftrust(VALUE self)
|
|
82
|
-
{
|
|
83
|
-
return trust_x_forward;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
static size_t MAX_HEADER_LEN = 1024 * (80 + 32); /* same as Mongrel */
|
|
35
|
+
static unsigned int MAX_HEADER_LEN = 1024 * (80 + 32); /* same as Mongrel */
|
|
87
36
|
|
|
88
37
|
/* this is only intended for use with Rainbows! */
|
|
89
38
|
static VALUE set_maxhdrlen(VALUE self, VALUE len)
|
|
90
39
|
{
|
|
91
|
-
return
|
|
40
|
+
return UINT2NUM(MAX_HEADER_LEN = NUM2UINT(len));
|
|
92
41
|
}
|
|
93
42
|
|
|
94
|
-
/* keep this small for
|
|
43
|
+
/* keep this small for other servers (e.g. yahns) since every client has one */
|
|
95
44
|
struct http_parser {
|
|
96
45
|
int cs; /* Ragel internal state */
|
|
97
46
|
unsigned int flags;
|
|
98
|
-
unsigned
|
|
99
|
-
|
|
100
|
-
size_t offset;
|
|
47
|
+
unsigned int mark;
|
|
48
|
+
unsigned int offset;
|
|
101
49
|
union { /* these 2 fields don't nest */
|
|
102
|
-
|
|
103
|
-
|
|
50
|
+
unsigned int field;
|
|
51
|
+
unsigned int query;
|
|
104
52
|
} start;
|
|
105
53
|
union {
|
|
106
|
-
|
|
107
|
-
|
|
54
|
+
unsigned int field_len; /* only used during header processing */
|
|
55
|
+
unsigned int dest_offset; /* only used during body processing */
|
|
108
56
|
} s;
|
|
109
57
|
VALUE buf;
|
|
110
58
|
VALUE env;
|
|
@@ -115,7 +63,8 @@ struct http_parser {
|
|
|
115
63
|
} len;
|
|
116
64
|
};
|
|
117
65
|
|
|
118
|
-
static ID
|
|
66
|
+
static ID id_set_backtrace, id_is_chunked_p;
|
|
67
|
+
static VALUE cHttpParser;
|
|
119
68
|
|
|
120
69
|
static void finalize_header(struct http_parser *hp);
|
|
121
70
|
|
|
@@ -124,13 +73,25 @@ static void parser_raise(VALUE klass, const char *msg)
|
|
|
124
73
|
VALUE exc = rb_exc_new2(klass, msg);
|
|
125
74
|
VALUE bt = rb_ary_new();
|
|
126
75
|
|
|
127
|
-
|
|
128
|
-
|
|
76
|
+
rb_funcall(exc, id_set_backtrace, 1, bt);
|
|
77
|
+
rb_exc_raise(exc);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static inline unsigned int ulong2uint(unsigned long n)
|
|
81
|
+
{
|
|
82
|
+
unsigned int i = (unsigned int)n;
|
|
83
|
+
|
|
84
|
+
if (sizeof(unsigned int) != sizeof(unsigned long)) {
|
|
85
|
+
if ((unsigned long)i != n) {
|
|
86
|
+
rb_raise(rb_eRangeError, "too large to be 32-bit uint: %lu", n);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return i;
|
|
129
90
|
}
|
|
130
91
|
|
|
131
92
|
#define REMAINING (unsigned long)(pe - p)
|
|
132
|
-
#define LEN(AT, FPC) (FPC - buffer - hp->AT)
|
|
133
|
-
#define MARK(M,FPC) (hp->M = (FPC) - buffer)
|
|
93
|
+
#define LEN(AT, FPC) (ulong2uint(FPC - buffer) - hp->AT)
|
|
94
|
+
#define MARK(M,FPC) (hp->M = ulong2uint((FPC) - buffer))
|
|
134
95
|
#define PTR_TO(F) (buffer + hp->F)
|
|
135
96
|
#define STR_NEW(M,FPC) rb_str_new(PTR_TO(M), LEN(M, FPC))
|
|
136
97
|
#define STRIPPED_STR_NEW(M,FPC) stripped_str_new(PTR_TO(M), LEN(M, FPC))
|
|
@@ -249,6 +210,19 @@ static void write_cont_value(struct http_parser *hp,
|
|
|
249
210
|
rb_str_buf_cat(hp->cont, vptr, end + 1);
|
|
250
211
|
}
|
|
251
212
|
|
|
213
|
+
static int is_chunked(VALUE v)
|
|
214
|
+
{
|
|
215
|
+
/* common case first */
|
|
216
|
+
if (STR_CSTR_CASE_EQ(v, "chunked"))
|
|
217
|
+
return 1;
|
|
218
|
+
|
|
219
|
+
/*
|
|
220
|
+
* call Ruby function in unicorn/http_request.rb to deal with unlikely
|
|
221
|
+
* comma-delimited case
|
|
222
|
+
*/
|
|
223
|
+
return rb_funcall(cHttpParser, id_is_chunked_p, 1, v) != Qfalse;
|
|
224
|
+
}
|
|
225
|
+
|
|
252
226
|
static void write_value(struct http_parser *hp,
|
|
253
227
|
const char *buffer, const char *p)
|
|
254
228
|
{
|
|
@@ -275,7 +249,9 @@ static void write_value(struct http_parser *hp,
|
|
|
275
249
|
f = uncommon_field(field, flen);
|
|
276
250
|
} else if (f == g_http_connection) {
|
|
277
251
|
hp_keepalive_connection(hp, v);
|
|
278
|
-
} else if (f == g_content_length) {
|
|
252
|
+
} else if (f == g_content_length && !HP_FL_TEST(hp, CHUNKED)) {
|
|
253
|
+
if (hp->len.content)
|
|
254
|
+
parser_raise(eHttpParserError, "Content-Length already set");
|
|
279
255
|
hp->len.content = parse_length(RSTRING_PTR(v), RSTRING_LEN(v));
|
|
280
256
|
if (hp->len.content < 0)
|
|
281
257
|
parser_raise(eHttpParserError, "invalid Content-Length");
|
|
@@ -283,9 +259,30 @@ static void write_value(struct http_parser *hp,
|
|
|
283
259
|
HP_FL_SET(hp, HASBODY);
|
|
284
260
|
hp_invalid_if_trailer(hp);
|
|
285
261
|
} else if (f == g_http_transfer_encoding) {
|
|
286
|
-
if (
|
|
262
|
+
if (is_chunked(v)) {
|
|
263
|
+
if (HP_FL_TEST(hp, CHUNKED))
|
|
264
|
+
/*
|
|
265
|
+
* RFC 7230 3.3.1:
|
|
266
|
+
* A sender MUST NOT apply chunked more than once to a message body
|
|
267
|
+
* (i.e., chunking an already chunked message is not allowed).
|
|
268
|
+
*/
|
|
269
|
+
parser_raise(eHttpParserError, "Transfer-Encoding double chunked");
|
|
270
|
+
|
|
287
271
|
HP_FL_SET(hp, CHUNKED);
|
|
288
272
|
HP_FL_SET(hp, HASBODY);
|
|
273
|
+
|
|
274
|
+
/* RFC 7230 3.3.3, 3: favor chunked if Content-Length exists */
|
|
275
|
+
hp->len.content = 0;
|
|
276
|
+
} else if (HP_FL_TEST(hp, CHUNKED)) {
|
|
277
|
+
/*
|
|
278
|
+
* RFC 7230 3.3.3, point 3 states:
|
|
279
|
+
* If a Transfer-Encoding header field is present in a request and
|
|
280
|
+
* the chunked transfer coding is not the final encoding, the
|
|
281
|
+
* message body length cannot be determined reliably; the server
|
|
282
|
+
* MUST respond with the 400 (Bad Request) status code and then
|
|
283
|
+
* close the connection.
|
|
284
|
+
*/
|
|
285
|
+
parser_raise(eHttpParserError, "invalid Transfer-Encoding");
|
|
289
286
|
}
|
|
290
287
|
hp_invalid_if_trailer(hp);
|
|
291
288
|
} else if (f == g_http_trailer) {
|
|
@@ -466,17 +463,37 @@ http_parser_execute(struct http_parser *hp, char *buffer, size_t len)
|
|
|
466
463
|
post_exec: /* "_out:" also goes here */
|
|
467
464
|
if (hp->cs != http_parser_error)
|
|
468
465
|
hp->cs = cs;
|
|
469
|
-
hp->offset = p - buffer;
|
|
466
|
+
hp->offset = ulong2uint(p - buffer);
|
|
470
467
|
|
|
471
468
|
assert(p <= pe && "buffer overflow after parsing execute");
|
|
472
469
|
assert(hp->offset <= len && "offset longer than length");
|
|
473
470
|
}
|
|
474
471
|
|
|
472
|
+
static void hp_mark(void *ptr)
|
|
473
|
+
{
|
|
474
|
+
struct http_parser *hp = ptr;
|
|
475
|
+
|
|
476
|
+
rb_gc_mark(hp->buf);
|
|
477
|
+
rb_gc_mark(hp->env);
|
|
478
|
+
rb_gc_mark(hp->cont);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
static size_t hp_memsize(const void *ptr)
|
|
482
|
+
{
|
|
483
|
+
return sizeof(struct http_parser);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
static const rb_data_type_t hp_type = {
|
|
487
|
+
"unicorn_http",
|
|
488
|
+
{ hp_mark, RUBY_TYPED_DEFAULT_FREE, hp_memsize, /* reserved */ },
|
|
489
|
+
/* parent, data, [ flags ] */
|
|
490
|
+
};
|
|
491
|
+
|
|
475
492
|
static struct http_parser *data_get(VALUE self)
|
|
476
493
|
{
|
|
477
494
|
struct http_parser *hp;
|
|
478
495
|
|
|
479
|
-
|
|
496
|
+
TypedData_Get_Struct(self, struct http_parser, &hp_type, hp);
|
|
480
497
|
assert(hp && "failed to extract http_parser struct");
|
|
481
498
|
return hp;
|
|
482
499
|
}
|
|
@@ -491,26 +508,29 @@ static void set_url_scheme(VALUE env, VALUE *server_port)
|
|
|
491
508
|
VALUE scheme = rb_hash_aref(env, g_rack_url_scheme);
|
|
492
509
|
|
|
493
510
|
if (NIL_P(scheme)) {
|
|
494
|
-
|
|
495
|
-
|
|
511
|
+
/*
|
|
512
|
+
* would anybody be horribly opposed to removing the X-Forwarded-SSL
|
|
513
|
+
* and X-Forwarded-Proto handling from this parser? We've had it
|
|
514
|
+
* forever and nobody has said anything against it, either.
|
|
515
|
+
* Anyways, please send comments to our public mailing list:
|
|
516
|
+
* unicorn-public@yhbt.net (no HTML mail, no subscription necessary)
|
|
517
|
+
*/
|
|
518
|
+
scheme = rb_hash_aref(env, g_http_x_forwarded_ssl);
|
|
519
|
+
if (!NIL_P(scheme) && STR_CSTR_EQ(scheme, "on")) {
|
|
520
|
+
*server_port = g_port_443;
|
|
521
|
+
scheme = g_https;
|
|
496
522
|
} else {
|
|
497
|
-
scheme = rb_hash_aref(env,
|
|
498
|
-
if (
|
|
499
|
-
|
|
500
|
-
scheme = g_https;
|
|
523
|
+
scheme = rb_hash_aref(env, g_http_x_forwarded_proto);
|
|
524
|
+
if (NIL_P(scheme)) {
|
|
525
|
+
scheme = g_http;
|
|
501
526
|
} else {
|
|
502
|
-
|
|
503
|
-
if (
|
|
504
|
-
|
|
527
|
+
long len = RSTRING_LEN(scheme);
|
|
528
|
+
if (len >= 5 && !memcmp(RSTRING_PTR(scheme), "https", 5)) {
|
|
529
|
+
if (len != 5)
|
|
530
|
+
scheme = g_https;
|
|
531
|
+
*server_port = g_port_443;
|
|
505
532
|
} else {
|
|
506
|
-
|
|
507
|
-
if (len >= 5 && !memcmp(RSTRING_PTR(scheme), "https", 5)) {
|
|
508
|
-
if (len != 5)
|
|
509
|
-
scheme = g_https;
|
|
510
|
-
*server_port = g_port_443;
|
|
511
|
-
} else {
|
|
512
|
-
scheme = g_http;
|
|
513
|
-
}
|
|
533
|
+
scheme = g_http;
|
|
514
534
|
}
|
|
515
535
|
}
|
|
516
536
|
}
|
|
@@ -579,21 +599,12 @@ static void finalize_header(struct http_parser *hp)
|
|
|
579
599
|
rb_hash_aset(hp->env, g_query_string, rb_str_new(NULL, 0));
|
|
580
600
|
}
|
|
581
601
|
|
|
582
|
-
static void hp_mark(void *ptr)
|
|
583
|
-
{
|
|
584
|
-
struct http_parser *hp = ptr;
|
|
585
|
-
|
|
586
|
-
rb_gc_mark(hp->buf);
|
|
587
|
-
rb_gc_mark(hp->env);
|
|
588
|
-
rb_gc_mark(hp->cont);
|
|
589
|
-
}
|
|
590
|
-
|
|
591
602
|
static VALUE HttpParser_alloc(VALUE klass)
|
|
592
603
|
{
|
|
593
604
|
struct http_parser *hp;
|
|
594
|
-
return Data_Make_Struct(klass, struct http_parser, hp_mark, -1, hp);
|
|
595
|
-
}
|
|
596
605
|
|
|
606
|
+
return TypedData_Make_Struct(klass, struct http_parser, &hp_type, hp);
|
|
607
|
+
}
|
|
597
608
|
|
|
598
609
|
/**
|
|
599
610
|
* call-seq:
|
|
@@ -608,7 +619,6 @@ static VALUE HttpParser_init(VALUE self)
|
|
|
608
619
|
http_parser_init(hp);
|
|
609
620
|
hp->buf = rb_str_new(NULL, 0);
|
|
610
621
|
hp->env = rb_hash_new();
|
|
611
|
-
hp->nr_requests = keepalive_requests;
|
|
612
622
|
|
|
613
623
|
return self;
|
|
614
624
|
}
|
|
@@ -624,62 +634,16 @@ static VALUE HttpParser_clear(VALUE self)
|
|
|
624
634
|
{
|
|
625
635
|
struct http_parser *hp = data_get(self);
|
|
626
636
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
return self;
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* call-seq:
|
|
636
|
-
* parser.dechunk! => parser
|
|
637
|
-
*
|
|
638
|
-
* Resets the parser to a state suitable for dechunking response bodies
|
|
639
|
-
*
|
|
640
|
-
*/
|
|
641
|
-
static VALUE HttpParser_dechunk_bang(VALUE self)
|
|
642
|
-
{
|
|
643
|
-
struct http_parser *hp = data_get(self);
|
|
637
|
+
/* we can't safely reuse .buf and .env if hijacked */
|
|
638
|
+
if (HP_FL_TEST(hp, HIJACK))
|
|
639
|
+
return HttpParser_init(self);
|
|
644
640
|
|
|
645
641
|
http_parser_init(hp);
|
|
646
|
-
|
|
647
|
-
/*
|
|
648
|
-
* we don't care about trailers in dechunk-only mode,
|
|
649
|
-
* but if we did we'd set UH_FL_HASTRAILER and clear hp->env
|
|
650
|
-
*/
|
|
651
|
-
if (0) {
|
|
652
|
-
rb_funcall(hp->env, id_clear, 0);
|
|
653
|
-
hp->flags = UH_FL_HASTRAILER;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
hp->flags |= UH_FL_HASBODY | UH_FL_INBODY | UH_FL_CHUNKED;
|
|
657
|
-
hp->cs = http_parser_en_ChunkedBody;
|
|
642
|
+
rb_hash_clear(hp->env);
|
|
658
643
|
|
|
659
644
|
return self;
|
|
660
645
|
}
|
|
661
646
|
|
|
662
|
-
/**
|
|
663
|
-
* call-seq:
|
|
664
|
-
* parser.reset => nil
|
|
665
|
-
*
|
|
666
|
-
* Resets the parser to it's initial state so that you can reuse it
|
|
667
|
-
* rather than making new ones.
|
|
668
|
-
*
|
|
669
|
-
* This method is deprecated and to be removed in Unicorn 4.x
|
|
670
|
-
*/
|
|
671
|
-
static VALUE HttpParser_reset(VALUE self)
|
|
672
|
-
{
|
|
673
|
-
static int warned;
|
|
674
|
-
|
|
675
|
-
if (!warned) {
|
|
676
|
-
rb_warn("Unicorn::HttpParser#reset is deprecated; "
|
|
677
|
-
"use Unicorn::HttpParser#clear instead");
|
|
678
|
-
}
|
|
679
|
-
HttpParser_clear(self);
|
|
680
|
-
return Qnil;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
647
|
static void advance_str(VALUE str, off_t nr)
|
|
684
648
|
{
|
|
685
649
|
long len = RSTRING_LEN(str);
|
|
@@ -842,15 +806,13 @@ static VALUE HttpParser_keepalive(VALUE self)
|
|
|
842
806
|
* parser.next? => true or false
|
|
843
807
|
*
|
|
844
808
|
* Exactly like HttpParser#keepalive?, except it will reset the internal
|
|
845
|
-
* parser state on next parse if it returns true.
|
|
846
|
-
* the maximum *keepalive_requests* value and return false if that is
|
|
847
|
-
* reached.
|
|
809
|
+
* parser state on next parse if it returns true.
|
|
848
810
|
*/
|
|
849
811
|
static VALUE HttpParser_next(VALUE self)
|
|
850
812
|
{
|
|
851
813
|
struct http_parser *hp = data_get(self);
|
|
852
814
|
|
|
853
|
-
if (
|
|
815
|
+
if (HP_FL_ALL(hp, KEEPALIVE)) {
|
|
854
816
|
HP_FL_SET(hp, TO_CLEAR);
|
|
855
817
|
return Qtrue;
|
|
856
818
|
}
|
|
@@ -882,6 +844,15 @@ static VALUE HttpParser_env(VALUE self)
|
|
|
882
844
|
return data_get(self)->env;
|
|
883
845
|
}
|
|
884
846
|
|
|
847
|
+
static VALUE HttpParser_hijacked_bang(VALUE self)
|
|
848
|
+
{
|
|
849
|
+
struct http_parser *hp = data_get(self);
|
|
850
|
+
|
|
851
|
+
HP_FL_SET(hp, HIJACK);
|
|
852
|
+
|
|
853
|
+
return self;
|
|
854
|
+
}
|
|
855
|
+
|
|
885
856
|
/**
|
|
886
857
|
* call-seq:
|
|
887
858
|
* parser.filter_body(dst, src) => nil/src
|
|
@@ -960,6 +931,25 @@ static VALUE HttpParser_filter_body(VALUE self, VALUE dst, VALUE src)
|
|
|
960
931
|
return src;
|
|
961
932
|
}
|
|
962
933
|
|
|
934
|
+
static VALUE HttpParser_rssset(VALUE self, VALUE boolean)
|
|
935
|
+
{
|
|
936
|
+
struct http_parser *hp = data_get(self);
|
|
937
|
+
|
|
938
|
+
if (RTEST(boolean))
|
|
939
|
+
HP_FL_SET(hp, RESSTART);
|
|
940
|
+
else
|
|
941
|
+
HP_FL_UNSET(hp, RESSTART);
|
|
942
|
+
|
|
943
|
+
return boolean; /* ignored by Ruby anyways */
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
static VALUE HttpParser_rssget(VALUE self)
|
|
947
|
+
{
|
|
948
|
+
struct http_parser *hp = data_get(self);
|
|
949
|
+
|
|
950
|
+
return HP_FL_TEST(hp, RESSTART) ? Qtrue : Qfalse;
|
|
951
|
+
}
|
|
952
|
+
|
|
963
953
|
#define SET_GLOBAL(var,str) do { \
|
|
964
954
|
var = find_common_field(str, sizeof(str) - 1); \
|
|
965
955
|
assert(!NIL_P(var) && "missed global field"); \
|
|
@@ -967,9 +957,9 @@ static VALUE HttpParser_filter_body(VALUE self, VALUE dst, VALUE src)
|
|
|
967
957
|
|
|
968
958
|
void Init_unicorn_http(void)
|
|
969
959
|
{
|
|
970
|
-
VALUE mUnicorn
|
|
960
|
+
VALUE mUnicorn;
|
|
971
961
|
|
|
972
|
-
mUnicorn =
|
|
962
|
+
mUnicorn = rb_define_module("Unicorn");
|
|
973
963
|
cHttpParser = rb_define_class_under(mUnicorn, "HttpParser", rb_cObject);
|
|
974
964
|
eHttpParserError =
|
|
975
965
|
rb_define_class_under(mUnicorn, "HttpParserError", rb_eIOError);
|
|
@@ -978,12 +968,11 @@ void Init_unicorn_http(void)
|
|
|
978
968
|
e414 = rb_define_class_under(mUnicorn, "RequestURITooLongError",
|
|
979
969
|
eHttpParserError);
|
|
980
970
|
|
|
971
|
+
id_uminus = rb_intern("-@");
|
|
981
972
|
init_globals();
|
|
982
973
|
rb_define_alloc_func(cHttpParser, HttpParser_alloc);
|
|
983
974
|
rb_define_method(cHttpParser, "initialize", HttpParser_init, 0);
|
|
984
975
|
rb_define_method(cHttpParser, "clear", HttpParser_clear, 0);
|
|
985
|
-
rb_define_method(cHttpParser, "reset", HttpParser_reset, 0);
|
|
986
|
-
rb_define_method(cHttpParser, "dechunk!", HttpParser_dechunk_bang, 0);
|
|
987
976
|
rb_define_method(cHttpParser, "parse", HttpParser_parse, 0);
|
|
988
977
|
rb_define_method(cHttpParser, "add_parse", HttpParser_add_parse, 1);
|
|
989
978
|
rb_define_method(cHttpParser, "headers", HttpParser_headers, 2);
|
|
@@ -996,6 +985,9 @@ void Init_unicorn_http(void)
|
|
|
996
985
|
rb_define_method(cHttpParser, "next?", HttpParser_next, 0);
|
|
997
986
|
rb_define_method(cHttpParser, "buf", HttpParser_buf, 0);
|
|
998
987
|
rb_define_method(cHttpParser, "env", HttpParser_env, 0);
|
|
988
|
+
rb_define_method(cHttpParser, "hijacked!", HttpParser_hijacked_bang, 0);
|
|
989
|
+
rb_define_method(cHttpParser, "response_start_sent=", HttpParser_rssset, 1);
|
|
990
|
+
rb_define_method(cHttpParser, "response_start_sent", HttpParser_rssget, 0);
|
|
999
991
|
|
|
1000
992
|
/*
|
|
1001
993
|
* The maximum size a single chunk when using chunked transfer encoding.
|
|
@@ -1012,14 +1004,6 @@ void Init_unicorn_http(void)
|
|
|
1012
1004
|
*/
|
|
1013
1005
|
rb_define_const(cHttpParser, "LENGTH_MAX", OFFT2NUM(UH_OFF_T_MAX));
|
|
1014
1006
|
|
|
1015
|
-
/* default value for keepalive_requests */
|
|
1016
|
-
rb_define_const(cHttpParser, "KEEPALIVE_REQUESTS_DEFAULT",
|
|
1017
|
-
ULONG2NUM(keepalive_requests));
|
|
1018
|
-
|
|
1019
|
-
rb_define_singleton_method(cHttpParser, "keepalive_requests", ka_req, 0);
|
|
1020
|
-
rb_define_singleton_method(cHttpParser, "keepalive_requests=", set_ka_req, 1);
|
|
1021
|
-
rb_define_singleton_method(cHttpParser, "trust_x_forwarded=", set_xftrust, 1);
|
|
1022
|
-
rb_define_singleton_method(cHttpParser, "trust_x_forwarded?", xftrust, 0);
|
|
1023
1007
|
rb_define_singleton_method(cHttpParser, "max_header_len=", set_maxhdrlen, 1);
|
|
1024
1008
|
|
|
1025
1009
|
init_common_fields();
|
|
@@ -1028,9 +1012,14 @@ void Init_unicorn_http(void)
|
|
|
1028
1012
|
SET_GLOBAL(g_http_transfer_encoding, "TRANSFER_ENCODING");
|
|
1029
1013
|
SET_GLOBAL(g_content_length, "CONTENT_LENGTH");
|
|
1030
1014
|
SET_GLOBAL(g_http_connection, "CONNECTION");
|
|
1031
|
-
id_clear = rb_intern("clear");
|
|
1032
1015
|
id_set_backtrace = rb_intern("set_backtrace");
|
|
1033
|
-
id_response_start_sent = rb_intern("@response_start_sent");
|
|
1034
1016
|
init_unicorn_httpdate();
|
|
1017
|
+
|
|
1018
|
+
#ifndef HAVE_RB_HASH_CLEAR
|
|
1019
|
+
id_clear = rb_intern("clear");
|
|
1020
|
+
#endif
|
|
1021
|
+
id_is_chunked_p = rb_intern("is_chunked?");
|
|
1022
|
+
|
|
1023
|
+
init_epollexclusive(mUnicorn);
|
|
1035
1024
|
}
|
|
1036
1025
|
#undef SET_GLOBAL
|