packet 0.1.2 → 0.1.3
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 +1 -1
- data/TODO +2 -0
- data/examples/netbeans.jpg +0 -0
- data/examples/write_bulk.rb +41 -0
- data/lib/packet.rb +19 -26
- data/lib/{disconnect_error.rb → packet/disconnect_error.rb} +3 -2
- data/lib/{double_keyed_hash.rb → packet/double_keyed_hash.rb} +0 -0
- data/lib/{callback.rb → packet/packet_callback.rb} +0 -0
- data/lib/{connection.rb → packet/packet_connection.rb} +10 -3
- data/lib/{core.rb → packet/packet_core.rb} +84 -40
- data/lib/{event.rb → packet/packet_event.rb} +1 -1
- data/lib/{packet_guid.rb → packet/packet_guid.rb} +0 -0
- data/lib/{class_helpers.rb → packet/packet_helper.rb} +0 -0
- data/lib/{packet_master.rb → packet/packet_master.rb} +18 -10
- data/lib/{meta_pimp.rb → packet/packet_meta_pimp.rb} +1 -1
- data/lib/packet/packet_mongrel.rb +218 -0
- data/lib/{nbio.rb → packet/packet_nbio.rb} +37 -37
- data/lib/{bin_parser.rb → packet/packet_parser.rb} +0 -0
- data/lib/{periodic_event.rb → packet/packet_periodic_event.rb} +0 -0
- data/lib/{pimp.rb → packet/packet_pimp.rb} +3 -1
- data/lib/{worker.rb → packet/packet_worker.rb} +1 -4
- data/lib/{timer_store.rb → packet/timer_store.rb} +26 -18
- data/lib/packet_mongrel.rb +200 -206
- data/spec/spec_helper.rb +10 -0
- data/spec/test_double_keyed_hash.rb +14 -0
- data/spec/test_packet_core.rb +38 -0
- metadata +25 -20
- data/lib/thread_pool.rb +0 -54
- data/lib/worker_pool.rb +0 -10
data/lib/packet_mongrel.rb
CHANGED
@@ -1,214 +1,208 @@
|
|
1
|
-
|
2
|
-
# order to change it from a threaded application to an event based
|
3
|
-
# application running inside an Packet event loop. It should
|
4
|
-
# be compatible with the existing Mongrel handlers for Rails,
|
5
|
-
# Camping, Nitro, etc....
|
6
|
-
|
7
|
-
require 'packet'
|
1
|
+
require "packet"
|
8
2
|
require 'mongrel'
|
9
3
|
|
10
4
|
module Mongrel
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
5
|
+
class MongrelProtocol
|
6
|
+
def post_init
|
7
|
+
@parser = HttpParser.new
|
8
|
+
@params = HttpParams.new
|
9
|
+
@nparsed = 0
|
10
|
+
@request = nil
|
11
|
+
@request_len = nil
|
12
|
+
@linebuffer = ''
|
13
|
+
end
|
14
|
+
|
15
|
+
def receive_data data
|
16
|
+
@linebuffer << data
|
17
|
+
@nparsed = @parser.execute(@params, @linebuffer, @nparsed) unless @parser.finished?
|
18
|
+
if @parser.finished?
|
19
|
+
if @request_len.nil?
|
20
|
+
@request_len = @params[::Mongrel::Const::CONTENT_LENGTH].to_i
|
21
|
+
script_name, path_info, handlers = ::Mongrel::HttpServer::Instance.classifier.resolve(@params[::Mongrel::Const::REQUEST_PATH])
|
22
|
+
if handlers
|
23
|
+
@params[::Mongrel::Const::PATH_INFO] = path_info
|
24
|
+
@params[::Mongrel::Const::SCRIPT_NAME] = script_name
|
25
|
+
@params[::Mongrel::Const::REMOTE_ADDR] = @params[::Mongrel::Const::HTTP_X_FORWARDED_FOR] #|| ::Socket.unpack_sockaddr_in(get_peername)[1]
|
26
|
+
@notifiers = handlers.select { |h| h.request_notify }
|
27
|
+
end
|
28
|
+
if @request_len > ::Mongrel::Const::MAX_BODY
|
29
|
+
new_buffer = Tempfile.new(::Mongrel::Const::MONGREL_TMP_BASE)
|
30
|
+
new_buffer.binmode
|
31
|
+
new_buffer << @linebuffer[@nparsed..-1]
|
32
|
+
@linebuffer = new_buffer
|
33
|
+
else
|
34
|
+
@linebuffer = StringIO.new(@linebuffer[@nparsed..-1])
|
35
|
+
@linebuffer.pos = @linebuffer.length
|
36
|
+
end
|
37
|
+
end
|
38
|
+
if @linebuffer.length >= @request_len
|
39
|
+
@linebuffer.rewind
|
40
|
+
::Mongrel::HttpServer::Instance.process_http_request(@params,@linebuffer,self)
|
41
|
+
@linebuffer.delete if Tempfile === @linebuffer
|
42
|
+
end
|
43
|
+
elsif @linebuffer.length > ::Mongrel::Const::MAX_HEADER
|
44
|
+
close_connection
|
45
|
+
raise ::Mongrel::HttpParserError.new("HEADER is longer than allowed, aborting client early.")
|
46
|
+
end
|
47
|
+
rescue ::Mongrel::HttpParserError
|
48
|
+
if $mongrel_debug_client
|
49
|
+
STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!"
|
50
|
+
STDERR.puts "#{Time.now}: REQUEST DATA: #{data.inspect}\n---\nPARAMS: #{params.inspect}\n---\n"
|
51
|
+
end
|
52
|
+
close_connection
|
53
|
+
rescue Exception => e
|
54
|
+
close_connection
|
55
|
+
raise e
|
56
|
+
end
|
57
|
+
|
58
|
+
def write data
|
59
|
+
send_data data
|
60
|
+
end
|
61
|
+
|
62
|
+
def closed?
|
63
|
+
false
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
class HttpServer
|
69
|
+
def initialize(host, port, num_processors=950, x=0, y=nil) # Deal with Mongrel 1.0.1 or earlier, as well as later.
|
70
|
+
@socket = nil
|
71
|
+
@classifier = URIClassifier.new
|
72
|
+
@host = host
|
73
|
+
@port = port
|
74
|
+
@workers = ThreadGroup.new
|
75
|
+
if y
|
76
|
+
@throttle = x
|
77
|
+
@timeout = y || 60
|
78
|
+
else
|
79
|
+
@timeout = x
|
80
|
+
end
|
81
|
+
@num_processors = num_processors #num_processors is pointless for evented....
|
82
|
+
@death_time = 60
|
83
|
+
self.class.const_set(:Instance,self)
|
84
|
+
end
|
85
|
+
|
86
|
+
def run
|
87
|
+
trap('INT') { raise StopServer }
|
88
|
+
trap('TERM') { raise StopServer }
|
89
|
+
@acceptor = Thread.new do
|
90
|
+
Packet::Reactor.run do |t_reactor|
|
91
|
+
begin
|
98
92
|
t_reactor.start_server(@host,@port,MongrelProtocol)
|
99
93
|
rescue StopServer
|
100
94
|
t_reactor.start_server
|
101
|
-
end
|
95
|
+
end
|
102
96
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
end
|
213
|
-
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def process_http_request(params,linebuffer,client)
|
101
|
+
if not params[Const::REQUEST_PATH]
|
102
|
+
uri = URI.parse(params[Const::REQUEST_URI])
|
103
|
+
params[Const::REQUEST_PATH] = uri.request_uri
|
104
|
+
end
|
105
|
+
|
106
|
+
raise "No REQUEST PATH" if not params[Const::REQUEST_PATH]
|
107
|
+
|
108
|
+
script_name, path_info, handlers = @classifier.resolve(params[Const::REQUEST_PATH])
|
109
|
+
|
110
|
+
if handlers
|
111
|
+
notifiers = handlers.select { |h| h.request_notify }
|
112
|
+
request = HttpRequest.new(params, linebuffer, notifiers)
|
113
|
+
|
114
|
+
# request is good so far, continue processing the response
|
115
|
+
response = HttpResponse.new(client)
|
116
|
+
|
117
|
+
# Process each handler in registered order until we run out or one finalizes the response.
|
118
|
+
dispatch_to_handlers(handlers,request,response)
|
119
|
+
|
120
|
+
# And finally, if nobody closed the response off, we finalize it.
|
121
|
+
unless response.done
|
122
|
+
response.finished
|
123
|
+
end
|
124
|
+
else
|
125
|
+
# Didn't find it, return a stock 404 response.
|
126
|
+
client.send_data(Const::ERROR_404_RESPONSE)
|
127
|
+
client.close_connection
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def dispatch_to_handlers(handlers,request,response)
|
132
|
+
handlers.each do |handler|
|
133
|
+
handler.process(request, response)
|
134
|
+
break if response.done
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class HttpRequest
|
140
|
+
def initialize(params, linebuffer, dispatchers)
|
141
|
+
@params = params
|
142
|
+
@dispatchers = dispatchers
|
143
|
+
@body = linebuffer
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class HttpResponse
|
148
|
+
def send_file(path, small_file = false)
|
149
|
+
File.open(path, "rb") do |f|
|
150
|
+
while chunk = f.read(Const::CHUNK_SIZE) and chunk.length > 0
|
151
|
+
begin
|
152
|
+
write(chunk)
|
153
|
+
rescue Object => exc
|
154
|
+
break
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
@body_sent = true
|
159
|
+
end
|
160
|
+
|
161
|
+
def write(data)
|
162
|
+
@socket.send_data data
|
163
|
+
end
|
164
|
+
|
165
|
+
def close_connection_after_writing
|
166
|
+
@socket.close_connection
|
167
|
+
end
|
168
|
+
|
169
|
+
def socket_error(details)
|
170
|
+
@socket.close_connection
|
171
|
+
done = true
|
172
|
+
raise details
|
173
|
+
end
|
174
|
+
|
175
|
+
def finished
|
176
|
+
send_status
|
177
|
+
send_header
|
178
|
+
send_body
|
179
|
+
@socket.close_connection
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
class Configurator
|
184
|
+
# This version fixes a bug in the regular Mongrel version by adding
|
185
|
+
# initialization of groups.
|
186
|
+
def change_privilege(user, group)
|
187
|
+
if user and group
|
188
|
+
log "Initializing groups for {#user}:{#group}."
|
189
|
+
Process.initgroups(user,Etc.getgrnam(group).gid)
|
190
|
+
end
|
191
|
+
|
192
|
+
if group
|
193
|
+
log "Changing group to #{group}."
|
194
|
+
Process::GID.change_privilege(Etc.getgrnam(group).gid)
|
195
|
+
end
|
196
|
+
|
197
|
+
if user
|
198
|
+
log "Changing user to #{user}."
|
199
|
+
Process::UID.change_privilege(Etc.getpwnam(user).uid)
|
200
|
+
end
|
201
|
+
rescue Errno::EPERM
|
202
|
+
log "FAILED to change user:group #{user}:#{group}: #$!"
|
203
|
+
exit 1
|
204
|
+
end
|
205
|
+
end
|
214
206
|
end
|
207
|
+
|
208
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__) + "/spec_helper")
|
2
|
+
context "Double Keyed Hash in general" do
|
3
|
+
xspecify "should allow muliple keys while storing the value in hash" do
|
4
|
+
end
|
5
|
+
|
6
|
+
xspecify "should return correct value when either of the keys is used" do
|
7
|
+
end
|
8
|
+
|
9
|
+
xspecify "should return nil if nither of keys match" do
|
10
|
+
end
|
11
|
+
|
12
|
+
xspecify "should allow deletion of value from hash based on either of keys" do
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__) + "/spec_helper")
|
2
|
+
context "Packet Core in general when mixed inside a class" do
|
3
|
+
xspecify "allow the class to act as a reactor" do
|
4
|
+
end
|
5
|
+
|
6
|
+
xspecify "should start a server on specified port" do
|
7
|
+
end
|
8
|
+
|
9
|
+
xspecify "should let clients connect to the server" do
|
10
|
+
end
|
11
|
+
|
12
|
+
xspecify "should be able to connect to external servers" do
|
13
|
+
end
|
14
|
+
|
15
|
+
xspecify "should be able to read data from clients when socket is ready" do
|
16
|
+
end
|
17
|
+
|
18
|
+
xspecify "should be able to write data to clients when socket is ready for write" do
|
19
|
+
end
|
20
|
+
|
21
|
+
xspecify "should invoke receive_data method data is receieved from clients" do
|
22
|
+
end
|
23
|
+
|
24
|
+
xspecify "should invoke post_init when client connects" do
|
25
|
+
end
|
26
|
+
|
27
|
+
xspecify "should invoke unbind when a client disconnects" do
|
28
|
+
end
|
29
|
+
|
30
|
+
xspecify "should invoke connection_completed when connection to external server is connected." do
|
31
|
+
end
|
32
|
+
|
33
|
+
xspecify "should check for ready timers on each iteration" do
|
34
|
+
end
|
35
|
+
|
36
|
+
xspecify "should run proper timer on each iteration." do
|
37
|
+
end
|
38
|
+
end
|