unicorn 3.1.0 → 3.2.1

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.
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