Handling bad incoming request (keep a check assertion to help during debugging period)

This commit is contained in:
Jocelyn Fiat
2011-12-12 10:44:50 +01:00
parent 59505ccdc4
commit 8b4f774bab
3 changed files with 54 additions and 20 deletions

View File

@@ -26,6 +26,7 @@ feature {NONE} -- Initialization
reset reset
do do
has_error := False
create method.make_empty create method.make_empty
create uri.make_empty create uri.make_empty
create request_header.make_empty create request_header.make_empty
@@ -48,7 +49,14 @@ feature -- Execution
end end
analyze_request_message (client_socket) analyze_request_message (client_socket)
process_request (Current, client_socket) if has_error then
check catch_bad_incoming_connection: False end
if is_verbose then
log ("ERROR: invalid HTTP incoming request")
end
else
process_request (Current, client_socket)
end
reset reset
end end
@@ -57,6 +65,7 @@ feature -- Request processing
process_request (a_handler: HTTP_CONNECTION_HANDLER; a_socket: TCP_STREAM_SOCKET) process_request (a_handler: HTTP_CONNECTION_HANDLER; a_socket: TCP_STREAM_SOCKET)
-- Process request ... -- Process request ...
require require
no_error: not has_error
a_handler_attached: a_handler /= Void a_handler_attached: a_handler /= Void
a_uri_attached: a_handler.uri /= Void a_uri_attached: a_handler.uri /= Void
a_method_attached: a_handler.method /= Void a_method_attached: a_handler.method /= Void
@@ -74,6 +83,9 @@ feature -- Access
request_header_map : HASH_TABLE [STRING,STRING] request_header_map : HASH_TABLE [STRING,STRING]
-- Contains key:value of the header -- Contains key:value of the header
has_error: BOOLEAN
-- Error occurred during `analyze_request_message'
method: STRING method: STRING
-- http verb -- http verb
@@ -85,10 +97,12 @@ feature -- Access
--| unused for now --| unused for now
remote_info: detachable TUPLE [addr: STRING; hostname: STRING; port: INTEGER] remote_info: detachable TUPLE [addr: STRING; hostname: STRING; port: INTEGER]
-- Information related to remote client
feature -- Parsing feature -- Parsing
analyze_request_message (a_socket: TCP_STREAM_SOCKET) analyze_request_message (a_socket: TCP_STREAM_SOCKET)
-- Analyze message extracted from `a_socket' as HTTP request
require require
input_readable: a_socket /= Void and then a_socket.is_open_read input_readable: a_socket /= Void and then a_socket.is_open_read
local local
@@ -97,23 +111,31 @@ feature -- Parsing
line : detachable STRING line : detachable STRING
k, val: STRING k, val: STRING
txt: STRING txt: STRING
l_is_verbose: BOOLEAN
do do
create txt.make (64) create txt.make (64)
line := next_line (a_socket) request_header := txt
if line /= Void then
analyze_request_line (line)
txt.append (line)
txt.append_character ('%N')
request_header := txt if attached next_line (a_socket) as l_request_line and then not l_request_line.is_empty then
txt.append (l_request_line)
txt.append_character ('%N')
analyze_request_line (l_request_line)
else
has_error := True
end
l_is_verbose := is_verbose
if not has_error or l_is_verbose then
-- if `is_verbose' we can try to print the request, even if it is a bad HTTP request
from from
line := next_line (a_socket) line := next_line (a_socket)
until until
line = Void or end_of_stream line = Void or end_of_stream
loop loop
n := line.count n := line.count
if is_verbose then if l_is_verbose then
print ("%N" + line) log (line)
end end
pos := line.index_of (':',1) pos := line.index_of (':',1)
if pos > 0 then if pos > 0 then
@@ -139,26 +161,26 @@ feature -- Parsing
end end
analyze_request_line (line: STRING) analyze_request_line (line: STRING)
-- Analyze `line' as a HTTP request line
require require
line /= Void valid_line: line /= Void and then not line.is_empty
local local
pos, next_pos: INTEGER pos, next_pos: INTEGER
do do
if is_verbose then if is_verbose then
print ("%N## Parse HTTP request line ##") log ("%N## Parse HTTP request line ##")
print ("%N") log (line)
print (line)
end end
pos := line.index_of (' ', 1) pos := line.index_of (' ', 1)
method := line.substring (1, pos - 1) method := line.substring (1, pos - 1)
next_pos := line.index_of (' ', pos + 1) next_pos := line.index_of (' ', pos + 1)
uri := line.substring (pos + 1, next_pos - 1) uri := line.substring (pos + 1, next_pos - 1)
version := line.substring (next_pos + 1, line.count) version := line.substring (next_pos + 1, line.count)
ensure has_error := method.is_empty
not_void_method: method /= Void
end end
next_line (a_socket: TCP_STREAM_SOCKET): detachable STRING next_line (a_socket: TCP_STREAM_SOCKET): detachable STRING
-- Next line fetched from `a_socket' is available.
require require
is_readable: a_socket.is_open_read is_readable: a_socket.is_open_read
do do

View File

@@ -32,6 +32,7 @@ feature -- Output
-- Log `a_message' -- Log `a_message'
do do
io.put_string (a_message) io.put_string (a_message)
io.put_new_line
end end
feature -- Inherited Features feature -- Inherited Features
@@ -50,14 +51,14 @@ feature -- Inherited Features
create l_listening_socket.make_server_by_port (l_http_port) create l_listening_socket.make_server_by_port (l_http_port)
if not l_listening_socket.is_bound then if not l_listening_socket.is_bound then
if is_verbose then if is_verbose then
log ("Socket could not be bound on port " + l_http_port.out ) log ("Socket could not be bound on port " + l_http_port.out)
end end
else else
l_http_port := l_listening_socket.port l_http_port := l_listening_socket.port
from from
l_listening_socket.listen (max_tcp_clients) l_listening_socket.listen (max_tcp_clients)
if is_verbose then if is_verbose then
log ("%NHTTP Connection Server ready on port " + l_http_port.out +" : http://localhost:" + l_http_port.out + "/%N") log ("%NHTTP Connection Server ready on port " + l_http_port.out +" : http://localhost:" + l_http_port.out + "/")
end end
on_launched (l_http_port) on_launched (l_http_port)
until until
@@ -102,12 +103,15 @@ feature -- Inherited Features
-- Process incoming connection -- Process incoming connection
do do
if is_verbose then if is_verbose then
log ("Incoming connection...%N") log ("Incoming connection...(socket:" + a_socket.descriptor.out + ")")
end end
--| FIXME jfiat [2011/11/03] : should use a Pool of Threads/Handler to process this connection --| FIXME jfiat [2011/11/03] : should use a Pool of Threads/Handler to process this connection
--| also handle permanent connection...? --| also handle permanent connection...?
receive_message_and_send_reply (a_socket) receive_message_and_send_reply (a_socket)
a_socket.cleanup a_socket.cleanup
if is_verbose then
log ("connection completed...")
end
ensure ensure
socket_closed: a_socket.is_closed socket_closed: a_socket.is_closed
end end

View File

@@ -22,8 +22,8 @@ feature -- Initialization
a_http_handler_valid: a_http_handler /= Void a_http_handler_valid: a_http_handler /= Void
do do
if configuration.is_verbose then if configuration.is_verbose then
print("%N%N%N") log ("%N%N%N")
print ("Starting Web Application Server (port="+ configuration.http_server_port.out +"):%N") log ("Starting Web Application Server (port="+ configuration.http_server_port.out +"):%N")
end end
stop_requested := False stop_requested := False
a_http_handler.execute a_http_handler.execute
@@ -42,6 +42,14 @@ feature -- Access
stop_requested: BOOLEAN stop_requested: BOOLEAN
-- Stops the server -- Stops the server
feature -- Output
log (a_message: READABLE_STRING_8)
-- Log `a_message'
do
io.put_string (a_message)
end
;note ;note
copyright: "2011-2011, Javier Velilla and others" copyright: "2011-2011, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"