[macruby-changes] [4274] ControlTower/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Fri Jun 25 02:03:38 PDT 2010
Revision: 4274
http://trac.macosforge.org/projects/ruby/changeset/4274
Author: joshua.ballanco at apple.com
Date: 2010-06-25 02:03:33 -0700 (Fri, 25 Jun 2010)
Log Message:
-----------
Opening bid
Modified Paths:
--------------
ControlTower/trunk/TODO
ControlTower/trunk/bin/control_tower
ControlTower/trunk/ext/CTParser/CTParser.h
ControlTower/trunk/ext/CTParser/CTParser.m
ControlTower/trunk/ext/CTParser/http11_parser.c
ControlTower/trunk/lib/control_tower/rack_socket.rb
Property Changed:
----------------
ControlTower/trunk/bin/control_tower
Modified: ControlTower/trunk/TODO
===================================================================
--- ControlTower/trunk/TODO 2010-06-25 01:27:57 UTC (rev 4273)
+++ ControlTower/trunk/TODO 2010-06-25 09:03:33 UTC (rev 4274)
@@ -12,9 +12,8 @@
[ ] Concurrency testing
[ ] Handle broken request pipes
[ ] Don't reset peer connections
-[ ] Protect against malformed Content-Length in headers
-
-For future:
-
+[ ] Handle multibyte characters in headers
[ ] Improve body loading
[ ] Fully-async file upload
+[ ] Handle EMFILE error condition
+[ ] Be smarter about using Tempfiles vs StringIO for request body
Property changes on: ControlTower/trunk/bin/control_tower
___________________________________________________________________
Added: svn:executable
+ *
Modified: ControlTower/trunk/ext/CTParser/CTParser.h
===================================================================
--- ControlTower/trunk/ext/CTParser/CTParser.h 2010-06-25 01:27:57 UTC (rev 4273)
+++ ControlTower/trunk/ext/CTParser/CTParser.h 2010-06-25 09:03:33 UTC (rev 4274)
@@ -12,16 +12,16 @@
@interface CTParser : NSObject
{
http_parser *_parser;
- NSString *_body;
+ NSMutableArray *_body;
}
- at property(copy) NSString *body;
+ at property(copy) NSMutableArray *body;
- (id)init;
- (void)reset;
-- (NSNumber *)parseData:(NSString *)dataBuf forEnvironment:(NSDictionary *)env startingAt:(NSNumber *)startingPos;
-- (NSNumber *)parseData:(NSString *)dataBuf forEnvironment:(NSDictionary *)env;
+- (NSNumber *)parseData:(NSData *)dataBuf forEnvironment:(NSDictionary *)env startingAt:(NSNumber *)startingPos;
+- (NSNumber *)parseData:(NSData *)dataBuf forEnvironment:(NSDictionary *)env;
- (BOOL)errorCond;
- (BOOL)finished;
@@ -30,8 +30,3 @@
- (void)finalize;
@end
-
-// Describe enough of the StringIO interface to write to one
- at interface RBStringIO : NSObject
-- (void)write:(NSString *)dataBuf;
- at end
Modified: ControlTower/trunk/ext/CTParser/CTParser.m
===================================================================
--- ControlTower/trunk/ext/CTParser/CTParser.m 2010-06-25 01:27:57 UTC (rev 4273)
+++ ControlTower/trunk/ext/CTParser/CTParser.m 2010-06-25 09:03:33 UTC (rev 4274)
@@ -102,9 +102,9 @@
}
// If we've been given any part of the body, put it here
- NSMutableString *body = [environment objectForKey:@"rack.input"];
+ NSMutableArray *body = [environment objectForKey:@"rack.input"];
if (body != nil) {
- [body appendString:[[NSString alloc] initWithBytes:at length:length encoding:NSASCIIStringEncoding]];
+ [body addObject:[NSData dataWithBytes:at length:length]];
}
else {
NSLog(@"Hmm...you seem to have body data but no where to put it. That's probably an error.");
@@ -142,10 +142,10 @@
}
-- (NSNumber *)parseData:(NSString *)dataBuf forEnvironment:(NSMutableDictionary *)env startingAt:(NSNumber *)startingPos
+- (NSNumber *)parseData:(NSData *)dataBuf forEnvironment:(NSMutableDictionary *)env startingAt:(NSNumber *)startingPos
{
- const char *data = [dataBuf UTF8String];
- size_t length = [dataBuf lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
+ const char *data = [dataBuf bytes];
+ size_t length = [dataBuf length];
size_t offset = [startingPos unsignedLongValue];
_parser->data = env;
@@ -159,7 +159,7 @@
return headerLength;
}
-- (NSNumber *)parseData:(NSString *)dataBuf forEnvironment:(NSDictionary *)env
+- (NSNumber *)parseData:(NSData *)dataBuf forEnvironment:(NSDictionary *)env
{
return [self parseData:dataBuf forEnvironment:env startingAt:0];
}
Modified: ControlTower/trunk/ext/CTParser/http11_parser.c
===================================================================
--- ControlTower/trunk/ext/CTParser/http11_parser.c 2010-06-25 01:27:57 UTC (rev 4273)
+++ ControlTower/trunk/ext/CTParser/http11_parser.c 2010-06-25 09:03:33 UTC (rev 4274)
@@ -56,7 +56,7 @@
p = buffer+off;
pe = buffer+len;
- assert(*pe == '\0' && "pointer does not end on NUL");
+ //assert(*pe == '\0' && "pointer does not end on NUL");
assert(pe - p == len - off && "pointers aren't same distance");
Modified: ControlTower/trunk/lib/control_tower/rack_socket.rb
===================================================================
--- ControlTower/trunk/lib/control_tower/rack_socket.rb 2010-06-25 01:27:57 UTC (rev 4273)
+++ ControlTower/trunk/lib/control_tower/rack_socket.rb 2010-06-25 09:03:33 UTC (rev 4274)
@@ -6,8 +6,6 @@
module ControlTower
class RackSocket
- READ_SIZE = 16 * 1024
- RACK_VERSION = 'rack.version'.freeze
VERSION = [1,0].freeze
def initialize(host, port, server, concurrent)
@@ -16,8 +14,8 @@
@status = :closed # Start closed and give the server time to start
#if concurrent
- # @env['rack.multithread'] = true
- # @request_queue = Dispatch::Queue.concurrent
+ @multithread = true
+ @request_queue = Dispatch::Queue.concurrent
#else
# @env['rack.multithread'] = false
# @request_queue = Dispatch::Queue.new('com.apple.ControlTower.rack_socket_queue')
@@ -29,17 +27,25 @@
@status = :open
while (@status == :open)
connection = @socket.accept
+ $stdout.puts "**********\nReceived a socket connection at #{Time.now.to_f}"
# TODO -- Concurrency doesn't quite work yet...
- #@request_group.dispatch(@request_queue) do
+ @request_queue.async do
req_data = parse!(connection, prepare_environment)
req_data['REMOTE_ADDR'] = connection.addr[3]
+ $stdout.puts "Sending for handling by the server at #{Time.now.to_f}"
data = @server.handle_request(req_data)
- data.each do |chunk|
- connection.write chunk
+ $stdout.puts "Finished constructing reply at #{Time.now.to_f}"
+ begin
+ data.each do |chunk|
+ connection.write chunk
+ end
+ $stdout.puts "Finished sending reply at #{Time.now.to_f}"
+ connection.close
+ rescue
+ nil
end
- connection.close
- #end
+ end
end
end
@@ -48,7 +54,7 @@
# You get 30 seconds to empty the request queue and get outa here!
Dispatch::Source.timer(30, 0, 1, Dispatch::Queue.concurrent) do
- puts "Timed out waiting for connections to close"
+ $stdout.puts "Timed out waiting for connections to close"
exit 1
end
#@request_group.wait
@@ -60,43 +66,60 @@
def prepare_environment
{ 'rack.errors' => $stderr,
- 'rack.input' => ''.force_encoding('ASCII-8BIT'),
+ 'rack.input' => NSMutableArray.alloc.init, # For now, collect the body as an array of NSData's
'rack.multiprocess' => false, # No multiprocess, yet...probably never
+ #'rack.multithread' => @multithread,
'rack.run_once' => false,
- RACK_VERSION => VERSION }
+ 'rack.version' => VERSION }
end
def parse!(connection, env)
parser = ::CTParser.new
- data = ""
- headers_done = false
+ data = NSMutableData.alloc.init
+ parsing_headers = true # Parse headers first
content_length = 0
+ content_uploaded = 0
connection_handle = NSFileHandle.alloc.initWithFileDescriptor(connection.fileno)
- while (!headers_done || env['rack.input'].bytesize < content_length) do
- select([connection], nil, nil, 1)
- if headers_done
- begin
- env['rack.input'].appendString(NSString.alloc.initWithData(connection_handle.availableData,
- encoding: NSUTF8StringEncoding))
- rescue EOFError
- break
- end
- else
- data.appendString(NSString.alloc.initWithData(connection_handle.availableData, encoding: NSUTF8StringEncoding))
+ $stdout.puts "Started parsing at #{Time.now.to_f}"
+ while (parsing_headers || content_uploaded < content_length) do
+ begin
+ # Read the availableData on the socket and rescue any errors:
+ incoming_bytes = connection_handle.availableData
+ rescue EOFError, Errno::ECONNRESET, Errno::EPIPE, Errno::EINVAL, Errno::EBADF
+ connection.close rescue nil
+ return nil
+ rescue Errno::EMFILE
+ # TODO: Need to do something about the dispatch queue...a group wait, maybe? or a dispatch semaphore?
+ rescue Object => e
+ $stdout.puts "Error receiving data: #{e.inspect}"
+ end
+
+ # Until the headers are done being parsed, we'll parse them
+ if parsing_headers
+ data.appendData(incoming_bytes)
+ $stdout.puts "Recieved #{incoming_bytes.length} and have a total of #{data.length} bytes"
nread = parser.parseData(data, forEnvironment: env, startingAt: nread)
if parser.finished
- headers_done = true
+ $stdout.puts "Finished parsing headers at #{Time.now.to_f}"
+ parsing_headers = false # We're done, now on to receiving the body
+ content_uploaded = env['rack.input'].first.length
content_length = env['CONTENT_LENGTH'].to_i
end
+ else # Done parsing headers, now just collect request body:
+ content_uploaded += incoming_bytes.length
+ env['rack.input'] << incoming_bytes
end
end
- # Rack says "Make that a StringIO!"
+ $stdout.puts "Finished receiving the body at #{Time.now.to_f}"
+ # Rack says "Make that a StringIO!" TODO: We could be smarter about this
body = Tempfile.new('control-tower-request-body-')
- body << env['rack.input']
+ body_handle = NSFileHandle.alloc.initWithFileDescriptor(body.fileno)
+ env['rack.input'].each { |upload_data| body_handle.writeData(upload_data) }
body.rewind
env['rack.input'] = body
+ $stdout.puts "Finished creating the rack.input file at #{Time.now.to_f}"
# Returning what we've got...
return env
end
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100625/3c2160ae/attachment-0001.html>
More information about the macruby-changes
mailing list