unicorn 0.9.2 → 0.90.0

Sign up to get free protection for your applications and to get access to all the features.
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 */