unicorn 2.0.0pre1 → 2.0.0pre2

Sign up to get free protection for your applications and to get access to all the features.
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v2.0.0pre1.GIT
4
+ DEF_VER=v2.0.0pre2.GIT
5
5
 
6
6
  LF='
7
7
  '
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ def tags
15
15
  timefmt = '%Y-%m-%dT%H:%M:%SZ'
16
16
  @tags ||= `git tag -l`.split(/\n/).map do |tag|
17
17
  next if tag == "v0.0.0"
18
- if %r{\Av[\d\.]+\z} =~ tag
18
+ if %r{\Av[\d\.]+} =~ tag
19
19
  header, subject, body = `git cat-file tag #{tag}`.split(/\n\n/, 3)
20
20
  header = header.split(/\n/)
21
21
  tagger = header.grep(/\Atagger /).first
data/bin/unicorn CHANGED
@@ -53,8 +53,8 @@ opts = OptionParser.new("", 24, ' ') do |opts|
53
53
  rackup_opts[:set_listener] = true
54
54
  end
55
55
 
56
- opts.on("-E", "--env ENVIRONMENT",
57
- "use ENVIRONMENT for defaults (default: development)") do |e|
56
+ opts.on("-E", "--env RACK_ENV",
57
+ "use RACK_ENV for defaults (default: development)") do |e|
58
58
  ENV["RACK_ENV"] = e
59
59
  end
60
60
 
@@ -8,10 +8,6 @@
8
8
  #define RSTRING_LEN(s) (RSTRING(s)->len)
9
9
  #endif /* !defined(RSTRING_LEN) */
10
10
 
11
- #ifndef RUBINIUS
12
- # define rb_str_update(x) do {} while (0)
13
- #endif /* !RUBINIUS */
14
-
15
11
  #ifndef HAVE_RB_STR_SET_LEN
16
12
  # ifdef RUBINIUS
17
13
  # error we should never get here with current Rubinius (1.x)
@@ -39,6 +39,8 @@ struct http_parser {
39
39
  size_t field_len; /* only used during header processing */
40
40
  size_t dest_offset; /* only used during body processing */
41
41
  } s;
42
+ VALUE buf;
43
+ VALUE env;
42
44
  VALUE cont; /* Qfalse: unset, Qnil: ignored header, T_STRING: append */
43
45
  union {
44
46
  off_t content;
@@ -46,7 +48,9 @@ struct http_parser {
46
48
  } len;
47
49
  };
48
50
 
49
- static void finalize_header(struct http_parser *hp, VALUE req);
51
+ static ID id_clear;
52
+
53
+ static void finalize_header(struct http_parser *hp);
50
54
 
51
55
  static void parser_error(const char *msg)
52
56
  {
@@ -97,7 +101,7 @@ static void hp_keepalive_connection(struct http_parser *hp, VALUE val)
97
101
  }
98
102
 
99
103
  static void
100
- request_method(struct http_parser *hp, VALUE req, const char *ptr, size_t len)
104
+ request_method(struct http_parser *hp, const char *ptr, size_t len)
101
105
  {
102
106
  VALUE v;
103
107
 
@@ -115,11 +119,11 @@ request_method(struct http_parser *hp, VALUE req, const char *ptr, size_t len)
115
119
  } else {
116
120
  v = rb_str_new(ptr, len);
117
121
  }
118
- rb_hash_aset(req, g_request_method, v);
122
+ rb_hash_aset(hp->env, g_request_method, v);
119
123
  }
120
124
 
121
125
  static void
122
- http_version(struct http_parser *hp, VALUE req, const char *ptr, size_t len)
126
+ http_version(struct http_parser *hp, const char *ptr, size_t len)
123
127
  {
124
128
  VALUE v;
125
129
 
@@ -134,8 +138,8 @@ http_version(struct http_parser *hp, VALUE req, const char *ptr, size_t len)
134
138
  } else {
135
139
  v = rb_str_new(ptr, len);
136
140
  }
137
- rb_hash_aset(req, g_server_protocol, v);
138
- rb_hash_aset(req, g_http_version, v);
141
+ rb_hash_aset(hp->env, g_server_protocol, v);
142
+ rb_hash_aset(hp->env, g_http_version, v);
139
143
  }
140
144
 
141
145
  static inline void hp_invalid_if_trailer(struct http_parser *hp)
@@ -172,7 +176,7 @@ static void write_cont_value(struct http_parser *hp,
172
176
  rb_str_buf_cat(hp->cont, vptr, LEN(mark, p));
173
177
  }
174
178
 
175
- static void write_value(VALUE req, struct http_parser *hp,
179
+ static void write_value(struct http_parser *hp,
176
180
  const char *buffer, const char *p)
177
181
  {
178
182
  VALUE f = find_common_field(PTR_TO(start.field), hp->s.field_len);
@@ -218,9 +222,9 @@ static void write_value(VALUE req, struct http_parser *hp,
218
222
  assert_frozen(f);
219
223
  }
220
224
 
221
- e = rb_hash_aref(req, f);
225
+ e = rb_hash_aref(hp->env, f);
222
226
  if (NIL_P(e)) {
223
- hp->cont = rb_hash_aset(req, f, v);
227
+ hp->cont = rb_hash_aset(hp->env, f, v);
224
228
  } else if (f == g_http_host) {
225
229
  /*
226
230
  * ignored, absolute URLs in REQUEST_URI take precedence over
@@ -245,51 +249,47 @@ static void write_value(VALUE req, struct http_parser *hp,
245
249
  action downcase_char { downcase_char(deconst(fpc)); }
246
250
  action write_field { hp->s.field_len = LEN(start.field, fpc); }
247
251
  action start_value { MARK(mark, fpc); }
248
- action write_value { write_value(req, hp, buffer, fpc); }
252
+ action write_value { write_value(hp, buffer, fpc); }
249
253
  action write_cont_value { write_cont_value(hp, buffer, fpc); }
250
- action request_method {
251
- request_method(hp, req, PTR_TO(mark), LEN(mark, fpc));
252
- }
254
+ action request_method { request_method(hp, PTR_TO(mark), LEN(mark, fpc)); }
253
255
  action scheme {
254
- rb_hash_aset(req, g_rack_url_scheme, STR_NEW(mark, fpc));
255
- }
256
- action host {
257
- rb_hash_aset(req, g_http_host, STR_NEW(mark, fpc));
256
+ rb_hash_aset(hp->env, g_rack_url_scheme, STR_NEW(mark, fpc));
258
257
  }
258
+ action host { rb_hash_aset(hp->env, g_http_host, STR_NEW(mark, fpc)); }
259
259
  action request_uri {
260
260
  VALUE str;
261
261
 
262
262
  VALIDATE_MAX_LENGTH(LEN(mark, fpc), REQUEST_URI);
263
- str = rb_hash_aset(req, g_request_uri, STR_NEW(mark, fpc));
263
+ str = rb_hash_aset(hp->env, g_request_uri, STR_NEW(mark, fpc));
264
264
  /*
265
265
  * "OPTIONS * HTTP/1.1\r\n" is a valid request, but we can't have '*'
266
266
  * in REQUEST_PATH or PATH_INFO or else Rack::Lint will complain
267
267
  */
268
268
  if (STR_CSTR_EQ(str, "*")) {
269
269
  str = rb_str_new(NULL, 0);
270
- rb_hash_aset(req, g_path_info, str);
271
- rb_hash_aset(req, g_request_path, str);
270
+ rb_hash_aset(hp->env, g_path_info, str);
271
+ rb_hash_aset(hp->env, g_request_path, str);
272
272
  }
273
273
  }
274
274
  action fragment {
275
275
  VALIDATE_MAX_LENGTH(LEN(mark, fpc), FRAGMENT);
276
- rb_hash_aset(req, g_fragment, STR_NEW(mark, fpc));
276
+ rb_hash_aset(hp->env, g_fragment, STR_NEW(mark, fpc));
277
277
  }
278
278
  action start_query {MARK(start.query, fpc); }
279
279
  action query_string {
280
280
  VALIDATE_MAX_LENGTH(LEN(start.query, fpc), QUERY_STRING);
281
- rb_hash_aset(req, g_query_string, STR_NEW(start.query, fpc));
281
+ rb_hash_aset(hp->env, g_query_string, STR_NEW(start.query, fpc));
282
282
  }
283
- action http_version { http_version(hp, req, PTR_TO(mark), LEN(mark, fpc)); }
283
+ action http_version { http_version(hp, PTR_TO(mark), LEN(mark, fpc)); }
284
284
  action request_path {
285
285
  VALUE val;
286
286
 
287
287
  VALIDATE_MAX_LENGTH(LEN(mark, fpc), REQUEST_PATH);
288
- val = rb_hash_aset(req, g_request_path, STR_NEW(mark, fpc));
288
+ val = rb_hash_aset(hp->env, g_request_path, STR_NEW(mark, fpc));
289
289
 
290
290
  /* rack says PATH_INFO must start with "/" or be empty */
291
291
  if (!STR_CSTR_EQ(val, "*"))
292
- rb_hash_aset(req, g_path_info, val);
292
+ rb_hash_aset(hp->env, g_path_info, val);
293
293
  }
294
294
  action add_to_chunk_size {
295
295
  hp->len.chunk = step_incr(hp->len.chunk, fc, 16);
@@ -297,7 +297,7 @@ static void write_value(VALUE req, struct http_parser *hp,
297
297
  parser_error("invalid chunk size");
298
298
  }
299
299
  action header_done {
300
- finalize_header(hp, req);
300
+ finalize_header(hp);
301
301
 
302
302
  cs = http_parser_first_final;
303
303
  if (HP_FL_TEST(hp, HASBODY)) {
@@ -330,7 +330,7 @@ static void write_value(VALUE req, struct http_parser *hp,
330
330
  action skip_chunk_data {
331
331
  skip_chunk_data_hack: {
332
332
  size_t nr = MIN((size_t)hp->len.chunk, REMAINING);
333
- memcpy(RSTRING_PTR(req) + hp->s.dest_offset, fpc, nr);
333
+ memcpy(RSTRING_PTR(hp->cont) + hp->s.dest_offset, fpc, nr);
334
334
  hp->s.dest_offset += nr;
335
335
  hp->len.chunk -= nr;
336
336
  p += nr;
@@ -353,15 +353,20 @@ static void write_value(VALUE req, struct http_parser *hp,
353
353
  static void http_parser_init(struct http_parser *hp)
354
354
  {
355
355
  int cs = 0;
356
- memset(hp, 0, sizeof(struct http_parser));
356
+ hp->flags = 0;
357
+ hp->mark = 0;
358
+ hp->offset = 0;
359
+ hp->start.field = 0;
360
+ hp->s.field_len = 0;
361
+ hp->len.content = 0;
357
362
  hp->cont = Qfalse; /* zero on MRI, should be optimized away by above */
358
363
  %% write init;
359
364
  hp->cs = cs;
360
365
  }
361
366
 
362
367
  /** exec **/
363
- static void http_parser_execute(struct http_parser *hp,
364
- VALUE req, char *buffer, size_t len)
368
+ static void
369
+ http_parser_execute(struct http_parser *hp, char *buffer, size_t len)
365
370
  {
366
371
  const char *p, *pe;
367
372
  int cs = hp->cs;
@@ -401,20 +406,20 @@ static struct http_parser *data_get(VALUE self)
401
406
  return hp;
402
407
  }
403
408
 
404
- static void finalize_header(struct http_parser *hp, VALUE req)
409
+ static void finalize_header(struct http_parser *hp)
405
410
  {
406
- VALUE temp = rb_hash_aref(req, g_rack_url_scheme);
411
+ VALUE temp = rb_hash_aref(hp->env, g_rack_url_scheme);
407
412
  VALUE server_name = g_localhost;
408
413
  VALUE server_port = g_port_80;
409
414
 
410
415
  /* set rack.url_scheme to "https" or "http", no others are allowed by Rack */
411
416
  if (NIL_P(temp)) {
412
- temp = rb_hash_aref(req, g_http_x_forwarded_proto);
417
+ temp = rb_hash_aref(hp->env, g_http_x_forwarded_proto);
413
418
  if (!NIL_P(temp) && STR_CSTR_EQ(temp, "https"))
414
419
  server_port = g_port_443;
415
420
  else
416
421
  temp = g_http;
417
- rb_hash_aset(req, g_rack_url_scheme, temp);
422
+ rb_hash_aset(hp->env, g_rack_url_scheme, temp);
418
423
  } else if (STR_CSTR_EQ(temp, "https")) {
419
424
  server_port = g_port_443;
420
425
  } else {
@@ -422,7 +427,7 @@ static void finalize_header(struct http_parser *hp, VALUE req)
422
427
  }
423
428
 
424
429
  /* parse and set the SERVER_NAME and SERVER_PORT variables */
425
- temp = rb_hash_aref(req, g_http_host);
430
+ temp = rb_hash_aref(hp->env, g_http_host);
426
431
  if (!NIL_P(temp)) {
427
432
  char *colon = memchr(RSTRING_PTR(temp), ':', RSTRING_LEN(temp));
428
433
  if (colon) {
@@ -435,20 +440,22 @@ static void finalize_header(struct http_parser *hp, VALUE req)
435
440
  server_name = temp;
436
441
  }
437
442
  }
438
- rb_hash_aset(req, g_server_name, server_name);
439
- rb_hash_aset(req, g_server_port, server_port);
443
+ rb_hash_aset(hp->env, g_server_name, server_name);
444
+ rb_hash_aset(hp->env, g_server_port, server_port);
440
445
  if (!HP_FL_TEST(hp, HASHEADER))
441
- rb_hash_aset(req, g_server_protocol, g_http_09);
446
+ rb_hash_aset(hp->env, g_server_protocol, g_http_09);
442
447
 
443
448
  /* rack requires QUERY_STRING */
444
- if (NIL_P(rb_hash_aref(req, g_query_string)))
445
- rb_hash_aset(req, g_query_string, rb_str_new(NULL, 0));
449
+ if (NIL_P(rb_hash_aref(hp->env, g_query_string)))
450
+ rb_hash_aset(hp->env, g_query_string, rb_str_new(NULL, 0));
446
451
  }
447
452
 
448
453
  static void hp_mark(void *ptr)
449
454
  {
450
455
  struct http_parser *hp = ptr;
451
456
 
457
+ rb_gc_mark(hp->buf);
458
+ rb_gc_mark(hp->env);
452
459
  rb_gc_mark(hp->cont);
453
460
  }
454
461
 
@@ -467,7 +474,11 @@ static VALUE HttpParser_alloc(VALUE klass)
467
474
  */
468
475
  static VALUE HttpParser_init(VALUE self)
469
476
  {
470
- http_parser_init(data_get(self));
477
+ struct http_parser *hp = data_get(self);
478
+
479
+ http_parser_init(hp);
480
+ hp->buf = rb_str_new(NULL, 0);
481
+ hp->env = rb_hash_new();
471
482
 
472
483
  return self;
473
484
  }
@@ -481,7 +492,11 @@ static VALUE HttpParser_init(VALUE self)
481
492
  */
482
493
  static VALUE HttpParser_reset(VALUE self)
483
494
  {
484
- http_parser_init(data_get(self));
495
+ struct http_parser *hp = data_get(self);
496
+
497
+ http_parser_init(hp);
498
+ rb_funcall(hp->env, id_clear, 0);
499
+ rb_str_set_len(hp->buf, 0);
485
500
 
486
501
  return Qnil;
487
502
  }
@@ -522,32 +537,23 @@ static VALUE HttpParser_content_length(VALUE self)
522
537
  }
523
538
 
524
539
  /**
525
- * Document-method: trailers
526
- * call-seq:
527
- * parser.trailers(req, data) => req or nil
528
- *
529
- * This is an alias for HttpParser#headers
530
- */
531
-
532
- /**
533
- * Document-method: headers
540
+ * Document-method: parse
534
541
  * call-seq:
535
- * parser.headers(req, data) => req or nil
542
+ * parser.parse => env or nil
536
543
  *
537
544
  * Takes a Hash and a String of data, parses the String of data filling
538
545
  * in the Hash returning the Hash if parsing is finished, nil otherwise
539
- * When returning the req Hash, it may modify data to point to where
546
+ * When returning the env Hash, it may modify data to point to where
540
547
  * body processing should begin.
541
548
  *
542
549
  * Raises HttpParserError if there are parsing errors.
543
550
  */
544
- static VALUE HttpParser_headers(VALUE self, VALUE req, VALUE data)
551
+ static VALUE HttpParser_parse(VALUE self)
545
552
  {
546
553
  struct http_parser *hp = data_get(self);
554
+ VALUE data = hp->buf;
547
555
 
548
- rb_str_update(data);
549
-
550
- http_parser_execute(hp, req, RSTRING_PTR(data), RSTRING_LEN(data));
556
+ http_parser_execute(hp, RSTRING_PTR(data), RSTRING_LEN(data));
551
557
  VALIDATE_MAX_LENGTH(hp->offset, HEADER);
552
558
 
553
559
  if (hp->cs == http_parser_first_final ||
@@ -555,7 +561,7 @@ static VALUE HttpParser_headers(VALUE self, VALUE req, VALUE data)
555
561
  advance_str(data, hp->offset + 1);
556
562
  hp->offset = 0;
557
563
 
558
- return req;
564
+ return hp->env;
559
565
  }
560
566
 
561
567
  if (hp->cs == http_parser_error)
@@ -564,6 +570,27 @@ static VALUE HttpParser_headers(VALUE self, VALUE req, VALUE data)
564
570
  return Qnil;
565
571
  }
566
572
 
573
+ /**
574
+ * Document-method: trailers
575
+ * call-seq:
576
+ * parser.trailers(req, data) => req or nil
577
+ *
578
+ * This is an alias for HttpParser#headers
579
+ */
580
+
581
+ /**
582
+ * Document-method: headers
583
+ */
584
+ static VALUE HttpParser_headers(VALUE self, VALUE env, VALUE buf)
585
+ {
586
+ struct http_parser *hp = data_get(self);
587
+
588
+ hp->env = env;
589
+ hp->buf = buf;
590
+
591
+ return HttpParser_parse(self);
592
+ }
593
+
567
594
  static int chunked_eof(struct http_parser *hp)
568
595
  {
569
596
  return ((hp->cs == http_parser_first_final) || HP_FL_TEST(hp, INTRAILER));
@@ -619,6 +646,16 @@ static VALUE HttpParser_has_headers(VALUE self)
619
646
  return HP_FL_TEST(hp, HASHEADER) ? Qtrue : Qfalse;
620
647
  }
621
648
 
649
+ static VALUE HttpParser_buf(VALUE self)
650
+ {
651
+ return data_get(self)->buf;
652
+ }
653
+
654
+ static VALUE HttpParser_env(VALUE self)
655
+ {
656
+ return data_get(self)->env;
657
+ }
658
+
622
659
  /**
623
660
  * call-seq:
624
661
  * parser.filter_body(buf, data) => nil/data
@@ -639,7 +676,6 @@ static VALUE HttpParser_filter_body(VALUE self, VALUE buf, VALUE data)
639
676
  char *dptr;
640
677
  long dlen;
641
678
 
642
- rb_str_update(data);
643
679
  dptr = RSTRING_PTR(data);
644
680
  dlen = RSTRING_LEN(data);
645
681
 
@@ -650,7 +686,9 @@ static VALUE HttpParser_filter_body(VALUE self, VALUE buf, VALUE data)
650
686
  if (HP_FL_TEST(hp, CHUNKED)) {
651
687
  if (!chunked_eof(hp)) {
652
688
  hp->s.dest_offset = 0;
653
- http_parser_execute(hp, buf, dptr, dlen);
689
+ hp->cont = buf;
690
+ hp->buf = data;
691
+ http_parser_execute(hp, dptr, dlen);
654
692
  if (hp->cs == http_parser_error)
655
693
  parser_error("Invalid HTTP format, parsing fails.");
656
694
 
@@ -702,13 +740,16 @@ void Init_unicorn_http(void)
702
740
  rb_define_alloc_func(cHttpParser, HttpParser_alloc);
703
741
  rb_define_method(cHttpParser, "initialize", HttpParser_init,0);
704
742
  rb_define_method(cHttpParser, "reset", HttpParser_reset,0);
743
+ rb_define_method(cHttpParser, "parse", HttpParser_parse, 0);
705
744
  rb_define_method(cHttpParser, "headers", HttpParser_headers, 2);
706
- rb_define_method(cHttpParser, "filter_body", HttpParser_filter_body, 2);
707
745
  rb_define_method(cHttpParser, "trailers", HttpParser_headers, 2);
746
+ rb_define_method(cHttpParser, "filter_body", HttpParser_filter_body, 2);
708
747
  rb_define_method(cHttpParser, "content_length", HttpParser_content_length, 0);
709
748
  rb_define_method(cHttpParser, "body_eof?", HttpParser_body_eof, 0);
710
749
  rb_define_method(cHttpParser, "keepalive?", HttpParser_keepalive, 0);
711
750
  rb_define_method(cHttpParser, "headers?", HttpParser_has_headers, 0);
751
+ rb_define_method(cHttpParser, "buf", HttpParser_buf, 0);
752
+ rb_define_method(cHttpParser, "env", HttpParser_env, 0);
712
753
 
713
754
  /*
714
755
  * The maximum size a single chunk when using chunked transfer encoding.
@@ -731,5 +772,6 @@ void Init_unicorn_http(void)
731
772
  SET_GLOBAL(g_http_transfer_encoding, "TRANSFER_ENCODING");
732
773
  SET_GLOBAL(g_content_length, "CONTENT_LENGTH");
733
774
  SET_GLOBAL(g_http_connection, "CONNECTION");
775
+ id_clear = rb_intern("clear");
734
776
  }
735
777
  #undef SET_GLOBAL
data/lib/unicorn.rb CHANGED
@@ -73,11 +73,11 @@ class Unicorn::ClientShutdown < EOFError; end
73
73
 
74
74
  require 'unicorn/const'
75
75
  require 'unicorn/socket_helper'
76
+ require 'unicorn/tee_input'
76
77
  require 'unicorn/http_request'
77
78
  require 'unicorn/configurator'
78
79
  require 'unicorn/tmpio'
79
80
  require 'unicorn/util'
80
- require 'unicorn/tee_input'
81
81
  require 'unicorn/http_response'
82
82
  require 'unicorn/worker'
83
83
  require 'unicorn/http_server'
data/lib/unicorn/const.rb CHANGED
@@ -7,8 +7,8 @@
7
7
  # improve things much compared to constants.
8
8
  module Unicorn::Const
9
9
 
10
- # The current version of Unicorn, currently 2.0.0pre1
11
- UNICORN_VERSION = "2.0.0pre1"
10
+ # The current version of Unicorn, currently 2.0.0pre2
11
+ UNICORN_VERSION = "2.0.0pre2"
12
12
 
13
13
  # default TCP listen host address (0.0.0.0, all interfaces)
14
14
  DEFAULT_HOST = "0.0.0.0"
@@ -2,7 +2,9 @@
2
2
 
3
3
  require 'unicorn_http'
4
4
 
5
- class Unicorn::HttpRequest
5
+ # TODO: remove redundant names
6
+ Unicorn.const_set(:HttpRequest, Unicorn::HttpParser)
7
+ class Unicorn::HttpParser
6
8
 
7
9
  # default parameters we merge into the request env for Rack handlers
8
10
  DEFAULTS = {
@@ -23,20 +25,9 @@ class Unicorn::HttpRequest
23
25
  # A frozen format for this is about 15% faster
24
26
  REMOTE_ADDR = 'REMOTE_ADDR'.freeze
25
27
  RACK_INPUT = 'rack.input'.freeze
28
+ TeeInput = Unicorn::TeeInput
26
29
  # :startdoc:
27
30
 
28
- attr_reader :env, :parser, :buf
29
-
30
- def initialize
31
- @parser = Unicorn::HttpParser.new
32
- @buf = ""
33
- @env = {}
34
- end
35
-
36
- def response_headers?
37
- @parser.headers?
38
- end
39
-
40
31
  # Does the majority of the IO processing. It has been written in
41
32
  # Ruby using about 8 different IO processing strategies.
42
33
  #
@@ -51,8 +42,8 @@ class Unicorn::HttpRequest
51
42
  # This does minimal exception trapping and it is up to the caller
52
43
  # to handle any socket errors (e.g. user aborted upload).
53
44
  def read(socket)
54
- @env.clear
55
- @parser.reset
45
+ reset
46
+ e = env
56
47
 
57
48
  # From http://www.ietf.org/rfc/rfc3875:
58
49
  # "Script authors should be aware that the REMOTE_ADDR and
@@ -61,18 +52,18 @@ class Unicorn::HttpRequest
61
52
  # identify the client for the immediate request to the server;
62
53
  # that client may be a proxy, gateway, or other intermediary
63
54
  # acting on behalf of the actual source client."
64
- @env[REMOTE_ADDR] = socket.kgio_addr
55
+ e[REMOTE_ADDR] = socket.kgio_addr
65
56
 
66
57
  # short circuit the common case with small GET requests first
67
- if @parser.headers(@env, socket.kgio_read!(16384, @buf)).nil?
58
+ socket.kgio_read!(16384, buf)
59
+ if parse.nil?
68
60
  # Parser is not done, queue up more data to read and continue parsing
69
- # an Exception thrown from the PARSER will throw us out of the loop
61
+ # an Exception thrown from the parser will throw us out of the loop
70
62
  begin
71
- @buf << socket.kgio_read!(16384)
72
- end while @parser.headers(@env, @buf).nil?
63
+ buf << socket.kgio_read!(16384)
64
+ end while parse.nil?
73
65
  end
74
- @env[RACK_INPUT] = 0 == @parser.content_length ?
75
- NULL_IO : Unicorn::TeeInput.new(socket, self)
76
- @env.merge!(DEFAULTS)
66
+ e[RACK_INPUT] = 0 == content_length ? NULL_IO : TeeInput.new(socket, self)
67
+ e.merge!(DEFAULTS)
77
68
  end
78
69
  end
@@ -7,9 +7,10 @@
7
7
  class Unicorn::HttpServer
8
8
  attr_accessor :app, :request, :timeout, :worker_processes,
9
9
  :before_fork, :after_fork, :before_exec,
10
- :logger, :pid, :listener_opts, :preload_app,
10
+ :listener_opts, :preload_app,
11
11
  :reexec_pid, :orig_app, :init_listeners,
12
12
  :master_pid, :config, :ready_pipe, :user
13
+ attr_reader :pid, :logger
13
14
 
14
15
  # :stopdoc:
15
16
  include Unicorn::SocketHelper
@@ -520,7 +521,7 @@ class Unicorn::HttpServer
520
521
  r = @app.call(env)
521
522
  end
522
523
  # r may be frozen or const, so don't modify it
523
- @request.response_headers? or r = [ r[0], nil, r[2] ]
524
+ @request.headers? or r = [ r[0], nil, r[2] ]
524
525
  http_response_write(client, r)
525
526
  rescue => e
526
527
  handle_error(client, e)
@@ -11,8 +11,8 @@
11
11
  #
12
12
  # When processing uploads, Unicorn exposes a TeeInput object under
13
13
  # "rack.input" of the Rack environment.
14
- class Unicorn::TeeInput < Struct.new(:socket, :req, :parser,
15
- :buf, :len, :tmp, :buf2)
14
+ class Unicorn::TeeInput
15
+ attr_accessor :tmp, :socket, :parser, :env, :buf, :len, :buf2
16
16
 
17
17
  # The maximum size (in +bytes+) to buffer in memory before
18
18
  # resorting to a temporary file. Default is 112 kilobytes.
@@ -26,18 +26,18 @@ class Unicorn::TeeInput < Struct.new(:socket, :req, :parser,
26
26
  # Initializes a new TeeInput object. You normally do not have to call
27
27
  # this unless you are writing an HTTP server.
28
28
  def initialize(socket, request)
29
- self.socket = socket
30
- self.req = request.env
31
- self.parser = request.parser
32
- self.buf = request.buf
33
- self.len = parser.content_length
34
- self.tmp = len && len < @@client_body_buffer_size ?
35
- StringIO.new("") : Unicorn::TmpIO.new
36
- self.buf2 = ""
37
- if buf.size > 0
38
- parser.filter_body(buf2, buf) and finalize_input
39
- tmp.write(buf2)
40
- tmp.rewind
29
+ @socket = socket
30
+ @parser = request
31
+ @buf = request.buf
32
+ @env = request.env
33
+ @len = request.content_length
34
+ @tmp = @len && @len < @@client_body_buffer_size ?
35
+ StringIO.new("") : Unicorn::TmpIO.new
36
+ @buf2 = ""
37
+ if @buf.size > 0
38
+ @parser.filter_body(@buf2, @buf) and finalize_input
39
+ @tmp.write(@buf2)
40
+ @tmp.rewind
41
41
  end
42
42
  end
43
43
 
@@ -58,16 +58,16 @@ class Unicorn::TeeInput < Struct.new(:socket, :req, :parser,
58
58
  # earlier. Most applications should only need to call +read+ with a
59
59
  # specified +length+ in a loop until it returns +nil+.
60
60
  def size
61
- len and return len
61
+ @len and return @len
62
62
 
63
63
  if socket
64
- pos = tmp.pos
65
- while tee(@@io_chunk_size, buf2)
64
+ pos = @tmp.pos
65
+ while tee(@@io_chunk_size, @buf2)
66
66
  end
67
- tmp.seek(pos)
67
+ @tmp.seek(pos)
68
68
  end
69
69
 
70
- self.len = tmp.size
70
+ @len = @tmp.size
71
71
  end
72
72
 
73
73
  # :call-seq:
@@ -90,22 +90,22 @@ class Unicorn::TeeInput < Struct.new(:socket, :req, :parser,
90
90
  # any data and only block when nothing is available (providing
91
91
  # IO#readpartial semantics).
92
92
  def read(*args)
93
- socket or return tmp.read(*args)
93
+ @socket or return @tmp.read(*args)
94
94
 
95
95
  length = args.shift
96
96
  if nil == length
97
- rv = tmp.read || ""
98
- while tee(@@io_chunk_size, buf2)
99
- rv << buf2
97
+ rv = @tmp.read || ""
98
+ while tee(@@io_chunk_size, @buf2)
99
+ rv << @buf2
100
100
  end
101
101
  rv
102
102
  else
103
103
  rv = args.shift || ""
104
- diff = tmp.size - tmp.pos
104
+ diff = @tmp.size - @tmp.pos
105
105
  if 0 == diff
106
106
  ensure_length(tee(length, rv), length)
107
107
  else
108
- ensure_length(tmp.read(diff > length ? length : diff, rv), length)
108
+ ensure_length(@tmp.read(diff > length ? length : diff, rv), length)
109
109
  end
110
110
  end
111
111
  end
@@ -120,27 +120,27 @@ class Unicorn::TeeInput < Struct.new(:socket, :req, :parser,
120
120
  # This takes zero arguments for strict Rack::Lint compatibility,
121
121
  # unlike IO#gets.
122
122
  def gets
123
- socket or return tmp.gets
123
+ @socket or return @tmp.gets
124
124
  sep = $/ or return read
125
125
 
126
- orig_size = tmp.size
127
- if tmp.pos == orig_size
128
- tee(@@io_chunk_size, buf2) or return nil
129
- tmp.seek(orig_size)
126
+ orig_size = @tmp.size
127
+ if @tmp.pos == orig_size
128
+ tee(@@io_chunk_size, @buf2) or return nil
129
+ @tmp.seek(orig_size)
130
130
  end
131
131
 
132
132
  sep_size = Rack::Utils.bytesize(sep)
133
- line = tmp.gets # cannot be nil here since size > pos
133
+ line = @tmp.gets # cannot be nil here since size > pos
134
134
  sep == line[-sep_size, sep_size] and return line
135
135
 
136
- # unlikely, if we got here, then tmp is at EOF
136
+ # unlikely, if we got here, then @tmp is at EOF
137
137
  begin
138
- orig_size = tmp.pos
139
- tee(@@io_chunk_size, buf2) or break
140
- tmp.seek(orig_size)
141
- line << tmp.gets
138
+ orig_size = @tmp.pos
139
+ tee(@@io_chunk_size, @buf2) or break
140
+ @tmp.seek(orig_size)
141
+ line << @tmp.gets
142
142
  sep == line[-sep_size, sep_size] and return line
143
- # tmp is at EOF again here, retry the loop
143
+ # @tmp is at EOF again here, retry the loop
144
144
  end while true
145
145
 
146
146
  line
@@ -166,7 +166,7 @@ class Unicorn::TeeInput < Struct.new(:socket, :req, :parser,
166
166
  # the offset (zero) of the +ios+ pointer. Subsequent reads will
167
167
  # start from the beginning of the previously-buffered input.
168
168
  def rewind
169
- tmp.rewind # Rack does not specify what the return value is here
169
+ @tmp.rewind # Rack does not specify what the return value is here
170
170
  end
171
171
 
172
172
  private
@@ -175,11 +175,11 @@ private
175
175
  # backing store as well as returning it. +dst+ must be specified.
176
176
  # returns nil if reading from the input returns nil
177
177
  def tee(length, dst)
178
- unless parser.body_eof?
179
- r = socket.kgio_read(length, buf) or eof!
180
- unless parser.filter_body(dst, r)
181
- tmp.write(dst)
182
- tmp.seek(0, IO::SEEK_END) # workaround FreeBSD/OSX + MRI 1.8.x bug
178
+ unless @parser.body_eof?
179
+ r = @socket.kgio_read(length, @buf) or eof!
180
+ unless @parser.filter_body(dst, @buf)
181
+ @tmp.write(dst)
182
+ @tmp.seek(0, IO::SEEK_END) # workaround FreeBSD/OSX + MRI 1.8.x bug
183
183
  return dst
184
184
  end
185
185
  end
@@ -187,11 +187,11 @@ private
187
187
  end
188
188
 
189
189
  def finalize_input
190
- while parser.trailers(req, buf).nil?
191
- r = socket.kgio_read(@@io_chunk_size) or eof!
192
- buf << r
190
+ while @parser.trailers(@env, @buf).nil?
191
+ r = @socket.kgio_read(@@io_chunk_size) or eof!
192
+ @buf << r
193
193
  end
194
- self.socket = nil
194
+ @socket = nil
195
195
  end
196
196
 
197
197
  # tee()s into +dst+ until it is of +length+ bytes (or until
@@ -204,10 +204,10 @@ private
204
204
  # len is nil for chunked bodies, so we can't ensure length for those
205
205
  # since they could be streaming bidirectionally and we don't want to
206
206
  # block the caller in that case.
207
- return dst if dst.nil? || len.nil?
207
+ return dst if dst.nil? || @len.nil?
208
208
 
209
- while dst.size < length && tee(length - dst.size, buf2)
210
- dst << buf2
209
+ while dst.size < length && tee(length - dst.size, @buf2)
210
+ dst << @buf2
211
211
  end
212
212
 
213
213
  dst
@@ -218,7 +218,7 @@ private
218
218
  # we do support clients that shutdown(SHUT_WR) after the
219
219
  # _entire_ request has been sent, and those will not have
220
220
  # raised EOFError on us.
221
- socket.close if socket
222
- raise Unicorn::ClientShutdown, "bytes_read=#{tmp.size}", []
221
+ @socket.close if @socket
222
+ raise Unicorn::ClientShutdown, "bytes_read=#{@tmp.size}", []
223
223
  end
224
224
  end
@@ -388,6 +388,7 @@ class HttpParserNgTest < Test::Unit::TestCase
388
388
  "*" => { qs => "", pi => "" },
389
389
  }.each do |uri,expect|
390
390
  assert_equal req, @parser.headers(req.clear, str % [ uri ])
391
+ req = req.dup
391
392
  @parser.reset
392
393
  assert_equal uri, req["REQUEST_URI"], "REQUEST_URI mismatch"
393
394
  assert_equal expect[qs], req[qs], "#{qs} mismatch"
@@ -412,6 +413,7 @@ class HttpParserNgTest < Test::Unit::TestCase
412
413
  "/1?a=b;c=d&e=f" => { qs => "a=b;c=d&e=f", pi => "/1" },
413
414
  }.each do |uri,expect|
414
415
  assert_equal req, @parser.headers(req.clear, str % [ uri ])
416
+ req = req.dup
415
417
  @parser.reset
416
418
  assert_equal uri, req["REQUEST_URI"], "REQUEST_URI mismatch"
417
419
  assert_equal "example.com", req["HTTP_HOST"], "Host: mismatch"
@@ -5,7 +5,6 @@ require 'digest/sha1'
5
5
  require 'unicorn'
6
6
 
7
7
  class TestTeeInput < Test::Unit::TestCase
8
- MockRequest = Struct.new(:env, :parser, :buf)
9
8
 
10
9
  def setup
11
10
  @rs = $/
@@ -164,7 +163,7 @@ class TestTeeInput < Test::Unit::TestCase
164
163
  @wr.write("0\r\n\r\n")
165
164
  }
166
165
  @wr.close
167
- ti = Unicorn::TeeInput.new(@rd, MockRequest.new(@env, @parser, @buf))
166
+ ti = Unicorn::TeeInput.new(@rd, @parser)
168
167
  assert_nil @parser.content_length
169
168
  assert_nil ti.len
170
169
  assert ! @parser.body_eof?
@@ -202,7 +201,7 @@ class TestTeeInput < Test::Unit::TestCase
202
201
  end
203
202
  @wr.write("0\r\n\r\n")
204
203
  }
205
- ti = Unicorn::TeeInput.new(@rd, MockRequest.new(@env, @parser, @buf))
204
+ ti = Unicorn::TeeInput.new(@rd, @parser)
206
205
  assert_nil @parser.content_length
207
206
  assert_nil ti.len
208
207
  assert ! @parser.body_eof?
@@ -231,7 +230,7 @@ class TestTeeInput < Test::Unit::TestCase
231
230
  @wr.write("Hello: World\r\n\r\n")
232
231
  }
233
232
  @wr.close
234
- ti = Unicorn::TeeInput.new(@rd, MockRequest.new(@env, @parser, @buf))
233
+ ti = Unicorn::TeeInput.new(@rd, @parser)
235
234
  assert_nil @parser.content_length
236
235
  assert_nil ti.len
237
236
  assert ! @parser.body_eof?
@@ -253,7 +252,7 @@ private
253
252
  "\r\n#{body}"
254
253
  assert_equal @env, @parser.headers(@env, @buf)
255
254
  assert_equal body, @buf
256
- MockRequest.new(@env, @parser, @buf)
255
+ @parser
257
256
  end
258
257
 
259
258
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unicorn
3
3
  version: !ruby/object:Gem::Version
4
- hash: -766259887
4
+ hash: -766259858
5
5
  prerelease: true
6
6
  segments:
7
7
  - 2
8
8
  - 0
9
- - 0pre1
10
- version: 2.0.0pre1
9
+ - 0pre2
10
+ version: 2.0.0pre2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Unicorn hackers
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-06 00:00:00 +00:00
18
+ date: 2010-10-07 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency