Renamed EWSGI_RESPONSE as EWSGI_RESPONSE_STREAM to avoid confusion with EWSGI_RESPONSE as stated in Paul's proposal Added default "configuration" (for nino and cgi) to be independant of the connector (at compilation time) Added example implementing Paul's proposal on top of EWSGI
380 lines
9.7 KiB
Plaintext
380 lines
9.7 KiB
Plaintext
note
|
|
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$"
|
|
revision: "$Revision$"
|
|
|
|
class
|
|
GW_HEADER
|
|
|
|
inherit
|
|
ANY
|
|
|
|
HTTP_STATUS_CODE_MESSAGES
|
|
export
|
|
{NONE} all
|
|
end
|
|
|
|
create
|
|
make
|
|
|
|
feature {NONE} -- Initialization
|
|
|
|
make
|
|
-- Initialize current
|
|
do
|
|
create {ARRAYED_LIST [STRING]} headers.make (3)
|
|
end
|
|
|
|
feature -- Recycle
|
|
|
|
recycle
|
|
do
|
|
headers.wipe_out
|
|
end
|
|
|
|
feature -- Access
|
|
|
|
headers: LIST [STRING]
|
|
-- Header's lines
|
|
|
|
string: STRING
|
|
-- String representation of the headers
|
|
local
|
|
l_headers: like headers
|
|
do
|
|
create Result.make (32)
|
|
l_headers := headers
|
|
if l_headers.is_empty then
|
|
put_content_type_text_html -- See if this make sense to define a default content-type
|
|
else
|
|
from
|
|
l_headers.start
|
|
until
|
|
l_headers.after
|
|
loop
|
|
append_line_to (l_headers.item, Result)
|
|
l_headers.forth
|
|
end
|
|
end
|
|
append_end_of_line_to (Result)
|
|
end
|
|
|
|
feature -- Header change: general
|
|
|
|
add_header (h: STRING)
|
|
do
|
|
headers.force (h)
|
|
end
|
|
|
|
put_header (h: STRING)
|
|
-- Add header `h' or replace existing header of same header name
|
|
do
|
|
force_header_by_name (header_name (h), h)
|
|
end
|
|
|
|
add_header_key_value (k,v: STRING)
|
|
-- Add header `k:v', or replace existing header of same header name/key
|
|
do
|
|
add_header (k + colon_space + v)
|
|
end
|
|
|
|
put_header_key_value (k,v: STRING)
|
|
-- Add header `k:v', or replace existing header of same header name/key
|
|
do
|
|
put_header (k + colon_space + v)
|
|
end
|
|
|
|
feature -- Content related header
|
|
|
|
put_status (c: INTEGER)
|
|
local
|
|
s: STRING
|
|
do
|
|
create s.make_from_string (c.out)
|
|
if attached http_status_code_message (c) as msg then
|
|
s.append_character (' ')
|
|
s.append (msg)
|
|
end
|
|
put_header_key_value ("Status", s)
|
|
end
|
|
|
|
put_content_type (t: STRING)
|
|
do
|
|
put_header_key_value (name_content_type, t)
|
|
end
|
|
|
|
add_content_type (t: STRING)
|
|
-- same as `put_content_type', but allow multiple definition of "Content-Type"
|
|
do
|
|
add_header_key_value (name_content_type, t)
|
|
end
|
|
|
|
put_content_type_with_name (t: STRING; n: STRING)
|
|
do
|
|
put_header_key_value (name_content_type, t + "; name=%"" + n + "%"")
|
|
end
|
|
|
|
add_content_type_with_name (t: STRING; n: STRING)
|
|
-- same as `put_content_type_with_name', but allow multiple definition of "Content-Type"
|
|
do
|
|
add_header_key_value (name_content_type, t + "; name=%"" + n + "%"")
|
|
end
|
|
|
|
put_content_type_text_css do put_content_type ("text/css") end
|
|
put_content_type_text_csv do put_content_type ("text/csv") end
|
|
put_content_type_text_html do put_content_type ("text/html") end
|
|
put_content_type_text_javascript do put_content_type ("text/javascript") end
|
|
put_content_type_text_json do put_content_type ("text/json") end
|
|
put_content_type_text_plain do put_content_type ("text/plain") end
|
|
put_content_type_text_xml do put_content_type ("text/xml") end
|
|
|
|
put_content_type_application_json do put_content_type ("application/json") end
|
|
put_content_type_application_javascript do put_content_type ("application/javascript") end
|
|
put_content_type_application_zip do put_content_type ("application/zip") end
|
|
|
|
put_content_type_image_gif do put_content_type ("image/gif") end
|
|
put_content_type_image_png do put_content_type ("image/png") end
|
|
put_content_type_image_jpg do put_content_type ("image/jpg") end
|
|
put_content_type_image_svg_xml do put_content_type ("image/svg+xml") end
|
|
|
|
put_content_type_message_http do put_content_type ("message/http") end
|
|
|
|
put_content_type_multipart_mixed do put_content_type ("multipart/mixed") end
|
|
put_content_type_multipart_alternative do put_content_type ("multipart/alternative") end
|
|
put_content_type_multipart_related do put_content_type ("multipart/related") end
|
|
put_content_type_multipart_form_data do put_content_type ("multipart/form-data") end
|
|
put_content_type_multipart_signed do put_content_type ("multipart/signed") end
|
|
put_content_type_multipart_encrypted do put_content_type ("multipart/encrypted") end
|
|
|
|
|
|
put_content_length (n: INTEGER)
|
|
do
|
|
put_header_key_value (name_content_length, n.out)
|
|
end
|
|
|
|
put_content_transfer_encoding (a_mechanism: STRING)
|
|
-- Put "Content-Transfer-Encoding" header with for instance "binary"
|
|
--| encoding := "Content-Transfer-Encoding" ":" mechanism
|
|
--|
|
|
--| mechanism := "7bit" ; case-insensitive
|
|
--| / "quoted-printable"
|
|
--| / "base64"
|
|
--| / "8bit"
|
|
--| / "binary"
|
|
--| / x-token
|
|
|
|
do
|
|
put_header_key_value ("Content-Transfer-Encoding", a_mechanism)
|
|
end
|
|
|
|
put_content_disposition (a_type: STRING; a_params: detachable STRING)
|
|
-- Put "Content-Disposition" header
|
|
--| See RFC2183
|
|
--| disposition := "Content-Disposition" ":"
|
|
--| disposition-type
|
|
--| *(";" disposition-parm)
|
|
--| disposition-type := "inline"
|
|
--| / "attachment"
|
|
--| / extension-token
|
|
--| ; values are not case-sensitive
|
|
--| disposition-parm := filename-parm
|
|
--| / creation-date-parm
|
|
--| / modification-date-parm
|
|
--| / read-date-parm
|
|
--| / size-parm
|
|
--| / parameter
|
|
--| filename-parm := "filename" "=" value
|
|
--| creation-date-parm := "creation-date" "=" quoted-date-time
|
|
--| modification-date-parm := "modification-date" "=" quoted-date-time
|
|
--| read-date-parm := "read-date" "=" quoted-date-time
|
|
--| size-parm := "size" "=" 1*DIGIT
|
|
--| quoted-date-time := quoted-string
|
|
--| ; contents MUST be an RFC 822 `date-time'
|
|
--| ; numeric timezones (+HHMM or -HHMM) MUST be used
|
|
do
|
|
if a_params /= Void then
|
|
put_header_key_value ("Content-Disposition", a_type + "; " + a_params)
|
|
else
|
|
put_header_key_value ("Content-Disposition", a_type)
|
|
end
|
|
end
|
|
|
|
feature -- Others
|
|
|
|
put_expires (n: INTEGER)
|
|
do
|
|
put_header_key_value ("Expires", n.out)
|
|
end
|
|
|
|
put_cache_control (s: STRING)
|
|
-- `s' could be for instance "no-cache, must-revalidate"
|
|
do
|
|
put_header_key_value ("Cache-Control", s)
|
|
end
|
|
|
|
put_pragma (s: STRING)
|
|
do
|
|
put_header_key_value ("Pragma", s)
|
|
end
|
|
|
|
put_pragma_no_cache
|
|
do
|
|
put_pragma ("no-cache")
|
|
end
|
|
|
|
feature -- Redirection
|
|
|
|
put_redirection (a_location: STRING; a_code: INTEGER)
|
|
do
|
|
put_header_key_value ("Location", a_location)
|
|
end
|
|
|
|
put_refresh (a_location: STRING; a_timeout: INTEGER; a_code: INTEGER)
|
|
do
|
|
put_header_key_value ("Refresh", a_timeout.out + "; url=" + a_location)
|
|
end
|
|
|
|
feature -- Cookie
|
|
|
|
put_cookie (key, value: STRING_8; expiration, path, domain, secure: detachable STRING_8)
|
|
-- Set a cookie on the client's machine
|
|
-- with key 'key' and value 'value'.
|
|
require
|
|
make_sense: (key /= Void and value /= Void) and then (not key.is_empty and not value.is_empty)
|
|
local
|
|
s: STRING
|
|
do
|
|
s := "Set-Cookie:" + key + "=" + value
|
|
if expiration /= Void then
|
|
s.append (";expires=" + expiration)
|
|
end
|
|
if path /= Void then
|
|
s.append (";path=" + path)
|
|
end
|
|
if domain /= Void then
|
|
s.append (";domain=" + domain)
|
|
end
|
|
if secure /= Void then
|
|
s.append (";secure=" + secure)
|
|
end
|
|
add_header (s)
|
|
end
|
|
|
|
feature -- Status report
|
|
|
|
has_header_named (a_name: STRING): BOOLEAN
|
|
-- Has header item for `n'?
|
|
local
|
|
c: like headers.new_cursor
|
|
n: INTEGER
|
|
do
|
|
from
|
|
n := a_name.count
|
|
c := headers.new_cursor
|
|
until
|
|
c.after or Result
|
|
loop
|
|
Result := c.item.starts_with (a_name) and then c.item [n + 1] = ':'
|
|
c.forth
|
|
end
|
|
end
|
|
|
|
has_content_length: BOOLEAN
|
|
-- Has header "content_length"
|
|
do
|
|
Result := has_header_named (name_content_length)
|
|
end
|
|
|
|
feature {NONE} -- Implementation: Header
|
|
|
|
force_header_by_name (n: detachable STRING; h: STRING)
|
|
-- Add header `h' or replace existing header of same header name `n'
|
|
require
|
|
h_has_name_n: (n /= Void and attached header_name (h) as hn) implies n.same_string (hn)
|
|
local
|
|
l_headers: like headers
|
|
do
|
|
if n /= Void then
|
|
from
|
|
l_headers := headers
|
|
l_headers.start
|
|
until
|
|
l_headers.after or l_headers.item.starts_with (n)
|
|
loop
|
|
l_headers.forth
|
|
end
|
|
if not l_headers.after then
|
|
l_headers.replace (h)
|
|
else
|
|
add_header (h)
|
|
end
|
|
else
|
|
add_header (h)
|
|
end
|
|
end
|
|
|
|
header_name (h: STRING): detachable STRING
|
|
-- If any, header's name with colon
|
|
--| ex: for "Foo-bar: something", this will return "Foo-bar:"
|
|
local
|
|
i,n: INTEGER
|
|
c: CHARACTER
|
|
do
|
|
from
|
|
i := 1
|
|
n := h.count
|
|
create Result.make (10)
|
|
until
|
|
i > n or c = ':' or Result = Void
|
|
loop
|
|
c := h[i]
|
|
inspect c
|
|
when ':' then
|
|
Result.extend (c)
|
|
when '-', 'a' .. 'z', 'A' .. 'Z' then
|
|
Result.extend (c)
|
|
else
|
|
Result := Void
|
|
end
|
|
i := i + 1
|
|
end
|
|
end
|
|
|
|
feature {NONE} -- Implementation
|
|
|
|
append_line_to (s, h: STRING)
|
|
do
|
|
h.append_string (s)
|
|
append_end_of_line_to (h)
|
|
end
|
|
|
|
append_end_of_line_to (h: like string)
|
|
do
|
|
h.append_character ('%R')
|
|
h.append_character ('%N')
|
|
end
|
|
|
|
feature {NONE} -- Constants
|
|
|
|
colon_space: STRING = ": "
|
|
name_content_length: STRING = "Content-Length"
|
|
name_content_type: STRING = "Content-Type"
|
|
|
|
note
|
|
copyright: "2011-2011, Eiffel Software and others"
|
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
|
source: "[
|
|
Eiffel Software
|
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
|
Telephone 805-685-1006, Fax 805-685-6869
|
|
Website http://www.eiffel.com
|
|
Customer support http://support.eiffel.com
|
|
]"
|
|
end
|