unicorn 0.9.2 → 0.90.0

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.
Files changed (60) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG +3 -0
  3. data/GNUmakefile +7 -7
  4. data/Manifest +20 -23
  5. data/README +16 -13
  6. data/TODO +5 -3
  7. data/bin/unicorn +1 -1
  8. data/bin/unicorn_rails +1 -1
  9. data/ext/unicorn_http/c_util.h +107 -0
  10. data/ext/unicorn_http/common_field_optimization.h +110 -0
  11. data/ext/unicorn_http/ext_help.h +41 -5
  12. data/ext/unicorn_http/extconf.rb +3 -1
  13. data/ext/unicorn_http/global_variables.h +93 -0
  14. data/ext/unicorn_http/unicorn_http.c +2123 -326
  15. data/ext/unicorn_http/unicorn_http.rl +488 -87
  16. data/ext/unicorn_http/unicorn_http_common.rl +12 -1
  17. data/lib/unicorn.rb +0 -2
  18. data/lib/unicorn/app/exec_cgi.rb +0 -1
  19. data/lib/unicorn/app/inetd.rb +2 -0
  20. data/lib/unicorn/app/old_rails/static.rb +0 -2
  21. data/lib/unicorn/const.rb +1 -5
  22. data/lib/unicorn/http_request.rb +13 -29
  23. data/lib/unicorn/http_response.rb +1 -1
  24. data/lib/unicorn/tee_input.rb +48 -46
  25. data/lib/unicorn/util.rb +3 -3
  26. data/test/benchmark/README +0 -5
  27. data/test/exec/test_exec.rb +4 -0
  28. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/.gitignore +0 -0
  29. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/Rakefile +0 -0
  30. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/app/controllers/application_controller.rb +0 -0
  31. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/app/controllers/foo_controller.rb +0 -0
  32. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/app/helpers/application_helper.rb +0 -0
  33. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/boot.rb +0 -0
  34. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/database.yml +0 -0
  35. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/environment.rb +0 -0
  36. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/environments/development.rb +0 -0
  37. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/environments/production.rb +0 -0
  38. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/config/routes.rb +0 -0
  39. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/db/.gitignore +0 -0
  40. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/public/404.html +0 -0
  41. data/test/rails/{app-2.3.2.1 → app-2.3.3.1}/public/500.html +0 -0
  42. data/test/unit/test_http_parser.rb +112 -47
  43. data/test/unit/test_http_parser_ng.rb +284 -0
  44. data/test/unit/test_request.rb +25 -7
  45. data/test/unit/test_response.rb +11 -0
  46. data/test/unit/test_server.rb +7 -2
  47. data/test/unit/test_signals.rb +2 -0
  48. data/test/unit/test_tee_input.rb +118 -2
  49. data/test/unit/test_upload.rb +1 -1
  50. data/test/unit/test_util.rb +5 -0
  51. data/unicorn.gemspec +6 -6
  52. metadata +33 -37
  53. data/ext/unicorn_http/unicorn_http.h +0 -1289
  54. data/lib/unicorn/chunked_reader.rb +0 -77
  55. data/lib/unicorn/trailer_parser.rb +0 -52
  56. data/test/benchmark/big_request.rb +0 -44
  57. data/test/benchmark/request.rb +0 -56
  58. data/test/benchmark/response.rb +0 -30
  59. data/test/unit/test_chunked_reader.rb +0 -123
  60. data/test/unit/test_trailer_parser.rb +0 -52
data/.gitignore CHANGED
@@ -8,6 +8,7 @@
8
8
  /local.mk
9
9
  /test/install-*
10
10
  ext/unicorn_http/Makefile
11
+ ext/unicorn_http/unicorn_http.c
11
12
  log/
12
13
  pkg/
13
14
  /vendor
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 := $(addprefix $(ext)/,ext_help.h unicorn_http.c unicorn_http.h)
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.h
37
- $(ext)/unicorn_http.h: $(rl_files)
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 $^ .install-tmp
110
+ cp -p bin/* .install-tmp
111
111
  $(ruby) setup.rb all
112
112
  $(RM) $^
113
- mv $(addprefix .install-tmp/,$(^F)) bin/
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.2.1/.gitignore
114
- test/rails/app-2.3.2.1/Rakefile
115
- test/rails/app-2.3.2.1/app/controllers/application_controller.rb
116
- test/rails/app-2.3.2.1/app/controllers/foo_controller.rb
117
- test/rails/app-2.3.2.1/app/helpers/application_helper.rb
118
- test/rails/app-2.3.2.1/config/boot.rb
119
- test/rails/app-2.3.2.1/config/database.yml
120
- test/rails/app-2.3.2.1/config/environment.rb
121
- test/rails/app-2.3.2.1/config/environments/development.rb
122
- test/rails/app-2.3.2.1/config/environments/production.rb
123
- test/rails/app-2.3.2.1/config/routes.rb
124
- test/rails/app-2.3.2.1/db/.gitignore
125
- test/rails/app-2.3.2.1/log/.gitignore
126
- test/rails/app-2.3.2.1/public/404.html
127
- test/rails/app-2.3.2.1/public/500.html
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/test_trailer_parser.rb
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 all things that are better-supported by nginx or Rack.
6
+ cut out everything that is better supported by the operating system,
7
+ nginx or Rack.
7
8
 
8
- * Mostly written in Ruby, only the HTTP parser (stolen and trimmed
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 fixed number of
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 re-execution without losing connections.
32
+ * nginx-style binary upgrades without losing connections.
35
33
  You can upgrade Unicorn, your entire application, libraries
36
- and even your Ruby interpreter as long as Unicorn is
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
- {Stable v0.8.2}[http://git.bogomips.org/cgit/unicorn.git/tag/?id=v0.8.2]
56
+ {Current v0.90.0}[http://git.bogomips.org/cgit/unicorn.git/tag/?id=v0.90.0]
54
57
 
55
- {Development v0.9.1}[http://git.bogomips.org/cgit/unicorn.git/tag/?id=v0.9.1]
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 -v0.8.2
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
- * integration tests with nginx including bad client handling
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 (launchers)
5
+ * code cleanups
6
6
 
7
- * Pure Ruby HTTP parser
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 */