A few change to make it more customizable

and prepare integration to EiffelWebReloaded (see on github)
This commit is contained in:
Jocelyn Fiat
2011-05-26 17:23:21 +02:00
parent 85cf39f3c6
commit 64cf2b6936
23 changed files with 590 additions and 298 deletions

View File

@@ -18,9 +18,20 @@ feature {NONE} -- Initialization
-- Run application.
local
l_server : HTTP_SERVER
l_cfg: HTTP_SERVER_CONFIGURATION
l_http_handler : HTTP_CONNECTION_HANDLER
do
create l_server.make
l_server.setup
create l_cfg.make
l_cfg.http_server_port := 9_000
l_cfg.document_root := default_document_root
create l_server.make (l_cfg)
create l_http_handler.make (l_server, "HTTP_HANDLER")
l_server.setup (l_http_handler)
end
feature -- Access
default_document_root: STRING = "webroot"
end

View File

@@ -0,0 +1,60 @@
note
description: "Summary description for {HTTP_SERVER_CONFIGURATION}."
date: "$Date$"
revision: "$Revision$"
class
HTTP_SERVER_CONFIGURATION
create
make
feature {NONE} -- Initialization
make
do
http_server_port := 9_000
max_tcp_clients := 100
socket_accept_timeout := 1_000
socket_connect_timeout := 5_000
document_root := "htdocs"
end
feature -- Access
Server_details : STRING = "Server : NANO Eiffel Server"
document_root: STRING assign set_document_root
http_server_port: INTEGER assign set_http_server_port
max_tcp_clients: INTEGER assign set_max_tcp_clients
socket_accept_timeout: INTEGER assign set_socket_accept_timeout
socket_connect_timeout: INTEGER assign set_socket_connect_timeout
feature -- Element change
set_http_server_port (v: like http_server_port)
do
http_server_port := v
end
set_document_root (v: like document_root)
do
document_root := v
end
set_max_tcp_clients (v: like max_tcp_clients)
do
max_tcp_clients := v
end
set_socket_accept_timeout (v: like socket_accept_timeout)
do
socket_accept_timeout := v
end
set_socket_connect_timeout (v: like socket_connect_timeout)
do
socket_connect_timeout := v
end
end

View File

@@ -0,0 +1,45 @@
note
description: "Summary description for {HTTP_SERVER_SHARED_CONFIGURATION}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
HTTP_SERVER_SHARED_CONFIGURATION
feature -- Access
server_configuration: detachable HTTP_SERVER_CONFIGURATION
-- Shared configuration
do
if attached server_configuration_cell.item as l_cfg then
Result := l_cfg
end
end
document_root: STRING_8
-- Shared document root
do
if attached server_configuration as l_cfg then
Result := l_cfg.document_root
else
Result := ""
end
end
feature -- Element change
set_server_configuration (a_cfg: like server_configuration)
-- Set `server_configuration' to `a_cfg'.
do
server_configuration_cell.replace (a_cfg)
end
feature {NONE} -- Implementation
server_configuration_cell: CELL [detachable HTTP_SERVER_CONFIGURATION]
once ("PROCESS")
create Result.put (Void)
end
end

View File

@@ -1,56 +0,0 @@
note
description: "Summary description for {HTTP_SERVER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
HTTP_SERVER
inherit
SHARED_DOCUMENT_ROOT
create
make
feature -- Initialization
make
do
end
setup
local
l_http_handler : HTTP_CONNECTION_HANDLER
do
print("%N%N%N")
print ("Starting Web Application Server:%N")
stop := False
document_root_cell.put (document_root)
create l_http_handler.make (current,"HTTP_HANDLER")
l_http_handler.launch
run
end
shutdown_server
do
stop := True
end
feature -- Access
stop: BOOLEAN
-- Stops the server
document_root: STRING = "./webroot"
feature {NONE} -- implementation
run
-- Start the server
local
l_thread: EXECUTION_ENVIRONMENT
do
create l_thread
from until stop loop
l_thread.sleep (1000000)
end
end
end

44
io/http_input_stream.e Normal file
View File

@@ -0,0 +1,44 @@
note
description: "Summary description for {HTTP_INPUT_STREAM}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
HTTP_INPUT_STREAM
create
make
feature {NONE} -- Initialization
make (a_socket: like source)
do
source := a_socket
create last_string.make_empty
end
source: TCP_STREAM_SOCKET
feature -- Basic operation
read_stream (nb_char: INTEGER)
-- Read a string of at most `nb_char' bound characters
-- or until end of file.
-- Make result available in `last_string'.
require
nb_char_positive: nb_char > 0
do
last_string.wipe_out
if source.socket_ok then
source.read_stream_thread_aware (nb_char)
last_string.append_string (source.last_string)
end
end
feature -- Access
last_string: STRING
-- Last string read
end

31
io/http_output_stream.e Normal file
View File

@@ -0,0 +1,31 @@
note
description: "Summary description for {HTTP_OUTPUT_STREAM}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
HTTP_OUTPUT_STREAM
create
make
feature {NONE} -- Initialization
make (a_socket: like target)
do
target := a_socket
end
target: TCP_STREAM_SOCKET
feature -- Basic operation
put_string (s: STRING)
-- Write string `s' to `target'
do
target.put_string (s)
end
end

View File

@@ -1,20 +1,20 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-5-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-5-0 http://www.eiffel.com/developers/xml/configuration-1-5-0.xsd" name="nino" uuid="32C1D67D-33DE-4F1E-864B-D45388F2E3E6">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="nino" uuid="32C1D67D-33DE-4F1E-864B-D45388F2E3E6">
<target name="nino">
<root feature="make" class="APPLICATION"/>
<option warning="true">
<root class="APPLICATION" feature="make"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
<exclude>/.git$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<setting name="multithreaded" value="true"/>
<setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
<cluster name="nino" location=".\" recursive="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/.svn$</exclude>
<exclude>/CVS$</exclude>
</file_rule>
</cluster>
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
<cluster name="nino" location=".\" recursive="true"/>
</target>
</system>

View File

@@ -2,40 +2,63 @@
GET_REQUEST_HANDLER
inherit
SHARED_DOCUMENT_ROOT
SHARED_URI_CONTENTS_TYPES
HTTP_REQUEST_HANDLER
SHARED_DOCUMENT_ROOT
undefine
default_create
end
SHARED_URI_CONTENTS_TYPES
undefine
default_create
end
HTTP_CONSTANTS
undefine
default_create
end
create
default_create
make
feature
feature {NONE} -- Initialization
make (a_input: like input; a_output: like output)
do
default_create
input := a_input
output := a_output
end
feature -- Access
input: HTTP_INPUT_STREAM
output: HTTP_OUTPUT_STREAM
feature -- Execution
process
-- process the request and create an answer
local
fname: STRING_8
f: RAW_FILE
ctype, extension: STRING_8
ctype, extension: detachable STRING_8
do
create answer.make
if request_uri.is_equal ("/") then
answer.reset
if script_name.is_equal ("/") then
process_default
answer.set_content_type ("text/html")
else
fname := Document_root_cell.item.twin
fname.append (request_uri)
create fname.make_from_string (Document_root)
fname.append (script_name)
debug
print ("URI name: " + fname)
print ("URI filename: " + fname)
end
create f.make (fname)
create answer.make
create f.make (real_filename (fname))
if f.exists then
extension := Ct_table.extension (request_uri)
extension := Ct_table.extension (script_name)
ctype := Ct_table.content_types.item (extension)
if f.is_directory then
process_directory (f)
@@ -58,11 +81,18 @@ feature
answer.set_reply_text ("Not found on this server")
end
end
answer.set_content_length (answer.reply_text.count.out)
if attached answer.reply_text as t then
answer.set_content_length (t.count)
else
answer.set_content_length (0)
end
--| Output the result
output.put_string (answer.reply_header + answer.reply_text)
end
process_default
-- Return a defaul response
-- Return a default response
local
html: STRING_8
do
@@ -118,14 +148,14 @@ feature
html2: STRING_8
htmldir: STRING_8
path: STRING_8
index: INTEGER_32
do
answer.set_reply_text ("")
html1 := " <html> <head> <title> NINO HTTPD </title> " + " </head> " + " <body> " + " <h1> Welcome to NINO HTTPD! </h1> " + " <p> Default page "
html2 := " </p> " + " </body> " + " </html> "
path := f.name.twin
index := path.last_index_of ('/', path.count)
path.remove_substring (1, index)
path := script_name
if path[path.count] = '/' then
path.remove_tail (1)
end
create l_dir.make_open_read (f.name)
files := l_dir.linear_representation
from
@@ -134,7 +164,7 @@ feature
until
files.after
loop
htmldir := htmldir + "<li><a href=%"./" + path + "/" + files.item_for_iteration + "%">" + files.item_for_iteration + "</a> </li>%N"
htmldir := htmldir + "<li><a href=%"" + path + "/" + files.item_for_iteration + "%">" + files.item_for_iteration + "</a> </li>%N"
files.forth
end
htmldir := htmldir + "</ul>"

View File

@@ -20,7 +20,7 @@ inherit
feature
process is
process
-- process the request and create an answer
local
fname: STRING
@@ -57,7 +57,7 @@ feature
end
end
process_default is
process_default
--
local
html : STRING
@@ -76,7 +76,7 @@ feature
end
process_text_file (f: FILE) is
process_text_file (f: FILE)
-- send a text file reply
require
valid_f: f /= Void
@@ -94,7 +94,7 @@ feature
f.close
end
process_raw_file (f: FILE) is
process_raw_file (f: FILE)
-- send a raw file reply
require
valid_f: f /= Void

View File

@@ -1,36 +1,45 @@
deferred class HTTP_REQUEST_HANDLER
feature
set_uri (new_uri: STRING)
-- set new URI
require
valid_uri: new_uri /= Void
do
request_uri := new_uri
inherit
ANY
redefine
default_create
end
feature {NONE} -- Initialization
default_create
do
Precursor
create request_uri.make_empty
create script_name.make_empty
create query_string.make_empty
create answer
create headers.make (0)
end
feature -- Access
request_uri: STRING
-- requested url
set_data (new_data: STRING)
-- set new data
do
data := new_data
end
script_name: STRING
-- Script name
data: STRING
query_string: STRING
-- Query string
data: detachable STRING
-- the entire request message
headers : HASH_TABLE [STRING, STRING]
-- Provides access to the request's HTTP headers, for example:
-- headers["Content-Type"] is "text/plain"
answer: HTTP_RESPONSE
-- reply to this request
set_headers ( a_header : HASH_TABLE [STRING, STRING] )
do
headers := a_header
end
feature -- Execution
process
-- process the request and create an answer
@@ -39,15 +48,68 @@ feature
deferred
end
answer: HTTP_RESPONSE
-- reply to this request
feature -- Recycle
reset
-- reinit the fields
do
request_uri := Void
request_uri.wipe_out
script_name.wipe_out
query_string.wipe_out
data := Void
answer := Void
answer.reset
end
feature -- Element change
set_uri (new_uri: STRING)
-- set new URI
require
valid_uri: new_uri /= Void
local
p: INTEGER
do
request_uri := new_uri
p := new_uri.index_of ('?', 1)
if p > 0 then
script_name := new_uri.substring (1, p - 1)
query_string := new_uri.substring (p + 1, new_uri.count)
else
script_name := new_uri.string
query_string := ""
end
end
set_data (new_data: STRING)
-- set new data
do
data := new_data
end
set_headers ( a_header : HASH_TABLE [STRING, STRING] )
do
headers := a_header
end
feature {NONE} -- Implementation
real_filename (fn: STRING): STRING
-- Real filename from url-path `fn'
--| Find a better design for this piece of code
--| Eventually in a spec/$ISE_PLATFORM/ specific cluster
do
if {PLATFORM}.is_windows then
create Result.make_from_string (fn)
Result.replace_substring_all ("/", "\")
if Result[Result.count] = '\' then
Result.remove_tail (1)
end
else
Result := fn
if Result[Result.count] = '/' then
Result := Result.substring (1, Result.count - 1)
end
end
end
end

View File

@@ -8,108 +8,35 @@ class
POST_REQUEST_HANDLER
inherit
GET_REQUEST_HANDLER
redefine
process
end
SHARED_DOCUMENT_ROOT
create
make
SHARED_URI_CONTENTS_TYPES
feature -- Execution
HTTP_REQUEST_HANDLER
HTTP_CONSTANTS
feature
process is
process
-- process the request and create an answer
local
fname: STRING
f: RAW_FILE
ctype, extension: STRING
l_data: STRING
s: STRING
n: INTEGER
do
fname := document_root_cell.item.twin
fname.append (request_uri)
debug
print ("URI name: " + fname )
end
create f.make (fname)
create answer.make
if f.exists then
extension := ct_table.extension (request_uri)
ctype := ct_table.content_types.item (extension)
-- TODO: This code could be improved to avoid string
-- comparisons
if ctype = Void then
process_default
answer.set_content_type ("text/html")
else
if ctype.is_equal ("text/html") then
process_text_file (f)
else
process_raw_file (f)
end
answer.set_content_type (ctype)
end
else
answer.set_status_code (not_found)
answer.set_reason_phrase (not_found_message)
answer.set_reply_text ("Not found on this server%N%R")
end
end
process_default is
--
local
html : STRING
do
answer.set_reply_text ("")
html := " <html> <head> <title> Micro HTTPD </title> " +
" </head> " +
" <body> " +
" <h1> Welcome to Micro HTTPD! </h1> "+
" <p> Default page " +
" </p> " +
" </body> " +
" </html> "
answer.append_reply_text (html)
end
process_text_file (f: FILE) is
-- send a text file reply
require
valid_f: f /= Void
do
f.open_read
from
answer.set_reply_text ("")
f.read_line
until f.end_of_file
n := 1_024
input.read_stream (n)
s := input.last_string
create l_data.make_empty
until
s.count < n
loop
answer.append_reply_text (f.last_string)
answer.append_reply_text (crlf)
f.read_line
l_data.append_string (s)
input.read_stream (n)
end
f.close
Precursor
end
process_raw_file (f: FILE) is
-- send a raw file reply
require
valid_f: f /= Void
do
-- this is not quite right....
f.open_read
from
answer.set_reply_text ("")
until f.end_of_file
loop
f.read_stream (1024)
answer.append_reply_text (f.last_string)
end
f.close
end
end

View File

@@ -2,12 +2,38 @@
class HTTP_RESPONSE
inherit
HTTP_CONSTANTS
redefine
default_create
end
create
default_create
make
feature -- creation
default_create
do
Precursor
set_defaults
end
set_defaults
-- Set default values for the reply
do
status_code := ok
create content_length_data.make_empty
reason_phrase := ok_message
content_type_data := text_html
set_reply_text (Void)
end
feature -- Recycle
reset
do
set_defaults
end
feature -- response header fields
@@ -17,11 +43,19 @@ feature -- response header fields
content_length_data : STRING
-- length
set_content_length (new_content_length: STRING)
reason_phrase: STRING
-- message, if any
content_type_data: STRING
-- type of content in this reply (eg. text/html)
feature -- Element change
set_content_length (new_content_length: INTEGER)
require
not_void: new_content_length /= Void
positive_or_zero: new_content_length >= 0
do
content_length_data := new_content_length
content_length_data := new_content_length.out
end
set_status_code (new_status_code: STRING)
@@ -31,9 +65,6 @@ feature -- response header fields
status_code := new_status_code
end
reason_phrase: STRING
-- message, if any
set_reason_phrase (new_reason_phrase: STRING)
require
not_void: new_reason_phrase /= Void
@@ -41,9 +72,6 @@ feature -- response header fields
reason_phrase := new_reason_phrase
end
content_type_data: STRING
-- type of content in this reply (eg. text/html)
set_content_type (new_content_type: STRING)
require
not_void: new_content_type /= Void
@@ -51,18 +79,7 @@ feature -- response header fields
content_type_data := new_content_type
end
feature -- creation
make
do
-- set default values for the reply
status_code := ok
reason_phrase := ok_message
content_type_data := text_html
end
feature -- access these to send a reply
feature -- Access: send reply
reply_header: STRING
-- header
@@ -73,7 +90,7 @@ feature -- access these to send a reply
Result.extend (' ')
Result.append (reason_phrase)
Result.append (crlf)
Result.append (Server_datails)
Result.append ({HTTP_SERVER_CONFIGURATION}.Server_details)
Result.append (crlf)
Result.append (Content_type + ": ")
Result.append (content_type_data)
@@ -89,7 +106,7 @@ feature -- access these to send a reply
reply_header_continue: STRING
-- header
do
Result :=http_version_1_1.twin
Result := http_version_1_1.twin
Result.extend (' ')
Result.append (status_code)
Result.extend (' ')
@@ -100,14 +117,19 @@ feature -- access these to send a reply
-- then keep the connection alive
end
reply_text: STRING
-- reply text
set_reply_text (new_text: STRING)
feature -- Change element: send reply
set_reply_text (new_text: detachable STRING)
-- text could be Void
do
reply_text := new_text
if new_text = Void then
create reply_text.make_empty
else
reply_text := new_text
end
end
append_reply_text (more_text: STRING)

View File

@@ -8,9 +8,10 @@ class
HTTP_CONNECTION_HANDLER
inherit
THREAD
HTTP_CONSTANTS
create
make
@@ -43,15 +44,17 @@ feature -- Inherited Features
-- Creates a socket and connects to the http server.
local
l_http_socket: detachable TCP_STREAM_SOCKET
l_http_port: INTEGER
do
is_stop_requested := False
create l_http_socket.make_server_by_port ({HTTP_CONSTANTS}.Http_server_port)
l_http_port := main_server_configuration.http_server_port
create l_http_socket.make_server_by_port (l_http_port)
if not l_http_socket.is_bound then
print ("Socket could not be bound on port " + {HTTP_CONSTANTS}.Http_server_port.out )
print ("Socket could not be bound on port " + l_http_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")
l_http_socket.listen (main_server_configuration.max_tcp_clients)
print ("%NHTTP Connection Server ready on port " + l_http_port.out +"%N")
until
is_stop_requested
loop
@@ -85,34 +88,90 @@ feature -- Inherited Features
retry
end
feature -- Request processing
process_request (a_uri: STRING; a_method: STRING; a_headers_map: HASH_TABLE [STRING, STRING]; a_headers_text: STRING; a_input: HTTP_INPUT_STREAM; a_output: HTTP_OUTPUT_STREAM)
-- Process request ...
require
a_uri_attached: a_uri /= Void
a_method_attached: a_method /= Void
a_headers_text_attached: a_headers_text /= Void
a_input_attached: a_input /= Void
a_output_attached: a_output /= Void
do
if a_method.is_equal (Get) then
execute_get_request (a_uri, a_headers_map, a_headers_text, a_input, a_output)
elseif a_method.is_equal (Post) then
execute_post_request (a_uri, a_headers_map, a_headers_text, a_input, a_output)
elseif a_method.is_equal (Put) then
elseif a_method.is_equal (Options) then
elseif a_method.is_equal (Head) then
elseif a_method.is_equal (Delete) then
elseif a_method.is_equal (Trace) then
elseif a_method.is_equal (Connect) then
else
debug
print ("Method [" + a_method + "] not supported")
end
end
end
execute_get_request (a_uri: STRING; a_headers_map: HASH_TABLE [STRING, STRING]; a_headers_text: STRING; a_input: HTTP_INPUT_STREAM; a_output: HTTP_OUTPUT_STREAM)
local
l_http_request : HTTP_REQUEST_HANDLER
do
create {GET_REQUEST_HANDLER} l_http_request.make (a_input, a_output)
l_http_request.set_uri (a_uri)
l_http_request.process
-- client_socket.put_string (l_http_request.answer.reply_header + l_http_request.answer.reply_text)
end
execute_post_request (a_uri: STRING; a_headers_map: HASH_TABLE [STRING, STRING]; a_headers_text: STRING; a_input: HTTP_INPUT_STREAM; a_output: HTTP_OUTPUT_STREAM)
local
l_http_request : HTTP_REQUEST_HANDLER
do
check not_yet_implemented: False end
create {POST_REQUEST_HANDLER} l_http_request.make (a_input, a_output)
l_http_request.set_uri (a_uri)
l_http_request.process
-- client_socket.put_string (l_http_request.answer.reply_header + l_http_request.answer.reply_text)
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
-- Contains key:value of the header
main_server: HTTP_SERVER
-- The main server object
main_server_configuration: HTTP_SERVER_CONFIGURATION
-- The main server's configuration
do
Result := main_server.configuration
end
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
method: STRING
-- http verb
uri : STRING
-- http endpoint
uri: STRING
-- http endpoint
version: detachable STRING
-- http_version
--| unused for now
version : STRING
-- http_version
feature -- Status setting
shutdown
@@ -123,8 +182,6 @@ feature -- Status setting
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
--
@@ -162,11 +219,8 @@ feature {NONE} -- Implementation
Result_attached: Result /= Void
end
feature -- New implementation
parse_http_request_line (line: STRING)
require
line /= Void
@@ -184,37 +238,24 @@ feature -- New implementation
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
l_headers_text: detachable STRING
l_input: HTTP_INPUT_STREAM
l_output: HTTP_OUTPUT_STREAM
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
l_headers_text := receive_message_internal (client_socket)
create l_input.make (client_socket)
create l_output.make (client_socket)
process_request (uri, method, request_header_map, l_headers_text, l_input, l_output)
end
parse_request_line (socket: NETWORK_STREAM_SOCKET)
require
@@ -240,10 +281,11 @@ feature -- New Implementation
loop
line := socket.last_string
print ("%N" +line+ "%N")
pos := line.index_of(':',1)
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
Result.append (line)
Result.append_character ('%N')
if not line.is_equal("%R") and socket.socket_ok then
socket.read_line_thread_aware
else
end_of_stream := True

View File

@@ -81,13 +81,6 @@ feature -- content types
text_html: STRING = "text/html"
feature -- Network
Server_datails : STRING = "Server : NANO Eiffel Server"
Http_server_port: INTEGER = 9000
Max_tcp_clients: INTEGER = 100
Socket_accept_timeout: INTEGER = 1000
Socket_connect_timeout: INTEGER = 5000
feature -- General Header Fields
-- There are a few header fields which have general applicability for both request and response messages,

61
server/http_server.e Normal file
View File

@@ -0,0 +1,61 @@
note
description: "Summary description for {HTTP_SERVER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
HTTP_SERVER
inherit
SHARED_DOCUMENT_ROOT
create
make
feature -- Initialization
make (cfg: like configuration)
do
configuration := cfg
end
setup (a_http_handler : HTTP_CONNECTION_HANDLER)
require
a_http_handler_valid: a_http_handler /= Void
do
print("%N%N%N")
print ("Starting Web Application Server:%N")
stop_requested := False
set_server_configuration (configuration)
a_http_handler.launch
run
end
shutdown_server
do
stop_requested := True
end
feature -- Access
configuration: HTTP_SERVER_CONFIGURATION
-- Configuration of the server
stop_requested: BOOLEAN
-- Stops the server
feature {NONE} -- implementation
run
-- Start the server
local
e: EXECUTION_ENVIRONMENT
do
create e
from until stop_requested loop
e.sleep (1_000_000)
end
end
end

View File

@@ -6,11 +6,10 @@ note
class
SHARED_DOCUMENT_ROOT
feature
document_root_cell: CELL [STRING]
once ("PROCESS")
create Result.put (Void)
end
obsolete "Use HTTP_SERVER_SHARED_CONFIGURATION"
inherit
HTTP_SERVER_SHARED_CONFIGURATION
end

View File

@@ -2,7 +2,7 @@ class SHARED_HTTP_REQUEST_HANDLERS
feature
http_request_handlers: HASH_TABLE [HTTP_REQUEST_HANDLER, STRING] is
http_request_handlers: HASH_TABLE [HTTP_REQUEST_HANDLER, STRING]
local
a_handler: HTTP_REQUEST_HANDLER
once

View File

@@ -1,11 +1,11 @@
note
description: "Summary description for {TCP_STREAM_SOCKET}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
TCP_STREAM_SOCKET
inherit
NETWORK_STREAM_SOCKET
@@ -15,7 +15,8 @@ create
create {NETWORK_STREAM_SOCKET}
make_from_descriptor_and_address
feature
feature -- Basic operation
send_message (a_msg: STRING)
local
a_package : PACKET
@@ -25,6 +26,7 @@ feature
create c_string.make (a_msg)
create a_data.make_from_pointer (c_string.item, a_msg.count + 1)
create a_package.make_from_managed_pointer (a_data)
Current.send (a_package, 1)
send (a_package, 1)
end
end

19
webroot/post/index.html Normal file
View File

@@ -0,0 +1,19 @@
<html>
<head>
<title>POST example</title>
</head>
<body>
<h1> POST example </h1>
<form action="index.html" method="POST">
<input type="text" name="name" value="a simple name"/> <br/>
<input type="text" name="text" value="a tiny text"/>
<input type="submit" value="POST"/>
</form>
<form action="index.html" method="GET">
<input type="text" name="name" value="a simple name"/> <br/>
<input type="text" name="text" value="a tiny text"/>
<input type="submit" value="GET"/>
</form>
</body>
</html>