Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Bug fixage.

  • Loading branch information...
commit 53b52fb4adef04c07f9a58c7761ac520ca623064 1 parent 14ffbd2
@wyhaines authored
View
62 src/swiftcore/Swiftiply.rb
@@ -96,6 +96,7 @@ module Swiftiply
Ccluster_port = 'cluster_port'.freeze
Ccluster_server = 'cluster_server'.freeze
CConnection_close = "Connection: close\r\n".freeze
+ CConnection_KeepAlive = "Connection: Keep-Alive\r\n".freeze
CBackendAddress = 'BackendAddress'.freeze
CBackendPort = 'BackendPort'.freeze
Ccertfile = 'certfile'.freeze
@@ -475,7 +476,11 @@ def serve_static_file(clnt,dr = nil)
end
clnt.close_connection_after_writing
true
- elsif path = find_static_file(dr,path_info,client_name)
+ elsif path = find_static_file(dr,path_info,client_name) # See if the static file that is wanted exists on the filesystem.
+ #TODO: There is a race condition here between when we detect whether the file is there, and when we start to deliver it.
+ # It'd be nice to handle an exception when trying to read the file in a graceful way, by falling out as if no static
+ # file had been found. That way, if the file is deleted between detection and the start of delivery, such as might
+ # happen when delivering files out of some sort of page cache, it can be handled in a reasonable manner.
none_match = clnt.none_match
etag,mtime = @etag_cache_map[client_name].etag_mtime(path)
same_response = nil
@@ -492,7 +497,7 @@ def serve_static_file(clnt,dr = nil)
oh = fc.owner_hash
log(oh).log(Cinfo,"#{Socket::unpack_sockaddr_in(clnt.get_peername || UnknownSocket).last} \"GET #{path_info} HTTP/#{clnt.http_version}\" 304 -") if level(oh) > 1
else
- ct = @typer.simple_type_for(path) || Caos
+ ct = @typer.simple_type_for(path) || Caos
fsize = File.size(path)
header_line = "HTTP/1.1 200 OK\r\nConnection: close\r\nETag: #{etag}\r\nContent-Type: #{ct}\r\nContent-Length: #{fsize}\r\n"
@@ -533,7 +538,8 @@ def serve_static_file(clnt,dr = nil)
rescue Object => e
puts e
@logger.log('error',"Failed request for #{dr.inspect}/#{path.inspect} -- #{e} @ #{e.backtrace.inspect}") if @log_level > 0
-
+
+ # TODO: This is uncivilized; if there is an unexpected error, a reasonable response MUST be returned.
clnt.close_connection_after_writing
false
end
@@ -762,10 +768,18 @@ def initialize *args
@data = Deque.new
#@data = []
@data_pos = 0
- @hmp = @name = @uri = @http_version = @request_method = @none_match = @done_parsing = nil
+ @connection_header = CConnection_close
+ @hmp = @name = @uri = @http_version = @request_method = @none_match = @done_parsing = @keepalive = nil
super
end
+ def reset_state
+ @data.clear
+ @data_pos = 0
+ @connection_header = CConnection_close
+ @hmp = @name = @uri = @http_version = @request_method = @none_match = @done_parsing = @keepalive = nil
+ end
+
# States:
# uri
# name
@@ -814,20 +828,24 @@ def receive_data data
# If the match fails, then this is a bad request, and an appropriate
# response will be returned.
#
- if data =~ /^(\w+) +(?:\w+:\/\/([^\/]+))?([^ \?]+)\S* +HTTP\/(\d\.\d)/
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec5.1.2
+ #
+ if data =~ /^(\w+) +(?:\w+:\/\/([^ \/]+))?([^ \?]*)\S* +HTTP\/(\d\.\d)/
@request_method = $1
- @uri = $3 || C_blank
+ @uri = $3
@http_version = $4
if $2
@name = $2.intern
+ @uri = C_slash if @uri.empty?
# Rewrite the request to get rid of the http://foo portion.
# It would be nice if this could be deferred until after the
# static file check; if a static file is going to be delivered
# by Swiftiply, this rewrite is unnecessary.
- data.sub!(/^\w+ +\w+:\/\/[^\/]+/,"#{@request_method} ")
+ data.sub!(/^\w+ +\w+:\/\/[^ \/]+([^ \?]*)/,"#{@request_method} #{@uri}")
end
- @uri = @uri.to_s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) {[$1.delete(C_percent)].pack('H*')} if @uri.include?(C_percent)
+ @uri = @uri.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) {[$1.delete(C_percent)].pack('H*')} if @uri.include?(C_percent)
else
+ puts data
send_400_response
return
end
@@ -847,7 +865,7 @@ def receive_data data
if d.include?(Crnrn)
@name = ProxyBag.default_name unless ProxyBag.incoming_mapping(@name)
@done_parsing = true
- if data =~ /^If-None-Match: *([^\r]+)/
+ if data =~ /If-None-Match: *([^\r]+)/
@none_match = $1
end
@@ -876,8 +894,28 @@ def receive_data data
#
# to the client.
-
if @name
+ if ProxyBag.keepalive(@name)
+ if @http_version == C1_0
+ if data =~ /Connection: Keep-Alive/
+ # Nonstandard HTTP 1.0 situation; apply keepalive.
+ @keepalive = true
+ @connection_header = CConnection_KeepAlive
+ else
+ # Standard HTTP 1.0 situation; connection will be closed.
+ @connection_header = C_empty
+ end
+ else
+ if data =~ /Connection: Close/
+ # Nonstandard HTTP 1.1 situation; connection will be closed.
+ else
+ # Standard HTTP 1.1 situation; apply keepalive.
+ @connection_header = C_empty
+ @keepalive = true
+ end
+ end
+ end
+
ProxyBag.add_frontend_client(self,@data,data)
else
send_404_response
@@ -1100,14 +1138,10 @@ def receive_data data
@associate.close_connection_after_writing
@dont_send_data = true
else
- #@associate.send_data @headers
- #@associate.send_data Crnrn
@associate.send_data @headers + Crnrn
end
end
else
- #@associate.send_data @headers
- #@associate.send_data Crnrn
@associate.send_data @headers + Crnrn
end
else
View
8 src/swiftcore/evented_mongrel.rb
@@ -21,6 +21,7 @@ module Mongrel
class MongrelProtocol < EventMachine::Connection
Cblank = ''.freeze
+ C400Header = "HTTP/1.0 400 Bad Request\r\nContent-Type: text/plain\r\nServer: Swiftiplied Mongrel 0.6.5\r\nConnection: close\r\n\r\n"
def post_init
@parser = HttpParser.new
@@ -35,7 +36,7 @@ def receive_data data
@linebuffer << data
@nparsed = @parser.execute(@params, @linebuffer, @nparsed) unless @parser.finished?
if @parser.finished?
- if @request_len.nil?
+ unless @request_len
@request_len = @params[::Mongrel::Const::CONTENT_LENGTH].to_i
script_name, path_info, handlers = ::Mongrel::HttpServer::Instance.classifier.resolve(@params[::Mongrel::Const::REQUEST_PATH] || Cblank)
if handlers
@@ -73,10 +74,11 @@ def receive_data data
STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!"
STDERR.puts "#{Time.now}: REQUEST DATA: #{data.inspect}\n---\nPARAMS: #{params.inspect}\n---\n"
end
- close_connection
rescue Exception => e
- close_connection
raise e
+ ensure
+ send_data C400Header
+ close_connection
end
def write data
View
28 src/swiftcore/swiftiplied_mongrel.rb
@@ -20,7 +20,10 @@
module Mongrel
C0s = [0,0,0,0].freeze unless const_defined?(:C0s)
CCCCC = 'CCCC'.freeze unless const_defined?(:CCCCC)
+ Cblank = ''.freeze
+ C400Header = "HTTP/1.0 400 Bad Request\r\nContent-Type: text/plain\r\nServer: Swiftiplied Mongrel 0.6.5\r\nConnection: close\r\n\r\n"
+
class MongrelProtocol < SwiftiplyClientProtocol
def post_init
@@ -34,13 +37,19 @@ def post_init
def receive_data data
@linebuffer << data
+
@nparsed = @parser.execute(@params, @linebuffer, @nparsed) unless @parser.finished?
if @parser.finished?
- if @request_len.nil?
+
+ unless @params[::Mongrel::Const::REQUEST_PATH]
+ params[::Mongrel::Const::REQUEST_PATH] = URI.parse(params[::Mongrel::Const::REQUEST_URI]).path
+ end
+
+ unless @request_len
@request_len = @params[::Mongrel::Const::CONTENT_LENGTH].to_i
script_name, path_info, handlers = ::Mongrel::HttpServer::Instance.classifier.resolve(@params[::Mongrel::Const::REQUEST_PATH])
if handlers
- @params[::Mongrel::Const::PATH_INFO] = path_info
+ @params[::Mongrel::Const::PATH_INFO] = path_info || Cblank # path_info shouldn't be nil, but just in case it somehow is, let's make sure we don't crash later because of it.
@params[::Mongrel::Const::SCRIPT_NAME] = script_name
# The previous behavior of this line set REMOTE_ADDR equal to HTTP_X_FORWARDED_FOR
# if it was defined. This behavior seems inconsistent with the intention of
@@ -74,11 +83,17 @@ def receive_data data
if $mongrel_debug_client
STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!"
STDERR.puts "#{Time.now}: REQUEST DATA: #{data.inspect}\n---\nPARAMS: #{params.inspect}\n---\n"
- end
- close_connection
+ end
rescue Exception => e
- close_connection
+ # This isn't a parse error; if this rescue caught an exception, then something
+ # significant happened.
raise e
+ ensure
+ # No matter what, disconnect from our upstream in a graceful way, or at
+ # least try to; if execution is still happening, it should be fine.
+ send_data C400Header
+ close_connection
+ @linebuffer.delete if Tempfile === @linebuffer
end
def write data
@@ -164,7 +179,7 @@ def process_http_request(params,linebuffer,client)
# 404 response.
response = HttpResponse.new(client)
response.status = 404
- response.body = "#{params[Const::REQUEST_PATH]} not found"
+ response.body << "#{params[Const::REQUEST_PATH]} not found"
response.finished
end
end
@@ -187,6 +202,7 @@ def initialize(params, linebuffer, dispatchers)
end
class HttpResponse
+
def send_file(path, small_file = false)
File.open(path, "rb") do |f|
while chunk = f.read(Const::CHUNK_SIZE) and chunk.length > 0
Please sign in to comment.
Something went wrong with that request. Please try again.