giraffesoft-unicorn 0.93.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.CHANGELOG.old +25 -0
- data/.document +16 -0
- data/.gitignore +20 -0
- data/.mailmap +26 -0
- data/CONTRIBUTORS +31 -0
- data/COPYING +339 -0
- data/DESIGN +105 -0
- data/Documentation/.gitignore +5 -0
- data/Documentation/GNUmakefile +30 -0
- data/Documentation/unicorn.1.txt +167 -0
- data/Documentation/unicorn_rails.1.txt +169 -0
- data/GIT-VERSION-GEN +40 -0
- data/GNUmakefile +270 -0
- data/HACKING +113 -0
- data/KNOWN_ISSUES +40 -0
- data/LICENSE +55 -0
- data/PHILOSOPHY +144 -0
- data/README +153 -0
- data/Rakefile +108 -0
- data/SIGNALS +97 -0
- data/TODO +16 -0
- data/TUNING +70 -0
- data/bin/unicorn +165 -0
- data/bin/unicorn_rails +208 -0
- data/examples/echo.ru +27 -0
- data/examples/git.ru +13 -0
- data/examples/init.sh +53 -0
- data/ext/unicorn_http/c_util.h +107 -0
- data/ext/unicorn_http/common_field_optimization.h +111 -0
- data/ext/unicorn_http/ext_help.h +73 -0
- data/ext/unicorn_http/extconf.rb +14 -0
- data/ext/unicorn_http/global_variables.h +91 -0
- data/ext/unicorn_http/unicorn_http.rl +715 -0
- data/ext/unicorn_http/unicorn_http_common.rl +74 -0
- data/lib/unicorn.rb +730 -0
- data/lib/unicorn/app/exec_cgi.rb +150 -0
- data/lib/unicorn/app/inetd.rb +109 -0
- data/lib/unicorn/app/old_rails.rb +31 -0
- data/lib/unicorn/app/old_rails/static.rb +60 -0
- data/lib/unicorn/cgi_wrapper.rb +145 -0
- data/lib/unicorn/configurator.rb +403 -0
- data/lib/unicorn/const.rb +37 -0
- data/lib/unicorn/http_request.rb +74 -0
- data/lib/unicorn/http_response.rb +74 -0
- data/lib/unicorn/launcher.rb +39 -0
- data/lib/unicorn/socket_helper.rb +138 -0
- data/lib/unicorn/tee_input.rb +174 -0
- data/lib/unicorn/util.rb +64 -0
- data/local.mk.sample +53 -0
- data/setup.rb +1586 -0
- data/test/aggregate.rb +15 -0
- data/test/benchmark/README +50 -0
- data/test/benchmark/dd.ru +18 -0
- data/test/exec/README +5 -0
- data/test/exec/test_exec.rb +855 -0
- data/test/rails/app-1.2.3/.gitignore +2 -0
- data/test/rails/app-1.2.3/Rakefile +7 -0
- data/test/rails/app-1.2.3/app/controllers/application.rb +6 -0
- data/test/rails/app-1.2.3/app/controllers/foo_controller.rb +36 -0
- data/test/rails/app-1.2.3/app/helpers/application_helper.rb +4 -0
- data/test/rails/app-1.2.3/config/boot.rb +11 -0
- data/test/rails/app-1.2.3/config/database.yml +12 -0
- data/test/rails/app-1.2.3/config/environment.rb +13 -0
- data/test/rails/app-1.2.3/config/environments/development.rb +9 -0
- data/test/rails/app-1.2.3/config/environments/production.rb +5 -0
- data/test/rails/app-1.2.3/config/routes.rb +6 -0
- data/test/rails/app-1.2.3/db/.gitignore +0 -0
- data/test/rails/app-1.2.3/public/404.html +1 -0
- data/test/rails/app-1.2.3/public/500.html +1 -0
- data/test/rails/app-2.0.2/.gitignore +2 -0
- data/test/rails/app-2.0.2/Rakefile +7 -0
- data/test/rails/app-2.0.2/app/controllers/application.rb +4 -0
- data/test/rails/app-2.0.2/app/controllers/foo_controller.rb +36 -0
- data/test/rails/app-2.0.2/app/helpers/application_helper.rb +4 -0
- data/test/rails/app-2.0.2/config/boot.rb +11 -0
- data/test/rails/app-2.0.2/config/database.yml +12 -0
- data/test/rails/app-2.0.2/config/environment.rb +17 -0
- data/test/rails/app-2.0.2/config/environments/development.rb +8 -0
- data/test/rails/app-2.0.2/config/environments/production.rb +5 -0
- data/test/rails/app-2.0.2/config/routes.rb +6 -0
- data/test/rails/app-2.0.2/db/.gitignore +0 -0
- data/test/rails/app-2.0.2/public/404.html +1 -0
- data/test/rails/app-2.0.2/public/500.html +1 -0
- data/test/rails/app-2.1.2/.gitignore +2 -0
- data/test/rails/app-2.1.2/Rakefile +7 -0
- data/test/rails/app-2.1.2/app/controllers/application.rb +4 -0
- data/test/rails/app-2.1.2/app/controllers/foo_controller.rb +36 -0
- data/test/rails/app-2.1.2/app/helpers/application_helper.rb +4 -0
- data/test/rails/app-2.1.2/config/boot.rb +111 -0
- data/test/rails/app-2.1.2/config/database.yml +12 -0
- data/test/rails/app-2.1.2/config/environment.rb +17 -0
- data/test/rails/app-2.1.2/config/environments/development.rb +7 -0
- data/test/rails/app-2.1.2/config/environments/production.rb +5 -0
- data/test/rails/app-2.1.2/config/routes.rb +6 -0
- data/test/rails/app-2.1.2/db/.gitignore +0 -0
- data/test/rails/app-2.1.2/public/404.html +1 -0
- data/test/rails/app-2.1.2/public/500.html +1 -0
- data/test/rails/app-2.2.2/.gitignore +2 -0
- data/test/rails/app-2.2.2/Rakefile +7 -0
- data/test/rails/app-2.2.2/app/controllers/application.rb +4 -0
- data/test/rails/app-2.2.2/app/controllers/foo_controller.rb +36 -0
- data/test/rails/app-2.2.2/app/helpers/application_helper.rb +4 -0
- data/test/rails/app-2.2.2/config/boot.rb +111 -0
- data/test/rails/app-2.2.2/config/database.yml +12 -0
- data/test/rails/app-2.2.2/config/environment.rb +17 -0
- data/test/rails/app-2.2.2/config/environments/development.rb +7 -0
- data/test/rails/app-2.2.2/config/environments/production.rb +5 -0
- data/test/rails/app-2.2.2/config/routes.rb +6 -0
- data/test/rails/app-2.2.2/db/.gitignore +0 -0
- data/test/rails/app-2.2.2/public/404.html +1 -0
- data/test/rails/app-2.2.2/public/500.html +1 -0
- data/test/rails/app-2.3.3.1/.gitignore +2 -0
- data/test/rails/app-2.3.3.1/Rakefile +7 -0
- data/test/rails/app-2.3.3.1/app/controllers/application_controller.rb +5 -0
- data/test/rails/app-2.3.3.1/app/controllers/foo_controller.rb +36 -0
- data/test/rails/app-2.3.3.1/app/helpers/application_helper.rb +4 -0
- data/test/rails/app-2.3.3.1/config/boot.rb +109 -0
- data/test/rails/app-2.3.3.1/config/database.yml +12 -0
- data/test/rails/app-2.3.3.1/config/environment.rb +17 -0
- data/test/rails/app-2.3.3.1/config/environments/development.rb +7 -0
- data/test/rails/app-2.3.3.1/config/environments/production.rb +6 -0
- data/test/rails/app-2.3.3.1/config/routes.rb +6 -0
- data/test/rails/app-2.3.3.1/db/.gitignore +0 -0
- data/test/rails/app-2.3.3.1/public/404.html +1 -0
- data/test/rails/app-2.3.3.1/public/500.html +1 -0
- data/test/rails/app-2.3.3.1/public/x.txt +1 -0
- data/test/rails/test_rails.rb +280 -0
- data/test/test_helper.rb +296 -0
- data/test/unit/test_configurator.rb +150 -0
- data/test/unit/test_http_parser.rb +492 -0
- data/test/unit/test_http_parser_ng.rb +308 -0
- data/test/unit/test_request.rb +184 -0
- data/test/unit/test_response.rb +110 -0
- data/test/unit/test_server.rb +188 -0
- data/test/unit/test_signals.rb +202 -0
- data/test/unit/test_socket_helper.rb +133 -0
- data/test/unit/test_tee_input.rb +229 -0
- data/test/unit/test_upload.rb +297 -0
- data/test/unit/test_util.rb +96 -0
- data/unicorn.gemspec +42 -0
- metadata +228 -0
data/examples/echo.ru
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#\-E none
|
2
|
+
#
|
3
|
+
# Example application that echoes read data back to the HTTP client.
|
4
|
+
# This emulates the old echo protocol people used to run.
|
5
|
+
#
|
6
|
+
# An example of using this in a client would be to run:
|
7
|
+
# curl --no-buffer -T- http://host:port/
|
8
|
+
#
|
9
|
+
# Then type random stuff in your terminal to watch it get echoed back!
|
10
|
+
|
11
|
+
class EchoBody < Struct.new(:input)
|
12
|
+
|
13
|
+
def each(&block)
|
14
|
+
while buf = input.read(4096)
|
15
|
+
yield buf
|
16
|
+
end
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
use Rack::Chunked
|
23
|
+
run lambda { |env|
|
24
|
+
/\A100-continue\z/i =~ env['HTTP_EXPECT'] and return [100, {}, []]
|
25
|
+
[ 200, { 'Content-Type' => 'application/octet-stream' },
|
26
|
+
EchoBody.new(env['rack.input']) ]
|
27
|
+
}
|
data/examples/git.ru
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#\-E none
|
2
|
+
|
3
|
+
# See http://thread.gmane.org/gmane.comp.web.curl.general/10473/raw on
|
4
|
+
# how to setup git for this. A better version of the above patch was
|
5
|
+
# accepted and committed on June 15, 2009, so you can pull the latest
|
6
|
+
# curl CVS snapshot to try this out.
|
7
|
+
require 'unicorn/app/inetd'
|
8
|
+
|
9
|
+
use Rack::Lint
|
10
|
+
use Rack::Chunked # important!
|
11
|
+
run Unicorn::App::Inetd.new(
|
12
|
+
*%w(git daemon --verbose --inetd --export-all --base-path=/home/ew/unicorn)
|
13
|
+
)
|
data/examples/init.sh
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
set -e
|
3
|
+
# Example init script, this can be used with nginx, too,
|
4
|
+
# since nginx and unicorn accept the same signals
|
5
|
+
|
6
|
+
# Feel free to change any of the following variables for your app:
|
7
|
+
APP_ROOT=/home/x/my_app/current
|
8
|
+
PID=$APP_ROOT/tmp/pids/unicorn.pid
|
9
|
+
CMD="/usr/bin/unicorn -D -c $APP_ROOT/config/unicorn.rb"
|
10
|
+
INIT_CONF=$APP_ROOT/config/init.conf
|
11
|
+
|
12
|
+
test -f "$INIT_CONF" && . $INIT_CONF
|
13
|
+
|
14
|
+
old_pid="$PID.oldbin"
|
15
|
+
|
16
|
+
cd $APP_ROOT || exit 1
|
17
|
+
|
18
|
+
sig () {
|
19
|
+
test -s "$PID" && kill -$1 `cat $PID`
|
20
|
+
}
|
21
|
+
|
22
|
+
oldsig () {
|
23
|
+
test -s $old_pid && kill -$1 `cat $old_pid`
|
24
|
+
}
|
25
|
+
|
26
|
+
case $1 in
|
27
|
+
start)
|
28
|
+
sig 0 && echo >&2 "Already running" && exit 0
|
29
|
+
$CMD
|
30
|
+
;;
|
31
|
+
stop)
|
32
|
+
sig QUIT && exit 0
|
33
|
+
echo >&2 "Not running"
|
34
|
+
;;
|
35
|
+
force-stop)
|
36
|
+
sig TERM && exit 0
|
37
|
+
echo >&2 "Not running"
|
38
|
+
;;
|
39
|
+
restart|reload)
|
40
|
+
sig HUP && echo reloaded OK && exit 0
|
41
|
+
echo >&2 "Couldn't reload, starting '$CMD' instead"
|
42
|
+
$CMD
|
43
|
+
;;
|
44
|
+
upgrade)
|
45
|
+
sig USR2 && sleep 2 && sig 0 && oldsig QUIT && exit 0
|
46
|
+
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
|
47
|
+
$CMD
|
48
|
+
;;
|
49
|
+
*)
|
50
|
+
echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop>"
|
51
|
+
exit 1
|
52
|
+
;;
|
53
|
+
esac
|
@@ -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 /* SIZEOF_OFF_T check */
|
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' && "invalid digit character");
|
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,111 @@
|
|
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' &&
|
107
|
+
"string didn't end with \\0"); /* paranoia */
|
108
|
+
return rb_obj_freeze(f);
|
109
|
+
}
|
110
|
+
|
111
|
+
#endif /* common_field_optimization_h */
|
@@ -0,0 +1,73 @@
|
|
1
|
+
#ifndef ext_help_h
|
2
|
+
#define ext_help_h
|
3
|
+
|
4
|
+
#ifndef RSTRING_PTR
|
5
|
+
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
6
|
+
#endif /* !defined(RSTRING_PTR) */
|
7
|
+
#ifndef RSTRING_LEN
|
8
|
+
#define RSTRING_LEN(s) (RSTRING(s)->len)
|
9
|
+
#endif /* !defined(RSTRING_LEN) */
|
10
|
+
|
11
|
+
#ifndef RUBINIUS
|
12
|
+
# define rb_str_update(x) do {} while (0)
|
13
|
+
# define rb_str_flush(x) do {} while (0)
|
14
|
+
#endif /* !RUBINIUS */
|
15
|
+
|
16
|
+
#ifndef HAVE_RB_STR_SET_LEN
|
17
|
+
/* this is taken from Ruby 1.8.7, 1.8.6 may not have it */
|
18
|
+
static void rb_18_str_set_len(VALUE str, long len)
|
19
|
+
{
|
20
|
+
RSTRING(str)->len = len;
|
21
|
+
RSTRING(str)->ptr[len] = '\0';
|
22
|
+
rb_str_flush(str);
|
23
|
+
}
|
24
|
+
# define rb_str_set_len(str,len) rb_18_str_set_len(str,len)
|
25
|
+
#endif /* !defined(HAVE_RB_STR_SET_LEN) */
|
26
|
+
|
27
|
+
/* not all Ruby implementations support frozen objects (Rubinius does not) */
|
28
|
+
#if defined(OBJ_FROZEN)
|
29
|
+
# define assert_frozen(f) assert(OBJ_FROZEN(f) && "unfrozen object")
|
30
|
+
#else
|
31
|
+
# define assert_frozen(f) do {} while (0)
|
32
|
+
#endif /* !defined(OBJ_FROZEN) */
|
33
|
+
|
34
|
+
#if !defined(OFFT2NUM)
|
35
|
+
# if SIZEOF_OFF_T == SIZEOF_LONG
|
36
|
+
# define OFFT2NUM(n) LONG2NUM(n)
|
37
|
+
# else
|
38
|
+
# define OFFT2NUM(n) LL2NUM(n)
|
39
|
+
# endif
|
40
|
+
#endif /* ! defined(OFFT2NUM) */
|
41
|
+
|
42
|
+
#ifndef HAVE_RB_STR_MODIFY
|
43
|
+
# define rb_str_modify(x) do {} while (0)
|
44
|
+
#endif /* ! defined(HAVE_RB_STR_MODIFY) */
|
45
|
+
|
46
|
+
static inline int str_cstr_eq(VALUE val, const char *ptr, size_t len)
|
47
|
+
{
|
48
|
+
return (RSTRING_LEN(val) == len && !memcmp(ptr, RSTRING_PTR(val), len));
|
49
|
+
}
|
50
|
+
|
51
|
+
#define STR_CSTR_EQ(val, const_str) \
|
52
|
+
str_cstr_eq(val, const_str, sizeof(const_str) - 1)
|
53
|
+
|
54
|
+
/* strcasecmp isn't locale independent */
|
55
|
+
static int str_cstr_case_eq(VALUE val, const char *ptr, size_t len)
|
56
|
+
{
|
57
|
+
if (RSTRING_LEN(val) == len) {
|
58
|
+
const char *v = RSTRING_PTR(val);
|
59
|
+
|
60
|
+
for (; len--; ++ptr, ++v) {
|
61
|
+
if ((*ptr == *v) || (*v >= 'A' && *v <= 'Z' && (*v | 0x20) == *ptr))
|
62
|
+
continue;
|
63
|
+
return 0;
|
64
|
+
}
|
65
|
+
return 1;
|
66
|
+
}
|
67
|
+
return 0;
|
68
|
+
}
|
69
|
+
|
70
|
+
#define STR_CSTR_CASE_EQ(val, const_str) \
|
71
|
+
str_cstr_case_eq(val, const_str, sizeof(const_str) - 1)
|
72
|
+
|
73
|
+
#endif /* ext_help_h */
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require 'mkmf'
|
3
|
+
|
4
|
+
dir_config("unicorn_http")
|
5
|
+
|
6
|
+
have_macro("SIZEOF_OFF_T", "ruby.h") or check_sizeof("off_t", "sys/types.h")
|
7
|
+
have_macro("SIZEOF_LONG", "ruby.h") or check_sizeof("long", "sys/types.h")
|
8
|
+
have_func("rb_str_set_len", "ruby.h")
|
9
|
+
have_func("rb_str_modify", "ruby.h")
|
10
|
+
|
11
|
+
# -fPIC is needed for Rubinius, MRI already uses it regardless
|
12
|
+
with_cflags($CFLAGS + " -fPIC ") do
|
13
|
+
create_makefile("unicorn_http")
|
14
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#ifndef global_variables_h
|
2
|
+
#define global_variables_h
|
3
|
+
static VALUE mUnicorn;
|
4
|
+
static VALUE cHttpParser;
|
5
|
+
static VALUE eHttpParserError;
|
6
|
+
|
7
|
+
static VALUE g_rack_url_scheme;
|
8
|
+
static VALUE g_request_method;
|
9
|
+
static VALUE g_request_uri;
|
10
|
+
static VALUE g_fragment;
|
11
|
+
static VALUE g_query_string;
|
12
|
+
static VALUE g_http_version;
|
13
|
+
static VALUE g_request_path;
|
14
|
+
static VALUE g_path_info;
|
15
|
+
static VALUE g_server_name;
|
16
|
+
static VALUE g_server_port;
|
17
|
+
static VALUE g_server_protocol;
|
18
|
+
static VALUE g_http_host;
|
19
|
+
static VALUE g_http_x_forwarded_proto;
|
20
|
+
static VALUE g_http_transfer_encoding;
|
21
|
+
static VALUE g_content_length;
|
22
|
+
static VALUE g_http_trailer;
|
23
|
+
static VALUE g_http_connection;
|
24
|
+
static VALUE g_port_80;
|
25
|
+
static VALUE g_port_443;
|
26
|
+
static VALUE g_localhost;
|
27
|
+
static VALUE g_http;
|
28
|
+
static VALUE g_http_09;
|
29
|
+
static VALUE g_http_10;
|
30
|
+
static VALUE g_http_11;
|
31
|
+
static VALUE g_GET;
|
32
|
+
static VALUE g_HEAD;
|
33
|
+
|
34
|
+
/** Defines common length and error messages for input length validation. */
|
35
|
+
#define DEF_MAX_LENGTH(N, length) \
|
36
|
+
static const size_t MAX_##N##_LENGTH = length; \
|
37
|
+
static const char * const MAX_##N##_LENGTH_ERR = \
|
38
|
+
"HTTP element " # N " is longer than the " # length " allowed length."
|
39
|
+
|
40
|
+
/**
|
41
|
+
* Validates the max length of given input and throws an HttpParserError
|
42
|
+
* exception if over.
|
43
|
+
*/
|
44
|
+
#define VALIDATE_MAX_LENGTH(len, N) do { \
|
45
|
+
if (len > MAX_##N##_LENGTH) \
|
46
|
+
rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR); \
|
47
|
+
} while (0)
|
48
|
+
|
49
|
+
/** Defines global strings in the init method. */
|
50
|
+
#define DEF_GLOBAL(N, val) do { \
|
51
|
+
g_##N = rb_obj_freeze(rb_str_new(val, sizeof(val) - 1)); \
|
52
|
+
rb_global_variable(&g_##N); \
|
53
|
+
} while (0)
|
54
|
+
|
55
|
+
/* Defines the maximum allowed lengths for various input elements.*/
|
56
|
+
DEF_MAX_LENGTH(FIELD_NAME, 256);
|
57
|
+
DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
|
58
|
+
DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
|
59
|
+
DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
|
60
|
+
DEF_MAX_LENGTH(REQUEST_PATH, 1024);
|
61
|
+
DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
|
62
|
+
DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
|
63
|
+
|
64
|
+
void init_globals(void)
|
65
|
+
{
|
66
|
+
DEF_GLOBAL(rack_url_scheme, "rack.url_scheme");
|
67
|
+
DEF_GLOBAL(request_method, "REQUEST_METHOD");
|
68
|
+
DEF_GLOBAL(request_uri, "REQUEST_URI");
|
69
|
+
DEF_GLOBAL(fragment, "FRAGMENT");
|
70
|
+
DEF_GLOBAL(query_string, "QUERY_STRING");
|
71
|
+
DEF_GLOBAL(http_version, "HTTP_VERSION");
|
72
|
+
DEF_GLOBAL(request_path, "REQUEST_PATH");
|
73
|
+
DEF_GLOBAL(path_info, "PATH_INFO");
|
74
|
+
DEF_GLOBAL(server_name, "SERVER_NAME");
|
75
|
+
DEF_GLOBAL(server_port, "SERVER_PORT");
|
76
|
+
DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");
|
77
|
+
DEF_GLOBAL(http_x_forwarded_proto, "HTTP_X_FORWARDED_PROTO");
|
78
|
+
DEF_GLOBAL(port_80, "80");
|
79
|
+
DEF_GLOBAL(port_443, "443");
|
80
|
+
DEF_GLOBAL(localhost, "localhost");
|
81
|
+
DEF_GLOBAL(http, "http");
|
82
|
+
DEF_GLOBAL(http_11, "HTTP/1.1");
|
83
|
+
DEF_GLOBAL(http_10, "HTTP/1.0");
|
84
|
+
DEF_GLOBAL(http_09, "HTTP/0.9");
|
85
|
+
DEF_GLOBAL(GET, "GET");
|
86
|
+
DEF_GLOBAL(HEAD, "HEAD");
|
87
|
+
}
|
88
|
+
|
89
|
+
#undef DEF_GLOBAL
|
90
|
+
|
91
|
+
#endif /* global_variables_h */
|