Files
EWF/http_connection_handler.e
2011-05-20 08:58:26 -03:00

275 lines
7.4 KiB
Plaintext

note
description: "Summary description for {HTTP_CONNECTION_HANDLER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
HTTP_CONNECTION_HANDLER
inherit
THREAD
HTTP_CONSTANTS
create
make
feature {NONE} -- Initialization
make (a_main_server: like main_server; a_name: STRING)
-- Creates a {HTTP_CONNECTION_HANDLER}, assigns the main_server and sets the current_request_message to empty.
--
-- `a_main_server': The main server object
-- `a_name': The name of this module
require
a_main_server_attached: a_main_server /= Void
a_name_attached: a_name /= Void
do
main_server := a_main_server
create current_request_message.make_empty
create method.make_empty
create uri.make_empty
create request_header_map.make (10)
is_stop_requested := False
ensure
main_server_set: a_main_server ~ main_server
current_request_message_attached: current_request_message /= Void
end
feature -- Inherited Features
execute
-- <Precursor>
-- Creates a socket and connects to the http server.
local
l_http_socket: detachable TCP_STREAM_SOCKET
do
is_stop_requested := False
create l_http_socket.make_server_by_port ({HTTP_CONSTANTS}.Http_server_port)
if not l_http_socket.is_bound then
print ("Socket could not be bound on port " + {HTTP_CONSTANTS}.Http_server_port.out )
else
from
l_http_socket.listen ({HTTP_CONSTANTS}.Max_tcp_clients)
print ("%NHTTP Connection Server ready on port " + {HTTP_CONSTANTS}.Http_server_port.out +"%N")
until
is_stop_requested
loop
l_http_socket.accept
if not is_stop_requested then
if attached l_http_socket.accepted as l_thread_http_socket then
receive_message_and_send_replay (l_thread_http_socket)
l_thread_http_socket.cleanup
check
socket_closed: l_thread_http_socket.is_closed
end
end
end
end
l_http_socket.cleanup
check
socket_is_closed: l_http_socket.is_closed
end
end
print ("HTTP Connection Server ends.")
rescue
print ("HTTP Connection Server shutdown due to exception. Please relaunch manually.")
if attached l_http_socket as ll_http_socket then
ll_http_socket.cleanup
check
socket_is_closed: ll_http_socket.is_closed
end
end
is_stop_requested := True
retry
end
feature -- Access
is_stop_requested: BOOLEAN
-- Set true to stop accept loop
feature {NONE} -- Access
request_header_map : HASH_TABLE [STRING,STRING]
-- Containts key value of the header
main_server: HTTP_SERVER
-- The main server object
current_request_message: STRING
-- Stores the current request message received from http server
Max_fragments: INTEGER = 1000
-- Defines the maximum number of fragments that can be received
method : STRING
-- http verb
uri : STRING
-- http endpoint
version : STRING
-- http_version
feature -- Status setting
shutdown
-- Stops the thread
do
is_stop_requested := True
end
feature {NONE} -- Implementation
read_string_from_socket (a_socket: TCP_STREAM_SOCKET; a_n: NATURAL): STRING
-- Reads characters from the socket and concatenates them to a string
--
-- `a_socket': The socket to read from
-- `a_n': The number of characters to read
-- `Result': The created string
require
socket_is_open: not a_socket.is_closed
local
l_read_size: INTEGER
l_buf: detachable STRING
do
create Result.make (a_n.as_integer_32)
from
l_read_size := 0
Result := ""
l_buf := ""
until
l_buf.is_equal ("%R")
loop
a_socket.read_line_thread_aware
l_buf := a_socket.last_string
if l_buf /= Void then
Result.append (l_buf)
end
if l_buf.is_equal ("%R") then
a_socket.set_nodelay
a_socket.put_string ("HTTP/1.1 100 Continue%/13/%/10/%/13/%/10/")
a_socket.close_socket
end
l_read_size := Result.count
end
ensure
Result_attached: Result /= Void
end
feature -- New implementation
parse_http_request_line (line: STRING)
require
line /= Void
local
pos, next_pos: INTEGER
do
print ("%N parse http request line:%N" + line)
-- parse (this should be done by a lexer)
pos := line.index_of (' ', 1)
method := line.substring (1, pos - 1)
next_pos := line.index_of (' ', pos+1)
uri := line.substring (pos+1, next_pos-1)
ensure
not_void_method: method /= Void
end
feature -- New Implementation
receive_message_and_send_replay (client_socket: TCP_STREAM_SOCKET)
require
socket_attached: client_socket /= Void
-- socket_valid: client_socket.is_open_read and then client_socket.is_open_write
a_http_socket:client_socket /= Void and then not client_socket.is_closed
local
message: detachable STRING
l_http_request : HTTP_REQUEST_HANDLER
do
parse_request_line (client_socket)
message := receive_message_internal (client_socket)
if method.is_equal (Get) then
create {GET_REQUEST_HANDLER} l_http_request
l_http_request.set_uri (uri)
l_http_request.process
-- client_socket.send_message (l_http_request.answer.reply_header + l_http_request.answer.reply_text)
client_socket.put_string (l_http_request.answer.reply_header + l_http_request.answer.reply_text)
elseif method.is_equal (Post) then
elseif method.is_equal (Put) then
elseif method.is_equal (Options) then
elseif method.is_equal (Head) then
elseif method.is_equal (Delete) then
elseif method.is_equal (Trace) then
elseif method.is_equal (Connect) then
else
debug
print ("Method not supported")
end
end
end
parse_request_line (socket: NETWORK_STREAM_SOCKET)
require
socket: socket /= Void and then not socket.is_closed
do
socket.read_line
parse_request_line_internal (socket.last_string)
end
receive_message_internal (socket: TCP_STREAM_SOCKET) : STRING
require
socket: socket /= Void and then not socket.is_closed
local
end_of_stream : BOOLEAN
pos : INTEGER
line : STRING
do
from
socket.read_line_thread_aware
Result := ""
until
end_of_stream
loop
line := socket.last_string
print ("%N" +line+ "%N")
pos := line.index_of(':',1)
request_header_map.put (line.substring (pos + 1, line.count), line.substring (1,pos-1))
Result.append(socket.last_string)
if not socket.last_string.is_equal("%R") and socket.socket_ok then
socket.read_line_thread_aware
else
end_of_stream := True
end
end
end
parse_request_line_internal (line: STRING)
require
line /= Void
local
pos, next_pos: INTEGER
do
print ("%N parse request line:%N" + line)
pos := line.index_of (' ', 1)
method := line.substring (1, pos - 1)
next_pos := line.index_of (' ', pos+1)
uri := line.substring (pos+1, next_pos-1)
version := line.substring (next_pos + 1, line.count)
ensure
not_void_method: method /= Void
end
invariant
main_server_attached: main_server /= Void
current_request_message_attached: current_request_message /= Void
end