eventmachine_httpserver 0.0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +69 -62
- data/{COPYING → docs/COPYING} +0 -0
- data/{README → docs/README} +0 -0
- data/{RELEASE_NOTES → docs/RELEASE_NOTES} +0 -0
- data/eventmachine_httpserver.gemspec +33 -0
- data/eventmachine_httpserver.gemspec.tmpl +23 -0
- data/ext/extconf.rb +7 -2
- data/ext/http.cpp +2 -4
- data/ext/http.h +0 -2
- data/ext/rubyhttp.cpp +5 -2
- data/lib/evma_httpserver.rb +0 -2
- data/lib/evma_httpserver/response.rb +37 -4
- data/test/test_app.rb +239 -0
- data/test/{response.rb → test_delegated.rb} +43 -39
- data/test/test_response.rb +178 -0
- metadata +53 -47
- data/ext/ptch +0 -148
- data/test/app.rb +0 -235
data/ext/ptch
DELETED
@@ -1,148 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
--- http.cpp 1969-12-31 18:00:00.000000000 -0600
|
6
|
-
+++ /usr/local/ruby185/lib/ruby/gems/1.8/gems/eventmachine_httpserver-0.0.1/ext/http.cpp 2007-03-10 08:13:24.000000000 -0600
|
7
|
-
@@ -29,6 +29,7 @@
|
8
|
-
#include <string>
|
9
|
-
#include <sstream>
|
10
|
-
#include <stdexcept>
|
11
|
-
+#include <stdio.h>
|
12
|
-
|
13
|
-
#ifdef OS_WIN32
|
14
|
-
#include <windows.h>
|
15
|
-
@@ -66,6 +67,7 @@
|
16
|
-
// (This is primarily beneficial because it lets the caller use Ruby's CGI classes.)
|
17
|
-
// The caller can switch this off in Ruby code, which greatly improves performance.
|
18
|
-
bSetEnvironmentStrings = true;
|
19
|
-
+ bAccumulatePost = true;
|
20
|
-
}
|
21
|
-
|
22
|
-
|
23
|
-
@@ -112,6 +114,7 @@
|
24
|
-
const char *query_string,
|
25
|
-
const char *path_info,
|
26
|
-
const char *request_uri,
|
27
|
-
+ const char *protocol,
|
28
|
-
int post_length,
|
29
|
-
const char *post_content,
|
30
|
-
const char *hdrblock,
|
31
|
-
@@ -121,7 +124,14 @@
|
32
|
-
}
|
33
|
-
|
34
|
-
|
35
|
-
+/********************************
|
36
|
-
+HttpConnection_t::ReceivePostData
|
37
|
-
+********************************/
|
38
|
-
|
39
|
-
+void HttpConnection_t::ReceivePostData (const char *data, int len)
|
40
|
-
+{
|
41
|
-
+ cerr << "UNIMPLEMENTED ReceivePostData" << endl;
|
42
|
-
+}
|
43
|
-
|
44
|
-
/*****************************
|
45
|
-
HttpConnection_t::ConsumeData
|
46
|
-
@@ -159,6 +169,7 @@
|
47
|
-
PathInfo.clear();
|
48
|
-
RequestUri.clear();
|
49
|
-
QueryString.clear();
|
50
|
-
+ Protocol.clear();
|
51
|
-
|
52
|
-
if (bSetEnvironmentStrings) {
|
53
|
-
unsetenv ("REQUEST_METHOD");
|
54
|
-
@@ -168,6 +179,7 @@
|
55
|
-
unsetenv ("PATH_INFO");
|
56
|
-
unsetenv ("REQUEST_URI");
|
57
|
-
unsetenv ("QUERY_STRING");
|
58
|
-
+ unsetenv ("PROTOCOL");
|
59
|
-
}
|
60
|
-
}
|
61
|
-
|
62
|
-
@@ -202,9 +214,15 @@
|
63
|
-
if (ContentLength > 0) {
|
64
|
-
if (_Content)
|
65
|
-
free (_Content);
|
66
|
-
- _Content = (char*) malloc (ContentLength + 1);
|
67
|
-
- if (!_Content)
|
68
|
-
- throw std::runtime_error ("resource exhaustion");
|
69
|
-
+ if (bAccumulatePost) {
|
70
|
-
+ _Content = (char*) malloc (ContentLength + 1);
|
71
|
-
+ if (!_Content)
|
72
|
-
+ throw std::runtime_error ("resource exhaustion");
|
73
|
-
+ }
|
74
|
-
+ else {
|
75
|
-
+ _Content = (char*) malloc (1);
|
76
|
-
+ _Content = 0;
|
77
|
-
+ }
|
78
|
-
ContentPos = 0;
|
79
|
-
ProtocolState = ReadingContentState;
|
80
|
-
}
|
81
|
-
@@ -241,12 +259,19 @@
|
82
|
-
int len = ContentLength - ContentPos;
|
83
|
-
if (len > length)
|
84
|
-
len = length;
|
85
|
-
- memcpy (_Content + ContentPos, data, len);
|
86
|
-
+ if (bAccumulatePost) {
|
87
|
-
+ memcpy (_Content + ContentPos, data, len);
|
88
|
-
+ } else {
|
89
|
-
+ ReceivePostData(data,len);
|
90
|
-
+ }
|
91
|
-
data += len;
|
92
|
-
length -= len;
|
93
|
-
ContentPos += len;
|
94
|
-
if (ContentPos == ContentLength) {
|
95
|
-
- _Content[ContentPos] = 0;
|
96
|
-
+ if (bAccumulatePost) {
|
97
|
-
+ _Content[ContentPos] = 0;
|
98
|
-
+ } else {
|
99
|
-
+ }
|
100
|
-
ProtocolState = DispatchState;
|
101
|
-
}
|
102
|
-
}
|
103
|
-
@@ -254,7 +279,7 @@
|
104
|
-
|
105
|
-
//----------------------------------- DispatchState
|
106
|
-
if (ProtocolState == DispatchState) {
|
107
|
-
- ProcessRequest (RequestMethod, Cookie.c_str(), IfNoneMatch.c_str(), ContentType.c_str(), QueryString.c_str(), PathInfo.c_str(), RequestUri.c_str(), ContentLength, _Content, HeaderBlock, HeaderBlockPos);
|
108
|
-
+ ProcessRequest (RequestMethod, Cookie.c_str(), IfNoneMatch.c_str(), ContentType.c_str(), QueryString.c_str(), PathInfo.c_str(), RequestUri.c_str(), Protocol.c_str(), ContentLength, _Content, HeaderBlock, HeaderBlockPos);
|
109
|
-
ProtocolState = BaseState;
|
110
|
-
}
|
111
|
-
}
|
112
|
-
@@ -424,6 +449,9 @@
|
113
|
-
return false;
|
114
|
-
}
|
115
|
-
|
116
|
-
+ string prot (blank2+1);
|
117
|
-
+ Protocol = prot.c_str();
|
118
|
-
+
|
119
|
-
// Here, the request starts at blank and ends just before blank2.
|
120
|
-
// Find the query-string (?) and/or fragment (#,;), if either are present.
|
121
|
-
const char *questionmark = strchr (blank, '?');
|
122
|
-
@@ -444,6 +472,7 @@
|
123
|
-
setenv ("PATH_INFO", req.c_str(), true);
|
124
|
-
setenv ("REQUEST_URI", req.c_str(), true);
|
125
|
-
setenv ("QUERY_STRING", qs.c_str(), true);
|
126
|
-
+ setenv ("PROTOCOL", prot.c_str(), true);
|
127
|
-
}
|
128
|
-
}
|
129
|
-
else if (fragment) {
|
130
|
-
@@ -455,6 +484,7 @@
|
131
|
-
setenv ("PATH_INFO", req.c_str(), true);
|
132
|
-
setenv ("REQUEST_URI", req.c_str(), true);
|
133
|
-
setenv ("QUERY_STRING", "", true);
|
134
|
-
+ setenv ("PROTOCOL", prot.c_str(), true);
|
135
|
-
}
|
136
|
-
}
|
137
|
-
else {
|
138
|
-
@@ -466,9 +496,9 @@
|
139
|
-
setenv ("PATH_INFO", req.c_str(), true);
|
140
|
-
setenv ("REQUEST_URI", req.c_str(), true);
|
141
|
-
setenv ("QUERY_STRING", "", true);
|
142
|
-
+ setenv ("PROTOCOL", prot.c_str(), true);
|
143
|
-
}
|
144
|
-
}
|
145
|
-
-
|
146
|
-
|
147
|
-
return true;
|
148
|
-
}
|
data/test/app.rb
DELETED
@@ -1,235 +0,0 @@
|
|
1
|
-
# $Id: app.rb 3893 2007-03-06 20:12:09Z francis $
|
2
|
-
#
|
3
|
-
#
|
4
|
-
|
5
|
-
|
6
|
-
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
7
|
-
|
8
|
-
require 'eventmachine'
|
9
|
-
require 'evma_httpserver'
|
10
|
-
|
11
|
-
|
12
|
-
#--------------------------------------
|
13
|
-
|
14
|
-
module EventMachine
|
15
|
-
module HttpServer
|
16
|
-
def process_http_request
|
17
|
-
send_data generate_response()
|
18
|
-
close_connection_after_writing
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
#--------------------------------------
|
24
|
-
|
25
|
-
|
26
|
-
class TestApp < Test::Unit::TestCase
|
27
|
-
|
28
|
-
TestHost = "127.0.0.1"
|
29
|
-
TestPort = 8911
|
30
|
-
|
31
|
-
TestResponse_1 = %Q(HTTP/1.0 200 ...
|
32
|
-
Content-length: 4
|
33
|
-
Content-type: text/plain
|
34
|
-
Connection: close
|
35
|
-
|
36
|
-
1234)
|
37
|
-
|
38
|
-
def setup
|
39
|
-
Thread.abort_on_exception = true
|
40
|
-
end
|
41
|
-
|
42
|
-
def teardown
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
def test_simple_get
|
48
|
-
received_response = nil
|
49
|
-
|
50
|
-
EventMachine::HttpServer.module_eval {
|
51
|
-
def generate_response
|
52
|
-
TestResponse_1
|
53
|
-
end
|
54
|
-
}
|
55
|
-
|
56
|
-
|
57
|
-
EventMachine.run {
|
58
|
-
EventMachine.start_server TestHost, TestPort, EventMachine::HttpServer
|
59
|
-
EventMachine.add_timer(1) {raise "timed out"} # make sure the test completes
|
60
|
-
|
61
|
-
EventMachine.defer proc {
|
62
|
-
tcp = TCPSocket.new TestHost, TestPort
|
63
|
-
tcp.write "GET / HTTP/1.0\r\n\r\n"
|
64
|
-
received_response = tcp.read
|
65
|
-
}, proc {
|
66
|
-
EventMachine.stop
|
67
|
-
}
|
68
|
-
}
|
69
|
-
|
70
|
-
assert_equal( TestResponse_1, received_response )
|
71
|
-
end
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
# This frowsy-looking protocol handler allows the test harness to make some
|
77
|
-
# its local variables visible, so we can set them here and they can be asserted later.
|
78
|
-
class MyTestServer < EventMachine::Connection
|
79
|
-
include EventMachine::HttpServer
|
80
|
-
def initialize *args
|
81
|
-
super
|
82
|
-
end
|
83
|
-
def generate_response
|
84
|
-
@assertions.call
|
85
|
-
TestResponse_1
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
def test_parameters
|
92
|
-
path_info = "/test.html"
|
93
|
-
query_string = "a=b&c=d"
|
94
|
-
cookie = "eat_me=I'm a cookie"
|
95
|
-
etag = "12345"
|
96
|
-
|
97
|
-
# collect all the stuff we want to assert outside the actual test,
|
98
|
-
# to ensure it gets asserted even if the test catches some exception.
|
99
|
-
received_response = nil
|
100
|
-
request_parms = {}
|
101
|
-
|
102
|
-
|
103
|
-
EventMachine.run {
|
104
|
-
EventMachine.start_server(TestHost, TestPort, MyTestServer) {|conn|
|
105
|
-
# In each accepted connection, set up a procedure that will copy
|
106
|
-
# the request parameters into a local variable visible here, so
|
107
|
-
# we can assert the values later.
|
108
|
-
conn.instance_eval {@assertions = proc {
|
109
|
-
%w( PATH_INFO
|
110
|
-
QUERY_STRING
|
111
|
-
HTTP_COOKIE
|
112
|
-
IF_NONE_MATCH
|
113
|
-
CONTENT_TYPE
|
114
|
-
REQUEST_METHOD
|
115
|
-
REQUEST_URI
|
116
|
-
).each {|parm|
|
117
|
-
# request_parms is bound to a local variable visible in this context.
|
118
|
-
request_parms[parm] = ENV[parm]
|
119
|
-
}
|
120
|
-
}}
|
121
|
-
}
|
122
|
-
EventMachine.add_timer(1) {raise "timed out"} # make sure the test completes
|
123
|
-
|
124
|
-
EventMachine.defer proc {
|
125
|
-
tcp = TCPSocket.new TestHost, TestPort
|
126
|
-
tcp.write [
|
127
|
-
"GET #{path_info}?#{query_string} HTTP/1.1\r\n",
|
128
|
-
"Cookie: #{cookie}\r\n",
|
129
|
-
"If-none-match: #{etag}\r\n",
|
130
|
-
"\r\n"
|
131
|
-
].join
|
132
|
-
received_response = tcp.read
|
133
|
-
}, proc {
|
134
|
-
EventMachine.stop
|
135
|
-
}
|
136
|
-
}
|
137
|
-
|
138
|
-
assert_equal( TestResponse_1, received_response )
|
139
|
-
assert_equal( path_info, request_parms["PATH_INFO"] )
|
140
|
-
assert_equal( query_string, request_parms["QUERY_STRING"] )
|
141
|
-
assert_equal( cookie, request_parms["HTTP_COOKIE"] )
|
142
|
-
assert_equal( etag, request_parms["IF_NONE_MATCH"] )
|
143
|
-
assert_equal( nil, request_parms["CONTENT_TYPE"] )
|
144
|
-
assert_equal( "GET", request_parms["REQUEST_METHOD"] )
|
145
|
-
assert_equal( path_info, request_parms["REQUEST_URI"] )
|
146
|
-
end
|
147
|
-
|
148
|
-
|
149
|
-
def test_headers
|
150
|
-
received_header_string = nil
|
151
|
-
received_header_ary = nil
|
152
|
-
|
153
|
-
EventMachine.run {
|
154
|
-
EventMachine.start_server(TestHost, TestPort, MyTestServer) {|conn|
|
155
|
-
# In each accepted connection, set up a procedure that will copy
|
156
|
-
# the request parameters into a local variable visible here, so
|
157
|
-
# we can assert the values later.
|
158
|
-
# The @http_headers is set automatically and can easily be parsed.
|
159
|
-
# It isn't automatically parsed into Ruby values because that is
|
160
|
-
# a costly operation, but we should provide an optional method that
|
161
|
-
# does the parsing so it doesn't need to be done by users.
|
162
|
-
conn.instance_eval {@assertions = proc {
|
163
|
-
received_header_string = @http_headers
|
164
|
-
received_header_ary = @http_headers.split(/\0/).map {|line| line.split(/:\s*/, 2) }
|
165
|
-
}}
|
166
|
-
}
|
167
|
-
EventMachine.add_timer(1) {raise "timed out"} # make sure the test completes
|
168
|
-
|
169
|
-
EventMachine.defer proc {
|
170
|
-
tcp = TCPSocket.new TestHost, TestPort
|
171
|
-
tcp.write [
|
172
|
-
"GET / HTTP/1.1\r\n",
|
173
|
-
"aaa: 111\r\n",
|
174
|
-
"bbb: 222\r\n",
|
175
|
-
"ccc: 333\r\n",
|
176
|
-
"ddd: 444\r\n",
|
177
|
-
"\r\n"
|
178
|
-
].join
|
179
|
-
received_response = tcp.read
|
180
|
-
}, proc {
|
181
|
-
EventMachine.stop
|
182
|
-
}
|
183
|
-
}
|
184
|
-
|
185
|
-
assert_equal( "aaa: 111\0bbb: 222\0ccc: 333\0ddd: 444\0\0", received_header_string )
|
186
|
-
assert_equal( [["aaa","111"], ["bbb","222"], ["ccc","333"], ["ddd","444"]], received_header_ary )
|
187
|
-
end
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
def test_post
|
194
|
-
received_header_string = nil
|
195
|
-
post_content = "1234567890"
|
196
|
-
content_type = "text/plain"
|
197
|
-
received_post_content = ""
|
198
|
-
received_content_type = ""
|
199
|
-
|
200
|
-
EventMachine.run {
|
201
|
-
EventMachine.start_server(TestHost, TestPort, MyTestServer) {|conn|
|
202
|
-
# In each accepted connection, set up a procedure that will copy
|
203
|
-
# the request parameters into a local variable visible here, so
|
204
|
-
# we can assert the values later.
|
205
|
-
# The @http_post_content variable is set automatically.
|
206
|
-
conn.instance_eval {@assertions = proc {
|
207
|
-
received_post_content = @http_post_content
|
208
|
-
received_content_type = ENV["CONTENT_TYPE"]
|
209
|
-
}}
|
210
|
-
}
|
211
|
-
EventMachine.add_timer(1) {raise "timed out"} # make sure the test completes
|
212
|
-
|
213
|
-
EventMachine.defer proc {
|
214
|
-
tcp = TCPSocket.new TestHost, TestPort
|
215
|
-
tcp.write [
|
216
|
-
"POST / HTTP/1.1\r\n",
|
217
|
-
"Content-type: #{content_type}\r\n",
|
218
|
-
"Content-length: #{post_content.length}\r\n",
|
219
|
-
"\r\n",
|
220
|
-
post_content
|
221
|
-
].join
|
222
|
-
received_response = tcp.read
|
223
|
-
}, proc {
|
224
|
-
EventMachine.stop
|
225
|
-
}
|
226
|
-
}
|
227
|
-
|
228
|
-
assert_equal( received_post_content, post_content )
|
229
|
-
assert_equal( received_content_type, content_type )
|
230
|
-
end
|
231
|
-
|
232
|
-
end
|
233
|
-
|
234
|
-
|
235
|
-
|