unicorn 4.9.0 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitattributes +5 -0
- data/.manifest +14 -15
- data/.olddoc.yml +16 -6
- 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 +17 -8
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +121 -56
- data/HACKING +2 -10
- data/ISSUES +40 -43
- data/KNOWN_ISSUES +11 -11
- data/LATEST +16 -22
- data/LICENSE +2 -2
- data/Links +24 -25
- data/NEWS +771 -0
- data/PHILOSOPHY +0 -6
- data/README +46 -40
- data/SIGNALS +2 -2
- data/Sandbox +11 -10
- data/TODO +0 -2
- data/TUNING +30 -9
- data/archive/slrnpull.conf +1 -1
- 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 +3 -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 -44
- 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 +255 -179
- data/lib/unicorn/launcher.rb +1 -1
- data/lib/unicorn/oob_gc.rb +6 -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 +8 -10
- data/lib/unicorn/tmpio.rb +8 -7
- 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 -46
- data/man/man1/unicorn.1 +123 -119
- data/man/man1/unicorn_rails.1 +106 -107
- data/t/GNUmakefile +3 -72
- data/t/README +4 -4
- 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 +73 -19
- data/test/test_helper.rb +40 -31
- data/test/unit/test_ccc.rb +91 -0
- data/test/unit/test_droplet.rb +1 -1
- data/test/unit/test_http_parser.rb +46 -16
- data/test/unit/test_http_parser_ng.rb +97 -114
- data/test/unit/test_request.rb +10 -10
- data/test/unit/test_response.rb +28 -16
- data/test/unit/test_server.rb +86 -12
- data/test/unit/test_signals.rb +8 -8
- data/test/unit/test_socket_helper.rb +14 -10
- data/test/unit/test_upload.rb +9 -14
- data/test/unit/test_util.rb +31 -5
- data/test/unit/test_waiter.rb +34 -0
- data/unicorn.gemspec +27 -19
- metadata +28 -45
- data/Documentation/GNUmakefile +0 -30
- data/Documentation/unicorn.1.txt +0 -185
- 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/t/hijack.ru +0 -42
- 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/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
|