unicorn 3.1.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document CHANGED
@@ -11,6 +11,7 @@ KNOWN_ISSUES
11
11
  TODO
12
12
  NEWS
13
13
  ChangeLog
14
+ LATEST
14
15
  lib
15
16
  ext/unicorn_http/unicorn_http.c
16
17
  unicorn_1
data/.gitignore CHANGED
@@ -21,3 +21,4 @@ pkg/
21
21
  /GIT-VERSION-FILE
22
22
  /man
23
23
  /tmp
24
+ /LATEST
data/.wrongdoc.yml ADDED
@@ -0,0 +1,8 @@
1
+ ---
2
+ cgit_url: http://git.bogomips.org/cgit/unicorn.git
3
+ git_url: git://git.bogomips.org/unicorn.git
4
+ rdoc_url: http://unicorn.bogomips.org/
5
+ changelog_start: v1.1.5
6
+ merge_html:
7
+ unicorn_1: Documentation/unicorn.1.html
8
+ unicorn_rails_1: Documentation/unicorn_rails.1.html
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v3.1.0.GIT
4
+ DEF_VER=v3.2.1.GIT
5
5
 
6
6
  LF='
7
7
  '
data/GNUmakefile CHANGED
@@ -1,7 +1,6 @@
1
1
  # use GNU Make to run tests in parallel, and without depending on RubyGems
2
2
  all:: test
3
3
 
4
- GIT_URL = git://git.bogomips.org/unicorn.git
5
4
  RLFLAGS = -G2
6
5
 
7
6
  MRI = ruby
@@ -156,77 +155,39 @@ clean:
156
155
  $(RM) $(setup_rb_files) $(t_log)
157
156
  $(RM) -r $(test_prefix) man
158
157
 
159
- man:
160
- $(MAKE) -C Documentation install-man
158
+ man html:
159
+ $(MAKE) -C Documentation install-$@
161
160
 
162
- pkg_extra := GIT-VERSION-FILE NEWS ChangeLog $(ext)/unicorn_http.c
163
- manifest: $(pkg_extra) man
164
- $(RM) .manifest
165
- $(MAKE) .manifest
161
+ pkg_extra := GIT-VERSION-FILE ChangeLog LATEST NEWS \
162
+ $(ext)/unicorn_http.c $(man1_paths)
166
163
 
167
- .manifest:
168
- (git ls-files && \
169
- for i in $@ $(pkg_extra) $(man1_paths); \
170
- do echo $$i; done) | LC_ALL=C sort > $@+
164
+ ChangeLog: GIT-VERSION-FILE .wrongdoc.yml
165
+ wrongdoc prepare
166
+
167
+ .manifest: ChangeLog $(ext)/unicorn_http.c
168
+ (git ls-files && for i in $@ $(pkg_extra); do echo $$i; done) | \
169
+ LC_ALL=C sort > $@+
171
170
  cmp $@+ $@ || mv $@+ $@
172
171
  $(RM) $@+
173
172
 
174
- NEWS: GIT-VERSION-FILE .manifest
175
- $(RAKE) -s news_rdoc > $@+
176
- mv $@+ $@
177
-
178
- SINCE = 1.1.5
179
- ChangeLog: LOG_VERSION = \
180
- $(shell git rev-parse -q "$(GIT_VERSION)" >/dev/null 2>&1 && \
181
- echo $(GIT_VERSION) || git describe)
182
- ChangeLog: log_range = v$(SINCE)..$(LOG_VERSION)
183
- ChangeLog: GIT-VERSION-FILE
184
- @echo "ChangeLog from $(GIT_URL) ($(log_range))" > $@+
185
- @echo >> $@+
186
- git log $(log_range) | sed -e 's/^/ /' >> $@+
187
- mv $@+ $@
188
-
189
- news_atom := http://unicorn.bogomips.org/NEWS.atom.xml
190
- cgit_atom := http://git.bogomips.org/cgit/unicorn.git/atom/?h=master
191
- atom = <link rel="alternate" title="Atom feed" href="$(1)" \
192
- type="application/atom+xml"/>
193
-
194
- # using rdoc 2.5.x+
195
- doc: .document $(ext)/unicorn_http.c NEWS ChangeLog
173
+ doc: .document $(ext)/unicorn_http.c man html .wrongdoc.yml
196
174
  for i in $(man1_rdoc); do echo > $$i; done
197
175
  find bin lib -type f -name '*.rbc' -exec rm -f '{}' ';'
198
- rdoc -t "$(shell sed -ne '1s/^= //p' README)"
176
+ $(RM) -r doc
177
+ wrongdoc all
199
178
  install -m644 COPYING doc/COPYING
200
- install -m644 $(shell grep '^[A-Z]' .document) doc/
201
- $(MAKE) -C Documentation install-html install-man
179
+ install -m644 $(shell grep '^[A-Z]' .document) doc/
202
180
  install -m644 $(man1_paths) doc/
203
- cd doc && for i in $(base_bins); do \
204
- $(RM) 1.html $${i}.1.html; \
205
- sed -e '/"documentation">/r man1/'$$i'.1.html' \
206
- < $${i}_1.html > tmp && mv tmp $${i}_1.html; \
207
- ln $${i}_1.html $${i}.1.html; \
208
- done
209
- $(RUBY) -i -p -e \
210
- '$$_.gsub!("</title>",%q{\&$(call atom,$(cgit_atom))})' \
211
- doc/ChangeLog.html
212
- $(RUBY) -i -p -e \
213
- '$$_.gsub!("</title>",%q{\&$(call atom,$(news_atom))})' \
214
- doc/NEWS.html doc/README.html
215
- $(RAKE) -s news_atom > doc/NEWS.atom.xml
216
- cd doc && ln README.html tmp && mv tmp index.html
181
+ tar cf - $$(git ls-files examples/) | (cd doc && tar xf -)
217
182
  $(RM) $(man1_rdoc)
218
183
 
219
184
  # publishes docs to http://unicorn.bogomips.org
220
185
  publish_doc:
221
186
  -git set-file-times
222
- $(RM) -r doc ChangeLog NEWS
223
- $(MAKE) doc LOG_VERSION=$(shell git tag -l | tail -1)
224
- @awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' \
225
- < NEWS > doc/LATEST
226
- find doc/images doc/js -type f | \
227
- TZ=UTC xargs touch -d '1970-01-01 00:00:00' doc/rdoc.css
187
+ $(MAKE) doc
188
+ find doc/images -type f | \
189
+ TZ=UTC xargs touch -d '1970-01-01 00:00:02' doc/rdoc.css
228
190
  $(MAKE) doc_gz
229
- tar cf - $$(git ls-files examples/) | (cd doc && tar xf -)
230
191
  chmod 644 $$(find doc -type f)
231
192
  $(RSYNC) -av doc/ unicorn.bogomips.org:/srv/unicorn/
232
193
  git ls-files | xargs touch
@@ -235,7 +196,6 @@ publish_doc:
235
196
  # "gzip_static on" can serve the gzipped versions directly.
236
197
  doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
237
198
  doc_gz:
238
- touch doc/NEWS.atom.xml -d "$$(awk 'NR==1{print $$4,$$5,$$6}' NEWS)"
239
199
  for i in $(docs); do \
240
200
  gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
241
201
 
@@ -274,10 +234,10 @@ release_changes := release_changes-$(VERSION)
274
234
  release-notes: $(release_notes)
275
235
  release-changes: $(release_changes)
276
236
  $(release_changes):
277
- $(RAKE) -s release_changes > $@+
237
+ wrongdoc release_changes > $@+
278
238
  $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
279
239
  $(release_notes):
280
- GIT_URL=$(GIT_URL) $(RAKE) -s release_notes > $@+
240
+ wrongdoc release_notes > $@+
281
241
  $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
282
242
 
283
243
  # ensures we're actually on the tagged $(VERSION), only used for release
@@ -297,18 +257,18 @@ gem: $(pkggem)
297
257
  install-gem: $(pkggem)
298
258
  gem install $(CURDIR)/$<
299
259
 
300
- $(pkggem): manifest fix-perms
260
+ $(pkggem): .manifest fix-perms
301
261
  gem build $(rfpackage).gemspec
302
262
  mkdir -p pkg
303
263
  mv $(@F) $@
304
264
 
305
265
  $(pkgtgz): distdir = $(basename $@)
306
266
  $(pkgtgz): HEAD = v$(VERSION)
307
- $(pkgtgz): manifest fix-perms
267
+ $(pkgtgz): .manifest fix-perms
308
268
  @test -n "$(distdir)"
309
269
  $(RM) -r $(distdir)
310
270
  mkdir -p $(distdir)
311
- tar cf - `cat .manifest` | (cd $(distdir) && tar xf -)
271
+ tar cf - $$(cat .manifest) | (cd $(distdir) && tar xf -)
312
272
  cd pkg && tar cf - $(basename $(@F)) | gzip -9 > $(@F)+
313
273
  mv $@+ $@
314
274
 
@@ -330,5 +290,5 @@ gem install-gem: GIT-VERSION-FILE
330
290
  $(MAKE) $@ VERSION=$(GIT_VERSION)
331
291
  endif
332
292
 
333
- .PHONY: .FORCE-GIT-VERSION-FILE doc $(T) $(slow_tests) manifest man
293
+ .PHONY: .FORCE-GIT-VERSION-FILE doc $(T) $(slow_tests) man
334
294
  .PHONY: test-install
data/Rakefile CHANGED
@@ -1,112 +1,9 @@
1
1
  # -*- encoding: binary -*-
2
2
  autoload :Gem, 'rubygems'
3
3
 
4
- # most tasks are in the GNUmakefile which offers better parallelism
5
-
6
- def old_summaries
7
- @old_summaries ||= File.readlines(".CHANGELOG.old").inject({}) do |hash, line|
8
- version, summary = line.split(/ - /, 2)
9
- hash[version] = summary
10
- hash
11
- end
12
- end
13
-
14
- def tags
15
- timefmt = '%Y-%m-%dT%H:%M:%SZ'
16
- @tags ||= `git tag -l`.split(/\n/).map do |tag|
17
- next if tag == "v0.0.0"
18
- if %r{\Av[\d\.]+} =~ tag
19
- header, subject, body = `git cat-file tag #{tag}`.split(/\n\n/, 3)
20
- header = header.split(/\n/)
21
- tagger = header.grep(/\Atagger /).first
22
- body ||= "initial"
23
- {
24
- :time => Time.at(tagger.split(/ /)[-2].to_i).utc.strftime(timefmt),
25
- :tagger_name => %r{^tagger ([^<]+)}.match(tagger)[1].strip,
26
- :tagger_email => %r{<([^>]+)>}.match(tagger)[1].strip,
27
- :id => `git rev-parse refs/tags/#{tag}`.chomp!,
28
- :tag => tag,
29
- :subject => subject,
30
- :body => (old = old_summaries[tag]) ? "#{old}\n#{body}" : body,
31
- }
32
- end
33
- end.compact.sort { |a,b| b[:time] <=> a[:time] }
34
- end
35
-
36
4
  cgit_url = "http://git.bogomips.org/cgit/unicorn.git"
37
5
  git_url = ENV['GIT_URL'] || 'git://git.bogomips.org/unicorn.git'
38
6
 
39
- desc 'prints news as an Atom feed'
40
- task :news_atom do
41
- require 'nokogiri'
42
- new_tags = tags[0,10]
43
- puts(Nokogiri::XML::Builder.new do
44
- feed :xmlns => "http://www.w3.org/2005/Atom" do
45
- id! "http://unicorn.bogomips.org/NEWS.atom.xml"
46
- title "Unicorn news"
47
- subtitle "Rack HTTP server for Unix and fast clients"
48
- link! :rel => 'alternate', :type => 'text/html',
49
- :href => 'http://unicorn.bogomips.org/NEWS.html'
50
- updated new_tags.first[:time]
51
- new_tags.each do |tag|
52
- entry do
53
- title tag[:subject]
54
- updated tag[:time]
55
- published tag[:time]
56
- author {
57
- name tag[:tagger_name]
58
- email tag[:tagger_email]
59
- }
60
- url = "#{cgit_url}/tag/?id=#{tag[:tag]}"
61
- link! :rel => "alternate", :type => "text/html", :href =>url
62
- id! url
63
- message_only = tag[:body].split(/\n.+\(\d+\):\n {6}/s).first.strip
64
- content({:type =>:text}, message_only)
65
- content(:type =>:xhtml) { pre tag[:body] }
66
- end
67
- end
68
- end
69
- end.to_xml)
70
- end
71
-
72
- desc 'prints RDoc-formatted news'
73
- task :news_rdoc do
74
- tags.each do |tag|
75
- time = tag[:time].tr!('T', ' ').gsub!(/:\d\dZ/, ' UTC')
76
- puts "=== #{tag[:tag].sub(/^v/, '')} / #{time}"
77
- puts ""
78
-
79
- body = tag[:body]
80
- puts tag[:body].gsub(/^/sm, " ").gsub(/[ \t]+$/sm, "")
81
- puts ""
82
- end
83
- end
84
-
85
- desc "print release changelog for Rubyforge"
86
- task :release_changes do
87
- version = ENV['VERSION'] or abort "VERSION= needed"
88
- version = "v#{version}"
89
- vtags = tags.map { |tag| tag[:tag] =~ /\Av/ and tag[:tag] }.sort
90
- prev = vtags[vtags.index(version) - 1]
91
- system('git', 'diff', '--stat', prev, version) or abort $?
92
- puts ""
93
- system('git', 'log', "#{prev}..#{version}") or abort $?
94
- end
95
-
96
- desc "print release notes for Rubyforge"
97
- task :release_notes do
98
- spec = Gem::Specification.load('unicorn.gemspec')
99
- puts spec.description.strip
100
- puts ""
101
- puts "* #{spec.homepage}"
102
- puts "* #{spec.email}"
103
- puts "* #{git_url}"
104
-
105
- _, _, body = `git cat-file tag v#{spec.version}`.split(/\n\n/, 3)
106
- print "\nChanges:\n\n"
107
- puts body
108
- end
109
-
110
7
  desc "post to RAA"
111
8
  task :raa_update do
112
9
  require 'net/http'
data/TODO CHANGED
@@ -1,7 +1,5 @@
1
1
  * Documentation improvements
2
2
 
3
- * performance validation (esp. TeeInput)
4
-
5
3
  * improve test suite
6
4
 
7
5
  * scalability to >= 1024 worker processes for crazy NUMA systems
@@ -15,6 +15,7 @@ static VALUE g_server_port;
15
15
  static VALUE g_server_protocol;
16
16
  static VALUE g_http_host;
17
17
  static VALUE g_http_x_forwarded_proto;
18
+ static VALUE g_http_x_forwarded_ssl;
18
19
  static VALUE g_http_transfer_encoding;
19
20
  static VALUE g_content_length;
20
21
  static VALUE g_http_trailer;
@@ -23,6 +24,7 @@ static VALUE g_port_80;
23
24
  static VALUE g_port_443;
24
25
  static VALUE g_localhost;
25
26
  static VALUE g_http;
27
+ static VALUE g_https;
26
28
  static VALUE g_http_09;
27
29
  static VALUE g_http_10;
28
30
  static VALUE g_http_11;
@@ -73,10 +75,12 @@ static void init_globals(void)
73
75
  DEF_GLOBAL(server_port, "SERVER_PORT");
74
76
  DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");
75
77
  DEF_GLOBAL(http_x_forwarded_proto, "HTTP_X_FORWARDED_PROTO");
78
+ DEF_GLOBAL(http_x_forwarded_ssl, "HTTP_X_FORWARDED_SSL");
76
79
  DEF_GLOBAL(port_80, "80");
77
80
  DEF_GLOBAL(port_443, "443");
78
81
  DEF_GLOBAL(localhost, "localhost");
79
82
  DEF_GLOBAL(http, "http");
83
+ DEF_GLOBAL(https, "https");
80
84
  DEF_GLOBAL(http_11, "HTTP/1.1");
81
85
  DEF_GLOBAL(http_10, "HTTP/1.0");
82
86
  DEF_GLOBAL(http_09, "HTTP/0.9");
@@ -21,14 +21,70 @@
21
21
  #define UH_FL_REQEOF 0x40
22
22
  #define UH_FL_KAVERSION 0x80
23
23
  #define UH_FL_HASHEADER 0x100
24
+ #define UH_FL_TO_CLEAR 0x200
24
25
 
25
26
  /* all of these flags need to be set for keepalive to be supported */
26
27
  #define UH_FL_KEEPALIVE (UH_FL_KAVERSION | UH_FL_REQEOF | UH_FL_HASHEADER)
27
28
 
29
+ /*
30
+ * whether or not to trust X-Forwarded-Proto and X-Forwarded-SSL when
31
+ * setting rack.url_scheme
32
+ */
33
+ static VALUE trust_x_forward = Qtrue;
34
+
35
+ static unsigned long keepalive_requests = 100; /* same as nginx */
36
+
37
+ /*
38
+ * Returns the maximum number of keepalive requests a client may make
39
+ * before the parser refuses to continue.
40
+ */
41
+ static VALUE ka_req(VALUE self)
42
+ {
43
+ return ULONG2NUM(keepalive_requests);
44
+ }
45
+
46
+ /*
47
+ * Sets the maximum number of keepalive requests a client may make.
48
+ * A special value of +nil+ causes this to be the maximum value
49
+ * possible (this is architecture-dependent).
50
+ */
51
+ static VALUE set_ka_req(VALUE self, VALUE val)
52
+ {
53
+ keepalive_requests = NIL_P(val) ? ULONG_MAX : NUM2ULONG(val);
54
+
55
+ return ka_req(self);
56
+ }
57
+
58
+ /*
59
+ * Sets whether or not the parser will trust X-Forwarded-Proto and
60
+ * X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly.
61
+ * Rainbows!/Zbatery installations facing untrusted clients directly
62
+ * should set this to +false+
63
+ */
64
+ static VALUE set_xftrust(VALUE self, VALUE val)
65
+ {
66
+ if (Qtrue == val || Qfalse == val)
67
+ trust_x_forward = val;
68
+ else
69
+ rb_raise(rb_eTypeError, "must be true or false");
70
+
71
+ return val;
72
+ }
73
+
74
+ /*
75
+ * returns whether or not the parser will trust X-Forwarded-Proto and
76
+ * X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly
77
+ */
78
+ static VALUE xftrust(VALUE self)
79
+ {
80
+ return trust_x_forward;
81
+ }
82
+
28
83
  /* keep this small for Rainbows! since every client has one */
29
84
  struct http_parser {
30
85
  int cs; /* Ragel internal state */
31
86
  unsigned int flags;
87
+ unsigned long nr_requests;
32
88
  size_t mark;
33
89
  size_t offset;
34
90
  union { /* these 2 fields don't nest */
@@ -391,42 +447,85 @@ static struct http_parser *data_get(VALUE self)
391
447
  return hp;
392
448
  }
393
449
 
394
- static void finalize_header(struct http_parser *hp)
450
+ /*
451
+ * set rack.url_scheme to "https" or "http", no others are allowed by Rack
452
+ * this resembles the Rack::Request#scheme method as of rack commit
453
+ * 35bb5ba6746b5d346de9202c004cc926039650c7
454
+ */
455
+ static void set_url_scheme(VALUE env, VALUE *server_port)
395
456
  {
396
- VALUE temp = rb_hash_aref(hp->env, g_rack_url_scheme);
397
- VALUE server_name = g_localhost;
398
- VALUE server_port = g_port_80;
457
+ VALUE scheme = rb_hash_aref(env, g_rack_url_scheme);
399
458
 
400
- /* set rack.url_scheme to "https" or "http", no others are allowed by Rack */
401
- if (NIL_P(temp)) {
402
- temp = rb_hash_aref(hp->env, g_http_x_forwarded_proto);
403
- if (!NIL_P(temp) && STR_CSTR_EQ(temp, "https"))
404
- server_port = g_port_443;
405
- else
406
- temp = g_http;
407
- rb_hash_aset(hp->env, g_rack_url_scheme, temp);
408
- } else if (STR_CSTR_EQ(temp, "https")) {
409
- server_port = g_port_443;
459
+ if (NIL_P(scheme)) {
460
+ if (trust_x_forward == Qfalse) {
461
+ scheme = g_http;
462
+ } else {
463
+ scheme = rb_hash_aref(env, g_http_x_forwarded_ssl);
464
+ if (!NIL_P(scheme) && STR_CSTR_EQ(scheme, "on")) {
465
+ *server_port = g_port_443;
466
+ scheme = g_https;
467
+ } else {
468
+ scheme = rb_hash_aref(env, g_http_x_forwarded_proto);
469
+ if (NIL_P(scheme)) {
470
+ scheme = g_http;
471
+ } else {
472
+ long len = RSTRING_LEN(scheme);
473
+ if (len >= 5 && !memcmp(RSTRING_PTR(scheme), "https", 5)) {
474
+ if (len != 5)
475
+ scheme = g_https;
476
+ *server_port = g_port_443;
477
+ } else {
478
+ scheme = g_http;
479
+ }
480
+ }
481
+ }
482
+ }
483
+ rb_hash_aset(env, g_rack_url_scheme, scheme);
484
+ } else if (STR_CSTR_EQ(scheme, "https")) {
485
+ *server_port = g_port_443;
410
486
  } else {
411
- assert(server_port == g_port_80 && "server_port not set");
487
+ assert(*server_port == g_port_80 && "server_port not set");
412
488
  }
489
+ }
490
+
491
+ /*
492
+ * Parse and set the SERVER_NAME and SERVER_PORT variables
493
+ * Not supporting X-Forwarded-Host/X-Forwarded-Port in here since
494
+ * anybody who needs them is using an unsupported configuration and/or
495
+ * incompetent. Rack::Request will handle X-Forwarded-{Port,Host} just
496
+ * fine.
497
+ */
498
+ static void set_server_vars(VALUE env, VALUE *server_port)
499
+ {
500
+ VALUE server_name = g_localhost;
501
+ VALUE host = rb_hash_aref(env, g_http_host);
502
+
503
+ if (!NIL_P(host)) {
504
+ char *host_ptr = RSTRING_PTR(host);
505
+ long host_len = RSTRING_LEN(host);
506
+ char *colon = memchr(host_ptr, ':', host_len);
413
507
 
414
- /* parse and set the SERVER_NAME and SERVER_PORT variables */
415
- temp = rb_hash_aref(hp->env, g_http_host);
416
- if (!NIL_P(temp)) {
417
- char *colon = memchr(RSTRING_PTR(temp), ':', RSTRING_LEN(temp));
418
508
  if (colon) {
419
- long port_start = colon - RSTRING_PTR(temp) + 1;
509
+ long port_start = colon - host_ptr + 1;
420
510
 
421
- server_name = rb_str_substr(temp, 0, colon - RSTRING_PTR(temp));
422
- if ((RSTRING_LEN(temp) - port_start) > 0)
423
- server_port = rb_str_substr(temp, port_start, RSTRING_LEN(temp));
511
+ server_name = rb_str_substr(host, 0, colon - host_ptr);
512
+ if ((host_len - port_start) > 0)
513
+ *server_port = rb_str_substr(host, port_start, host_len);
424
514
  } else {
425
- server_name = temp;
515
+ server_name = host;
426
516
  }
427
517
  }
428
- rb_hash_aset(hp->env, g_server_name, server_name);
429
- rb_hash_aset(hp->env, g_server_port, server_port);
518
+ rb_hash_aset(env, g_server_name, server_name);
519
+ rb_hash_aset(env, g_server_port, *server_port);
520
+ }
521
+
522
+ static void finalize_header(struct http_parser *hp)
523
+ {
524
+ VALUE server_port = g_port_80;
525
+
526
+ set_url_scheme(hp->env, &server_port);
527
+ set_server_vars(hp->env, &server_port);
528
+
430
529
  if (!HP_FL_TEST(hp, HASHEADER))
431
530
  rb_hash_aset(hp->env, g_server_protocol, g_http_09);
432
531
 
@@ -464,6 +563,7 @@ static VALUE HttpParser_init(VALUE self)
464
563
  http_parser_init(hp);
465
564
  hp->buf = rb_str_new(NULL, 0);
466
565
  hp->env = rb_hash_new();
566
+ hp->nr_requests = keepalive_requests;
467
567
 
468
568
  return self;
469
569
  }
@@ -537,6 +637,11 @@ static VALUE HttpParser_parse(VALUE self)
537
637
  struct http_parser *hp = data_get(self);
538
638
  VALUE data = hp->buf;
539
639
 
640
+ if (HP_FL_TEST(hp, TO_CLEAR)) {
641
+ http_parser_init(hp);
642
+ rb_funcall(hp->env, id_clear, 0);
643
+ }
644
+
540
645
  http_parser_execute(hp, RSTRING_PTR(data), RSTRING_LEN(data));
541
646
  VALIDATE_MAX_LENGTH(hp->offset, HEADER);
542
647
 
@@ -622,15 +727,16 @@ static VALUE HttpParser_keepalive(VALUE self)
622
727
  * parser.next? => true or false
623
728
  *
624
729
  * Exactly like HttpParser#keepalive?, except it will reset the internal
625
- * parser state if it returns true.
730
+ * parser state on next parse if it returns true. It will also respect
731
+ * the maximum *keepalive_requests* value and return false if that is
732
+ * reached.
626
733
  */
627
734
  static VALUE HttpParser_next(VALUE self)
628
735
  {
629
736
  struct http_parser *hp = data_get(self);
630
737
 
631
- if (HP_FL_ALL(hp, KEEPALIVE)) {
632
- http_parser_init(hp);
633
- rb_funcall(hp->env, id_clear, 0);
738
+ if ((HP_FL_ALL(hp, KEEPALIVE)) && (hp->nr_requests-- != 0)) {
739
+ HP_FL_SET(hp, TO_CLEAR);
634
740
  return Qtrue;
635
741
  }
636
742
  return Qfalse;
@@ -775,6 +881,15 @@ void Init_unicorn_http(void)
775
881
  */
776
882
  rb_define_const(cHttpParser, "LENGTH_MAX", OFFT2NUM(UH_OFF_T_MAX));
777
883
 
884
+ /* default value for keepalive_requests */
885
+ rb_define_const(cHttpParser, "KEEPALIVE_REQUESTS_DEFAULT",
886
+ ULONG2NUM(keepalive_requests));
887
+
888
+ rb_define_singleton_method(cHttpParser, "keepalive_requests", ka_req, 0);
889
+ rb_define_singleton_method(cHttpParser, "keepalive_requests=", set_ka_req, 1);
890
+ rb_define_singleton_method(cHttpParser, "trust_x_forwarded=", set_xftrust, 1);
891
+ rb_define_singleton_method(cHttpParser, "trust_x_forwarded?", xftrust, 0);
892
+
778
893
  init_common_fields();
779
894
  SET_GLOBAL(g_http_host, "HOST");
780
895
  SET_GLOBAL(g_http_trailer, "TRAILER");
@@ -10,9 +10,10 @@ require 'logger'
10
10
  # http://unicorn.bogomips.org/examples/nginx.conf
11
11
  class Unicorn::Configurator
12
12
  include Unicorn
13
- attr_accessor :set, :config_file, :after_reload
14
13
 
15
14
  # :stopdoc:
15
+ attr_accessor :set, :config_file, :after_reload
16
+
16
17
  # used to stash stuff for deferred processing of cli options in
17
18
  # config.ru after "working_directory" is bound. Do not rely on
18
19
  # this being around later on...
@@ -42,6 +43,7 @@ class Unicorn::Configurator
42
43
  :preload_app => false,
43
44
  :rewindable_input => true, # for Rack 2.x: (Rack::VERSION[0] <= 1),
44
45
  :client_body_buffer_size => Unicorn::Const::MAX_BODY,
46
+ :trust_x_forwarded => true,
45
47
  }
46
48
  #:startdoc:
47
49
 
@@ -448,6 +450,15 @@ class Unicorn::Configurator
448
450
  set[:user] = [ user, group ]
449
451
  end
450
452
 
453
+ # Sets whether or not the parser will trust X-Forwarded-Proto and
454
+ # X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly.
455
+ # Rainbows!/Zbatery installations facing untrusted clients directly
456
+ # should set this to +false+. This is +true+ by default as Unicorn
457
+ # is designed to only sit behind trusted nginx proxies.
458
+ def trust_x_forwarded(bool)
459
+ set_bool(:trust_x_forwarded, bool)
460
+ end
461
+
451
462
  # expands "unix:path/to/foo" to a socket relative to the current path
452
463
  # expands pathnames of sockets if relative to "~" or "~username"
453
464
  # expands "*:port and ":port" to "0.0.0.0:port"
@@ -472,7 +483,7 @@ class Unicorn::Configurator
472
483
  end
473
484
 
474
485
  private
475
- def set_int(var, n, min)
486
+ def set_int(var, n, min) #:nodoc:
476
487
  Integer === n or raise ArgumentError, "not an integer: #{var}=#{n.inspect}"
477
488
  n >= min or raise ArgumentError, "too low (< #{min}): #{var}=#{n.inspect}"
478
489
  set[var] = n
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 3.1.0
11
- UNICORN_VERSION = "3.1.0"
10
+ # The current version of Unicorn, currently 3.2.1
11
+ UNICORN_VERSION = "3.2.1"
12
12
 
13
13
  # default TCP listen host address (0.0.0.0, all interfaces)
14
14
  DEFAULT_HOST = "0.0.0.0"
@@ -9,8 +9,6 @@ require 'time'
9
9
  #
10
10
  # Most header correctness (including Content-Length and Content-Type)
11
11
  # is the job of Rack, with the exception of the "Date" and "Status" header.
12
- #
13
- # TODO: allow keepalive
14
12
  module Unicorn::HttpResponse
15
13
 
16
14
  # Every standard HTTP code mapped to the appropriate message.
@@ -73,19 +73,17 @@ class Unicorn::HttpServer
73
73
  # Unicorn::HttpServer::START_CTX[0] = "/home/bofh/1.9.2/bin/unicorn"
74
74
  START_CTX = {
75
75
  :argv => ARGV.map { |arg| arg.dup },
76
- :cwd => lambda {
77
- # favor ENV['PWD'] since it is (usually) symlink aware for
78
- # Capistrano and like systems
79
- begin
80
- a = File.stat(pwd = ENV['PWD'])
81
- b = File.stat(Dir.pwd)
82
- a.ino == b.ino && a.dev == b.dev ? pwd : Dir.pwd
83
- rescue
84
- Dir.pwd
85
- end
86
- }.call,
87
76
  0 => $0.dup,
88
77
  }
78
+ # We favor ENV['PWD'] since it is (usually) symlink aware for Capistrano
79
+ # and like systems
80
+ START_CTX[:cwd] = begin
81
+ a = File.stat(pwd = ENV['PWD'])
82
+ b = File.stat(Dir.pwd)
83
+ a.ino == b.ino && a.dev == b.dev ? pwd : Dir.pwd
84
+ rescue
85
+ Dir.pwd
86
+ end
89
87
 
90
88
  # Creates a working server on host:port (strange things happen if
91
89
  # port isn't a Number). Use HttpServer::run to start the server and
@@ -372,6 +370,14 @@ class Unicorn::HttpServer
372
370
  Unicorn::TeeInput.client_body_buffer_size = bytes
373
371
  end
374
372
 
373
+ def trust_x_forwarded
374
+ Unicorn::HttpParser.trust_x_forwarded?
375
+ end
376
+
377
+ def trust_x_forwarded=(bool)
378
+ Unicorn::HttpParser.trust_x_forwarded = bool
379
+ end
380
+
375
381
  private
376
382
 
377
383
  # wait for a signal hander to wake us up and then consume the pipe
@@ -17,7 +17,7 @@ opts = {
17
17
  pid = fork do
18
18
  Isolate.now!(opts) do
19
19
  gem 'sqlite3-ruby', '1.2.5'
20
- gem 'kgio', '2.0.0'
20
+ gem 'kgio', '2.1.1'
21
21
  gem 'rack', '1.1.0'
22
22
  end
23
23
  end
@@ -0,0 +1,30 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 5 "trust_x_forwarded=false configuration test"
4
+
5
+ t_begin "setup and start" && {
6
+ unicorn_setup
7
+ echo "trust_x_forwarded false" >> $unicorn_config
8
+ unicorn -D -c $unicorn_config env.ru
9
+ unicorn_wait_start
10
+ }
11
+
12
+ t_begin "spoofed request with X-Forwarded-Proto does not trigger" && {
13
+ curl -H 'X-Forwarded-Proto: https' http://$listen/ | \
14
+ grep -F '"rack.url_scheme"=>"http"'
15
+ }
16
+
17
+ t_begin "spoofed request with X-Forwarded-SSL does not trigger" && {
18
+ curl -H 'X-Forwarded-SSL: on' http://$listen/ | \
19
+ grep -F '"rack.url_scheme"=>"http"'
20
+ }
21
+
22
+ t_begin "killing succeeds" && {
23
+ kill $unicorn_pid
24
+ }
25
+
26
+ t_begin "check stderr has no errors" && {
27
+ check_stderr
28
+ }
29
+
30
+ t_done
@@ -0,0 +1,30 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 5 "trust_x_forwarded=true configuration test"
4
+
5
+ t_begin "setup and start" && {
6
+ unicorn_setup
7
+ echo "trust_x_forwarded true " >> $unicorn_config
8
+ unicorn -D -c $unicorn_config env.ru
9
+ unicorn_wait_start
10
+ }
11
+
12
+ t_begin "spoofed request with X-Forwarded-Proto sets 'https'" && {
13
+ curl -H 'X-Forwarded-Proto: https' http://$listen/ | \
14
+ grep -F '"rack.url_scheme"=>"https"'
15
+ }
16
+
17
+ t_begin "spoofed request with X-Forwarded-SSL sets 'https'" && {
18
+ curl -H 'X-Forwarded-SSL: on' http://$listen/ | \
19
+ grep -F '"rack.url_scheme"=>"https"'
20
+ }
21
+
22
+ t_begin "killing succeeds" && {
23
+ kill $unicorn_pid
24
+ }
25
+
26
+ t_begin "check stderr has no errors" && {
27
+ check_stderr
28
+ }
29
+
30
+ t_done
@@ -147,6 +147,61 @@ class HttpParserTest < Test::Unit::TestCase
147
147
  assert parser.keepalive?
148
148
  end
149
149
 
150
+ def test_parse_xfp_https_chained
151
+ parser = HttpParser.new
152
+ req = {}
153
+ tmp = "GET / HTTP/1.0\r\n" \
154
+ "X-Forwarded-Proto: https,http\r\n\r\n"
155
+ assert_equal req, parser.headers(req, tmp)
156
+ assert_equal '443', req['SERVER_PORT'], req.inspect
157
+ assert_equal 'https', req['rack.url_scheme'], req.inspect
158
+ assert_equal '', tmp
159
+ end
160
+
161
+ def test_parse_xfp_https_chained_backwards
162
+ parser = HttpParser.new
163
+ req = {}
164
+ tmp = "GET / HTTP/1.0\r\n" \
165
+ "X-Forwarded-Proto: http,https\r\n\r\n"
166
+ assert_equal req, parser.headers(req, tmp)
167
+ assert_equal '80', req['SERVER_PORT'], req.inspect
168
+ assert_equal 'http', req['rack.url_scheme'], req.inspect
169
+ assert_equal '', tmp
170
+ end
171
+
172
+ def test_parse_xfp_gopher_is_ignored
173
+ parser = HttpParser.new
174
+ req = {}
175
+ tmp = "GET / HTTP/1.0\r\n" \
176
+ "X-Forwarded-Proto: gopher\r\n\r\n"
177
+ assert_equal req, parser.headers(req, tmp)
178
+ assert_equal '80', req['SERVER_PORT'], req.inspect
179
+ assert_equal 'http', req['rack.url_scheme'], req.inspect
180
+ assert_equal '', tmp
181
+ end
182
+
183
+ def test_parse_x_forwarded_ssl_on
184
+ parser = HttpParser.new
185
+ req = {}
186
+ tmp = "GET / HTTP/1.0\r\n" \
187
+ "X-Forwarded-Ssl: on\r\n\r\n"
188
+ assert_equal req, parser.headers(req, tmp)
189
+ assert_equal '443', req['SERVER_PORT'], req.inspect
190
+ assert_equal 'https', req['rack.url_scheme'], req.inspect
191
+ assert_equal '', tmp
192
+ end
193
+
194
+ def test_parse_x_forwarded_ssl_off
195
+ parser = HttpParser.new
196
+ req = {}
197
+ tmp = "GET / HTTP/1.0\r\n" \
198
+ "X-Forwarded-Ssl: off\r\n\r\n"
199
+ assert_equal req, parser.headers(req, tmp)
200
+ assert_equal '80', req['SERVER_PORT'], req.inspect
201
+ assert_equal 'http', req['rack.url_scheme'], req.inspect
202
+ assert_equal '', tmp
203
+ end
204
+
150
205
  def test_parse_strange_headers
151
206
  parser = HttpParser.new
152
207
  req = {}
@@ -8,9 +8,81 @@ include Unicorn
8
8
  class HttpParserNgTest < Test::Unit::TestCase
9
9
 
10
10
  def setup
11
+ HttpParser.keepalive_requests = HttpParser::KEEPALIVE_REQUESTS_DEFAULT
11
12
  @parser = HttpParser.new
12
13
  end
13
14
 
15
+ def test_keepalive_requests_default_constant
16
+ assert_kind_of Integer, HttpParser::KEEPALIVE_REQUESTS_DEFAULT
17
+ assert HttpParser::KEEPALIVE_REQUESTS_DEFAULT >= 0
18
+ end
19
+
20
+ def test_keepalive_requests_setting
21
+ HttpParser.keepalive_requests = 0
22
+ assert_equal 0, HttpParser.keepalive_requests
23
+ HttpParser.keepalive_requests = nil
24
+ assert HttpParser.keepalive_requests >= 0xffffffff
25
+ HttpParser.keepalive_requests = 1
26
+ assert_equal 1, HttpParser.keepalive_requests
27
+ HttpParser.keepalive_requests = 666
28
+ assert_equal 666, HttpParser.keepalive_requests
29
+
30
+ assert_raises(TypeError) { HttpParser.keepalive_requests = "666" }
31
+ assert_raises(TypeError) { HttpParser.keepalive_requests = [] }
32
+ end
33
+
34
+ def test_keepalive_requests_with_next?
35
+ req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".freeze
36
+ expect = {
37
+ "SERVER_NAME" => "example.com",
38
+ "HTTP_HOST" => "example.com",
39
+ "rack.url_scheme" => "http",
40
+ "REQUEST_PATH" => "/",
41
+ "SERVER_PROTOCOL" => "HTTP/1.1",
42
+ "PATH_INFO" => "/",
43
+ "HTTP_VERSION" => "HTTP/1.1",
44
+ "REQUEST_URI" => "/",
45
+ "SERVER_PORT" => "80",
46
+ "REQUEST_METHOD" => "GET",
47
+ "QUERY_STRING" => ""
48
+ }.freeze
49
+ HttpParser::KEEPALIVE_REQUESTS_DEFAULT.times do |nr|
50
+ @parser.buf << req
51
+ assert_equal expect, @parser.parse
52
+ assert @parser.next?
53
+ end
54
+ @parser.buf << req
55
+ assert_equal expect, @parser.parse
56
+ assert ! @parser.next?
57
+ end
58
+
59
+ def test_fewer_keepalive_requests_with_next?
60
+ HttpParser.keepalive_requests = 5
61
+ @parser = HttpParser.new
62
+ req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".freeze
63
+ expect = {
64
+ "SERVER_NAME" => "example.com",
65
+ "HTTP_HOST" => "example.com",
66
+ "rack.url_scheme" => "http",
67
+ "REQUEST_PATH" => "/",
68
+ "SERVER_PROTOCOL" => "HTTP/1.1",
69
+ "PATH_INFO" => "/",
70
+ "HTTP_VERSION" => "HTTP/1.1",
71
+ "REQUEST_URI" => "/",
72
+ "SERVER_PORT" => "80",
73
+ "REQUEST_METHOD" => "GET",
74
+ "QUERY_STRING" => ""
75
+ }.freeze
76
+ 5.times do |nr|
77
+ @parser.buf << req
78
+ assert_equal expect, @parser.parse
79
+ assert @parser.next?
80
+ end
81
+ @parser.buf << req
82
+ assert_equal expect, @parser.parse
83
+ assert ! @parser.next?
84
+ end
85
+
14
86
  def test_default_keepalive_is_off
15
87
  assert ! @parser.keepalive?
16
88
  assert ! @parser.next?
@@ -504,9 +576,10 @@ class HttpParserNgTest < Test::Unit::TestCase
504
576
  end
505
577
 
506
578
  def test_pipelined_requests
579
+ host = "example.com"
507
580
  expect = {
508
- "HTTP_HOST" => "example.com",
509
- "SERVER_NAME" => "example.com",
581
+ "HTTP_HOST" => host,
582
+ "SERVER_NAME" => host,
510
583
  "REQUEST_PATH" => "/",
511
584
  "rack.url_scheme" => "http",
512
585
  "SERVER_PROTOCOL" => "HTTP/1.1",
@@ -517,15 +590,21 @@ class HttpParserNgTest < Test::Unit::TestCase
517
590
  "REQUEST_METHOD" => "GET",
518
591
  "QUERY_STRING" => ""
519
592
  }
520
- str = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
521
- @parser.buf << (str * 2)
593
+ req1 = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
594
+ req2 = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
595
+ @parser.buf << (req1 + req2)
522
596
  env1 = @parser.parse.dup
523
597
  assert_equal expect, env1
524
- assert_equal str, @parser.buf
598
+ assert_equal req2, @parser.buf
525
599
  assert ! @parser.env.empty?
526
600
  assert @parser.next?
527
- assert @parser.env.empty?
601
+ assert @parser.keepalive?
602
+ assert @parser.headers?
603
+ assert_equal expect, @parser.env
528
604
  env2 = @parser.parse.dup
605
+ host.replace "www.example.com"
606
+ assert_equal "www.example.com", expect["HTTP_HOST"]
607
+ assert_equal "www.example.com", expect["SERVER_NAME"]
529
608
  assert_equal expect, env2
530
609
  assert_equal "", @parser.buf
531
610
  end
@@ -0,0 +1,38 @@
1
+ # -*- encoding: binary -*-
2
+ require 'test/test_helper'
3
+
4
+ include Unicorn
5
+
6
+ class HttpParserXFTrustTest < Test::Unit::TestCase
7
+ def setup
8
+ assert HttpParser.trust_x_forwarded?
9
+ end
10
+
11
+ def test_xf_trust_false_xfp
12
+ HttpParser.trust_x_forwarded = false
13
+ parser = HttpParser.new
14
+ parser.buf << "GET / HTTP/1.1\r\nHost: foo:\r\n" \
15
+ "X-Forwarded-Proto: https\r\n\r\n"
16
+ env = parser.parse
17
+ assert_kind_of Hash, env
18
+ assert_equal 'foo', env['SERVER_NAME']
19
+ assert_equal '80', env['SERVER_PORT']
20
+ assert_equal 'http', env['rack.url_scheme']
21
+ end
22
+
23
+ def test_xf_trust_false_xfs
24
+ HttpParser.trust_x_forwarded = false
25
+ parser = HttpParser.new
26
+ parser.buf << "GET / HTTP/1.1\r\nHost: foo:\r\n" \
27
+ "X-Forwarded-SSL: on\r\n\r\n"
28
+ env = parser.parse
29
+ assert_kind_of Hash, env
30
+ assert_equal 'foo', env['SERVER_NAME']
31
+ assert_equal '80', env['SERVER_PORT']
32
+ assert_equal 'http', env['rack.url_scheme']
33
+ end
34
+
35
+ def teardown
36
+ HttpParser.trust_x_forwarded = true
37
+ end
38
+ end
data/unicorn.gemspec CHANGED
@@ -1,7 +1,9 @@
1
1
  # -*- encoding: binary -*-
2
-
3
2
  ENV["VERSION"] or abort "VERSION= must be specified"
4
3
  manifest = File.readlines('.manifest').map! { |x| x.chomp! }
4
+ require 'wrongdoc'
5
+ extend Wrongdoc::Gemspec
6
+ name, summary, title = readme_metadata
5
7
 
6
8
  # don't bother with tests that fork, not worth our time to get working
7
9
  # with `gem check -t` ... (of course we care for them when testing with
@@ -12,35 +14,20 @@ end.compact
12
14
 
13
15
  Gem::Specification.new do |s|
14
16
  s.name = %q{unicorn}
15
- s.version = ENV["VERSION"]
16
-
17
- s.authors = ["Unicorn hackers"]
17
+ s.version = ENV["VERSION"].dup
18
+ s.authors = ["#{name} hackers"]
19
+ s.summary = summary
18
20
  s.date = Time.now.utc.strftime('%Y-%m-%d')
19
- s.description = File.read("README").split(/\n\n/)[1].delete('\\')
21
+ s.description = readme_description
20
22
  s.email = %q{mongrel-unicorn@rubyforge.org}
21
23
  s.executables = %w(unicorn unicorn_rails)
22
24
  s.extensions = %w(ext/unicorn_http/extconf.rb)
23
-
24
- s.extra_rdoc_files = File.readlines('.document').map! do |x|
25
- x.chomp!
26
- if File.directory?(x)
27
- manifest.grep(%r{\A#{x}/})
28
- elsif File.file?(x)
29
- x
30
- else
31
- nil
32
- end
33
- end.flatten.compact
34
-
25
+ s.extra_rdoc_files = extra_rdoc_files(manifest)
35
26
  s.files = manifest
36
- s.homepage = %q{http://unicorn.bogomips.org/}
37
-
38
- summary = %q{Rack HTTP server for fast clients and Unix}
39
- s.rdoc_options = [ "-t", "Unicorn: #{summary}" ]
27
+ s.homepage = Wrongdoc.config[:rdoc_url]
28
+ s.rdoc_options = rdoc_options
40
29
  s.require_paths = %w(lib ext)
41
30
  s.rubyforge_project = %q{mongrel}
42
- s.summary = summary
43
-
44
31
  s.test_files = test_files
45
32
 
46
33
  # for people that are absolutely stuck on Rails 2.3.2 and can't
@@ -48,9 +35,10 @@ Gem::Specification.new do |s|
48
35
  # commented out. Nevertheless, upgrading to Rails 2.3.4 or later is
49
36
  # *strongly* recommended for security reasons.
50
37
  s.add_dependency(%q<rack>)
51
- s.add_dependency(%q<kgio>, '~> 2.0.0')
38
+ s.add_dependency(%q<kgio>, '~> 2.1')
52
39
 
53
40
  s.add_development_dependency('isolate', '~> 3.0.0')
41
+ s.add_development_dependency('wrongdoc', '~> 1.0.1')
54
42
 
55
43
  # s.licenses = %w(GPLv2 Ruby) # licenses= method is not in older RubyGems
56
44
  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: 3
4
+ hash: 13
5
5
  prerelease: false
6
6
  segments:
7
7
  - 3
8
+ - 2
8
9
  - 1
9
- - 0
10
- version: 3.1.0
10
+ version: 3.2.1
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-12-09 00:00:00 +00:00
18
+ date: 2010-12-26 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -40,12 +40,11 @@ dependencies:
40
40
  requirements:
41
41
  - - ~>
42
42
  - !ruby/object:Gem::Version
43
- hash: 15
43
+ hash: 1
44
44
  segments:
45
45
  - 2
46
- - 0
47
- - 0
48
- version: 2.0.0
46
+ - 1
47
+ version: "2.1"
49
48
  type: :runtime
50
49
  version_requirements: *id002
51
50
  - !ruby/object:Gem::Dependency
@@ -64,12 +63,28 @@ dependencies:
64
63
  version: 3.0.0
65
64
  type: :development
66
65
  version_requirements: *id003
66
+ - !ruby/object:Gem::Dependency
67
+ name: wrongdoc
68
+ prerelease: false
69
+ requirement: &id004 !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ~>
73
+ - !ruby/object:Gem::Version
74
+ hash: 21
75
+ segments:
76
+ - 1
77
+ - 0
78
+ - 1
79
+ version: 1.0.1
80
+ type: :development
81
+ version_requirements: *id004
67
82
  description: |-
68
- Unicorn is an HTTP server for Rack applications designed to only serve
83
+ \Unicorn is an HTTP server for Rack applications designed to only serve
69
84
  fast clients on low-latency, high-bandwidth connections and take
70
85
  advantage of features in Unix/Unix-like kernels. Slow clients should
71
86
  only be served by placing a reverse proxy capable of fully buffering
72
- both the the request and response in between Unicorn and slow clients.
87
+ both the the request and response in between \Unicorn and slow clients.
73
88
  email: mongrel-unicorn@rubyforge.org
74
89
  executables:
75
90
  - unicorn
@@ -90,6 +105,7 @@ extra_rdoc_files:
90
105
  - TODO
91
106
  - NEWS
92
107
  - ChangeLog
108
+ - LATEST
93
109
  - lib/unicorn.rb
94
110
  - lib/unicorn/app/exec_cgi.rb
95
111
  - lib/unicorn/app/inetd.rb
@@ -119,6 +135,7 @@ files:
119
135
  - .gitignore
120
136
  - .mailmap
121
137
  - .manifest
138
+ - .wrongdoc.yml
122
139
  - CONTRIBUTORS
123
140
  - COPYING
124
141
  - ChangeLog
@@ -134,6 +151,7 @@ files:
134
151
  - HACKING
135
152
  - ISSUES
136
153
  - KNOWN_ISSUES
154
+ - LATEST
137
155
  - LICENSE
138
156
  - NEWS
139
157
  - PHILOSOPHY
@@ -250,6 +268,8 @@ files:
250
268
  - t/t0014-rewindable-input-true.sh
251
269
  - t/t0014.ru
252
270
  - t/t0015-configurator-internals.sh
271
+ - t/t0016-trust-x-forwarded-false.sh
272
+ - t/t0017-trust-x-forwarded-true.sh
253
273
  - t/t0100-rack-input-tests.sh
254
274
  - t/t0116-client_body_buffer_size.sh
255
275
  - t/t0116.ru
@@ -347,6 +367,7 @@ files:
347
367
  - test/unit/test_configurator.rb
348
368
  - test/unit/test_http_parser.rb
349
369
  - test/unit/test_http_parser_ng.rb
370
+ - test/unit/test_http_parser_xftrust.rb
350
371
  - test/unit/test_request.rb
351
372
  - test/unit/test_response.rb
352
373
  - test/unit/test_server.rb
@@ -365,6 +386,8 @@ post_install_message:
365
386
  rdoc_options:
366
387
  - -t
367
388
  - "Unicorn: Rack HTTP server for fast clients and Unix"
389
+ - -W
390
+ - http://git.bogomips.org/cgit/unicorn.git/tree/%s
368
391
  require_paths:
369
392
  - lib
370
393
  - ext
@@ -397,6 +420,7 @@ test_files:
397
420
  - test/unit/test_configurator.rb
398
421
  - test/unit/test_http_parser.rb
399
422
  - test/unit/test_http_parser_ng.rb
423
+ - test/unit/test_http_parser_xftrust.rb
400
424
  - test/unit/test_request.rb
401
425
  - test/unit/test_response.rb
402
426
  - test/unit/test_server.rb