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.
Files changed (95) hide show
  1. checksums.yaml +5 -5
  2. data/.gitattributes +5 -0
  3. data/.olddoc.yml +13 -6
  4. data/Application_Timeouts +7 -7
  5. data/DESIGN +2 -4
  6. data/Documentation/.gitignore +1 -3
  7. data/Documentation/unicorn.1 +222 -0
  8. data/Documentation/unicorn_rails.1 +207 -0
  9. data/FAQ +17 -8
  10. data/GIT-VERSION-GEN +1 -1
  11. data/GNUmakefile +121 -56
  12. data/HACKING +1 -2
  13. data/ISSUES +40 -41
  14. data/KNOWN_ISSUES +11 -11
  15. data/LICENSE +2 -2
  16. data/Links +24 -25
  17. data/PHILOSOPHY +0 -6
  18. data/README +46 -39
  19. data/SIGNALS +2 -2
  20. data/Sandbox +10 -9
  21. data/TODO +0 -2
  22. data/TUNING +30 -9
  23. data/archive/slrnpull.conf +1 -1
  24. data/bin/unicorn +4 -2
  25. data/bin/unicorn_rails +3 -3
  26. data/examples/big_app_gc.rb +1 -1
  27. data/examples/init.sh +36 -8
  28. data/examples/logrotate.conf +17 -2
  29. data/examples/nginx.conf +14 -14
  30. data/examples/unicorn.conf.minimal.rb +2 -2
  31. data/examples/unicorn.conf.rb +3 -6
  32. data/examples/unicorn.socket +11 -0
  33. data/examples/unicorn@.service +40 -0
  34. data/ext/unicorn_http/common_field_optimization.h +23 -5
  35. data/ext/unicorn_http/ext_help.h +0 -20
  36. data/ext/unicorn_http/extconf.rb +37 -1
  37. data/ext/unicorn_http/global_variables.h +1 -1
  38. data/ext/unicorn_http/httpdate.c +2 -2
  39. data/ext/unicorn_http/unicorn_http.rl +167 -170
  40. data/ext/unicorn_http/unicorn_http_common.rl +1 -1
  41. data/lib/unicorn.rb +66 -46
  42. data/lib/unicorn/configurator.rb +110 -44
  43. data/lib/unicorn/const.rb +2 -25
  44. data/lib/unicorn/http_request.rb +110 -31
  45. data/lib/unicorn/http_response.rb +17 -31
  46. data/lib/unicorn/http_server.rb +238 -157
  47. data/lib/unicorn/launcher.rb +1 -1
  48. data/lib/unicorn/oob_gc.rb +6 -6
  49. data/lib/unicorn/socket_helper.rb +58 -78
  50. data/lib/unicorn/stream_input.rb +8 -7
  51. data/lib/unicorn/tee_input.rb +8 -10
  52. data/lib/unicorn/tmpio.rb +8 -7
  53. data/lib/unicorn/util.rb +5 -4
  54. data/lib/unicorn/worker.rb +36 -23
  55. data/t/GNUmakefile +3 -72
  56. data/t/README +4 -4
  57. data/t/t0011-active-unix-socket.sh +1 -1
  58. data/t/t0012-reload-empty-config.sh +2 -1
  59. data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
  60. data/t/t0301.ru +13 -0
  61. data/t/test-lib.sh +2 -2
  62. data/test/benchmark/README +14 -4
  63. data/test/benchmark/ddstream.ru +50 -0
  64. data/test/benchmark/readinput.ru +40 -0
  65. data/test/benchmark/uconnect.perl +66 -0
  66. data/test/exec/test_exec.rb +73 -19
  67. data/test/test_helper.rb +40 -31
  68. data/test/unit/test_ccc.rb +91 -0
  69. data/test/unit/test_droplet.rb +1 -1
  70. data/test/unit/test_http_parser.rb +46 -16
  71. data/test/unit/test_http_parser_ng.rb +97 -114
  72. data/test/unit/test_request.rb +10 -10
  73. data/test/unit/test_response.rb +28 -16
  74. data/test/unit/test_server.rb +86 -12
  75. data/test/unit/test_signals.rb +8 -8
  76. data/test/unit/test_socket_helper.rb +14 -10
  77. data/test/unit/test_upload.rb +9 -14
  78. data/test/unit/test_util.rb +27 -2
  79. data/unicorn.gemspec +27 -19
  80. metadata +24 -45
  81. data/Documentation/GNUmakefile +0 -30
  82. data/Documentation/unicorn.1.txt +0 -185
  83. data/Documentation/unicorn_rails.1.txt +0 -175
  84. data/examples/git.ru +0 -13
  85. data/lib/unicorn/app/exec_cgi.rb +0 -154
  86. data/lib/unicorn/app/inetd.rb +0 -109
  87. data/lib/unicorn/ssl_client.rb +0 -11
  88. data/lib/unicorn/ssl_configurator.rb +0 -104
  89. data/lib/unicorn/ssl_server.rb +0 -42
  90. data/t/hijack.ru +0 -42
  91. data/t/t0016-trust-x-forwarded-false.sh +0 -30
  92. data/t/t0017-trust-x-forwarded-true.sh +0 -30
  93. data/t/t0200-rack-hijack.sh +0 -27
  94. data/test/unit/test_http_parser_xftrust.rb +0 -38
  95. 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
- rb_global_variable(&g_##N); \
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.*/
@@ -66,11 +66,11 @@ static VALUE httpdate(VALUE self)
66
66
 
67
67
  void init_unicorn_httpdate(void)
68
68
  {
69
- VALUE mod = rb_const_get(rb_cObject, rb_intern("Unicorn"));
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
- rb_global_variable(&buf);
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 SIZET2NUM(MAX_HEADER_LEN = NUM2SIZET(len));
39
+ return UINT2NUM(MAX_HEADER_LEN = NUM2UINT(len));
92
40
  }
93
41
 
94
- /* keep this small for Rainbows! since every client has one */
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 long nr_requests;
99
- size_t mark;
100
- size_t offset;
46
+ unsigned int mark;
47
+ unsigned int offset;
101
48
  union { /* these 2 fields don't nest */
102
- size_t field;
103
- size_t query;
49
+ unsigned int field;
50
+ unsigned int query;
104
51
  } start;
105
52
  union {
106
- size_t field_len; /* only used during header processing */
107
- size_t dest_offset; /* only used during body processing */
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 id_clear, id_set_backtrace, id_response_start_sent;
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
- rb_funcall(exc, id_set_backtrace, 1, bt);
128
- rb_exc_raise(exc);
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 (STR_CSTR_CASE_EQ(v, "chunked")) {
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
- Data_Get_Struct(self, struct http_parser, hp);
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
- if (trust_x_forward == Qfalse) {
495
- scheme = g_http;
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, g_http_x_forwarded_ssl);
498
- if (!NIL_P(scheme) && STR_CSTR_EQ(scheme, "on")) {
499
- *server_port = g_port_443;
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
- scheme = rb_hash_aref(env, g_http_x_forwarded_proto);
503
- if (NIL_P(scheme)) {
504
- scheme = g_http;
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
- long len = RSTRING_LEN(scheme);
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
- http_parser_init(hp);
628
- rb_funcall(hp->env, id_clear, 0);
629
- rb_ivar_set(self, id_response_start_sent, Qfalse);
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. It will also respect
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 ((HP_FL_ALL(hp, KEEPALIVE)) && (hp->nr_requests-- != 0)) {
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, cHttpParser;
971
+ VALUE mUnicorn;
971
972
 
972
- mUnicorn = rb_const_get(rb_cObject, rb_intern("Unicorn"));
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