ebb 0.1.0 → 0.2.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.
- data/README +4 -7
- data/benchmark/application.rb +12 -4
- data/benchmark/server_test.rb +10 -11
- data/bin/ebb_rails +0 -0
- data/libev/ev.c +235 -128
- data/libev/ev.h +84 -27
- data/libev/ev_epoll.c +30 -22
- data/libev/ev_kqueue.c +30 -22
- data/libev/ev_poll.c +30 -22
- data/libev/ev_port.c +30 -22
- data/libev/ev_select.c +34 -26
- data/libev/ev_vars.h +49 -0
- data/libev/ev_win32.c +31 -23
- data/libev/ev_wrap.h +12 -0
- data/ruby_lib/ebb.rb +94 -67
- data/ruby_lib/ebb/runner.rb +4 -5
- data/ruby_lib/ebb/runner/rails.rb +1 -4
- data/ruby_lib/rack/adapter/rails.rb +5 -0
- data/src/ebb.c +261 -387
- data/src/ebb.h +19 -29
- data/src/ebb_ruby.c +113 -108
- data/src/extconf.rb +0 -1
- data/src/parser.c +1755 -724
- data/src/parser.h +13 -10
- data/test/basic_test.rb +18 -1
- data/test/env_test.rb +6 -5
- data/test/helper.rb +53 -1
- metadata +3 -4
- data/benchmark/bench_results.rb +0 -58
data/src/parser.h
CHANGED
@@ -12,14 +12,24 @@
|
|
12
12
|
#include <stddef.h>
|
13
13
|
#endif
|
14
14
|
|
15
|
-
|
15
|
+
enum { MONGREL_CONTENT_LENGTH
|
16
|
+
, MONGREL_CONTENT_TYPE
|
17
|
+
, MONGREL_FRAGMENT
|
18
|
+
, MONGREL_HTTP_VERSION
|
19
|
+
, MONGREL_QUERY_STRING
|
20
|
+
, MONGREL_REQUEST_PATH
|
21
|
+
, MONGREL_REQUEST_METHOD
|
22
|
+
, MONGREL_REQUEST_URI
|
23
|
+
};
|
24
|
+
|
16
25
|
typedef void (*field_cb)(void *data, const char *field, size_t flen, const char *value, size_t vlen);
|
26
|
+
typedef void (*element_cb)(void *data, int type, const char *at, size_t length);
|
17
27
|
|
18
28
|
typedef struct http_parser {
|
19
29
|
int cs;
|
20
30
|
int overflow_error;
|
21
31
|
size_t body_start;
|
22
|
-
|
32
|
+
size_t content_length;
|
23
33
|
size_t nread;
|
24
34
|
size_t mark;
|
25
35
|
size_t field_start;
|
@@ -29,14 +39,7 @@ typedef struct http_parser {
|
|
29
39
|
void *data;
|
30
40
|
|
31
41
|
field_cb http_field;
|
32
|
-
element_cb
|
33
|
-
element_cb request_uri;
|
34
|
-
element_cb fragment;
|
35
|
-
element_cb request_path;
|
36
|
-
element_cb query_string;
|
37
|
-
element_cb http_version;
|
38
|
-
element_cb header_done;
|
39
|
-
element_cb content_length;
|
42
|
+
element_cb on_element;
|
40
43
|
} http_parser;
|
41
44
|
|
42
45
|
void http_parser_init(http_parser *parser);
|
data/test/basic_test.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/helper'
|
2
2
|
|
3
|
-
|
3
|
+
module BasicTests
|
4
4
|
def test_get_bytes
|
5
5
|
[1,10,1000].each do |i|
|
6
6
|
response = get("/bytes/#{i}")
|
@@ -27,3 +27,20 @@ class BasicTest < ServerTest
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
30
|
+
|
31
|
+
class BasicTest < ServerTest
|
32
|
+
include BasicTests
|
33
|
+
end
|
34
|
+
|
35
|
+
class BasicTestFD < ServerTestFD
|
36
|
+
include BasicTests
|
37
|
+
end
|
38
|
+
|
39
|
+
class BasicTestUnixSocket < ServerTestSocket
|
40
|
+
include BasicTests
|
41
|
+
|
42
|
+
def test_socket_file_exists
|
43
|
+
assert File.exists?(@socketfile)
|
44
|
+
assert File.readable?(@socketfile)
|
45
|
+
end
|
46
|
+
end
|
data/test/env_test.rb
CHANGED
@@ -35,20 +35,21 @@ end
|
|
35
35
|
class HttpParserTest < ServerTest
|
36
36
|
|
37
37
|
def test_parse_simple
|
38
|
-
env = send_request("GET / HTTP/1.
|
38
|
+
env = send_request("GET / HTTP/1.0\r\n\r\n")
|
39
39
|
|
40
40
|
assert_equal 'HTTP/1.1', env['SERVER_PROTOCOL']
|
41
41
|
assert_equal '/', env['REQUEST_PATH']
|
42
|
-
assert_equal 'HTTP/1.
|
42
|
+
assert_equal 'HTTP/1.0', env['HTTP_VERSION']
|
43
43
|
assert_equal '/', env['REQUEST_URI']
|
44
44
|
assert_equal 'GET', env['REQUEST_METHOD']
|
45
45
|
assert_nil env['FRAGMENT']
|
46
46
|
assert_nil env['QUERY_STRING']
|
47
47
|
assert_equal "", env['rack.input']
|
48
|
+
assert_equal '127.0.0.1', env['HTTP_CLIENT_IP']
|
48
49
|
end
|
49
50
|
|
50
51
|
def test_parse_dumbfuck_headers
|
51
|
-
should_be_good = "GET / HTTP/1.
|
52
|
+
should_be_good = "GET / HTTP/1.0\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n"
|
52
53
|
env = send_request(should_be_good)
|
53
54
|
assert_equal "++++++++++", env["HTTP_AAAAAAAAAAAAA"]
|
54
55
|
assert_equal "", env['rack.input']
|
@@ -62,7 +63,7 @@ class HttpParserTest < ServerTest
|
|
62
63
|
end
|
63
64
|
|
64
65
|
def test_fragment_in_uri
|
65
|
-
env = send_request("GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.
|
66
|
+
env = send_request("GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.0\r\n\r\n")
|
66
67
|
assert_equal '/forums/1/topics/2375?page=1', env['REQUEST_URI']
|
67
68
|
assert_equal 'posts-17408', env['FRAGMENT']
|
68
69
|
assert_equal "", env['rack.input']
|
@@ -91,7 +92,7 @@ class HttpParserTest < ServerTest
|
|
91
92
|
# then that large mangled field values are caught
|
92
93
|
10.times do |c|
|
93
94
|
req = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
|
94
|
-
|
95
|
+
assert drops_request?(req), "large mangled field values are caught"
|
95
96
|
### XXX this is broken! fix me. this test should drop the request.
|
96
97
|
end
|
97
98
|
|
data/test/helper.rb
CHANGED
@@ -25,7 +25,7 @@ class HelperApp
|
|
25
25
|
elsif commands.include?('test_post_length')
|
26
26
|
input_body = env['rack.input'].read
|
27
27
|
|
28
|
-
content_length_header = env['
|
28
|
+
content_length_header = env['CONTENT_LENGTH'].to_i
|
29
29
|
|
30
30
|
if content_length_header == input_body.length
|
31
31
|
body = "Content-Length matches input length"
|
@@ -84,3 +84,55 @@ class ServerTest < Test::Unit::TestCase
|
|
84
84
|
assert true
|
85
85
|
end
|
86
86
|
end
|
87
|
+
|
88
|
+
class ServerTestFD < ServerTest
|
89
|
+
def setup
|
90
|
+
@tcp_server = TCPServer.new('0.0.0.0', TEST_PORT);
|
91
|
+
Thread.new { Ebb.start_server(HelperApp.new, :fileno => @tcp_server.fileno) }
|
92
|
+
sleep 0.1 until Ebb.running?
|
93
|
+
end
|
94
|
+
|
95
|
+
def teardown
|
96
|
+
super
|
97
|
+
@tcp_server = nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class ServerTestSocket < ServerTest
|
102
|
+
def get(path)
|
103
|
+
socket = UNIXSocket.open(@socketfile)
|
104
|
+
socket.write("GET #{path} HTTP/1.0\r\n\r\n")
|
105
|
+
response = ""
|
106
|
+
while chunk = socket.read(100)
|
107
|
+
response << chunk
|
108
|
+
end
|
109
|
+
body = response.split("\r\n\r\n")[1]
|
110
|
+
env = JSON.parse(body)
|
111
|
+
ensure
|
112
|
+
socket.close if socket
|
113
|
+
end
|
114
|
+
|
115
|
+
def post(path, data)
|
116
|
+
socket = UNIXSocket.open(@socketfile)
|
117
|
+
socket.write("POST #{path} HTTP/1.0\r\nContent-Length: #{data.length}\r\n\r\n#{data}")
|
118
|
+
response = ""
|
119
|
+
while chunk = socket.read(100)
|
120
|
+
response << chunk
|
121
|
+
end
|
122
|
+
body = response.split("\r\n\r\n")[1]
|
123
|
+
env = JSON.parse(body)
|
124
|
+
ensure
|
125
|
+
socket.close if socket
|
126
|
+
end
|
127
|
+
|
128
|
+
def setup
|
129
|
+
@socketfile = '/tmp/ebb_unittest.sock'
|
130
|
+
Thread.new { Ebb.start_server(HelperApp.new, :unix_socket => @socketfile) }
|
131
|
+
sleep 0.1 until Ebb.running?
|
132
|
+
end
|
133
|
+
|
134
|
+
def teardown
|
135
|
+
super
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ebb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ry dahl
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-04-19 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -56,7 +56,6 @@ files:
|
|
56
56
|
- ruby_lib/rack/adapter
|
57
57
|
- ruby_lib/rack/adapter/rails.rb
|
58
58
|
- benchmark/application.rb
|
59
|
-
- benchmark/bench_results.rb
|
60
59
|
- benchmark/server_test.rb
|
61
60
|
- bin/ebb_rails
|
62
61
|
- test/basic_test.rb
|
@@ -85,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
84
|
requirements: []
|
86
85
|
|
87
86
|
rubyforge_project: ebb
|
88
|
-
rubygems_version: 1.0
|
87
|
+
rubygems_version: 1.1.0
|
89
88
|
signing_key:
|
90
89
|
specification_version: 2
|
91
90
|
summary: A Web Server
|
data/benchmark/bench_results.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
# supply the benchmark dump file as an argumetn to this program
|
2
|
-
require 'rubygems'
|
3
|
-
require 'google_chart'
|
4
|
-
require 'server_test'
|
5
|
-
|
6
|
-
class Array
|
7
|
-
def max
|
8
|
-
inject(first) { |m, i| i > m ? i : m }
|
9
|
-
end
|
10
|
-
|
11
|
-
def min
|
12
|
-
inject(first) { |m, i| i < m ? i : m }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
colors = %w{F74343 444130 7DA478 E4AC3D 1F479E}
|
19
|
-
data_x = []
|
20
|
-
data_y = []
|
21
|
-
results = ServerTestResults.open(ARGV[0])
|
22
|
-
|
23
|
-
response_chart = GoogleChart::LineChart.new('500x300', Time.now.strftime('%Y.%m.%d'), true)
|
24
|
-
servers = results.servers.sort_by do |x,y|
|
25
|
-
results.data(x).map { |d| d[1] }.mean
|
26
|
-
end.reverse
|
27
|
-
|
28
|
-
cmap = {}
|
29
|
-
results.servers.sort.each { |x| cmap[x] = colors.shift }
|
30
|
-
|
31
|
-
servers.each do |server|
|
32
|
-
data = results.data(server).sort
|
33
|
-
data_x += data.map { |d| d[0] }
|
34
|
-
data_y += data.map { |d| d[1] }
|
35
|
-
end
|
36
|
-
|
37
|
-
servers.each do |server|
|
38
|
-
data = results.data(server).sort
|
39
|
-
data.map! { |d| [d[0]-data_x.min, d[1]-data_y.min]}
|
40
|
-
response_chart.data(server, data, cmap[server])
|
41
|
-
end
|
42
|
-
|
43
|
-
label = case results.benchmark
|
44
|
-
when "response_size"
|
45
|
-
"kilobytes served"
|
46
|
-
when "wait_fib", "concurrency"
|
47
|
-
"concurrency"
|
48
|
-
when "post_size"
|
49
|
-
"kilobytes uploaded"
|
50
|
-
when "wait", "wait_fib"
|
51
|
-
"seconds waited every 10 requests"
|
52
|
-
end
|
53
|
-
|
54
|
-
response_chart.axis(:y, :range => [data_y.min,data_y.max])
|
55
|
-
response_chart.axis(:y, :labels => ['req/s'], :positions => [50])
|
56
|
-
response_chart.axis(:x, :range => [data_x.min,data_x.max])
|
57
|
-
response_chart.axis(:x, :labels => [label], :positions => [50])
|
58
|
-
puts response_chart.to_url
|