unicorn 0.95.2 → 0.95.3
Sign up to get free protection for your applications and to get access to all the features.
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +25 -17
- data/Rakefile +29 -0
- data/ext/unicorn_http/unicorn_http_common.rl +2 -1
- data/lib/unicorn.rb +1 -4
- data/lib/unicorn/const.rb +1 -1
- data/lib/unicorn/tee_input.rb +42 -13
- data/local.mk.sample +2 -2
- data/test/unit/test_http_parser.rb +39 -0
- metadata +2 -2
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
@@ -1,21 +1,28 @@
|
|
1
1
|
# use GNU Make to run tests in parallel, and without depending on RubyGems
|
2
2
|
all:: test
|
3
|
+
|
3
4
|
ruby = ruby
|
4
5
|
rake = rake
|
5
6
|
ragel = ragel
|
7
|
+
|
6
8
|
GIT_URL = git://git.bogomips.org/unicorn.git
|
7
9
|
RLFLAGS = -G2
|
8
10
|
|
11
|
+
# lower-case vars are deprecated
|
12
|
+
RUBY = $(ruby)
|
13
|
+
RAKE = $(rake)
|
14
|
+
RAGEL = $(ragel)
|
15
|
+
|
9
16
|
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
10
17
|
@./GIT-VERSION-GEN
|
11
18
|
-include GIT-VERSION-FILE
|
12
19
|
-include local.mk
|
13
|
-
ruby_bin := $(shell which $(
|
20
|
+
ruby_bin := $(shell which $(RUBY))
|
14
21
|
ifeq ($(DLEXT),) # "so" for Linux
|
15
|
-
DLEXT := $(shell $(
|
22
|
+
DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts Config::CONFIG["DLEXT"]')
|
16
23
|
endif
|
17
24
|
ifeq ($(RUBY_VERSION),)
|
18
|
-
RUBY_VERSION := $(shell $(
|
25
|
+
RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
|
19
26
|
endif
|
20
27
|
|
21
28
|
# dunno how to implement this as concisely in Ruby, and hell, I love awk
|
@@ -45,9 +52,9 @@ inst_deps := $(c_files) $(rb_files) GNUmakefile test/test_helper.rb
|
|
45
52
|
|
46
53
|
ragel: $(ext)/unicorn_http.c
|
47
54
|
$(ext)/unicorn_http.c: $(rl_files)
|
48
|
-
cd $(@D) && $(
|
55
|
+
cd $(@D) && $(RAGEL) unicorn_http.rl -C $(RLFLAGS) -o $(@F)
|
49
56
|
$(ext)/Makefile: $(ext)/extconf.rb $(c_files)
|
50
|
-
cd $(@D) && $(
|
57
|
+
cd $(@D) && $(RUBY) extconf.rb
|
51
58
|
$(ext)/unicorn_http.$(DLEXT): $(ext)/Makefile
|
52
59
|
$(MAKE) -C $(@D)
|
53
60
|
lib/unicorn_http.$(DLEXT): $(ext)/unicorn_http.$(DLEXT)
|
@@ -65,11 +72,11 @@ $(test_prefix)/.stamp: $(inst_deps)
|
|
65
72
|
|
66
73
|
# this is only intended to be run within $(test_prefix)
|
67
74
|
shebang: $(bins)
|
68
|
-
$(
|
75
|
+
$(RUBY) -i -p -e '$$_.gsub!(%r{^#!.*$$},"#!$(ruby_bin)")' $^
|
69
76
|
|
70
77
|
t_log := $(T_log) $(T_n_log)
|
71
78
|
test: $(T) $(T_n)
|
72
|
-
@cat $(t_log) | $(
|
79
|
+
@cat $(t_log) | $(RUBY) test/aggregate.rb
|
73
80
|
@$(RM) $(t_log)
|
74
81
|
|
75
82
|
test-exec: $(wildcard test/exec/test_*.rb)
|
@@ -87,18 +94,18 @@ else
|
|
87
94
|
# so we use a stamp file to indicate success and
|
88
95
|
# have rm fail if the stamp didn't get created
|
89
96
|
stamp = $@$(log_suffix).ok
|
90
|
-
quiet_pre = @echo $(
|
97
|
+
quiet_pre = @echo $(RUBY) $(arg) $(TEST_OPTS); ! test -f $(stamp) && (
|
91
98
|
quiet_post = && > $(stamp) )2>&1 | tee $(t); \
|
92
99
|
rm $(stamp) 2>/dev/null && $(check_test)
|
93
100
|
endif
|
94
101
|
|
95
102
|
# not all systems have setsid(8), we need it because we spam signals
|
96
103
|
# stupidly in some tests...
|
97
|
-
rb_setsid := $(
|
104
|
+
rb_setsid := $(RUBY) -e 'Process.setsid' -e 'exec *ARGV'
|
98
105
|
|
99
106
|
# TRACER='strace -f -o $(t).strace -s 100000'
|
100
107
|
run_test = $(quiet_pre) \
|
101
|
-
$(rb_setsid) $(TRACER) $(
|
108
|
+
$(rb_setsid) $(TRACER) $(RUBY) -w $(arg) $(TEST_OPTS) $(quiet_post) || \
|
102
109
|
(sed "s,^,$(extra): ," >&2 < $(t); exit 1)
|
103
110
|
|
104
111
|
%.n: arg = $(subst .n,,$(subst --, -n ,$@))
|
@@ -121,7 +128,7 @@ install: $(bins) $(ext)/unicorn_http.c
|
|
121
128
|
$(RM) -r .install-tmp
|
122
129
|
mkdir .install-tmp
|
123
130
|
cp -p bin/* .install-tmp
|
124
|
-
$(
|
131
|
+
$(RUBY) setup.rb all
|
125
132
|
$(RM) $^
|
126
133
|
mv .install-tmp/* bin/
|
127
134
|
$(RM) -r .install-tmp
|
@@ -153,7 +160,7 @@ manifest: $(pkg_extra) man
|
|
153
160
|
$(RM) $@+
|
154
161
|
|
155
162
|
NEWS: GIT-VERSION-FILE
|
156
|
-
$(
|
163
|
+
$(RAKE) -s news_rdoc > $@+
|
157
164
|
mv $@+ $@
|
158
165
|
|
159
166
|
SINCE = 0.94.0
|
@@ -175,6 +182,7 @@ atom = <link rel="alternate" title="Atom feed" href="$(1)" \
|
|
175
182
|
# using rdoc 2.4.1+
|
176
183
|
doc: .document $(ext)/unicorn_http.c NEWS ChangeLog
|
177
184
|
for i in $(man1_bins); do > $$i; done
|
185
|
+
find bin lib -type f -name '*.rbc' -exec rm -f '{}' ';'
|
178
186
|
rdoc -Na -t "$(shell sed -ne '1s/^= //p' README)"
|
179
187
|
install -m644 COPYING doc/COPYING
|
180
188
|
install -m644 $(shell grep '^[A-Z]' .document) doc/
|
@@ -183,13 +191,13 @@ doc: .document $(ext)/unicorn_http.c NEWS ChangeLog
|
|
183
191
|
cd doc && for i in $(base_bins); do \
|
184
192
|
sed -e '/"documentation">/r man1/'$$i'.1.html' \
|
185
193
|
< $${i}_1.html > tmp && mv tmp $${i}_1.html; done
|
186
|
-
$(
|
194
|
+
$(RUBY) -i -p -e \
|
187
195
|
'$$_.gsub!("</title>",%q{\&$(call atom,$(cgit_atom))})' \
|
188
196
|
doc/ChangeLog.html
|
189
|
-
$(
|
197
|
+
$(RUBY) -i -p -e \
|
190
198
|
'$$_.gsub!("</title>",%q{\&$(call atom,$(news_atom))})' \
|
191
199
|
doc/NEWS.html doc/README.html
|
192
|
-
$(
|
200
|
+
$(RAKE) -s news_atom > doc/NEWS.atom.xml
|
193
201
|
cd doc && ln README.html tmp && mv tmp index.html
|
194
202
|
$(RM) $(man1_bins)
|
195
203
|
|
@@ -223,10 +231,10 @@ release_changes := release_changes-$(VERSION)
|
|
223
231
|
release-notes: $(release_notes)
|
224
232
|
release-changes: $(release_changes)
|
225
233
|
$(release_changes):
|
226
|
-
$(
|
234
|
+
$(RAKE) -s release_changes > $@+
|
227
235
|
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
228
236
|
$(release_notes):
|
229
|
-
GIT_URL=$(GIT_URL) $(
|
237
|
+
GIT_URL=$(GIT_URL) $(RAKE) -s release_notes > $@+
|
230
238
|
$(VISUAL) $@+ && test -s $@+ && mv $@+ $@
|
231
239
|
|
232
240
|
# ensures we're actually on the tagged $(VERSION), only used for release
|
data/Rakefile
CHANGED
@@ -146,6 +146,35 @@ task :raa_update do
|
|
146
146
|
puts res.body
|
147
147
|
end
|
148
148
|
|
149
|
+
desc "post to FM"
|
150
|
+
task :fm_update do
|
151
|
+
require 'tempfile'
|
152
|
+
require 'net/http'
|
153
|
+
require 'net/netrc'
|
154
|
+
require 'json'
|
155
|
+
version = ENV['VERSION'] or abort "VERSION= needed"
|
156
|
+
uri = URI.parse('http://freshmeat.net/projects/unicorn/releases.json')
|
157
|
+
rc = Net::Netrc.locate('unicorn-fm') or abort "~/.netrc not found"
|
158
|
+
api_token = rc.password
|
159
|
+
changelog = tags.find { |t| t[:tag] == "v#{version}" }[:body]
|
160
|
+
tmp = Tempfile.new('fm-changelog')
|
161
|
+
tmp.syswrite(changelog)
|
162
|
+
system(ENV["VISUAL"], tmp.path) or abort "#{ENV["VISUAL"]} failed: #$?"
|
163
|
+
changelog = File.read(tmp.path).strip
|
164
|
+
|
165
|
+
req = {
|
166
|
+
"auth_code" => api_token,
|
167
|
+
"release" => {
|
168
|
+
"tag_list" => "Stable",
|
169
|
+
"version" => version,
|
170
|
+
"changelog" => changelog,
|
171
|
+
},
|
172
|
+
}.to_json
|
173
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
174
|
+
p http.post(uri.path, req, {'Content-Type'=>'application/json'})
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
149
178
|
# optional rake-compiler support in case somebody needs to cross compile
|
150
179
|
begin
|
151
180
|
require 'rubygems'
|
@@ -28,6 +28,7 @@
|
|
28
28
|
scheme = ( "http"i ("s"i)? ) $downcase_char >mark %scheme;
|
29
29
|
hostname = (alnum | "-" | "." | "_")+;
|
30
30
|
host_with_port = (hostname (":" digit*)?) >mark %host;
|
31
|
+
userinfo = ((unreserved | escape | ";" | ":" | "&" | "=" | "+")+ "@")*;
|
31
32
|
|
32
33
|
path = ( pchar+ ( "/" pchar* )* ) ;
|
33
34
|
query = ( uchar | reserved )* %query_string ;
|
@@ -36,7 +37,7 @@
|
|
36
37
|
rel_path = (path? (";" params)? %request_path) ("?" %start_query query)?;
|
37
38
|
absolute_path = ( "/"+ rel_path );
|
38
39
|
path_uri = absolute_path > mark %request_uri;
|
39
|
-
Absolute_URI = (scheme "://" host_with_port path_uri);
|
40
|
+
Absolute_URI = (scheme "://" userinfo host_with_port path_uri);
|
40
41
|
|
41
42
|
Request_URI = ((absolute_path | "*") >mark %request_uri) | Absolute_URI;
|
42
43
|
Fragment = ( uchar | reserved )* >mark %fragment;
|
data/lib/unicorn.rb
CHANGED
@@ -249,9 +249,6 @@ module Unicorn
|
|
249
249
|
def stdout_path=(path); redirect_io($stdout, path); end
|
250
250
|
def stderr_path=(path); redirect_io($stderr, path); end
|
251
251
|
|
252
|
-
alias_method :set_pid, :pid=
|
253
|
-
undef_method :pid=
|
254
|
-
|
255
252
|
# sets the path for the PID file of the master process
|
256
253
|
def pid=(path)
|
257
254
|
if path
|
@@ -274,7 +271,7 @@ module Unicorn
|
|
274
271
|
File.rename(fp.path, path)
|
275
272
|
fp.close
|
276
273
|
end
|
277
|
-
|
274
|
+
super(path)
|
278
275
|
end
|
279
276
|
|
280
277
|
# add a given address to the +listeners+ set, idempotently
|
data/lib/unicorn/const.rb
CHANGED
@@ -7,7 +7,7 @@ module Unicorn
|
|
7
7
|
# gave about a 3% to 10% performance improvement over using the strings directly.
|
8
8
|
# Symbols did not really improve things much compared to constants.
|
9
9
|
module Const
|
10
|
-
UNICORN_VERSION="0.95.
|
10
|
+
UNICORN_VERSION="0.95.3"
|
11
11
|
|
12
12
|
DEFAULT_HOST = "0.0.0.0" # default TCP listen host address
|
13
13
|
DEFAULT_PORT = 8080 # default TCP listen port
|
data/lib/unicorn/tee_input.rb
CHANGED
@@ -3,15 +3,20 @@
|
|
3
3
|
module Unicorn
|
4
4
|
|
5
5
|
# acts like tee(1) on an input input to provide a input-like stream
|
6
|
-
# while providing rewindable semantics through a File/StringIO
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
6
|
+
# while providing rewindable semantics through a File/StringIO backing
|
7
|
+
# store. On the first pass, the input is only read on demand so your
|
8
|
+
# Rack application can use input notification (upload progress and
|
9
|
+
# like). This should fully conform to the Rack::Lint::InputWrapper
|
10
10
|
# specification on the public API. This class is intended to be a
|
11
|
-
# strict interpretation of Rack::InputWrapper functionality and
|
12
|
-
# not support any deviations from it.
|
11
|
+
# strict interpretation of Rack::Lint::InputWrapper functionality and
|
12
|
+
# will not support any deviations from it.
|
13
|
+
#
|
14
|
+
# When processing uploads, Unicorn exposes a TeeInput object under
|
15
|
+
# "rack.input" of the Rack environment.
|
13
16
|
class TeeInput < Struct.new(:socket, :req, :parser, :buf)
|
14
17
|
|
18
|
+
# Initializes a new TeeInput object. You normally do not have to call
|
19
|
+
# this unless you are writing an HTTP server.
|
15
20
|
def initialize(*args)
|
16
21
|
super(*args)
|
17
22
|
@size = parser.content_length
|
@@ -24,10 +29,16 @@ module Unicorn
|
|
24
29
|
end
|
25
30
|
end
|
26
31
|
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
32
|
+
# :call-seq:
|
33
|
+
# ios.size => Integer
|
34
|
+
#
|
35
|
+
# Returns the size of the input. For requests with a Content-Length
|
36
|
+
# header value, this will not read data off the socket and just return
|
37
|
+
# the value of the Content-Length header as an Integer.
|
38
|
+
#
|
39
|
+
# For Transfer-Encoding:chunked requests, this requires consuming
|
40
|
+
# all of the input stream before returning since there's no other
|
41
|
+
# way to determine the size of the request body beforehand.
|
31
42
|
def size
|
32
43
|
@size and return @size
|
33
44
|
|
@@ -41,8 +52,7 @@ module Unicorn
|
|
41
52
|
@size = @tmp.size
|
42
53
|
end
|
43
54
|
|
44
|
-
# call-seq:
|
45
|
-
# ios = env['rack.input']
|
55
|
+
# :call-seq:
|
46
56
|
# ios.read([length [, buffer ]]) => string, buffer, or nil
|
47
57
|
#
|
48
58
|
# Reads at most length bytes from the I/O stream, or to the end of
|
@@ -82,7 +92,15 @@ module Unicorn
|
|
82
92
|
end
|
83
93
|
end
|
84
94
|
|
85
|
-
#
|
95
|
+
# :call-seq:
|
96
|
+
# ios.gets => string or nil
|
97
|
+
#
|
98
|
+
# Reads the next ``line'' from the I/O stream; lines are separated
|
99
|
+
# by the global record separator ($/, typically "\n"). A global
|
100
|
+
# record separator of nil reads the entire unread contents of ios.
|
101
|
+
# Returns nil if called at the end of file.
|
102
|
+
# This takes zero arguments for strict Rack::Lint compatibility,
|
103
|
+
# unlike IO#gets.
|
86
104
|
def gets
|
87
105
|
socket or return @tmp.gets
|
88
106
|
nil == $/ and return read
|
@@ -109,6 +127,11 @@ module Unicorn
|
|
109
127
|
line
|
110
128
|
end
|
111
129
|
|
130
|
+
# :call-seq:
|
131
|
+
# ios.each { |line| block } => ios
|
132
|
+
#
|
133
|
+
# Executes the block for every ``line'' in *ios*, where lines are
|
134
|
+
# separated by the global record separator ($/, typically "\n").
|
112
135
|
def each(&block)
|
113
136
|
while line = gets
|
114
137
|
yield line
|
@@ -117,6 +140,12 @@ module Unicorn
|
|
117
140
|
self # Rack does not specify what the return value is here
|
118
141
|
end
|
119
142
|
|
143
|
+
# :call-seq:
|
144
|
+
# ios.rewind => 0
|
145
|
+
#
|
146
|
+
# Positions the *ios* pointer to the beginning of input, returns
|
147
|
+
# the offset (zero) of the +ios+ pointer. Subsequent reads will
|
148
|
+
# start from the beginning of the previously-buffered input.
|
120
149
|
def rewind
|
121
150
|
@tmp.rewind # Rack does not specify what the return value is here
|
122
151
|
end
|
data/local.mk.sample
CHANGED
@@ -11,12 +11,12 @@ gems := rack-1.0.1
|
|
11
11
|
# fork+exec heavy with Ruby.
|
12
12
|
prefix = $(HOME)
|
13
13
|
ifeq ($(r19),)
|
14
|
-
|
14
|
+
RUBY := $(prefix)/bin/ruby
|
15
15
|
gem_paths := $(addprefix $(prefix)/lib/ruby/gems/1.8/gems/,$(gems))
|
16
16
|
else
|
17
17
|
prefix := $(prefix)/ruby-1.9
|
18
18
|
export PATH := $(prefix)/bin:$(PATH)
|
19
|
-
|
19
|
+
RUBY := $(prefix)/bin/ruby --disable-gems
|
20
20
|
gem_paths := $(addprefix $(prefix)/lib/ruby/gems/1.9.1/gems/,$(gems))
|
21
21
|
endif
|
22
22
|
|
@@ -298,6 +298,45 @@ class HttpParserTest < Test::Unit::TestCase
|
|
298
298
|
assert ! parser.keepalive?
|
299
299
|
end
|
300
300
|
|
301
|
+
# some dumb clients add users because they're stupid
|
302
|
+
def test_absolute_uri_w_user
|
303
|
+
parser = HttpParser.new
|
304
|
+
req = {}
|
305
|
+
http = "GET http://user%20space@example.com/foo?q=bar HTTP/1.0\r\n\r\n"
|
306
|
+
assert_equal req, parser.headers(req, http)
|
307
|
+
assert_equal 'http', req['rack.url_scheme']
|
308
|
+
assert_equal '/foo?q=bar', req['REQUEST_URI']
|
309
|
+
assert_equal '/foo', req['REQUEST_PATH']
|
310
|
+
assert_equal 'q=bar', req['QUERY_STRING']
|
311
|
+
|
312
|
+
assert_equal 'example.com', req['HTTP_HOST']
|
313
|
+
assert_equal 'example.com', req['SERVER_NAME']
|
314
|
+
assert_equal '80', req['SERVER_PORT']
|
315
|
+
assert_equal "", http
|
316
|
+
assert ! parser.keepalive?
|
317
|
+
end
|
318
|
+
|
319
|
+
# since Mongrel supported anything URI.parse supported, we're stuck
|
320
|
+
# supporting everything URI.parse supports
|
321
|
+
def test_absolute_uri_uri_parse
|
322
|
+
"#{URI::REGEXP::PATTERN::UNRESERVED};:&=+$,".split(//).each do |char|
|
323
|
+
parser = HttpParser.new
|
324
|
+
req = {}
|
325
|
+
http = "GET http://#{char}@example.com/ HTTP/1.0\r\n\r\n"
|
326
|
+
assert_equal req, parser.headers(req, http)
|
327
|
+
assert_equal 'http', req['rack.url_scheme']
|
328
|
+
assert_equal '/', req['REQUEST_URI']
|
329
|
+
assert_equal '/', req['REQUEST_PATH']
|
330
|
+
assert_equal '', req['QUERY_STRING']
|
331
|
+
|
332
|
+
assert_equal 'example.com', req['HTTP_HOST']
|
333
|
+
assert_equal 'example.com', req['SERVER_NAME']
|
334
|
+
assert_equal '80', req['SERVER_PORT']
|
335
|
+
assert_equal "", http
|
336
|
+
assert ! parser.keepalive?
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
301
340
|
def test_absolute_uri
|
302
341
|
parser = HttpParser.new
|
303
342
|
req = {}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unicorn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.95.
|
4
|
+
version: 0.95.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Unicorn hackers
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-12-
|
12
|
+
date: 2009-12-21 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|