275 lines
7.4 KiB
Plaintext
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
|