unicorn 0.9.2 → 0.90.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/CHANGELOG +3 -0
- data/GNUmakefile +7 -7
- data/Manifest +20 -23
- data/README +16 -13
- data/TODO +5 -3
- data/bin/unicorn +1 -1
- data/bin/unicorn_rails +1 -1
- data/ext/unicorn_http/c_util.h +107 -0
- data/ext/unicorn_http/common_field_optimization.h +110 -0
- data/ext/unicorn_http/ext_help.h +41 -5
- data/ext/unicorn_http/extconf.rb +3 -1
- data/ext/unicorn_http/global_variables.h +93 -0
- data/ext/unicorn_http/unicorn_http.c +2123 -326
- data/ext/unicorn_http/unicorn_http.rl +488 -87
- data/ext/unicorn_http/unicorn_http_common.rl +12 -1
- data/lib/unicorn.rb +0 -2
- data/lib/unicorn/app/exec_cgi.rb +0 -1
- data/lib/unicorn/app/inetd.rb +2 -0
- data/lib/unicorn/app/old_rails/static.rb +0 -2
- data/lib/unicorn/const.rb +1 -5
- data/lib/unicorn/http_request.rb +13 -29
- data/lib/unicorn/http_response.rb +1 -1
- data/lib/unicorn/tee_input.rb +48 -46
- data/lib/unicorn/util.rb +3 -3
- data/test/benchmark/README +0 -5
- data/test/exec/test_exec.rb +4 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/.gitignore +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/Rakefile +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/app/controllers/application_controller.rb +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/app/controllers/foo_controller.rb +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/app/helpers/application_helper.rb +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/boot.rb +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/database.yml +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/environment.rb +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/environments/development.rb +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/environments/production.rb +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/routes.rb +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/db/.gitignore +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/public/404.html +0 -0
- data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/public/500.html +0 -0
- data/test/unit/test_http_parser.rb +112 -47
- data/test/unit/test_http_parser_ng.rb +284 -0
- data/test/unit/test_request.rb +25 -7
- data/test/unit/test_response.rb +11 -0
- data/test/unit/test_server.rb +7 -2
- data/test/unit/test_signals.rb +2 -0
- data/test/unit/test_tee_input.rb +118 -2
- data/test/unit/test_upload.rb +1 -1
- data/test/unit/test_util.rb +5 -0
- data/unicorn.gemspec +6 -6
- metadata +33 -37
- data/ext/unicorn_http/unicorn_http.h +0 -1289
- data/lib/unicorn/chunked_reader.rb +0 -77
- data/lib/unicorn/trailer_parser.rb +0 -52
- data/test/benchmark/big_request.rb +0 -44
- data/test/benchmark/request.rb +0 -56
- data/test/benchmark/response.rb +0 -30
- data/test/unit/test_chunked_reader.rb +0 -123
- data/test/unit/test_trailer_parser.rb +0 -52
data/.gitignore
CHANGED
data/CHANGELOG
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
v0.90.0 - switch chunking+trailer handling to Ragel, v0.8.4 fixes
|
1
2
|
v0.9.2 - Ruby 1.9.2 preview1 compatibility
|
2
3
|
v0.9.1 - FD_CLOEXEC portability fix (v0.8.2 port)
|
3
4
|
v0.9.0 - bodies: "Transfer-Encoding: chunked", rewindable streaming
|
5
|
+
v0.8.4 - pass through unknown HTTP status codes
|
6
|
+
v0.8.3 - Ruby 1.9.2 preview1 compatibility
|
4
7
|
v0.8.2 - socket handling bugfixes and usability tweaks
|
5
8
|
v0.8.1 - safer timeout handling, more consistent reload behavior
|
6
9
|
v0.8.0 - enforce Rack dependency, minor performance improvements and fixes
|
data/GNUmakefile
CHANGED
@@ -28,13 +28,13 @@ T_r_log := $(subst .r,$(log_suffix),$(T_r))
|
|
28
28
|
test_prefix = $(CURDIR)/test/install-$(RUBY_VERSION)
|
29
29
|
|
30
30
|
ext := ext/unicorn_http
|
31
|
-
c_files := $(
|
31
|
+
c_files := $(ext)/unicorn_http.c $(wildcard $(ext)/*.h)
|
32
32
|
rl_files := $(addprefix $(ext)/,unicorn_http.rl unicorn_http_common.rl)
|
33
33
|
rb_files := $(shell grep '^\(bin\|lib\)' Manifest)
|
34
34
|
inst_deps := $(c_files) $(rb_files)
|
35
35
|
|
36
|
-
ragel: $(ext)/unicorn_http.
|
37
|
-
$(ext)/unicorn_http.
|
36
|
+
ragel: $(ext)/unicorn_http.c
|
37
|
+
$(ext)/unicorn_http.c: $(rl_files)
|
38
38
|
cd $(@D) && $(ragel) unicorn_http.rl -C $(RLFLAGS) -o $(@F)
|
39
39
|
$(ruby) -i -p -e '$$_.gsub!(%r{[ \t]*$$},"")' $@
|
40
40
|
$(ext)/Makefile: $(ext)/extconf.rb $(c_files)
|
@@ -103,14 +103,14 @@ $(T): export RUBYLIB := $(test_prefix):$(test_prefix)/lib:$(RUBYLIB)
|
|
103
103
|
$(T): $(test_prefix)/.stamp
|
104
104
|
$(run_test)
|
105
105
|
|
106
|
-
install: $(bins)
|
106
|
+
install: $(bins) $(ext)/unicorn_http.c
|
107
107
|
$(prep_setup_rb)
|
108
108
|
$(RM) -r .install-tmp
|
109
109
|
mkdir .install-tmp
|
110
|
-
cp -p
|
110
|
+
cp -p bin/* .install-tmp
|
111
111
|
$(ruby) setup.rb all
|
112
112
|
$(RM) $^
|
113
|
-
mv
|
113
|
+
mv .install-tmp/* bin/
|
114
114
|
$(RM) -r .install-tmp
|
115
115
|
$(prep_setup_rb)
|
116
116
|
|
@@ -124,7 +124,7 @@ clean:
|
|
124
124
|
$(RM) -r $(test_prefix)
|
125
125
|
|
126
126
|
Manifest:
|
127
|
-
git ls-files > $@+
|
127
|
+
(git ls-files && echo $(ext)/unicorn_http.c) | LC_ALL=C sort > $@+
|
128
128
|
cmp $@+ $@ || mv $@+ $@
|
129
129
|
$(RM) -f $@+
|
130
130
|
|
data/Manifest
CHANGED
@@ -18,10 +18,12 @@ bin/unicorn_rails
|
|
18
18
|
examples/echo.ru
|
19
19
|
examples/git.ru
|
20
20
|
examples/init.sh
|
21
|
+
ext/unicorn_http/c_util.h
|
22
|
+
ext/unicorn_http/common_field_optimization.h
|
21
23
|
ext/unicorn_http/ext_help.h
|
22
24
|
ext/unicorn_http/extconf.rb
|
25
|
+
ext/unicorn_http/global_variables.h
|
23
26
|
ext/unicorn_http/unicorn_http.c
|
24
|
-
ext/unicorn_http/unicorn_http.h
|
25
27
|
ext/unicorn_http/unicorn_http.rl
|
26
28
|
ext/unicorn_http/unicorn_http_common.rl
|
27
29
|
lib/unicorn.rb
|
@@ -30,7 +32,6 @@ lib/unicorn/app/inetd.rb
|
|
30
32
|
lib/unicorn/app/old_rails.rb
|
31
33
|
lib/unicorn/app/old_rails/static.rb
|
32
34
|
lib/unicorn/cgi_wrapper.rb
|
33
|
-
lib/unicorn/chunked_reader.rb
|
34
35
|
lib/unicorn/configurator.rb
|
35
36
|
lib/unicorn/const.rb
|
36
37
|
lib/unicorn/http_request.rb
|
@@ -38,16 +39,12 @@ lib/unicorn/http_response.rb
|
|
38
39
|
lib/unicorn/launcher.rb
|
39
40
|
lib/unicorn/socket_helper.rb
|
40
41
|
lib/unicorn/tee_input.rb
|
41
|
-
lib/unicorn/trailer_parser.rb
|
42
42
|
lib/unicorn/util.rb
|
43
43
|
local.mk.sample
|
44
44
|
setup.rb
|
45
45
|
test/aggregate.rb
|
46
46
|
test/benchmark/README
|
47
|
-
test/benchmark/big_request.rb
|
48
47
|
test/benchmark/dd.ru
|
49
|
-
test/benchmark/request.rb
|
50
|
-
test/benchmark/response.rb
|
51
48
|
test/exec/README
|
52
49
|
test/exec/test_exec.rb
|
53
50
|
test/rails/app-1.2.3/.gitignore
|
@@ -110,31 +107,31 @@ test/rails/app-2.2.2/db/.gitignore
|
|
110
107
|
test/rails/app-2.2.2/log/.gitignore
|
111
108
|
test/rails/app-2.2.2/public/404.html
|
112
109
|
test/rails/app-2.2.2/public/500.html
|
113
|
-
test/rails/app-2.3.
|
114
|
-
test/rails/app-2.3.
|
115
|
-
test/rails/app-2.3.
|
116
|
-
test/rails/app-2.3.
|
117
|
-
test/rails/app-2.3.
|
118
|
-
test/rails/app-2.3.
|
119
|
-
test/rails/app-2.3.
|
120
|
-
test/rails/app-2.3.
|
121
|
-
test/rails/app-2.3.
|
122
|
-
test/rails/app-2.3.
|
123
|
-
test/rails/app-2.3.
|
124
|
-
test/rails/app-2.3.
|
125
|
-
test/rails/app-2.3.
|
126
|
-
test/rails/app-2.3.
|
127
|
-
test/rails/app-2.3.
|
110
|
+
test/rails/app-2.3.3.1/.gitignore
|
111
|
+
test/rails/app-2.3.3.1/Rakefile
|
112
|
+
test/rails/app-2.3.3.1/app/controllers/application_controller.rb
|
113
|
+
test/rails/app-2.3.3.1/app/controllers/foo_controller.rb
|
114
|
+
test/rails/app-2.3.3.1/app/helpers/application_helper.rb
|
115
|
+
test/rails/app-2.3.3.1/config/boot.rb
|
116
|
+
test/rails/app-2.3.3.1/config/database.yml
|
117
|
+
test/rails/app-2.3.3.1/config/environment.rb
|
118
|
+
test/rails/app-2.3.3.1/config/environments/development.rb
|
119
|
+
test/rails/app-2.3.3.1/config/environments/production.rb
|
120
|
+
test/rails/app-2.3.3.1/config/routes.rb
|
121
|
+
test/rails/app-2.3.3.1/db/.gitignore
|
122
|
+
test/rails/app-2.3.3.1/log/.gitignore
|
123
|
+
test/rails/app-2.3.3.1/public/404.html
|
124
|
+
test/rails/app-2.3.3.1/public/500.html
|
128
125
|
test/rails/test_rails.rb
|
129
126
|
test/test_helper.rb
|
130
|
-
test/unit/test_chunked_reader.rb
|
131
127
|
test/unit/test_configurator.rb
|
132
128
|
test/unit/test_http_parser.rb
|
129
|
+
test/unit/test_http_parser_ng.rb
|
133
130
|
test/unit/test_request.rb
|
134
131
|
test/unit/test_response.rb
|
135
132
|
test/unit/test_server.rb
|
136
133
|
test/unit/test_signals.rb
|
137
134
|
test/unit/test_socket_helper.rb
|
138
|
-
test/unit/
|
135
|
+
test/unit/test_tee_input.rb
|
139
136
|
test/unit/test_upload.rb
|
140
137
|
test/unit/test_util.rb
|
data/README
CHANGED
@@ -3,16 +3,14 @@
|
|
3
3
|
== Features
|
4
4
|
|
5
5
|
* Designed for Rack, Unix, fast clients, and ease-of-debugging. We
|
6
|
-
cut out
|
6
|
+
cut out everything that is better supported by the operating system,
|
7
|
+
nginx or Rack.
|
7
8
|
|
8
|
-
*
|
9
|
-
down from Mongrel) is written in C. Unicorn is compatible with
|
10
|
-
both Ruby 1.8 and 1.9. A pure-Ruby (but still Unix-only) version
|
11
|
-
is planned.
|
9
|
+
* Compatible with both Ruby 1.8 and 1.9, Rubinius support is planned.
|
12
10
|
|
13
11
|
* Process management: Unicorn will reap and restart workers that
|
14
12
|
die from broken apps. There is no need to manage multiple processes
|
15
|
-
or ports yourself. Unicorn can spawn and manage any
|
13
|
+
or ports yourself. Unicorn can spawn and manage any number of
|
16
14
|
worker processes you choose to scale to your backend.
|
17
15
|
|
18
16
|
* Load balancing is done entirely by the operating system kernel.
|
@@ -20,7 +18,7 @@
|
|
20
18
|
|
21
19
|
* Does not care if your application is thread-safe or not, workers
|
22
20
|
all run within their own isolated address space and only serve one
|
23
|
-
client at a time.
|
21
|
+
client at a time for maximum robustness.
|
24
22
|
|
25
23
|
* Supports all Rack applications, along with pre-Rack versions of
|
26
24
|
Ruby on Rails via a Rack wrapper.
|
@@ -31,10 +29,9 @@
|
|
31
29
|
Unicorn also takes steps to ensure multi-line log entries from one
|
32
30
|
request all stay within the same file.
|
33
31
|
|
34
|
-
* nginx-style binary
|
32
|
+
* nginx-style binary upgrades without losing connections.
|
35
33
|
You can upgrade Unicorn, your entire application, libraries
|
36
|
-
and even your Ruby interpreter
|
37
|
-
installed in the same path.
|
34
|
+
and even your Ruby interpreter without dropping clients.
|
38
35
|
|
39
36
|
* before_fork and after_fork hooks in case your application
|
40
37
|
has special needs when dealing with forked processes. These
|
@@ -48,11 +45,17 @@
|
|
48
45
|
each worker process can also bind to a private port via the
|
49
46
|
after_fork hook for easy debugging.
|
50
47
|
|
48
|
+
* Simple and easy Ruby DSL for configuration.
|
49
|
+
|
50
|
+
* Decodes chunked transfers on-the-fly, thus allowing upload progress
|
51
|
+
notification to be implemented as well as being able to tunnel
|
52
|
+
arbitrary stream-based protocols over HTTP.
|
53
|
+
|
51
54
|
== Versions
|
52
55
|
|
53
|
-
{
|
56
|
+
{Current v0.90.0}[http://git.bogomips.org/cgit/unicorn.git/tag/?id=v0.90.0]
|
54
57
|
|
55
|
-
{
|
58
|
+
{Old Stable v0.8.4}[http://git.bogomips.org/cgit/unicorn.git/tag/?id=v0.8.4]
|
56
59
|
|
57
60
|
== License
|
58
61
|
|
@@ -77,7 +80,7 @@ http://rubyforge.org/frs/?group_id=1306
|
|
77
80
|
|
78
81
|
You may also install it via Rubygems on Rubyforge:
|
79
82
|
|
80
|
-
gem install unicorn
|
83
|
+
gem install unicorn
|
81
84
|
|
82
85
|
You can get the latest source via git from the following locations
|
83
86
|
(these versions may not be stable):
|
data/TODO
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
*
|
1
|
+
* security audit, fuzz testing
|
2
2
|
|
3
3
|
* manpages (why do so few Ruby executables come with proper manpages?)
|
4
4
|
|
5
|
-
* code cleanups
|
5
|
+
* code cleanups
|
6
6
|
|
7
|
-
*
|
7
|
+
* launchers - add stop/start/kill/upgrade commands
|
8
|
+
|
9
|
+
* Rainbows!
|
8
10
|
|
9
11
|
* Rubinius support
|
data/bin/unicorn
CHANGED
@@ -120,10 +120,10 @@ require 'pp' if $DEBUG
|
|
120
120
|
app = lambda do ||
|
121
121
|
# require Rack as late as possible in case $LOAD_PATH is modified
|
122
122
|
# in config.ru or command-line
|
123
|
-
require 'rack'
|
124
123
|
inner_app = case config
|
125
124
|
when /\.ru$/
|
126
125
|
raw = File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) }
|
126
|
+
raw.sub!(/^__END__\n.*/, '')
|
127
127
|
eval("Rack::Builder.new {(#{raw}\n)}.to_app", nil, config)
|
128
128
|
else
|
129
129
|
require config
|
data/bin/unicorn_rails
CHANGED
@@ -140,7 +140,6 @@ app = lambda do ||
|
|
140
140
|
end
|
141
141
|
|
142
142
|
if old_rails
|
143
|
-
require 'rack'
|
144
143
|
require 'unicorn/app/old_rails'
|
145
144
|
Unicorn::App::OldRails.new
|
146
145
|
else
|
@@ -148,6 +147,7 @@ app = lambda do ||
|
|
148
147
|
end
|
149
148
|
when /\.ru$/
|
150
149
|
raw = File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) }
|
150
|
+
raw.sub!(/^__END__\n.*/, '')
|
151
151
|
eval("Rack::Builder.new {(#{raw}\n)}.to_app", nil, config)
|
152
152
|
else
|
153
153
|
require config
|
@@ -0,0 +1,107 @@
|
|
1
|
+
/*
|
2
|
+
* Generic C functions and macros go here, there are no dependencies
|
3
|
+
* on Unicorn internal structures or the Ruby C API in here.
|
4
|
+
*/
|
5
|
+
|
6
|
+
#ifndef UH_util_h
|
7
|
+
#define UH_util_h
|
8
|
+
|
9
|
+
#include <unistd.h>
|
10
|
+
#include <assert.h>
|
11
|
+
|
12
|
+
#define MIN(a,b) (a < b ? a : b)
|
13
|
+
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
14
|
+
|
15
|
+
#ifndef SIZEOF_OFF_T
|
16
|
+
# define SIZEOF_OFF_T 4
|
17
|
+
# warning SIZEOF_OFF_T not defined, guessing 4. Did you run extconf.rb?
|
18
|
+
#endif
|
19
|
+
|
20
|
+
#if SIZEOF_OFF_T == 4
|
21
|
+
# define UH_OFF_T_MAX 0x7fffffff
|
22
|
+
#elif SIZEOF_OFF_T == 8
|
23
|
+
# if SIZEOF_LONG == 4
|
24
|
+
# define UH_OFF_T_MAX 0x7fffffffffffffffLL
|
25
|
+
# else
|
26
|
+
# define UH_OFF_T_MAX 0x7fffffffffffffff
|
27
|
+
# endif
|
28
|
+
#else
|
29
|
+
# error off_t size unknown for this platform!
|
30
|
+
#endif
|
31
|
+
|
32
|
+
/*
|
33
|
+
* capitalizes all lower-case ASCII characters and converts dashes
|
34
|
+
* to underscores for HTTP headers. Locale-agnostic.
|
35
|
+
*/
|
36
|
+
static void snake_upcase_char(char *c)
|
37
|
+
{
|
38
|
+
if (*c >= 'a' && *c <= 'z')
|
39
|
+
*c &= ~0x20;
|
40
|
+
else if (*c == '-')
|
41
|
+
*c = '_';
|
42
|
+
}
|
43
|
+
|
44
|
+
/* Downcases a single ASCII character. Locale-agnostic. */
|
45
|
+
static void downcase_char(char *c)
|
46
|
+
{
|
47
|
+
if (*c >= 'A' && *c <= 'Z')
|
48
|
+
*c |= 0x20;
|
49
|
+
}
|
50
|
+
|
51
|
+
static int hexchar2int(int xdigit)
|
52
|
+
{
|
53
|
+
if (xdigit >= 'A' && xdigit <= 'F')
|
54
|
+
return xdigit - 'A' + 10;
|
55
|
+
if (xdigit >= 'a' && xdigit <= 'f')
|
56
|
+
return xdigit - 'a' + 10;
|
57
|
+
|
58
|
+
/* Ragel already does runtime range checking for us in Unicorn: */
|
59
|
+
assert(xdigit >= '0' && xdigit <= '9');
|
60
|
+
|
61
|
+
return xdigit - '0';
|
62
|
+
}
|
63
|
+
|
64
|
+
/*
|
65
|
+
* multiplies +i+ by +base+ and increments the result by the parsed
|
66
|
+
* integer value of +xdigit+. +xdigit+ is a character byte
|
67
|
+
* representing a number the range of 0..(base-1)
|
68
|
+
* returns the new value of +i+ on success
|
69
|
+
* returns -1 on errors (including overflow)
|
70
|
+
*/
|
71
|
+
static off_t step_incr(off_t i, int xdigit, const int base)
|
72
|
+
{
|
73
|
+
static const off_t max = UH_OFF_T_MAX;
|
74
|
+
const off_t next_max = (max - (max % base)) / base;
|
75
|
+
off_t offset = hexchar2int(xdigit);
|
76
|
+
|
77
|
+
if (offset > (base - 1))
|
78
|
+
return -1;
|
79
|
+
if (i > next_max)
|
80
|
+
return -1;
|
81
|
+
i *= base;
|
82
|
+
|
83
|
+
if ((offset > (base - 1)) || ((max - i) < offset))
|
84
|
+
return -1;
|
85
|
+
|
86
|
+
return i + offset;
|
87
|
+
}
|
88
|
+
|
89
|
+
/*
|
90
|
+
* parses a non-negative length according to base-10 and
|
91
|
+
* returns it as an off_t value. Returns -1 on errors
|
92
|
+
* (including overflow).
|
93
|
+
*/
|
94
|
+
static off_t parse_length(const char *value, size_t length)
|
95
|
+
{
|
96
|
+
off_t rv;
|
97
|
+
|
98
|
+
for (rv = 0; length-- && rv >= 0; ++value)
|
99
|
+
rv = step_incr(rv, *value, 10);
|
100
|
+
|
101
|
+
return rv;
|
102
|
+
}
|
103
|
+
|
104
|
+
#define CONST_MEM_EQ(const_p, buf, len) \
|
105
|
+
((sizeof(const_p) - 1) == len && !memcmp(const_p, buf, sizeof(const_p) - 1))
|
106
|
+
|
107
|
+
#endif /* UH_util_h */
|
@@ -0,0 +1,110 @@
|
|
1
|
+
#ifndef common_field_optimization
|
2
|
+
#define common_field_optimization
|
3
|
+
#include "ruby.h"
|
4
|
+
#include "c_util.h"
|
5
|
+
|
6
|
+
struct common_field {
|
7
|
+
const signed long len;
|
8
|
+
const char *name;
|
9
|
+
VALUE value;
|
10
|
+
};
|
11
|
+
|
12
|
+
/*
|
13
|
+
* A list of common HTTP headers we expect to receive.
|
14
|
+
* This allows us to avoid repeatedly creating identical string
|
15
|
+
* objects to be used with rb_hash_aset().
|
16
|
+
*/
|
17
|
+
static struct common_field common_http_fields[] = {
|
18
|
+
# define f(N) { (sizeof(N) - 1), N, Qnil }
|
19
|
+
f("ACCEPT"),
|
20
|
+
f("ACCEPT_CHARSET"),
|
21
|
+
f("ACCEPT_ENCODING"),
|
22
|
+
f("ACCEPT_LANGUAGE"),
|
23
|
+
f("ALLOW"),
|
24
|
+
f("AUTHORIZATION"),
|
25
|
+
f("CACHE_CONTROL"),
|
26
|
+
f("CONNECTION"),
|
27
|
+
f("CONTENT_ENCODING"),
|
28
|
+
f("CONTENT_LENGTH"),
|
29
|
+
f("CONTENT_TYPE"),
|
30
|
+
f("COOKIE"),
|
31
|
+
f("DATE"),
|
32
|
+
f("EXPECT"),
|
33
|
+
f("FROM"),
|
34
|
+
f("HOST"),
|
35
|
+
f("IF_MATCH"),
|
36
|
+
f("IF_MODIFIED_SINCE"),
|
37
|
+
f("IF_NONE_MATCH"),
|
38
|
+
f("IF_RANGE"),
|
39
|
+
f("IF_UNMODIFIED_SINCE"),
|
40
|
+
f("KEEP_ALIVE"), /* Firefox sends this */
|
41
|
+
f("MAX_FORWARDS"),
|
42
|
+
f("PRAGMA"),
|
43
|
+
f("PROXY_AUTHORIZATION"),
|
44
|
+
f("RANGE"),
|
45
|
+
f("REFERER"),
|
46
|
+
f("TE"),
|
47
|
+
f("TRAILER"),
|
48
|
+
f("TRANSFER_ENCODING"),
|
49
|
+
f("UPGRADE"),
|
50
|
+
f("USER_AGENT"),
|
51
|
+
f("VIA"),
|
52
|
+
f("X_FORWARDED_FOR"), /* common for proxies */
|
53
|
+
f("X_FORWARDED_PROTO"), /* common for proxies */
|
54
|
+
f("X_REAL_IP"), /* common for proxies */
|
55
|
+
f("WARNING")
|
56
|
+
# undef f
|
57
|
+
};
|
58
|
+
|
59
|
+
#define HTTP_PREFIX "HTTP_"
|
60
|
+
#define HTTP_PREFIX_LEN (sizeof(HTTP_PREFIX) - 1)
|
61
|
+
|
62
|
+
/* this function is not performance-critical, called only at load time */
|
63
|
+
static void init_common_fields(void)
|
64
|
+
{
|
65
|
+
int i;
|
66
|
+
struct common_field *cf = common_http_fields;
|
67
|
+
char tmp[64];
|
68
|
+
memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN);
|
69
|
+
|
70
|
+
for(i = 0; i < ARRAY_SIZE(common_http_fields); cf++, i++) {
|
71
|
+
/* Rack doesn't like certain headers prefixed with "HTTP_" */
|
72
|
+
if (!strcmp("CONTENT_LENGTH", cf->name) ||
|
73
|
+
!strcmp("CONTENT_TYPE", cf->name)) {
|
74
|
+
cf->value = rb_str_new(cf->name, cf->len);
|
75
|
+
} else {
|
76
|
+
memcpy(tmp + HTTP_PREFIX_LEN, cf->name, cf->len + 1);
|
77
|
+
cf->value = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len);
|
78
|
+
}
|
79
|
+
cf->value = rb_obj_freeze(cf->value);
|
80
|
+
rb_global_variable(&cf->value);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
/* this function is called for every header set */
|
85
|
+
static VALUE find_common_field(const char *field, size_t flen)
|
86
|
+
{
|
87
|
+
int i;
|
88
|
+
struct common_field *cf = common_http_fields;
|
89
|
+
|
90
|
+
for(i = 0; i < ARRAY_SIZE(common_http_fields); i++, cf++) {
|
91
|
+
if (cf->len == flen && !memcmp(cf->name, field, flen))
|
92
|
+
return cf->value;
|
93
|
+
}
|
94
|
+
return Qnil;
|
95
|
+
}
|
96
|
+
|
97
|
+
/*
|
98
|
+
* We got a strange header that we don't have a memoized value for.
|
99
|
+
* Fallback to creating a new string to use as a hash key.
|
100
|
+
*/
|
101
|
+
static VALUE uncommon_field(const char *field, size_t flen)
|
102
|
+
{
|
103
|
+
VALUE f = rb_str_new(NULL, HTTP_PREFIX_LEN + flen);
|
104
|
+
memcpy(RSTRING_PTR(f), HTTP_PREFIX, HTTP_PREFIX_LEN);
|
105
|
+
memcpy(RSTRING_PTR(f) + HTTP_PREFIX_LEN, field, flen);
|
106
|
+
assert(*(RSTRING_PTR(f) + RSTRING_LEN(f)) == '\0'); /* paranoia */
|
107
|
+
return rb_obj_freeze(f);
|
108
|
+
}
|
109
|
+
|
110
|
+
#endif /* common_field_optimization_h */
|