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.
@@ -1,214 +1,208 @@
1
- # This module rewrites pieces of the very good Mongrel web server in
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
- class MongrelProtocol < Packet::Connection
12
- def post_init
13
- @parser = HttpParser.new
14
- @params = HttpParams.new
15
- @nparsed = 0
16
- @request = nil
17
- @request_len = nil
18
- @linebuffer = ''
19
- end
20
-
21
- def receive_data data
22
- @linebuffer << data
23
- @nparsed = @parser.execute(@params, @linebuffer, @nparsed) unless @parser.finished?
24
- if @parser.finished?
25
- if @request_len.nil?
26
- @request_len = @params[::Mongrel::Const::CONTENT_LENGTH].to_i
27
- script_name, path_info, handlers = ::Mongrel::HttpServer::Instance.classifier.resolve(@params[::Mongrel::Const::REQUEST_PATH])
28
- if handlers
29
- @params[::Mongrel::Const::PATH_INFO] = path_info
30
- @params[::Mongrel::Const::SCRIPT_NAME] = script_name
31
- @params[::Mongrel::Const::REMOTE_ADDR] = @params[::Mongrel::Const::HTTP_X_FORWARDED_FOR] #|| ::Socket.unpack_sockaddr_in(get_peername)[1]
32
- @notifiers = handlers.select { |h| h.request_notify }
33
- end
34
- if @request_len > ::Mongrel::Const::MAX_BODY
35
- new_buffer = Tempfile.new(::Mongrel::Const::MONGREL_TMP_BASE)
36
- new_buffer.binmode
37
- new_buffer << @linebuffer[@nparsed..-1]
38
- @linebuffer = new_buffer
39
- else
40
- @linebuffer = StringIO.new(@linebuffer[@nparsed..-1])
41
- @linebuffer.pos = @linebuffer.length
42
- end
43
- end
44
- if @linebuffer.length >= @request_len
45
- @linebuffer.rewind
46
- ::Mongrel::HttpServer::Instance.process_http_request(@params,@linebuffer,self)
47
- @linebuffer.delete if Tempfile === @linebuffer
48
- end
49
- elsif @linebuffer.length > ::Mongrel::Const::MAX_HEADER
50
- close_connection
51
- raise ::Mongrel::HttpParserError.new("HEADER is longer than allowed, aborting client early.")
52
- end
53
- rescue ::Mongrel::HttpParserError
54
- if $mongrel_debug_client
55
- STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!"
56
- STDERR.puts "#{Time.now}: REQUEST DATA: #{data.inspect}\n---\nPARAMS: #{params.inspect}\n---\n"
57
- end
58
- close_connection
59
- rescue Exception => e
60
- close_connection
61
- raise e
62
- end
63
-
64
- def write data
65
- send_data data
66
- end
67
-
68
- def closed?
69
- false
70
- end
71
-
72
- end
73
-
74
- class HttpServer
75
- def initialize(host, port, num_processors=950, x=0, y=nil) # Deal with Mongrel 1.0.1 or earlier, as well as later.
76
- @socket = nil
77
- @classifier = URIClassifier.new
78
- @host = host
79
- @port = port
80
- @workers = ThreadGroup.new
81
- if y
82
- @throttle = x
83
- @timeout = y || 60
84
- else
85
- @timeout = x
86
- end
87
- @num_processors = num_processors #num_processors is pointless for evented....
88
- @death_time = 60
89
- self.class.const_set(:Instance,self)
90
- end
91
-
92
- def run
93
- trap('INT') { raise StopServer }
94
- trap('TERM') { raise StopServer }
95
- @acceptor = Thread.new do
96
- Packet::Reactor.run do |t_reactor|
97
- begin
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
- end
104
- end
105
-
106
- def process_http_request(params,linebuffer,client)
107
- if not params[Const::REQUEST_PATH]
108
- uri = URI.parse(params[Const::REQUEST_URI])
109
- params[Const::REQUEST_PATH] = uri.request_uri
110
- end
111
-
112
- raise "No REQUEST PATH" if not params[Const::REQUEST_PATH]
113
-
114
- script_name, path_info, handlers = @classifier.resolve(params[Const::REQUEST_PATH])
115
-
116
- if handlers
117
- notifiers = handlers.select { |h| h.request_notify }
118
- request = HttpRequest.new(params, linebuffer, notifiers)
119
-
120
- # request is good so far, continue processing the response
121
- response = HttpResponse.new(client)
122
-
123
- # Process each handler in registered order until we run out or one finalizes the response.
124
- dispatch_to_handlers(handlers,request,response)
125
-
126
- # And finally, if nobody closed the response off, we finalize it.
127
- unless response.done
128
- response.finished
129
- else
130
- response.close_connection
131
- end
132
- else
133
- # Didn't find it, return a stock 404 response.
134
- client.send_data(Const::ERROR_404_RESPONSE)
135
- client.close_connection
136
- end
137
- end
138
-
139
- def dispatch_to_handlers(handlers,request,response)
140
- handlers.each do |handler|
141
- handler.process(request, response)
142
- break if response.done
143
- end
144
- end
145
- end
146
-
147
- class HttpRequest
148
- def initialize(params, linebuffer, dispatchers)
149
- @params = params
150
- @dispatchers = dispatchers
151
- @body = linebuffer
152
- end
153
- end
154
-
155
- class HttpResponse
156
- def send_file(path, small_file = false)
157
- File.open(path, "rb") do |f|
158
- while chunk = f.read(Const::CHUNK_SIZE) and chunk.length > 0
159
- begin
160
- write(chunk)
161
- rescue Object => exc
162
- break
163
- end
164
- end
165
- end
166
- @body_sent = true
167
- end
168
-
169
- def write(data)
170
- @socket.send_data data
171
- end
172
-
173
- def close_connection_after_writing
174
- @socket.close_connection
175
- end
176
-
177
- def socket_error(details)
178
- @socket.close_connection
179
- done = true
180
- raise details
181
- end
182
-
183
- def finished
184
- send_status
185
- send_header
186
- send_body
187
- @socket.close_connection
188
- end
189
- end
190
-
191
- class Configurator
192
- # This version fixes a bug in the regular Mongrel version by adding
193
- # initialization of groups.
194
- def change_privilege(user, group)
195
- if user and group
196
- log "Initializing groups for {#user}:{#group}."
197
- Process.initgroups(user,Etc.getgrnam(group).gid)
198
- end
199
-
200
- if group
201
- log "Changing group to #{group}."
202
- Process::GID.change_privilege(Etc.getgrnam(group).gid)
203
- end
204
-
205
- if user
206
- log "Changing user to #{user}."
207
- Process::UID.change_privilege(Etc.getpwnam(user).uid)
208
- end
209
- rescue Errno::EPERM
210
- log "FAILED to change user:group #{user}:#{group}: #$!"
211
- exit 1
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
+
@@ -0,0 +1,10 @@
1
+ PACKET_APP = File.expand_path(File.join(File.dirname(__FILE__) + "/.."))
2
+ ["lib"].each { |x| $LOAD_PATH.unshift(EVAL_APP_ROOT + "/#{x}")}
3
+ require "packet"
4
+ require "rubygems"
5
+ require "test/spec"
6
+ require "mocha"
7
+
8
+
9
+
10
+
@@ -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