removed the notion of status from GW_HEADER, since it should not be part of the HTTP header

added status setting in GW_RESPONSE
added a default implementation for write_status in OUTPUT_STREAM
  (it should be moved away in the future)
removed any implementation from GW_REQUEST, and put it in GW_REQUEST_IMP
This commit is contained in:
Jocelyn Fiat
2011-07-27 14:51:47 +02:00
parent 65800371cd
commit 4075b08b7e
8 changed files with 259 additions and 193 deletions

View File

@@ -48,6 +48,7 @@ feature -- Content type
feature -- Server
http_version_1_0: STRING = "HTTP/1.0"
http_version_1_1: STRING = "HTTP/1.1"
http_host_header: STRING = "Host"
http_authorization_header: STRING = "Authorization: "
http_end_of_header_line: STRING = "%R%N"
@@ -85,7 +86,7 @@ feature -- Misc
note
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
copyright: "2011-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -40,8 +40,7 @@ feature -- Access: environment variables
-- Environment variable related to `a_name'
require
a_name_valid: a_name /= Void and then not a_name.is_empty
do
Result := environment.variable (a_name)
deferred
end
feature -- Access: execution variables
@@ -55,36 +54,37 @@ feature -- Access: execution variables
-- Execution variable related to `a_name'
require
a_name_valid: a_name /= Void and then not a_name.is_empty
do
Result := execution_variables.variable (a_name)
deferred
end
feature -- URL Parameters
parameter (n: STRING): detachable STRING_32
-- Parameter for name `n'.
do
Result := parameters.variable (n)
end
parameters: GW_REQUEST_VARIABLES
-- Variables extracted from QUERY_STRING
deferred
end
feature -- Form fields and related
form_field (n: STRING): detachable STRING_32
-- Field for name `n'.
do
Result := form_fields.variable (n)
parameter (a_name: STRING): detachable STRING_32
-- Parameter for name `n'.
require
a_name_valid: a_name /= Void and then not a_name.is_empty
deferred
end
feature -- Form fields and related
form_fields: GW_REQUEST_VARIABLES
-- Variables sent by POST request
deferred
end
form_field (a_name: STRING): detachable STRING_32
-- Field for name `a_name'.
require
a_name_valid: a_name /= Void and then not a_name.is_empty
deferred
end
uploaded_files: HASH_TABLE [GW_UPLOADED_FILE_DATA, STRING]
-- Table of uploaded files information
--| name: original path from the user
@@ -98,17 +98,18 @@ feature -- Form fields and related
feature -- Cookies
cookies_variable (n: STRING): detachable STRING
-- Field for name `n'.
do
Result := cookies_variables.item (n)
end
cookies_variables: HASH_TABLE [STRING, STRING]
-- Expanded cookies variable
deferred
end
cookies_variable (a_name: STRING): detachable STRING
-- Field for name `a_name'.
require
a_name_valid: a_name /= Void and then not a_name.is_empty
deferred
end
cookies: HASH_TABLE [GW_COOKIE, STRING]
-- Cookies Information
deferred
@@ -120,85 +121,16 @@ feature -- Access: global variable
-- Table containing all the various variables
-- Warning: this is computed each time, if you change the content of other containers
-- this won't update this Result's content, unless you query it again
local
vars: HASH_TABLE [STRING_GENERAL, STRING_GENERAL]
do
create Result.make (100)
vars := execution_variables
from
vars.start
until
vars.after
loop
Result.put (vars.item_for_iteration, vars.key_for_iteration)
vars.forth
deferred
end
vars := environment.table
from
vars.start
until
vars.after
loop
Result.put (vars.item_for_iteration, vars.key_for_iteration)
vars.forth
end
vars := parameters.table
from
vars.start
until
vars.after
loop
Result.put (vars.item_for_iteration, vars.key_for_iteration)
vars.forth
end
vars := form_fields.table
from
vars.start
until
vars.after
loop
Result.put (vars.item_for_iteration, vars.key_for_iteration)
vars.forth
end
vars := cookies_variables
from
vars.start
until
vars.after
loop
Result.put (vars.item_for_iteration, vars.key_for_iteration)
vars.forth
end
end
variable (n8: STRING_8): detachable STRING_32
-- Variable named `n' from any of the variables container
variable (a_name: STRING_8): detachable STRING_32
-- Variable named `a_name' from any of the variables container
-- and following a specific order
-- execution, environment, get, post, cookies
local
s: detachable STRING_GENERAL
do
s := execution_variable (n8)
if s = Void then
s := environment_variable (n8)
if s = Void then
s := parameter (n8)
if s = Void then
s := form_field (n8)
if s = Void then
s := cookies_variable (n8)
end
end
end
end
if s /= Void then
Result := s.as_string_32
end
require
a_name_valid: a_name /= Void and then not a_name.is_empty
deferred
end
feature -- Uploaded File Handling
@@ -208,15 +140,6 @@ feature -- Uploaded File Handling
deferred
end
feature {NONE} -- Temporary File handling
delete_uploaded_file (f: GW_UPLOADED_FILE_DATA)
-- Delete file `f'
require
f_valid: f /= Void
deferred
end
feature -- URL Utility
absolute_script_url (a_path: STRING): STRING

View File

@@ -61,7 +61,7 @@ feature {NONE} -- Execution
and a_exception /= Void and then attached a_exception.exception_trace as l_trace
then
res.write_header ({HTTP_STATUS_CODE}.internal_server_error, Void)
res.write ("<pre>" + l_trace + "</pre>")
res.write_string ("<pre>" + l_trace + "</pre>")
end
post_execute (req, res)
end

View File

@@ -98,6 +98,12 @@ feature -- Access: environment variables
environment: GW_ENVIRONMENT
-- Environment variables
environment_variable (a_name: STRING): detachable STRING
-- Environment variable related to `a_name'
do
Result := environment.variable (a_name)
end
content_length: INTEGER
-- Extracted Content-Length value
@@ -106,6 +112,12 @@ feature -- Access: execution variables
execution_variables: GW_EXECUTION_VARIABLES
-- Execution variables set by the application
execution_variable (a_name: STRING): detachable STRING_32
-- Execution variable related to `a_name'
do
Result := execution_variables.variable (a_name)
end
feature -- URL parameters
parameters: GW_REQUEST_VARIABLES
@@ -141,6 +153,12 @@ feature -- URL parameters
Result := vars
end
parameter (a_name: STRING): detachable STRING_32
-- Parameter for name `n'.
do
Result := parameters.variable (a_name)
end
feature -- Form fields and related
form_fields: GW_REQUEST_VARIABLES
@@ -178,6 +196,12 @@ feature -- Form fields and related
Result := vars
end
form_field (a_name: STRING): detachable STRING_32
-- Field for name `a_name'.
do
Result := form_fields.variable (a_name)
end
uploaded_files: HASH_TABLE [GW_UPLOADED_FILE_DATA, STRING]
-- Table of uploaded files information
--| name: original path from the user
@@ -218,6 +242,12 @@ feature -- Cookies
end
end
cookies_variable (a_name: STRING): detachable STRING
-- Field for name `a_name'.
do
Result := cookies_variables.item (a_name)
end
cookies: HASH_TABLE [GW_COOKIE, STRING]
-- Cookies Information
local
@@ -261,6 +291,94 @@ feature -- Cookies
Result := l_cookies
end
feature -- Access: global variable
variables: HASH_TABLE [STRING_32, STRING_32]
-- Table containing all the various variables
-- Warning: this is computed each time, if you change the content of other containers
-- this won't update this Result's content, unless you query it again
local
vars: HASH_TABLE [STRING_GENERAL, STRING_GENERAL]
do
create Result.make (100)
vars := execution_variables
from
vars.start
until
vars.after
loop
Result.put (vars.item_for_iteration, vars.key_for_iteration)
vars.forth
end
vars := environment.table
from
vars.start
until
vars.after
loop
Result.put (vars.item_for_iteration, vars.key_for_iteration)
vars.forth
end
vars := parameters.table
from
vars.start
until
vars.after
loop
Result.put (vars.item_for_iteration, vars.key_for_iteration)
vars.forth
end
vars := form_fields.table
from
vars.start
until
vars.after
loop
Result.put (vars.item_for_iteration, vars.key_for_iteration)
vars.forth
end
vars := cookies_variables
from
vars.start
until
vars.after
loop
Result.put (vars.item_for_iteration, vars.key_for_iteration)
vars.forth
end
end
variable (a_name: STRING_8): detachable STRING_32
-- Variable named `a_name' from any of the variables container
-- and following a specific order
-- execution, environment, get, post, cookies
local
s: detachable STRING_GENERAL
do
s := execution_variable (a_name)
if s = Void then
s := environment_variable (a_name)
if s = Void then
s := parameter (a_name)
if s = Void then
s := form_field (a_name)
if s = Void then
s := cookies_variable (a_name)
end
end
end
end
if s /= Void then
Result := s.as_string_32
end
end
feature -- Access extra information
request_time: detachable DATE_TIME
@@ -397,6 +515,8 @@ feature {NONE} -- Temporary File handling
delete_uploaded_file (uf: GW_UPLOADED_FILE_DATA)
-- Delete file `a_filename'
require
uf_valid: uf /= Void
local
f: RAW_FILE
do

View File

@@ -1,5 +1,9 @@
note
description: "Summary description for {GW_HEADER}."
description: "[
Summary description for {GW_HEADER}.
Note the return status code is not part of the HTTP header
]"
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
@@ -8,9 +12,6 @@ note
class
GW_HEADER
inherit
HTTP_STATUS_CODE_MESSAGES
create
make
@@ -20,16 +21,12 @@ feature {NONE} -- Initialization
-- Initialize current
do
create {ARRAYED_LIST [STRING]} headers.make (3)
http_version := "HTTP/1.1"
end
feature -- Recycle
recycle
do
status_code := 0
status_message := Void
http_version := "HTTP/1.1"
headers.wipe_out
end
@@ -38,33 +35,22 @@ feature -- Access
headers: LIST [STRING]
-- Header's lines
send_to (a_output: GW_OUTPUT_STREAM)
send_to (res: GW_RESPONSE)
-- Send Current string representation to `a_output'
do
a_output.put_string (string)
--| TO OPTIMIZE
res.write_string (string)
--| Could be optimized
end
string: STRING
-- String representation of the headers
local
l_headers: like headers
h: STRING
do
create Result.make (32)
create h.make (16)
h.append_string (http_version)
h.append_character (' ')
h.append_integer (status_code)
h.append_character (' ')
if attached status_message as l_status_message then
h.append_string (l_status_message)
end
append_line_to (h, Result)
l_headers := headers
if l_headers.is_empty then
put_content_type_text_html
put_content_type_text_html -- See if this make sense to define a default content-type
else
from
l_headers.start
@@ -206,23 +192,6 @@ feature -- Content related header
end
end
feature -- Status, ...
status_code: INTEGER
-- Status
status_message: detachable STRING
-- Optional reason
http_version: STRING
-- HTTP version
put_status (a_code: INTEGER)
do
status_code := a_code
status_message := http_status_code_message (a_code)
end
feature -- Others
put_expires (n: INTEGER)
@@ -250,21 +219,11 @@ feature -- Redirection
put_redirection (a_location: STRING; a_code: INTEGER)
do
if a_code > 0 then
put_status (a_code)
else
put_status (302) -- Found
end
put_header_key_value ("Location", a_location)
end
put_refresh (a_location: STRING; a_timeout: INTEGER; a_code: INTEGER)
do
if a_code > 0 then
put_status (a_code)
else
put_status (200) -- Ok
end
put_header_key_value ("Refresh", a_timeout.out + "; url=" + a_location)
end

View File

@@ -16,21 +16,59 @@ feature {GW_APPLICATION} -- Commit
a_output_stream.flush
end
feature -- Output operation
feature {NONE} -- Core output operation
write (s: STRING)
-- Send the content of `s'
-- Send the string `s'
-- this can be used for header and body
deferred
end
feature -- Status setting
is_status_set: BOOLEAN
do
Result := status_code /= 0
end
set_status_code (a_code: INTEGER)
-- Set response status code
-- Should be done before sending any data back to the client
require
status_not_set: not is_status_set
do
status_code := a_code
write_status (a_code)
ensure
status_set: is_status_set
end
status_code: INTEGER
-- Response status
feature {NONE} -- Status output
write_status (a_code: INTEGER)
-- Send status line for `a_code'
deferred
ensure
status_set: is_status_set
end
feature -- Output operation
write_string (s: STRING)
-- Send the content of `s'
-- Send the string `s'
require
status_set: is_status_set
do
write (s)
end
write_file_content (fn: STRING)
-- Send the content of file `fn'
require
status_set: is_status_set
deferred
end
@@ -38,17 +76,21 @@ feature -- Header output operation
write_header_object (h: GW_HEADER)
-- Send `header' to `output'.
require
status_set: is_status_set
deferred
end
write_header (a_status: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]])
write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]])
-- Send headers with status `a_status', and headers from `a_headers'
require
status_not_set: not is_status_set
local
h: GW_HEADER
i,n: INTEGER
do
set_status_code (a_status_code)
create h.make
h.put_status (a_status)
if a_headers /= Void then
from
i := a_headers.lower
@@ -61,13 +103,8 @@ feature -- Header output operation
end
end
write_header_object (h)
end
write_header_line (s: STRING)
-- Send `s' to http client as header line
do
write (s)
write ("%R%N")
ensure
status_set: is_status_set
end
note

View File

@@ -20,7 +20,7 @@ feature {NONE} -- Initialization
output := a_output
end
feature -- Output operation
feature {NONE} -- Core output operation
write (s: STRING)
-- Send the content of `s'
@@ -28,6 +28,16 @@ feature -- Output operation
output.put_string (s)
end
feature {NONE} -- Status output
write_status (a_code: INTEGER)
-- Send status line for `a_code'
do
output.put_status_line (a_code)
end
feature -- Output operation
write_file_content (fn: STRING)
-- Send the content of file `fn'
do
@@ -37,7 +47,7 @@ feature -- Output operation
write_header_object (h: GW_HEADER)
-- Send `header' to `output'.
do
h.send_to (output)
h.send_to (Current)
end
feature {NONE} -- Implementation: Access

View File

@@ -10,6 +10,14 @@ note
deferred class
GW_OUTPUT_STREAM
inherit
ANY
HTTP_STATUS_CODE_MESSAGES
export
{NONE} all
end
feature -- Core operation
put_string (s: STRING_8)
@@ -24,8 +32,36 @@ feature -- Core operation
do
end
feature -- Status writing
put_status_line (a_code: INTEGER)
-- Put status code line for `a_code'
--| Note this is a default implemantation, and could be redefined
--| for instance in relation to NPH CGI script
local
s: STRING
do
create s.make (16)
s.append ({HTTP_CONSTANTS}.http_version_1_1)
s.append_character (' ')
s.append_integer (a_code)
if attached http_status_code_message (a_code) as l_status_message then
s.append_character (' ')
s.append_string (l_status_message)
end
put_header_line (s)
end
feature -- Basic operation
put_substring (s: STRING; start_index, end_index: INTEGER)
-- Write `s[start_index:end_index]' into the output stream
require
s_not_empty: s /= Void and then not s.is_empty
do
put_string (s.substring (start_index, end_index))
end
put_file_content (fn: STRING)
-- Send the content of file `fn'
local
@@ -38,33 +74,13 @@ feature -- Basic operation
until
f.exhausted
loop
f.read_stream (1024)
f.read_stream (4096)
put_string (f.last_string)
end
f.close
end
end
put_header (a_status: INTEGER; a_headers: ARRAY [TUPLE [key: STRING; value: STRING]])
-- Send headers with status `a_status', and headers from `a_headers'
local
h: GW_HEADER
i,n: INTEGER
do
create h.make
h.put_status (a_status)
from
i := a_headers.lower
n := a_headers.upper
until
i > n
loop
h.put_header_key_value (a_headers[i].key, a_headers[i].value)
i := i + 1
end
put_string (h.string)
end
put_header_line (s: STRING)
-- Send `s' to http client as header line
do