unicorn 4.9.0 → 6.0.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 +5 -5
- data/.gitattributes +5 -0
- data/.olddoc.yml +13 -6
- data/Application_Timeouts +7 -7
- 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-GEN +1 -1
- data/GNUmakefile +121 -56
- data/HACKING +1 -2
- data/ISSUES +40 -41
- data/KNOWN_ISSUES +11 -11
- data/LICENSE +2 -2
- data/Links +24 -25
- data/PHILOSOPHY +0 -6
- data/README +46 -39
- data/SIGNALS +2 -2
- data/Sandbox +10 -9
- 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/common_field_optimization.h +23 -5
- data/ext/unicorn_http/ext_help.h +0 -20
- data/ext/unicorn_http/extconf.rb +37 -1
- data/ext/unicorn_http/global_variables.h +1 -1
- data/ext/unicorn_http/httpdate.c +2 -2
- data/ext/unicorn_http/unicorn_http.rl +167 -170
- data/ext/unicorn_http/unicorn_http_common.rl +1 -1
- data/lib/unicorn.rb +66 -46
- 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 +238 -157
- data/lib/unicorn/launcher.rb +1 -1
- data/lib/unicorn/oob_gc.rb +6 -6
- 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/worker.rb +36 -23
- 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 +2 -2
- 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 +27 -2
- data/unicorn.gemspec +27 -19
- metadata +24 -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
@@ -56,7 +56,7 @@ NORETURN(static void parser_raise(VALUE klass, const char *));
|
|
56
56
|
/** Defines global strings in the init method. */
|
57
57
|
#define DEF_GLOBAL(N, val) do { \
|
58
58
|
g_##N = rb_obj_freeze(rb_str_new(val, sizeof(val) - 1)); \
|
59
|
-
|
59
|
+
rb_gc_register_mark_object(g_##N); \
|
60
60
|
} while (0)
|
61
61
|
|
62
62
|
/* Defines the maximum allowed lengths for various input elements.*/
|
data/ext/unicorn_http/httpdate.c
CHANGED
@@ -66,11 +66,11 @@ static VALUE httpdate(VALUE self)
|
|
66
66
|
|
67
67
|
void init_unicorn_httpdate(void)
|
68
68
|
{
|
69
|
-
VALUE mod =
|
69
|
+
VALUE mod = rb_define_module("Unicorn");
|
70
70
|
mod = rb_define_module_under(mod, "HttpResponse");
|
71
71
|
|
72
72
|
buf = rb_str_new(0, buf_capa - 1);
|
73
|
-
|
73
|
+
rb_gc_register_mark_object(buf);
|
74
74
|
buf_ptr = RSTRING_PTR(buf);
|
75
75
|
httpdate(Qnil);
|
76
76
|
|
@@ -25,86 +25,33 @@ void init_unicorn_httpdate(void);
|
|
25
25
|
#define UH_FL_KAVERSION 0x80
|
26
26
|
#define UH_FL_HASHEADER 0x100
|
27
27
|
#define UH_FL_TO_CLEAR 0x200
|
28
|
+
#define UH_FL_RESSTART 0x400 /* for check_client_connection */
|
29
|
+
#define UH_FL_HIJACK 0x800
|
28
30
|
|
29
31
|
/* all of these flags need to be set for keepalive to be supported */
|
30
32
|
#define UH_FL_KEEPALIVE (UH_FL_KAVERSION | UH_FL_REQEOF | UH_FL_HASHEADER)
|
31
33
|
|
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 */
|
34
|
+
static unsigned int MAX_HEADER_LEN = 1024 * (80 + 32); /* same as Mongrel */
|
87
35
|
|
88
36
|
/* this is only intended for use with Rainbows! */
|
89
37
|
static VALUE set_maxhdrlen(VALUE self, VALUE len)
|
90
38
|
{
|
91
|
-
return
|
39
|
+
return UINT2NUM(MAX_HEADER_LEN = NUM2UINT(len));
|
92
40
|
}
|
93
41
|
|
94
|
-
/* keep this small for
|
42
|
+
/* keep this small for other servers (e.g. yahns) since every client has one */
|
95
43
|
struct http_parser {
|
96
44
|
int cs; /* Ragel internal state */
|
97
45
|
unsigned int flags;
|
98
|
-
unsigned
|
99
|
-
|
100
|
-
size_t offset;
|
46
|
+
unsigned int mark;
|
47
|
+
unsigned int offset;
|
101
48
|
union { /* these 2 fields don't nest */
|
102
|
-
|
103
|
-
|
49
|
+
unsigned int field;
|
50
|
+
unsigned int query;
|
104
51
|
} start;
|
105
52
|
union {
|
106
|
-
|
107
|
-
|
53
|
+
unsigned int field_len; /* only used during header processing */
|
54
|
+
unsigned int dest_offset; /* only used during body processing */
|
108
55
|
} s;
|
109
56
|
VALUE buf;
|
110
57
|
VALUE env;
|
@@ -115,7 +62,20 @@ struct http_parser {
|
|
115
62
|
} len;
|
116
63
|
};
|
117
64
|
|
118
|
-
static ID
|
65
|
+
static ID id_set_backtrace, id_is_chunked_p;
|
66
|
+
static VALUE cHttpParser;
|
67
|
+
|
68
|
+
#ifdef HAVE_RB_HASH_CLEAR /* Ruby >= 2.0 */
|
69
|
+
# define my_hash_clear(h) (void)rb_hash_clear(h)
|
70
|
+
#else /* !HAVE_RB_HASH_CLEAR - Ruby <= 1.9.3 */
|
71
|
+
|
72
|
+
static ID id_clear;
|
73
|
+
|
74
|
+
static void my_hash_clear(VALUE h)
|
75
|
+
{
|
76
|
+
rb_funcall(h, id_clear, 0);
|
77
|
+
}
|
78
|
+
#endif /* HAVE_RB_HASH_CLEAR */
|
119
79
|
|
120
80
|
static void finalize_header(struct http_parser *hp);
|
121
81
|
|
@@ -124,13 +84,25 @@ static void parser_raise(VALUE klass, const char *msg)
|
|
124
84
|
VALUE exc = rb_exc_new2(klass, msg);
|
125
85
|
VALUE bt = rb_ary_new();
|
126
86
|
|
127
|
-
|
128
|
-
|
87
|
+
rb_funcall(exc, id_set_backtrace, 1, bt);
|
88
|
+
rb_exc_raise(exc);
|
89
|
+
}
|
90
|
+
|
91
|
+
static inline unsigned int ulong2uint(unsigned long n)
|
92
|
+
{
|
93
|
+
unsigned int i = (unsigned int)n;
|
94
|
+
|
95
|
+
if (sizeof(unsigned int) != sizeof(unsigned long)) {
|
96
|
+
if ((unsigned long)i != n) {
|
97
|
+
rb_raise(rb_eRangeError, "too large to be 32-bit uint: %lu", n);
|
98
|
+
}
|
99
|
+
}
|
100
|
+
return i;
|
129
101
|
}
|
130
102
|
|
131
103
|
#define REMAINING (unsigned long)(pe - p)
|
132
|
-
#define LEN(AT, FPC) (FPC - buffer - hp->AT)
|
133
|
-
#define MARK(M,FPC) (hp->M = (FPC) - buffer)
|
104
|
+
#define LEN(AT, FPC) (ulong2uint(FPC - buffer) - hp->AT)
|
105
|
+
#define MARK(M,FPC) (hp->M = ulong2uint((FPC) - buffer))
|
134
106
|
#define PTR_TO(F) (buffer + hp->F)
|
135
107
|
#define STR_NEW(M,FPC) rb_str_new(PTR_TO(M), LEN(M, FPC))
|
136
108
|
#define STRIPPED_STR_NEW(M,FPC) stripped_str_new(PTR_TO(M), LEN(M, FPC))
|
@@ -249,6 +221,19 @@ static void write_cont_value(struct http_parser *hp,
|
|
249
221
|
rb_str_buf_cat(hp->cont, vptr, end + 1);
|
250
222
|
}
|
251
223
|
|
224
|
+
static int is_chunked(VALUE v)
|
225
|
+
{
|
226
|
+
/* common case first */
|
227
|
+
if (STR_CSTR_CASE_EQ(v, "chunked"))
|
228
|
+
return 1;
|
229
|
+
|
230
|
+
/*
|
231
|
+
* call Ruby function in unicorn/http_request.rb to deal with unlikely
|
232
|
+
* comma-delimited case
|
233
|
+
*/
|
234
|
+
return rb_funcall(cHttpParser, id_is_chunked_p, 1, v) != Qfalse;
|
235
|
+
}
|
236
|
+
|
252
237
|
static void write_value(struct http_parser *hp,
|
253
238
|
const char *buffer, const char *p)
|
254
239
|
{
|
@@ -275,7 +260,9 @@ static void write_value(struct http_parser *hp,
|
|
275
260
|
f = uncommon_field(field, flen);
|
276
261
|
} else if (f == g_http_connection) {
|
277
262
|
hp_keepalive_connection(hp, v);
|
278
|
-
} else if (f == g_content_length) {
|
263
|
+
} else if (f == g_content_length && !HP_FL_TEST(hp, CHUNKED)) {
|
264
|
+
if (hp->len.content)
|
265
|
+
parser_raise(eHttpParserError, "Content-Length already set");
|
279
266
|
hp->len.content = parse_length(RSTRING_PTR(v), RSTRING_LEN(v));
|
280
267
|
if (hp->len.content < 0)
|
281
268
|
parser_raise(eHttpParserError, "invalid Content-Length");
|
@@ -283,9 +270,30 @@ static void write_value(struct http_parser *hp,
|
|
283
270
|
HP_FL_SET(hp, HASBODY);
|
284
271
|
hp_invalid_if_trailer(hp);
|
285
272
|
} else if (f == g_http_transfer_encoding) {
|
286
|
-
if (
|
273
|
+
if (is_chunked(v)) {
|
274
|
+
if (HP_FL_TEST(hp, CHUNKED))
|
275
|
+
/*
|
276
|
+
* RFC 7230 3.3.1:
|
277
|
+
* A sender MUST NOT apply chunked more than once to a message body
|
278
|
+
* (i.e., chunking an already chunked message is not allowed).
|
279
|
+
*/
|
280
|
+
parser_raise(eHttpParserError, "Transfer-Encoding double chunked");
|
281
|
+
|
287
282
|
HP_FL_SET(hp, CHUNKED);
|
288
283
|
HP_FL_SET(hp, HASBODY);
|
284
|
+
|
285
|
+
/* RFC 7230 3.3.3, 3: favor chunked if Content-Length exists */
|
286
|
+
hp->len.content = 0;
|
287
|
+
} else if (HP_FL_TEST(hp, CHUNKED)) {
|
288
|
+
/*
|
289
|
+
* RFC 7230 3.3.3, point 3 states:
|
290
|
+
* If a Transfer-Encoding header field is present in a request and
|
291
|
+
* the chunked transfer coding is not the final encoding, the
|
292
|
+
* message body length cannot be determined reliably; the server
|
293
|
+
* MUST respond with the 400 (Bad Request) status code and then
|
294
|
+
* close the connection.
|
295
|
+
*/
|
296
|
+
parser_raise(eHttpParserError, "invalid Transfer-Encoding");
|
289
297
|
}
|
290
298
|
hp_invalid_if_trailer(hp);
|
291
299
|
} else if (f == g_http_trailer) {
|
@@ -466,17 +474,37 @@ http_parser_execute(struct http_parser *hp, char *buffer, size_t len)
|
|
466
474
|
post_exec: /* "_out:" also goes here */
|
467
475
|
if (hp->cs != http_parser_error)
|
468
476
|
hp->cs = cs;
|
469
|
-
hp->offset = p - buffer;
|
477
|
+
hp->offset = ulong2uint(p - buffer);
|
470
478
|
|
471
479
|
assert(p <= pe && "buffer overflow after parsing execute");
|
472
480
|
assert(hp->offset <= len && "offset longer than length");
|
473
481
|
}
|
474
482
|
|
483
|
+
static void hp_mark(void *ptr)
|
484
|
+
{
|
485
|
+
struct http_parser *hp = ptr;
|
486
|
+
|
487
|
+
rb_gc_mark(hp->buf);
|
488
|
+
rb_gc_mark(hp->env);
|
489
|
+
rb_gc_mark(hp->cont);
|
490
|
+
}
|
491
|
+
|
492
|
+
static size_t hp_memsize(const void *ptr)
|
493
|
+
{
|
494
|
+
return sizeof(struct http_parser);
|
495
|
+
}
|
496
|
+
|
497
|
+
static const rb_data_type_t hp_type = {
|
498
|
+
"unicorn_http",
|
499
|
+
{ hp_mark, RUBY_TYPED_DEFAULT_FREE, hp_memsize, /* reserved */ },
|
500
|
+
/* parent, data, [ flags ] */
|
501
|
+
};
|
502
|
+
|
475
503
|
static struct http_parser *data_get(VALUE self)
|
476
504
|
{
|
477
505
|
struct http_parser *hp;
|
478
506
|
|
479
|
-
|
507
|
+
TypedData_Get_Struct(self, struct http_parser, &hp_type, hp);
|
480
508
|
assert(hp && "failed to extract http_parser struct");
|
481
509
|
return hp;
|
482
510
|
}
|
@@ -491,26 +519,29 @@ static void set_url_scheme(VALUE env, VALUE *server_port)
|
|
491
519
|
VALUE scheme = rb_hash_aref(env, g_rack_url_scheme);
|
492
520
|
|
493
521
|
if (NIL_P(scheme)) {
|
494
|
-
|
495
|
-
|
522
|
+
/*
|
523
|
+
* would anybody be horribly opposed to removing the X-Forwarded-SSL
|
524
|
+
* and X-Forwarded-Proto handling from this parser? We've had it
|
525
|
+
* forever and nobody has said anything against it, either.
|
526
|
+
* Anyways, please send comments to our public mailing list:
|
527
|
+
* unicorn-public@yhbt.net (no HTML mail, no subscription necessary)
|
528
|
+
*/
|
529
|
+
scheme = rb_hash_aref(env, g_http_x_forwarded_ssl);
|
530
|
+
if (!NIL_P(scheme) && STR_CSTR_EQ(scheme, "on")) {
|
531
|
+
*server_port = g_port_443;
|
532
|
+
scheme = g_https;
|
496
533
|
} else {
|
497
|
-
scheme = rb_hash_aref(env,
|
498
|
-
if (
|
499
|
-
|
500
|
-
scheme = g_https;
|
534
|
+
scheme = rb_hash_aref(env, g_http_x_forwarded_proto);
|
535
|
+
if (NIL_P(scheme)) {
|
536
|
+
scheme = g_http;
|
501
537
|
} else {
|
502
|
-
|
503
|
-
if (
|
504
|
-
|
538
|
+
long len = RSTRING_LEN(scheme);
|
539
|
+
if (len >= 5 && !memcmp(RSTRING_PTR(scheme), "https", 5)) {
|
540
|
+
if (len != 5)
|
541
|
+
scheme = g_https;
|
542
|
+
*server_port = g_port_443;
|
505
543
|
} 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
|
-
}
|
544
|
+
scheme = g_http;
|
514
545
|
}
|
515
546
|
}
|
516
547
|
}
|
@@ -579,21 +610,12 @@ static void finalize_header(struct http_parser *hp)
|
|
579
610
|
rb_hash_aset(hp->env, g_query_string, rb_str_new(NULL, 0));
|
580
611
|
}
|
581
612
|
|
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
613
|
static VALUE HttpParser_alloc(VALUE klass)
|
592
614
|
{
|
593
615
|
struct http_parser *hp;
|
594
|
-
return Data_Make_Struct(klass, struct http_parser, hp_mark, -1, hp);
|
595
|
-
}
|
596
616
|
|
617
|
+
return TypedData_Make_Struct(klass, struct http_parser, &hp_type, hp);
|
618
|
+
}
|
597
619
|
|
598
620
|
/**
|
599
621
|
* call-seq:
|
@@ -608,7 +630,6 @@ static VALUE HttpParser_init(VALUE self)
|
|
608
630
|
http_parser_init(hp);
|
609
631
|
hp->buf = rb_str_new(NULL, 0);
|
610
632
|
hp->env = rb_hash_new();
|
611
|
-
hp->nr_requests = keepalive_requests;
|
612
633
|
|
613
634
|
return self;
|
614
635
|
}
|
@@ -624,62 +645,16 @@ static VALUE HttpParser_clear(VALUE self)
|
|
624
645
|
{
|
625
646
|
struct http_parser *hp = data_get(self);
|
626
647
|
|
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);
|
648
|
+
/* we can't safely reuse .buf and .env if hijacked */
|
649
|
+
if (HP_FL_TEST(hp, HIJACK))
|
650
|
+
return HttpParser_init(self);
|
644
651
|
|
645
652
|
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;
|
653
|
+
my_hash_clear(hp->env);
|
658
654
|
|
659
655
|
return self;
|
660
656
|
}
|
661
657
|
|
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
658
|
static void advance_str(VALUE str, off_t nr)
|
684
659
|
{
|
685
660
|
long len = RSTRING_LEN(str);
|
@@ -842,15 +817,13 @@ static VALUE HttpParser_keepalive(VALUE self)
|
|
842
817
|
* parser.next? => true or false
|
843
818
|
*
|
844
819
|
* 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.
|
820
|
+
* parser state on next parse if it returns true.
|
848
821
|
*/
|
849
822
|
static VALUE HttpParser_next(VALUE self)
|
850
823
|
{
|
851
824
|
struct http_parser *hp = data_get(self);
|
852
825
|
|
853
|
-
if (
|
826
|
+
if (HP_FL_ALL(hp, KEEPALIVE)) {
|
854
827
|
HP_FL_SET(hp, TO_CLEAR);
|
855
828
|
return Qtrue;
|
856
829
|
}
|
@@ -882,6 +855,15 @@ static VALUE HttpParser_env(VALUE self)
|
|
882
855
|
return data_get(self)->env;
|
883
856
|
}
|
884
857
|
|
858
|
+
static VALUE HttpParser_hijacked_bang(VALUE self)
|
859
|
+
{
|
860
|
+
struct http_parser *hp = data_get(self);
|
861
|
+
|
862
|
+
HP_FL_SET(hp, HIJACK);
|
863
|
+
|
864
|
+
return self;
|
865
|
+
}
|
866
|
+
|
885
867
|
/**
|
886
868
|
* call-seq:
|
887
869
|
* parser.filter_body(dst, src) => nil/src
|
@@ -960,6 +942,25 @@ static VALUE HttpParser_filter_body(VALUE self, VALUE dst, VALUE src)
|
|
960
942
|
return src;
|
961
943
|
}
|
962
944
|
|
945
|
+
static VALUE HttpParser_rssset(VALUE self, VALUE boolean)
|
946
|
+
{
|
947
|
+
struct http_parser *hp = data_get(self);
|
948
|
+
|
949
|
+
if (RTEST(boolean))
|
950
|
+
HP_FL_SET(hp, RESSTART);
|
951
|
+
else
|
952
|
+
HP_FL_UNSET(hp, RESSTART);
|
953
|
+
|
954
|
+
return boolean; /* ignored by Ruby anyways */
|
955
|
+
}
|
956
|
+
|
957
|
+
static VALUE HttpParser_rssget(VALUE self)
|
958
|
+
{
|
959
|
+
struct http_parser *hp = data_get(self);
|
960
|
+
|
961
|
+
return HP_FL_TEST(hp, RESSTART) ? Qtrue : Qfalse;
|
962
|
+
}
|
963
|
+
|
963
964
|
#define SET_GLOBAL(var,str) do { \
|
964
965
|
var = find_common_field(str, sizeof(str) - 1); \
|
965
966
|
assert(!NIL_P(var) && "missed global field"); \
|
@@ -967,9 +968,9 @@ static VALUE HttpParser_filter_body(VALUE self, VALUE dst, VALUE src)
|
|
967
968
|
|
968
969
|
void Init_unicorn_http(void)
|
969
970
|
{
|
970
|
-
VALUE mUnicorn
|
971
|
+
VALUE mUnicorn;
|
971
972
|
|
972
|
-
mUnicorn =
|
973
|
+
mUnicorn = rb_define_module("Unicorn");
|
973
974
|
cHttpParser = rb_define_class_under(mUnicorn, "HttpParser", rb_cObject);
|
974
975
|
eHttpParserError =
|
975
976
|
rb_define_class_under(mUnicorn, "HttpParserError", rb_eIOError);
|
@@ -982,8 +983,6 @@ void Init_unicorn_http(void)
|
|
982
983
|
rb_define_alloc_func(cHttpParser, HttpParser_alloc);
|
983
984
|
rb_define_method(cHttpParser, "initialize", HttpParser_init, 0);
|
984
985
|
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
986
|
rb_define_method(cHttpParser, "parse", HttpParser_parse, 0);
|
988
987
|
rb_define_method(cHttpParser, "add_parse", HttpParser_add_parse, 1);
|
989
988
|
rb_define_method(cHttpParser, "headers", HttpParser_headers, 2);
|
@@ -996,6 +995,9 @@ void Init_unicorn_http(void)
|
|
996
995
|
rb_define_method(cHttpParser, "next?", HttpParser_next, 0);
|
997
996
|
rb_define_method(cHttpParser, "buf", HttpParser_buf, 0);
|
998
997
|
rb_define_method(cHttpParser, "env", HttpParser_env, 0);
|
998
|
+
rb_define_method(cHttpParser, "hijacked!", HttpParser_hijacked_bang, 0);
|
999
|
+
rb_define_method(cHttpParser, "response_start_sent=", HttpParser_rssset, 1);
|
1000
|
+
rb_define_method(cHttpParser, "response_start_sent", HttpParser_rssget, 0);
|
999
1001
|
|
1000
1002
|
/*
|
1001
1003
|
* The maximum size a single chunk when using chunked transfer encoding.
|
@@ -1012,14 +1014,6 @@ void Init_unicorn_http(void)
|
|
1012
1014
|
*/
|
1013
1015
|
rb_define_const(cHttpParser, "LENGTH_MAX", OFFT2NUM(UH_OFF_T_MAX));
|
1014
1016
|
|
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
1017
|
rb_define_singleton_method(cHttpParser, "max_header_len=", set_maxhdrlen, 1);
|
1024
1018
|
|
1025
1019
|
init_common_fields();
|
@@ -1028,9 +1022,12 @@ void Init_unicorn_http(void)
|
|
1028
1022
|
SET_GLOBAL(g_http_transfer_encoding, "TRANSFER_ENCODING");
|
1029
1023
|
SET_GLOBAL(g_content_length, "CONTENT_LENGTH");
|
1030
1024
|
SET_GLOBAL(g_http_connection, "CONNECTION");
|
1031
|
-
id_clear = rb_intern("clear");
|
1032
1025
|
id_set_backtrace = rb_intern("set_backtrace");
|
1033
|
-
id_response_start_sent = rb_intern("@response_start_sent");
|
1034
1026
|
init_unicorn_httpdate();
|
1027
|
+
|
1028
|
+
#ifndef HAVE_RB_HASH_CLEAR
|
1029
|
+
id_clear = rb_intern("clear");
|
1030
|
+
#endif
|
1031
|
+
id_is_chunked_p = rb_intern("is_chunked?");
|
1035
1032
|
}
|
1036
1033
|
#undef SET_GLOBAL
|