eventmachine_httpserver 0.0.1 → 0.1.1
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/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
|
-
|