Merge branch 'master' into void-safe
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
note
|
note
|
||||||
description: "[
|
description: "[
|
||||||
The class provides an easy way to build HTTP header.
|
The class represents a HTTP header, and it provides simple routine
|
||||||
|
to build it.
|
||||||
|
|
||||||
You will also find some helper feature to help coding most common usage
|
You will also find some helper features to help coding most common usages
|
||||||
|
|
||||||
Please, have a look at constants classes such as
|
Please, have a look at constants classes such as
|
||||||
HTTP_MIME_TYPES
|
HTTP_MIME_TYPES
|
||||||
@@ -24,6 +25,8 @@ class
|
|||||||
inherit
|
inherit
|
||||||
ITERABLE [READABLE_STRING_8]
|
ITERABLE [READABLE_STRING_8]
|
||||||
|
|
||||||
|
HTTP_HEADER_MODIFIER
|
||||||
|
|
||||||
create
|
create
|
||||||
make,
|
make,
|
||||||
make_with_count,
|
make_with_count,
|
||||||
@@ -116,6 +119,8 @@ feature -- Access
|
|||||||
result_has_single_ending_cr_lf: Result.count >= 4 implies not Result.substring (Result.count - 3, Result.count).same_string ("%R%N%R%N")
|
result_has_single_ending_cr_lf: Result.count >= 4 implies not Result.substring (Result.count - 3, Result.count).same_string ("%R%N%R%N")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature -- Conversion
|
||||||
|
|
||||||
to_name_value_iterable: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]
|
to_name_value_iterable: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]
|
||||||
-- Iterable representation of the header entries.
|
-- Iterable representation of the header entries.
|
||||||
local
|
local
|
||||||
@@ -132,7 +137,7 @@ feature -- Access
|
|||||||
Result := res
|
Result := res
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Conversion
|
feature --
|
||||||
|
|
||||||
append_string_to (a_result: STRING_8)
|
append_string_to (a_result: STRING_8)
|
||||||
-- Append current as string representation to `a_result'
|
-- Append current as string representation to `a_result'
|
||||||
@@ -250,60 +255,6 @@ feature -- Header: merging
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
has, has_header_named (a_name: READABLE_STRING_8): BOOLEAN
|
|
||||||
-- Has header item for `n'?
|
|
||||||
do
|
|
||||||
Result := across headers as c some has_same_header_name (c.item, a_name) end
|
|
||||||
end
|
|
||||||
|
|
||||||
has_content_length: BOOLEAN
|
|
||||||
-- Has header "Content-Length"
|
|
||||||
do
|
|
||||||
Result := has_header_named ({HTTP_HEADER_NAMES}.header_content_length)
|
|
||||||
end
|
|
||||||
|
|
||||||
has_content_type: BOOLEAN
|
|
||||||
-- Has header "Content-Type"
|
|
||||||
do
|
|
||||||
Result := has_header_named ({HTTP_HEADER_NAMES}.header_content_type)
|
|
||||||
end
|
|
||||||
|
|
||||||
has_transfer_encoding_chunked: BOOLEAN
|
|
||||||
-- Has "Transfer-Encoding: chunked" header
|
|
||||||
do
|
|
||||||
if has_header_named ({HTTP_HEADER_NAMES}.header_transfer_encoding) then
|
|
||||||
Result := attached header_named_value ({HTTP_HEADER_NAMES}.header_transfer_encoding) as v and then v.same_string (str_chunked)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
header_named_value (a_name: READABLE_STRING_8): detachable STRING_8
|
|
||||||
-- First header item found for `a_name' if any
|
|
||||||
require
|
|
||||||
has_header: has_header_named (a_name)
|
|
||||||
local
|
|
||||||
n: INTEGER
|
|
||||||
l_line: READABLE_STRING_8
|
|
||||||
do
|
|
||||||
n := a_name.count
|
|
||||||
|
|
||||||
across
|
|
||||||
headers as ic
|
|
||||||
until
|
|
||||||
Result /= Void
|
|
||||||
loop
|
|
||||||
l_line := ic.item
|
|
||||||
if has_same_header_name (l_line, a_name) then
|
|
||||||
Result := l_line.substring (n + 2, l_line.count)
|
|
||||||
Result.left_adjust
|
|
||||||
Result.right_adjust
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Removal
|
feature -- Removal
|
||||||
|
|
||||||
remove_header_named (a_name: READABLE_STRING_8)
|
remove_header_named (a_name: READABLE_STRING_8)
|
||||||
@@ -334,375 +285,16 @@ feature -- Header change: general
|
|||||||
-- Add header `h'
|
-- Add header `h'
|
||||||
-- if it already exists, there will be multiple header with same name
|
-- if it already exists, there will be multiple header with same name
|
||||||
-- which can also be valid
|
-- which can also be valid
|
||||||
require
|
|
||||||
h_not_empty: not h.is_empty
|
|
||||||
do
|
do
|
||||||
headers.force (h)
|
headers.force (h)
|
||||||
end
|
end
|
||||||
|
|
||||||
put_header (h: READABLE_STRING_8)
|
put_header (h: READABLE_STRING_8)
|
||||||
-- Add header `h' or replace existing header of same header name
|
-- Add header `h' or replace existing header of same header name
|
||||||
require
|
|
||||||
h_not_empty: not h.is_empty
|
|
||||||
do
|
do
|
||||||
force_header_by_name (header_name_colon (h), h)
|
force_header_by_name (header_name_colon (h), h)
|
||||||
end
|
end
|
||||||
|
|
||||||
add_header_key_value (k,v: READABLE_STRING_8)
|
|
||||||
-- Add header `k:v'.
|
|
||||||
-- If it already exists, there will be multiple header with same name
|
|
||||||
-- which can also be valid
|
|
||||||
local
|
|
||||||
s: STRING_8
|
|
||||||
do
|
|
||||||
create s.make (k.count + 2 + v.count)
|
|
||||||
s.append (k)
|
|
||||||
s.append (colon_space)
|
|
||||||
s.append (v)
|
|
||||||
add_header (s)
|
|
||||||
ensure
|
|
||||||
added: has_header_named (k)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_header_key_value (k,v: READABLE_STRING_8)
|
|
||||||
-- Add header `k:v', or replace existing header of same header name/key
|
|
||||||
local
|
|
||||||
s: STRING_8
|
|
||||||
do
|
|
||||||
create s.make (k.count + 2 + v.count)
|
|
||||||
s.append (k)
|
|
||||||
s.append (colon_space)
|
|
||||||
s.append (v)
|
|
||||||
put_header (s)
|
|
||||||
ensure
|
|
||||||
added: has_header_named (k)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_header_key_values (k: READABLE_STRING_8; a_values: ITERABLE [READABLE_STRING_8]; a_separator: detachable READABLE_STRING_8)
|
|
||||||
-- Add header `k: a_values', or replace existing header of same header values/key.
|
|
||||||
-- Use `comma_space' as default separator if `a_separator' is Void or empty.
|
|
||||||
local
|
|
||||||
s: STRING_8
|
|
||||||
l_separator: READABLE_STRING_8
|
|
||||||
do
|
|
||||||
if a_separator /= Void and then not a_separator.is_empty then
|
|
||||||
l_separator := a_separator
|
|
||||||
else
|
|
||||||
l_separator := comma_space
|
|
||||||
end
|
|
||||||
create s.make_empty
|
|
||||||
across
|
|
||||||
a_values as c
|
|
||||||
loop
|
|
||||||
if not s.is_empty then
|
|
||||||
s.append_string (l_separator)
|
|
||||||
end
|
|
||||||
s.append (c.item)
|
|
||||||
end
|
|
||||||
if not s.is_empty then
|
|
||||||
put_header_key_value (k, s)
|
|
||||||
end
|
|
||||||
ensure
|
|
||||||
added: has_header_named (k)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Content related header
|
|
||||||
|
|
||||||
put_content_type (t: READABLE_STRING_8)
|
|
||||||
do
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t)
|
|
||||||
end
|
|
||||||
|
|
||||||
add_content_type (t: READABLE_STRING_8)
|
|
||||||
-- same as `put_content_type', but allow multiple definition of "Content-Type"
|
|
||||||
do
|
|
||||||
add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_content_type_with_parameters (t: READABLE_STRING_8; a_params: detachable ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
|
|
||||||
local
|
|
||||||
s: STRING_8
|
|
||||||
do
|
|
||||||
if a_params /= Void and then not a_params.is_empty then
|
|
||||||
create s.make_from_string (t)
|
|
||||||
across
|
|
||||||
a_params as p
|
|
||||||
loop
|
|
||||||
if attached p.item as nv then
|
|
||||||
s.append_character (';')
|
|
||||||
s.append_character (' ')
|
|
||||||
s.append (nv.name)
|
|
||||||
s.append_character ('=')
|
|
||||||
s.append_character ('%"')
|
|
||||||
s.append (nv.value)
|
|
||||||
s.append_character ('%"')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, s)
|
|
||||||
else
|
|
||||||
put_content_type (t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
add_content_type_with_parameters (t: READABLE_STRING_8; a_params: detachable ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
|
|
||||||
local
|
|
||||||
s: STRING_8
|
|
||||||
do
|
|
||||||
if a_params /= Void and then not a_params.is_empty then
|
|
||||||
create s.make_from_string (t)
|
|
||||||
across
|
|
||||||
a_params as p
|
|
||||||
loop
|
|
||||||
if attached p.item as nv then
|
|
||||||
s.append_character (';')
|
|
||||||
s.append_character (' ')
|
|
||||||
s.append (nv.name)
|
|
||||||
s.append_character ('=')
|
|
||||||
s.append_character ('%"')
|
|
||||||
s.append (nv.value)
|
|
||||||
s.append_character ('%"')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, s)
|
|
||||||
else
|
|
||||||
add_content_type (t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
put_content_type_with_charset (t: READABLE_STRING_8; c: READABLE_STRING_8)
|
|
||||||
do
|
|
||||||
put_content_type_with_parameters (t, <<["charset", c]>>)
|
|
||||||
end
|
|
||||||
|
|
||||||
add_content_type_with_charset (t: READABLE_STRING_8; c: READABLE_STRING_8)
|
|
||||||
-- same as `put_content_type_with_charset', but allow multiple definition of "Content-Type"
|
|
||||||
do
|
|
||||||
add_content_type_with_parameters (t, <<["charset", c]>>)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_content_type_with_name (t: READABLE_STRING_8; n: READABLE_STRING_8)
|
|
||||||
do
|
|
||||||
put_content_type_with_parameters (t, <<["name", n]>>)
|
|
||||||
end
|
|
||||||
|
|
||||||
add_content_type_with_name (t: READABLE_STRING_8; n: READABLE_STRING_8)
|
|
||||||
-- same as `put_content_type_with_name', but allow multiple definition of "Content-Type"
|
|
||||||
do
|
|
||||||
add_content_type_with_parameters (t, <<["name", n]>>)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_content_length (n: INTEGER)
|
|
||||||
do
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_length, n.out)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_content_transfer_encoding (a_mechanism: READABLE_STRING_8)
|
|
||||||
-- 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 ({HTTP_HEADER_NAMES}.header_content_transfer_encoding, a_mechanism)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_content_language (a_lang: READABLE_STRING_8)
|
|
||||||
-- Put "Content-Language" header of value `a_lang'.
|
|
||||||
do
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_language, a_lang)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_content_encoding (a_enc: READABLE_STRING_8)
|
|
||||||
-- Put "Content-Encoding" header of value `a_enc'.
|
|
||||||
do
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_encoding, a_enc)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_transfer_encoding (a_enc: READABLE_STRING_8)
|
|
||||||
-- Put "Transfer-Encoding" header with for instance "chunked"
|
|
||||||
do
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_transfer_encoding, a_enc)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_transfer_encoding_binary
|
|
||||||
-- Put "Transfer-Encoding: binary" header
|
|
||||||
do
|
|
||||||
put_transfer_encoding (str_binary)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_transfer_encoding_chunked
|
|
||||||
-- Put "Transfer-Encoding: chunked" header
|
|
||||||
do
|
|
||||||
put_transfer_encoding (str_chunked)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_content_disposition (a_type: READABLE_STRING_8; a_params: detachable READABLE_STRING_8)
|
|
||||||
-- 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 ({HTTP_HEADER_NAMES}.header_content_disposition, a_type + semi_colon_space + a_params)
|
|
||||||
else
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_disposition, a_type)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Content-type helpers
|
|
||||||
|
|
||||||
put_content_type_text_css do put_content_type ({HTTP_MIME_TYPES}.text_css) end
|
|
||||||
put_content_type_text_csv do put_content_type ({HTTP_MIME_TYPES}.text_csv) end
|
|
||||||
put_content_type_text_html do put_content_type ({HTTP_MIME_TYPES}.text_html) end
|
|
||||||
put_content_type_text_javascript do put_content_type ({HTTP_MIME_TYPES}.text_javascript) end
|
|
||||||
put_content_type_text_json do put_content_type ({HTTP_MIME_TYPES}.text_json) end
|
|
||||||
put_content_type_text_plain do put_content_type ({HTTP_MIME_TYPES}.text_plain) end
|
|
||||||
put_content_type_text_xml do put_content_type ({HTTP_MIME_TYPES}.text_xml) end
|
|
||||||
|
|
||||||
put_content_type_application_json do put_content_type ({HTTP_MIME_TYPES}.application_json) end
|
|
||||||
put_content_type_application_javascript do put_content_type ({HTTP_MIME_TYPES}.application_javascript) end
|
|
||||||
put_content_type_application_zip do put_content_type ({HTTP_MIME_TYPES}.application_zip) end
|
|
||||||
put_content_type_application_pdf do put_content_type ({HTTP_MIME_TYPES}.application_pdf) end
|
|
||||||
|
|
||||||
put_content_type_image_gif do put_content_type ({HTTP_MIME_TYPES}.image_gif) end
|
|
||||||
put_content_type_image_png do put_content_type ({HTTP_MIME_TYPES}.image_png) end
|
|
||||||
put_content_type_image_jpg do put_content_type ({HTTP_MIME_TYPES}.image_jpg) end
|
|
||||||
put_content_type_image_svg_xml do put_content_type ({HTTP_MIME_TYPES}.image_svg_xml) end
|
|
||||||
|
|
||||||
put_content_type_message_http do put_content_type ({HTTP_MIME_TYPES}.message_http) end
|
|
||||||
|
|
||||||
put_content_type_multipart_mixed do put_content_type ({HTTP_MIME_TYPES}.multipart_mixed) end
|
|
||||||
put_content_type_multipart_alternative do put_content_type ({HTTP_MIME_TYPES}.multipart_alternative) end
|
|
||||||
put_content_type_multipart_related do put_content_type ({HTTP_MIME_TYPES}.multipart_related) end
|
|
||||||
put_content_type_multipart_form_data do put_content_type ({HTTP_MIME_TYPES}.multipart_form_data) end
|
|
||||||
put_content_type_multipart_signed do put_content_type ({HTTP_MIME_TYPES}.multipart_signed) end
|
|
||||||
put_content_type_multipart_encrypted do put_content_type ({HTTP_MIME_TYPES}.multipart_encrypted) end
|
|
||||||
put_content_type_application_x_www_form_encoded do put_content_type ({HTTP_MIME_TYPES}.application_x_www_form_encoded) end
|
|
||||||
|
|
||||||
feature -- Cross-Origin Resource Sharing
|
|
||||||
|
|
||||||
put_access_control_allow_origin (s: READABLE_STRING_8)
|
|
||||||
-- Put "Access-Control-Allow-Origin" header.
|
|
||||||
do
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_origin, s)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_access_control_allow_all_origin
|
|
||||||
-- Put "Access-Control-Allow-Origin: *" header.
|
|
||||||
do
|
|
||||||
put_access_control_allow_origin ("*")
|
|
||||||
end
|
|
||||||
|
|
||||||
put_access_control_allow_methods (a_methods: ITERABLE [READABLE_STRING_8])
|
|
||||||
-- If `a_methods' is not empty, put `Access-Control-Allow-Methods' header with list `a_methods' of methods
|
|
||||||
do
|
|
||||||
put_header_key_values ({HTTP_HEADER_NAMES}.header_access_control_allow_methods, a_methods, Void)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_access_control_allow_headers (s: READABLE_STRING_8)
|
|
||||||
-- Put "Access-Control-Allow-Headers" header.
|
|
||||||
do
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_headers, s)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Method related
|
|
||||||
|
|
||||||
put_allow (a_methods: ITERABLE [READABLE_STRING_8])
|
|
||||||
-- If `a_methods' is not empty, put `Allow' header with list `a_methods' of methods
|
|
||||||
do
|
|
||||||
put_header_key_values ({HTTP_HEADER_NAMES}.header_allow, a_methods, Void)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Date
|
|
||||||
|
|
||||||
put_date (s: READABLE_STRING_8)
|
|
||||||
-- Put "Date: " header
|
|
||||||
do
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_date, s)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_current_date
|
|
||||||
-- Put current date time with "Date" header
|
|
||||||
do
|
|
||||||
put_utc_date (create {DATE_TIME}.make_now_utc)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_utc_date (a_utc_date: DATE_TIME)
|
|
||||||
-- Put UTC date time `dt' with "Date" header
|
|
||||||
do
|
|
||||||
put_date (date_to_rfc1123_http_date_format (a_utc_date))
|
|
||||||
end
|
|
||||||
|
|
||||||
put_last_modified (a_utc_date: DATE_TIME)
|
|
||||||
-- Put UTC date time `dt' with "Date" header
|
|
||||||
do
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_last_modified, date_to_rfc1123_http_date_format (a_utc_date))
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Authorization
|
|
||||||
|
|
||||||
put_authorization (s: READABLE_STRING_8)
|
|
||||||
-- Put authorization `s' with "Authorization" header
|
|
||||||
do
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_authorization, s)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Others
|
|
||||||
|
|
||||||
put_expires (sec: INTEGER)
|
|
||||||
do
|
|
||||||
put_expires_string (sec.out)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_expires_string (s: STRING)
|
|
||||||
do
|
|
||||||
put_header_key_value ("Expires", s)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_expires_date (a_utc_date: DATE_TIME)
|
|
||||||
do
|
|
||||||
put_header_key_value ("Expires", date_to_rfc1123_http_date_format (a_utc_date))
|
|
||||||
end
|
|
||||||
|
|
||||||
put_cache_control (s: READABLE_STRING_8)
|
|
||||||
-- `s' could be for instance "no-cache, must-revalidate"
|
|
||||||
do
|
|
||||||
put_header_key_value ("Cache-Control", s)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_pragma (s: READABLE_STRING_8)
|
|
||||||
do
|
|
||||||
put_header_key_value ("Pragma", s)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_pragma_no_cache
|
|
||||||
do
|
|
||||||
put_pragma ("no-cache")
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Redirection
|
feature -- Redirection
|
||||||
|
|
||||||
remove_location
|
remove_location
|
||||||
@@ -711,79 +303,7 @@ feature -- Redirection
|
|||||||
remove_header_named ({HTTP_HEADER_NAMES}.header_location)
|
remove_header_named ({HTTP_HEADER_NAMES}.header_location)
|
||||||
end
|
end
|
||||||
|
|
||||||
put_location (a_location: READABLE_STRING_8)
|
feature {NONE} -- Implementation: Header change
|
||||||
-- Tell the client the new location `a_location'
|
|
||||||
require
|
|
||||||
a_location_valid: not a_location.is_empty
|
|
||||||
do
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_location, a_location)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_refresh (a_location: READABLE_STRING_8; a_timeout_in_seconds: INTEGER)
|
|
||||||
-- Tell the client to refresh page with `a_location' after `a_timeout_in_seconds' in seconds
|
|
||||||
require
|
|
||||||
a_location_valid: not a_location.is_empty
|
|
||||||
do
|
|
||||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_refresh, a_timeout_in_seconds.out + "; url=" + a_location)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Cookie
|
|
||||||
|
|
||||||
put_cookie (key, value: READABLE_STRING_8; expiration, path, domain: detachable READABLE_STRING_8; secure, http_only: BOOLEAN)
|
|
||||||
-- Set a cookie on the client's machine
|
|
||||||
-- with key 'key' and value 'value'.
|
|
||||||
-- Note: you should avoid using "localhost" as `domain' for local cookies
|
|
||||||
-- since they are not always handled by browser (for instance Chrome)
|
|
||||||
require
|
|
||||||
make_sense: (key /= Void and value /= Void) and then (not key.is_empty and not value.is_empty)
|
|
||||||
domain_without_port_info: domain /= Void implies domain.index_of (':', 1) = 0
|
|
||||||
local
|
|
||||||
s: STRING
|
|
||||||
do
|
|
||||||
s := {HTTP_HEADER_NAMES}.header_set_cookie + colon_space + key + "=" + value
|
|
||||||
if
|
|
||||||
domain /= Void and then not domain.same_string ("localhost")
|
|
||||||
then
|
|
||||||
s.append ("; Domain=")
|
|
||||||
s.append (domain)
|
|
||||||
end
|
|
||||||
if path /= Void then
|
|
||||||
s.append ("; Path=")
|
|
||||||
s.append (path)
|
|
||||||
end
|
|
||||||
if expiration /= Void then
|
|
||||||
s.append ("; Expires=")
|
|
||||||
s.append (expiration)
|
|
||||||
end
|
|
||||||
if secure then
|
|
||||||
s.append ("; Secure")
|
|
||||||
end
|
|
||||||
if http_only then
|
|
||||||
s.append ("; HttpOnly")
|
|
||||||
end
|
|
||||||
add_header (s)
|
|
||||||
end
|
|
||||||
|
|
||||||
put_cookie_with_expiration_date (key, value: READABLE_STRING_8; expiration: DATE_TIME; path, domain: detachable READABLE_STRING_8; secure, http_only: BOOLEAN)
|
|
||||||
-- 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)
|
|
||||||
do
|
|
||||||
put_cookie (key, value, date_to_rfc1123_http_date_format (expiration), path, domain, secure, http_only)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation: Header
|
|
||||||
|
|
||||||
has_same_header_name (h: READABLE_STRING_8; a_name: READABLE_STRING_8): BOOLEAN
|
|
||||||
-- Header line `h' has same name as `a_name' ?
|
|
||||||
do
|
|
||||||
if h.starts_with (a_name) then
|
|
||||||
if h.valid_index (a_name.count + 1) then
|
|
||||||
Result := h[a_name.count + 1] = ':'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
force_header_by_name (n: detachable READABLE_STRING_8; h: READABLE_STRING_8)
|
force_header_by_name (n: detachable READABLE_STRING_8; h: READABLE_STRING_8)
|
||||||
-- Add header `h' or replace existing header of same header name `n'
|
-- Add header `h' or replace existing header of same header name `n'
|
||||||
@@ -811,6 +331,27 @@ feature {NONE} -- Implementation: Header
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation: Header conversion
|
||||||
|
|
||||||
|
append_line_to (a_line: READABLE_STRING_8; h: STRING_8)
|
||||||
|
-- Append header line `a_line' to string `h'.
|
||||||
|
--| this is used to build the header text
|
||||||
|
require
|
||||||
|
not_ending_with_new_line: not a_line.ends_with_general ("%N")
|
||||||
|
do
|
||||||
|
h.append_string (a_line)
|
||||||
|
append_end_of_line_to (h)
|
||||||
|
end
|
||||||
|
|
||||||
|
append_end_of_line_to (h: STRING_8)
|
||||||
|
-- Append the CRLN end of header line to string `h'.
|
||||||
|
do
|
||||||
|
h.append_character ('%R')
|
||||||
|
h.append_character ('%N')
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation: Header queries
|
||||||
|
|
||||||
header_name_colon (h: READABLE_STRING_8): detachable STRING_8
|
header_name_colon (h: READABLE_STRING_8): detachable STRING_8
|
||||||
-- If any, header's name with colon
|
-- If any, header's name with colon
|
||||||
--| ex: for "Foo-bar: something", this will return "Foo-bar:"
|
--| ex: for "Foo-bar: something", this will return "Foo-bar:"
|
||||||
@@ -870,51 +411,6 @@ feature {NONE} -- Implementation: Header
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
|
||||||
|
|
||||||
append_line_to (s: READABLE_STRING_8; h: STRING_8)
|
|
||||||
do
|
|
||||||
h.append_string (s)
|
|
||||||
append_end_of_line_to (h)
|
|
||||||
end
|
|
||||||
|
|
||||||
append_end_of_line_to (h: STRING_8)
|
|
||||||
do
|
|
||||||
h.append_character ('%R')
|
|
||||||
h.append_character ('%N')
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
date_to_rfc1123_http_date_format (dt: DATE_TIME): STRING_8
|
|
||||||
-- String representation of `dt' using the RFC 1123
|
|
||||||
local
|
|
||||||
d: HTTP_DATE
|
|
||||||
do
|
|
||||||
create d.make_from_date_time (dt)
|
|
||||||
Result := d.string
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Constants
|
|
||||||
|
|
||||||
str_binary: STRING = "binary"
|
|
||||||
str_chunked: STRING = "chunked"
|
|
||||||
|
|
||||||
colon_space: IMMUTABLE_STRING_8
|
|
||||||
once
|
|
||||||
create Result.make_from_string (": ")
|
|
||||||
end
|
|
||||||
|
|
||||||
semi_colon_space: IMMUTABLE_STRING_8
|
|
||||||
once
|
|
||||||
create Result.make_from_string ("; ")
|
|
||||||
end
|
|
||||||
|
|
||||||
comma_space: IMMUTABLE_STRING_8
|
|
||||||
once
|
|
||||||
create Result.make_from_string (", ")
|
|
||||||
end
|
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
|||||||
667
library/network/protocol/http/src/http_header_modifier.e
Normal file
667
library/network/protocol/http/src/http_header_modifier.e
Normal file
@@ -0,0 +1,667 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
The class provides an easy way to build and modify HTTP header text
|
||||||
|
thanks to add_header (..) and put_header (..)
|
||||||
|
|
||||||
|
You will also find some helper features to help coding most common usages
|
||||||
|
|
||||||
|
Please, have a look at constants classes such as
|
||||||
|
HTTP_MIME_TYPES
|
||||||
|
HTTP_HEADER_NAMES
|
||||||
|
HTTP_STATUS_CODE
|
||||||
|
HTTP_REQUEST_METHODS
|
||||||
|
(or HTTP_CONSTANTS which groups them for convenience)
|
||||||
|
|
||||||
|
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$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
HTTP_HEADER_MODIFIER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ITERABLE [READABLE_STRING_8]
|
||||||
|
|
||||||
|
feature -- Access: deferred
|
||||||
|
|
||||||
|
new_cursor: INDEXABLE_ITERATION_CURSOR [READABLE_STRING_8]
|
||||||
|
-- Fresh cursor associated with current structure.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Header change: deferred
|
||||||
|
|
||||||
|
add_header (h: READABLE_STRING_8)
|
||||||
|
-- Add header `h'
|
||||||
|
-- if it already exists, there will be multiple header with same name
|
||||||
|
-- which can also be valid
|
||||||
|
require
|
||||||
|
h_not_empty: h /= Void and then not h.is_empty
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
put_header (h: READABLE_STRING_8)
|
||||||
|
-- Add header `h' or replace existing header of same header name
|
||||||
|
require
|
||||||
|
h_not_empty: h /= Void and then not h.is_empty
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
has, has_header_named (a_name: READABLE_STRING_8): BOOLEAN
|
||||||
|
-- Has header item for `n'?
|
||||||
|
local
|
||||||
|
ic: like new_cursor
|
||||||
|
do
|
||||||
|
from
|
||||||
|
ic := new_cursor
|
||||||
|
until
|
||||||
|
ic.after or Result
|
||||||
|
loop
|
||||||
|
Result := has_same_header_name (ic.item, a_name)
|
||||||
|
ic.forth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
has_content_length: BOOLEAN
|
||||||
|
-- Has header "Content-Length"
|
||||||
|
do
|
||||||
|
Result := has_header_named ({HTTP_HEADER_NAMES}.header_content_length)
|
||||||
|
end
|
||||||
|
|
||||||
|
has_content_type: BOOLEAN
|
||||||
|
-- Has header "Content-Type"
|
||||||
|
do
|
||||||
|
Result := has_header_named ({HTTP_HEADER_NAMES}.header_content_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
has_transfer_encoding_chunked: BOOLEAN
|
||||||
|
-- Has "Transfer-Encoding: chunked" header
|
||||||
|
do
|
||||||
|
if has_header_named ({HTTP_HEADER_NAMES}.header_transfer_encoding) then
|
||||||
|
Result := attached item ({HTTP_HEADER_NAMES}.header_transfer_encoding) as v and then v.same_string (str_chunked)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
item alias "[]" (a_header_name: READABLE_STRING_8): detachable READABLE_STRING_8 assign force
|
||||||
|
-- First header item found for `a_name' if any
|
||||||
|
local
|
||||||
|
res: STRING_8
|
||||||
|
n: INTEGER
|
||||||
|
l_line: READABLE_STRING_8
|
||||||
|
ic: like new_cursor
|
||||||
|
do
|
||||||
|
n := a_header_name.count
|
||||||
|
|
||||||
|
from
|
||||||
|
ic := new_cursor
|
||||||
|
until
|
||||||
|
ic.after or Result /= Void
|
||||||
|
loop
|
||||||
|
l_line := ic.item
|
||||||
|
if has_same_header_name (l_line, a_header_name) then
|
||||||
|
res := l_line.substring (n + 2, l_line.count)
|
||||||
|
res.left_adjust
|
||||||
|
res.right_adjust
|
||||||
|
Result := res
|
||||||
|
end
|
||||||
|
ic.forth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
header_named_value (a_name: READABLE_STRING_8): like item
|
||||||
|
-- First header item found for `a_name' if any
|
||||||
|
obsolete
|
||||||
|
"Use `item' [2014-03]"
|
||||||
|
do
|
||||||
|
Result := item (a_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Header change: general
|
||||||
|
|
||||||
|
force (a_value: detachable READABLE_STRING_8; a_header_name: READABLE_STRING_8)
|
||||||
|
-- Put header `a_header_name:a_value' or replace existing header of name `a_header_name'.
|
||||||
|
--| this is used as assigner for `item'
|
||||||
|
do
|
||||||
|
if a_value = Void then
|
||||||
|
put_header_key_value (a_header_name, "")
|
||||||
|
else
|
||||||
|
put_header_key_value (a_header_name, a_value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
add_header_key_value (a_header_name, a_value: READABLE_STRING_8)
|
||||||
|
-- Add header `a_header_name:a_value'.
|
||||||
|
-- If it already exists, there will be multiple header with same name
|
||||||
|
-- which can also be valid
|
||||||
|
local
|
||||||
|
s: STRING_8
|
||||||
|
do
|
||||||
|
create s.make (a_header_name.count + 2 + a_value.count)
|
||||||
|
s.append (a_header_name)
|
||||||
|
s.append (colon_space)
|
||||||
|
s.append (a_value)
|
||||||
|
add_header (s)
|
||||||
|
ensure
|
||||||
|
added: has_header_named (a_header_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_header_key_value (a_header_name, a_value: READABLE_STRING_8)
|
||||||
|
-- Add header `a_header_name:a_value', or replace existing header of same header name/key
|
||||||
|
local
|
||||||
|
s: STRING_8
|
||||||
|
do
|
||||||
|
create s.make (a_header_name.count + 2 + a_value.count)
|
||||||
|
s.append (a_header_name)
|
||||||
|
s.append (colon_space)
|
||||||
|
s.append (a_value)
|
||||||
|
put_header (s)
|
||||||
|
ensure
|
||||||
|
added: has_header_named (a_header_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_header_key_values (a_header_name: READABLE_STRING_8; a_values: ITERABLE [READABLE_STRING_8]; a_separator: detachable READABLE_STRING_8)
|
||||||
|
-- Add header `a_header_name: a_values', or replace existing header of same header values/key.
|
||||||
|
-- Use `comma_space' as default separator if `a_separator' is Void or empty.
|
||||||
|
local
|
||||||
|
s: STRING_8
|
||||||
|
l_separator: READABLE_STRING_8
|
||||||
|
do
|
||||||
|
if a_separator /= Void and then not a_separator.is_empty then
|
||||||
|
l_separator := a_separator
|
||||||
|
else
|
||||||
|
l_separator := comma_space
|
||||||
|
end
|
||||||
|
create s.make_empty
|
||||||
|
across
|
||||||
|
a_values as c
|
||||||
|
loop
|
||||||
|
if not s.is_empty then
|
||||||
|
s.append_string (l_separator)
|
||||||
|
end
|
||||||
|
s.append (c.item)
|
||||||
|
end
|
||||||
|
if not s.is_empty then
|
||||||
|
put_header_key_value (a_header_name, s)
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
added: has_header_named (a_header_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Content related header
|
||||||
|
|
||||||
|
put_content_type (a_content_type: READABLE_STRING_8)
|
||||||
|
-- Put header line "Content-Type:" + type `a_content_type'
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, a_content_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
add_content_type (a_content_type: READABLE_STRING_8)
|
||||||
|
-- same as `put_content_type', but allow multiple definition of "Content-Type"
|
||||||
|
do
|
||||||
|
add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, a_content_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_content_type_with_parameters (a_content_type: READABLE_STRING_8; a_params: detachable ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
|
||||||
|
-- Put header line "Content-Type:" + type `a_content_type' and extra paramaters `a_params'
|
||||||
|
--| note: see `put_content_type_with_charset' for examples.
|
||||||
|
local
|
||||||
|
s: STRING_8
|
||||||
|
do
|
||||||
|
if a_params /= Void and then not a_params.is_empty then
|
||||||
|
create s.make_from_string (a_content_type)
|
||||||
|
across
|
||||||
|
a_params as p
|
||||||
|
loop
|
||||||
|
if attached p.item as nv then
|
||||||
|
s.append_character (';')
|
||||||
|
s.append_character (' ')
|
||||||
|
s.append (nv.name)
|
||||||
|
s.append_character ('=')
|
||||||
|
s.append_character ('%"')
|
||||||
|
s.append (nv.value)
|
||||||
|
s.append_character ('%"')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, s)
|
||||||
|
else
|
||||||
|
put_content_type (a_content_type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
add_content_type_with_parameters (a_content_type: READABLE_STRING_8; a_params: detachable ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
|
||||||
|
-- Add header line "Content-Type:" + type `a_content_type' and extra paramaters `a_params'.
|
||||||
|
--| note: see `put_content_type_with_charset' for examples.
|
||||||
|
local
|
||||||
|
s: STRING_8
|
||||||
|
do
|
||||||
|
if a_params /= Void and then not a_params.is_empty then
|
||||||
|
create s.make_from_string (a_content_type)
|
||||||
|
across
|
||||||
|
a_params as p
|
||||||
|
loop
|
||||||
|
if attached p.item as nv then
|
||||||
|
s.append_character (';')
|
||||||
|
s.append_character (' ')
|
||||||
|
s.append (nv.name)
|
||||||
|
s.append_character ('=')
|
||||||
|
s.append_character ('%"')
|
||||||
|
s.append (nv.value)
|
||||||
|
s.append_character ('%"')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, s)
|
||||||
|
else
|
||||||
|
add_content_type (a_content_type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
put_content_type_with_charset (a_content_type: READABLE_STRING_8; a_charset: READABLE_STRING_8)
|
||||||
|
-- Put content type `a_content_type' with `a_charset' as "charset" parameter.
|
||||||
|
do
|
||||||
|
put_content_type_with_parameters (a_content_type, <<["charset", a_charset]>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
add_content_type_with_charset (a_content_type: READABLE_STRING_8; a_charset: READABLE_STRING_8)
|
||||||
|
-- Same as `put_content_type_with_charset', but allow multiple definition of "Content-Type".
|
||||||
|
do
|
||||||
|
add_content_type_with_parameters (a_content_type, <<["charset", a_charset]>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_content_type_with_name (a_content_type: READABLE_STRING_8; a_name: READABLE_STRING_8)
|
||||||
|
-- Put content type `a_content_type' with `a_name' as "name" parameter.
|
||||||
|
do
|
||||||
|
put_content_type_with_parameters (a_content_type, <<["name", a_name]>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
add_content_type_with_name (a_content_type: READABLE_STRING_8; a_name: READABLE_STRING_8)
|
||||||
|
-- same as `put_content_type_with_name', but allow multiple definition of "Content-Type"
|
||||||
|
do
|
||||||
|
add_content_type_with_parameters (a_content_type, <<["name", a_name]>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_content_length (a_length: INTEGER)
|
||||||
|
-- Put "Content-Length:" + length `a_length'.
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_length, a_length.out)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_content_transfer_encoding (a_mechanism: READABLE_STRING_8)
|
||||||
|
-- Put "Content-Transfer-Encoding" header with `a_mechanism'
|
||||||
|
--| encoding := "Content-Transfer-Encoding" ":" mechanism
|
||||||
|
--|
|
||||||
|
--| mechanism := "7bit" ; case-insensitive
|
||||||
|
--| / "quoted-printable"
|
||||||
|
--| / "base64"
|
||||||
|
--| / "8bit"
|
||||||
|
--| / "binary"
|
||||||
|
--| / x-token
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_transfer_encoding, a_mechanism)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_content_language (a_lang: READABLE_STRING_8)
|
||||||
|
-- Put "Content-Language" header of value `a_lang'.
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_language, a_lang)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_content_encoding (a_encoding: READABLE_STRING_8)
|
||||||
|
-- Put "Content-Encoding" header of value `a_encoding'.
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_encoding, a_encoding)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_transfer_encoding (a_encoding: READABLE_STRING_8)
|
||||||
|
-- Put "Transfer-Encoding" header with `a_encoding' value.
|
||||||
|
--| for instance "chunked"
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_transfer_encoding, a_encoding)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_transfer_encoding_binary
|
||||||
|
-- Put "Transfer-Encoding: binary" header
|
||||||
|
do
|
||||||
|
put_transfer_encoding (str_binary)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_transfer_encoding_chunked
|
||||||
|
-- Put "Transfer-Encoding: chunked" header
|
||||||
|
do
|
||||||
|
put_transfer_encoding (str_chunked)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_content_disposition (a_type: READABLE_STRING_8; a_params: detachable READABLE_STRING_8)
|
||||||
|
-- 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 ({HTTP_HEADER_NAMES}.header_content_disposition, a_type + semi_colon_space + a_params)
|
||||||
|
else
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_disposition, a_type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Content-type helpers
|
||||||
|
|
||||||
|
put_content_type_text_css do put_content_type ({HTTP_MIME_TYPES}.text_css) end
|
||||||
|
put_content_type_text_csv do put_content_type ({HTTP_MIME_TYPES}.text_csv) end
|
||||||
|
put_content_type_text_html do put_content_type ({HTTP_MIME_TYPES}.text_html) end
|
||||||
|
put_content_type_text_javascript do put_content_type ({HTTP_MIME_TYPES}.text_javascript) end
|
||||||
|
put_content_type_text_json do put_content_type ({HTTP_MIME_TYPES}.text_json) end
|
||||||
|
put_content_type_text_plain do put_content_type ({HTTP_MIME_TYPES}.text_plain) end
|
||||||
|
put_content_type_text_xml do put_content_type ({HTTP_MIME_TYPES}.text_xml) end
|
||||||
|
|
||||||
|
put_content_type_application_json do put_content_type ({HTTP_MIME_TYPES}.application_json) end
|
||||||
|
put_content_type_application_javascript do put_content_type ({HTTP_MIME_TYPES}.application_javascript) end
|
||||||
|
put_content_type_application_zip do put_content_type ({HTTP_MIME_TYPES}.application_zip) end
|
||||||
|
put_content_type_application_pdf do put_content_type ({HTTP_MIME_TYPES}.application_pdf) end
|
||||||
|
|
||||||
|
put_content_type_image_gif do put_content_type ({HTTP_MIME_TYPES}.image_gif) end
|
||||||
|
put_content_type_image_png do put_content_type ({HTTP_MIME_TYPES}.image_png) end
|
||||||
|
put_content_type_image_jpg do put_content_type ({HTTP_MIME_TYPES}.image_jpg) end
|
||||||
|
put_content_type_image_svg_xml do put_content_type ({HTTP_MIME_TYPES}.image_svg_xml) end
|
||||||
|
|
||||||
|
put_content_type_message_http do put_content_type ({HTTP_MIME_TYPES}.message_http) end
|
||||||
|
|
||||||
|
put_content_type_multipart_mixed do put_content_type ({HTTP_MIME_TYPES}.multipart_mixed) end
|
||||||
|
put_content_type_multipart_alternative do put_content_type ({HTTP_MIME_TYPES}.multipart_alternative) end
|
||||||
|
put_content_type_multipart_related do put_content_type ({HTTP_MIME_TYPES}.multipart_related) end
|
||||||
|
put_content_type_multipart_form_data do put_content_type ({HTTP_MIME_TYPES}.multipart_form_data) end
|
||||||
|
put_content_type_multipart_signed do put_content_type ({HTTP_MIME_TYPES}.multipart_signed) end
|
||||||
|
put_content_type_multipart_encrypted do put_content_type ({HTTP_MIME_TYPES}.multipart_encrypted) end
|
||||||
|
put_content_type_application_x_www_form_encoded do put_content_type ({HTTP_MIME_TYPES}.application_x_www_form_encoded) end
|
||||||
|
|
||||||
|
put_content_type_utf_8_text_plain do put_content_type_with_charset ({HTTP_MIME_TYPES}.text_plain, "utf-8") end
|
||||||
|
|
||||||
|
feature -- Cross-Origin Resource Sharing
|
||||||
|
|
||||||
|
put_access_control_allow_origin (a_origin: READABLE_STRING_8)
|
||||||
|
-- Put "Access-Control-Allow-Origin: " + `a_origin' header.
|
||||||
|
-- `a_origin' specifies a URI that may access the resource
|
||||||
|
--| for instance "http://example.com"
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_origin, a_origin)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_access_control_allow_all_origin
|
||||||
|
-- Put "Access-Control-Allow-Origin: *" header.
|
||||||
|
do
|
||||||
|
put_access_control_allow_origin ("*")
|
||||||
|
end
|
||||||
|
|
||||||
|
put_access_control_allow_credentials (b: BOOLEAN)
|
||||||
|
-- Indicates whether or not the response to the request can be exposed when the credentials flag is true.
|
||||||
|
-- When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials.
|
||||||
|
-- Note that simple GET requests are not preflighted, and so if a request is made for a resource with credentials,
|
||||||
|
-- if this header is not returned with the resource, the response is ignored by the browser and not returned to web content.
|
||||||
|
-- ex: Access-Control-Allow-Credentials: true | false
|
||||||
|
do
|
||||||
|
if b then
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_Credentials, "true")
|
||||||
|
else
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_Credentials, "false")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
put_access_control_allow_methods (a_methods: ITERABLE [READABLE_STRING_8])
|
||||||
|
-- If `a_methods' is not empty, put `Access-Control-Allow-Methods' header with list `a_methods' of methods
|
||||||
|
-- `a_methods' specifies the method or methods allowed when accessing the resource.
|
||||||
|
-- This is used in response to a preflight request.
|
||||||
|
-- ex: Access-Control-Allow-Methods: <method>[, <method>]*
|
||||||
|
do
|
||||||
|
put_header_key_values ({HTTP_HEADER_NAMES}.header_access_control_allow_methods, a_methods, Void)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_access_control_allow_headers (a_headers: READABLE_STRING_8)
|
||||||
|
-- Put "Access-Control-Allow-Headers" header. with value `a_headers'
|
||||||
|
-- Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.
|
||||||
|
-- ex: Access-Control-Allow-Headers: <field-name>[, <field-name>]*
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_headers, a_headers)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_access_control_allow_iterable_headers (a_fields: ITERABLE [READABLE_STRING_8])
|
||||||
|
-- Put "Access-Control-Allow-Headers" header. with value `a_headers'
|
||||||
|
-- Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.
|
||||||
|
-- ex: Access-Control-Allow-Headers: <field-name>[, <field-name>]*
|
||||||
|
do
|
||||||
|
put_header_key_values ({HTTP_HEADER_NAMES}.header_access_control_allow_headers, a_fields, Void)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Method related
|
||||||
|
|
||||||
|
put_allow (a_methods: ITERABLE [READABLE_STRING_8])
|
||||||
|
-- If `a_methods' is not empty, put `Allow' header with list `a_methods' of methods
|
||||||
|
do
|
||||||
|
put_header_key_values ({HTTP_HEADER_NAMES}.header_allow, a_methods, Void)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Date
|
||||||
|
|
||||||
|
put_date (a_date: READABLE_STRING_8)
|
||||||
|
-- Put "Date: " header
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_date, a_date)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_current_date
|
||||||
|
-- Put current date time with "Date" header
|
||||||
|
do
|
||||||
|
put_utc_date (create {DATE_TIME}.make_now_utc)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_utc_date (a_utc_date: DATE_TIME)
|
||||||
|
-- Put UTC date time `a_utc_date' with "Date" header
|
||||||
|
-- using RFC1123 date formating.
|
||||||
|
do
|
||||||
|
put_date (date_to_rfc1123_http_date_format (a_utc_date))
|
||||||
|
end
|
||||||
|
|
||||||
|
put_last_modified (a_utc_date: DATE_TIME)
|
||||||
|
-- Put UTC date time `dt' with "Last-Modified" header
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_last_modified, date_to_rfc1123_http_date_format (a_utc_date))
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Authorization
|
||||||
|
|
||||||
|
put_authorization (a_authorization: READABLE_STRING_8)
|
||||||
|
-- Put `a_authorization' with "Authorization" header
|
||||||
|
-- The Authorization header is constructed as follows:
|
||||||
|
-- 1. Username and password are combined into a string "username:password".
|
||||||
|
-- 2. The resulting string literal is then encoded using Base64.
|
||||||
|
-- 3. The authorization method and a space, i.e. "Basic " is then put before the encoded string.
|
||||||
|
-- ex: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_authorization, a_authorization)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Others
|
||||||
|
|
||||||
|
put_expires (a_seconds: INTEGER)
|
||||||
|
-- Put "Expires" header to `a_seconds' seconds
|
||||||
|
do
|
||||||
|
put_expires_string (a_seconds.out)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_expires_string (a_expires: STRING)
|
||||||
|
-- Put "Expires" header with `a_expires' string value
|
||||||
|
do
|
||||||
|
put_header_key_value ("Expires", a_expires)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_expires_date (a_utc_date: DATE_TIME)
|
||||||
|
-- Put "Expires" header with UTC date time value
|
||||||
|
-- formatted following RFC1123 specification.
|
||||||
|
do
|
||||||
|
put_header_key_value ("Expires", date_to_rfc1123_http_date_format (a_utc_date))
|
||||||
|
end
|
||||||
|
|
||||||
|
put_cache_control (a_cache_control: READABLE_STRING_8)
|
||||||
|
-- Put "Cache-Control" header with value `a_cache_control'
|
||||||
|
--| note: ex "Cache-Control: no-cache, must-revalidate"
|
||||||
|
do
|
||||||
|
put_header_key_value ("Cache-Control", a_cache_control)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_pragma (a_pragma: READABLE_STRING_8)
|
||||||
|
-- Put "Pragma" header with value `a_pragma'
|
||||||
|
do
|
||||||
|
put_header_key_value ("Pragma", a_pragma)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_pragma_no_cache
|
||||||
|
-- Put "Pragma" header with "no-cache" a_pragma
|
||||||
|
do
|
||||||
|
put_pragma ("no-cache")
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Redirection
|
||||||
|
|
||||||
|
put_location (a_uri: READABLE_STRING_8)
|
||||||
|
-- Tell the client the new location `a_uri'
|
||||||
|
-- using "Location" header.
|
||||||
|
require
|
||||||
|
a_uri_valid: not a_uri.is_empty
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_location, a_uri)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_refresh (a_uri: READABLE_STRING_8; a_timeout_in_seconds: INTEGER)
|
||||||
|
-- Tell the client to refresh page with `a_uri' after `a_timeout_in_seconds' in seconds
|
||||||
|
-- using "Refresh" header.
|
||||||
|
require
|
||||||
|
a_uri_valid: not a_uri.is_empty
|
||||||
|
do
|
||||||
|
put_header_key_value ({HTTP_HEADER_NAMES}.header_refresh, a_timeout_in_seconds.out + "; url=" + a_uri)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Cookie
|
||||||
|
|
||||||
|
put_cookie (key, value: READABLE_STRING_8; expiration, path, domain: detachable READABLE_STRING_8; secure, http_only: BOOLEAN)
|
||||||
|
-- Set a cookie on the client's machine
|
||||||
|
-- with key 'key' and value 'value'.
|
||||||
|
-- Note: you should avoid using "localhost" as `domain' for local cookies
|
||||||
|
-- since they are not always handled by browser (for instance Chrome)
|
||||||
|
require
|
||||||
|
make_sense: (key /= Void and value /= Void) and then (not key.is_empty and not value.is_empty)
|
||||||
|
domain_without_port_info: domain /= Void implies domain.index_of (':', 1) = 0
|
||||||
|
local
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s := {HTTP_HEADER_NAMES}.header_set_cookie + colon_space + key + "=" + value
|
||||||
|
if
|
||||||
|
domain /= Void and then not domain.same_string ("localhost")
|
||||||
|
then
|
||||||
|
s.append ("; Domain=")
|
||||||
|
s.append (domain)
|
||||||
|
end
|
||||||
|
if path /= Void then
|
||||||
|
s.append ("; Path=")
|
||||||
|
s.append (path)
|
||||||
|
end
|
||||||
|
if expiration /= Void then
|
||||||
|
s.append ("; Expires=")
|
||||||
|
s.append (expiration)
|
||||||
|
end
|
||||||
|
if secure then
|
||||||
|
s.append ("; Secure")
|
||||||
|
end
|
||||||
|
if http_only then
|
||||||
|
s.append ("; HttpOnly")
|
||||||
|
end
|
||||||
|
add_header (s)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_cookie_with_expiration_date (key, value: READABLE_STRING_8; expiration: DATE_TIME; path, domain: detachable READABLE_STRING_8; secure, http_only: BOOLEAN)
|
||||||
|
-- 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)
|
||||||
|
do
|
||||||
|
put_cookie (key, value, date_to_rfc1123_http_date_format (expiration), path, domain, secure, http_only)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
date_to_rfc1123_http_date_format (dt: DATE_TIME): STRING_8
|
||||||
|
-- String representation of `dt' using the RFC 1123
|
||||||
|
local
|
||||||
|
d: HTTP_DATE
|
||||||
|
do
|
||||||
|
create d.make_from_date_time (dt)
|
||||||
|
Result := d.string
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
has_same_header_name (h: READABLE_STRING_8; a_name: READABLE_STRING_8): BOOLEAN
|
||||||
|
-- Header line `h' has same name as `a_name' ?
|
||||||
|
do
|
||||||
|
if h.starts_with (a_name) then
|
||||||
|
if h.valid_index (a_name.count + 1) then
|
||||||
|
Result := h[a_name.count + 1] = ':'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Constants
|
||||||
|
|
||||||
|
str_binary: STRING = "binary"
|
||||||
|
str_chunked: STRING = "chunked"
|
||||||
|
|
||||||
|
colon_space: IMMUTABLE_STRING_8
|
||||||
|
once
|
||||||
|
create Result.make_from_string (": ")
|
||||||
|
end
|
||||||
|
|
||||||
|
semi_colon_space: IMMUTABLE_STRING_8
|
||||||
|
once
|
||||||
|
create Result.make_from_string ("; ")
|
||||||
|
end
|
||||||
|
|
||||||
|
comma_space: IMMUTABLE_STRING_8
|
||||||
|
once
|
||||||
|
create Result.make_from_string (", ")
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2014, Jocelyn Fiat, 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
|
||||||
@@ -199,17 +199,26 @@ feature -- Cross-Origin Resource Sharing
|
|||||||
header_access_control_allow_origin: STRING = "Access-Control-Allow-Origin"
|
header_access_control_allow_origin: STRING = "Access-Control-Allow-Origin"
|
||||||
-- Indicates whether a resource can be shared based by returning
|
-- Indicates whether a resource can be shared based by returning
|
||||||
-- the value of the Origin request header in the response.
|
-- the value of the Origin request header in the response.
|
||||||
-- | Example: Access-Control-Allow-Origin: http://example.org
|
--| Example: Access-Control-Allow-Origin: http://example.org
|
||||||
|
|
||||||
|
header_access_control_allow_credentials: STRING = "Access-Control-Allow-Credentials"
|
||||||
|
-- Indicates whether or not the response to the request can be exposed when the credentials flag is true.
|
||||||
|
-- When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials.
|
||||||
|
-- Note that simple GET requests are not preflighted, and so if a request is made for a resource with credentials,
|
||||||
|
-- if this header is not returned with the resource, the response is ignored by the browser and not returned to web content.
|
||||||
|
--| Access-Control-Allow-Credentials: true | false
|
||||||
|
|
||||||
header_access_control_allow_methods: STRING = "Access-Control-Allow-Methods"
|
header_access_control_allow_methods: STRING = "Access-Control-Allow-Methods"
|
||||||
-- Indicates, as part of the response to a preflight request,
|
-- Indicates, as part of the response to a preflight request,
|
||||||
-- which methods can be used during the actual request.
|
-- which methods can be used during the actual request.
|
||||||
-- | Example: Access-Control-Allow-Methods: PUT, DELETE
|
--| Access-Control-Allow-Methods: <method>[, <method>]*
|
||||||
|
--| Example: Access-Control-Allow-Methods: PUT, DELETE
|
||||||
|
|
||||||
header_access_control_allow_headers: STRING = "Access-Control-Allow-Headers"
|
header_access_control_allow_headers: STRING = "Access-Control-Allow-Headers"
|
||||||
-- Indicates, as part of the response to a preflight request,
|
-- Indicates, as part of the response to a preflight request,
|
||||||
-- which header field names can be used during the actual request.
|
-- which header field names can be used during the actual request.
|
||||||
-- | Example: Access-Control-Allow-Headers: Authorization
|
--| Access-Control-Allow-Headers: <field-name>[, <field-name>]*
|
||||||
|
--| Example: Access-Control-Allow-Headers: Authorization
|
||||||
|
|
||||||
feature -- Request or Response header name
|
feature -- Request or Response header name
|
||||||
|
|
||||||
@@ -265,7 +274,7 @@ feature -- MIME related
|
|||||||
header_content_transfer_encoding: STRING = "Content-Transfer-Encoding"
|
header_content_transfer_encoding: STRING = "Content-Transfer-Encoding"
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -376,10 +376,11 @@ feature -- Error reporting
|
|||||||
local
|
local
|
||||||
h: HTTP_HEADER
|
h: HTTP_HEADER
|
||||||
m: READABLE_STRING_8
|
m: READABLE_STRING_8
|
||||||
|
utf: UTF_CONVERTER
|
||||||
do
|
do
|
||||||
m := req.error_handler.as_string_representation
|
m := utf.string_32_to_utf_8_string_8 (req.error_handler.as_string_representation)
|
||||||
create h.make
|
create h.make
|
||||||
h.put_content_type_text_plain
|
h.put_content_type_utf_8_text_plain
|
||||||
h.put_content_length (m.count)
|
h.put_content_length (m.count)
|
||||||
res.set_status_code (req.error_handler.primary_error_code)
|
res.set_status_code (req.error_handler.primary_error_code)
|
||||||
res.put_header_lines (h)
|
res.put_header_lines (h)
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ feature {WSF_RESPONSE} -- Output
|
|||||||
local
|
local
|
||||||
h: HTTP_HEADER
|
h: HTTP_HEADER
|
||||||
l_description: STRING_8
|
l_description: STRING_8
|
||||||
l_base_url: STRING_8
|
l_base_url: READABLE_STRING_8
|
||||||
l_api_resource: detachable STRING_8
|
l_api_resource: detachable READABLE_STRING_8
|
||||||
do
|
do
|
||||||
create h.make
|
create h.make
|
||||||
h.put_content_type_text_html
|
h.put_content_type_text_html
|
||||||
@@ -132,7 +132,7 @@ feature {WSF_RESPONSE} -- Output
|
|||||||
if attached router.base_url as u then
|
if attached router.base_url as u then
|
||||||
l_base_url := u
|
l_base_url := u
|
||||||
else
|
else
|
||||||
create l_base_url.make_empty
|
create {STRING_8} l_base_url.make_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
debug
|
debug
|
||||||
@@ -324,7 +324,7 @@ feature {NONE} -- Implementation
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ note
|
|||||||
Entry of WSF_ROUTER
|
Entry of WSF_ROUTER
|
||||||
It contains
|
It contains
|
||||||
- mapping
|
- mapping
|
||||||
- request methods
|
- request methods
|
||||||
|
|
||||||
]"
|
]"
|
||||||
date: "$Date$"
|
date: "$Date$"
|
||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
@@ -40,20 +40,23 @@ feature -- Access
|
|||||||
|
|
||||||
feature -- Status report
|
feature -- Status report
|
||||||
|
|
||||||
debug_output: STRING
|
debug_output: READABLE_STRING_GENERAL
|
||||||
-- String that should be displayed in debugger to represent `Current'.
|
-- String that should be displayed in debugger to represent `Current'.
|
||||||
|
local
|
||||||
|
s: STRING_32
|
||||||
do
|
do
|
||||||
create Result.make_from_string (mapping.debug_output)
|
create s.make_from_string_general (mapping.debug_output)
|
||||||
if attached request_methods as mtds then
|
if attached request_methods as mtds then
|
||||||
Result.append_string (" [ ")
|
s.append_string (" [ ")
|
||||||
across
|
across
|
||||||
mtds as c
|
mtds as c
|
||||||
loop
|
loop
|
||||||
Result.append_string (c.item)
|
s.append_string (c.item)
|
||||||
Result.append_string (" ")
|
s.append_string (" ")
|
||||||
end
|
end
|
||||||
Result.append_string ("]")
|
s.append_string ("]")
|
||||||
end
|
end
|
||||||
|
Result := s
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Change
|
feature -- Change
|
||||||
@@ -68,7 +71,7 @@ invariant
|
|||||||
mapping_attached: mapping /= Void
|
mapping_attached: mapping /= Void
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ feature -- Documentation
|
|||||||
|
|
||||||
feature -- Status report
|
feature -- Status report
|
||||||
|
|
||||||
debug_output: STRING
|
debug_output: READABLE_STRING_GENERAL
|
||||||
-- String that should be displayed in debugger to represent `Current'.
|
-- String that should be displayed in debugger to represent `Current'.
|
||||||
do
|
do
|
||||||
Result := description.as_string_8 + " : " + associated_resource
|
Result := description + {STRING_32} " : " + associated_resource.to_string_32
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Status
|
feature -- Status
|
||||||
@@ -88,7 +88,7 @@ feature -- Helper
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -45,14 +45,14 @@ feature {NONE} -- Execution
|
|||||||
|
|
||||||
feature -- Status report
|
feature -- Status report
|
||||||
|
|
||||||
debug_output: STRING
|
debug_output: READABLE_STRING_GENERAL
|
||||||
-- String that should be displayed in debugger to represent `Current'.
|
-- String that should be displayed in debugger to represent `Current'.
|
||||||
do
|
do
|
||||||
Result := Precursor + " {" + ({C}).name + "}"
|
Result := Precursor + " {" + ({C}).name + "}"
|
||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ feature -- Access
|
|||||||
|
|
||||||
feature -- Status report
|
feature -- Status report
|
||||||
|
|
||||||
debug_output: STRING
|
debug_output: READABLE_STRING_GENERAL
|
||||||
-- String that should be displayed in debugger to represent `Current'.
|
-- String that should be displayed in debugger to represent `Current'.
|
||||||
do
|
do
|
||||||
Result := Precursor + " {" + ({C}).name + "}"
|
Result := Precursor + " {" + ({C}).name + "}"
|
||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -60,15 +60,16 @@ feature {NONE} -- Initialization
|
|||||||
|
|
||||||
feature -- Cookie
|
feature -- Cookie
|
||||||
|
|
||||||
apply_to (h: HTTP_HEADER; a_request: WSF_REQUEST; a_path: detachable READABLE_STRING_8)
|
apply_to (h: HTTP_HEADER_MODIFIER; a_request: WSF_REQUEST; a_path: detachable READABLE_STRING_8)
|
||||||
|
-- <Precursor>
|
||||||
local
|
local
|
||||||
dt: detachable DATE_TIME
|
dt: detachable DATE_TIME
|
||||||
l_domain: detachable READABLE_STRING_8
|
l_domain: detachable READABLE_STRING_8
|
||||||
do
|
do
|
||||||
l_domain := a_request.server_name
|
l_domain := a_request.server_name
|
||||||
if l_domain.same_string ("localhost") then
|
if l_domain.same_string ("localhost") then
|
||||||
-- Due to limitation of specific handling of local cookies
|
-- Due to limitation of specific handling of local cookies
|
||||||
-- it is recommended to use Void or IP instead of "localhost"
|
-- it is recommended to use Void or IP instead of "localhost"
|
||||||
l_domain := Void
|
l_domain := Void
|
||||||
end
|
end
|
||||||
if is_destroyed then
|
if is_destroyed then
|
||||||
@@ -79,13 +80,18 @@ feature -- Cookie
|
|||||||
create dt.make_now_utc
|
create dt.make_now_utc
|
||||||
dt.day_add (40)
|
dt.day_add (40)
|
||||||
end
|
end
|
||||||
h.put_cookie_with_expiration_date (cookie_name, uuid, dt, a_path, l_domain, False, True)
|
h.put_cookie_with_expiration_date (cookie_name, id, dt, a_path, l_domain, False, True)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
cookie_name: READABLE_STRING_8
|
cookie_name: READABLE_STRING_8
|
||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
|
id: READABLE_STRING_8
|
||||||
|
do
|
||||||
|
Result := uuid
|
||||||
|
end
|
||||||
|
|
||||||
uuid: READABLE_STRING_8
|
uuid: READABLE_STRING_8
|
||||||
|
|
||||||
@@ -135,8 +141,8 @@ feature {NONE} -- Storage
|
|||||||
|
|
||||||
load
|
load
|
||||||
do
|
do
|
||||||
if manager.session_exists (uuid) then
|
if manager.session_exists (id) then
|
||||||
if attached manager.session_data (uuid) as d then
|
if attached manager.session_data (id) as d then
|
||||||
data := d
|
data := d
|
||||||
set_expiration (data.expiration)
|
set_expiration (data.expiration)
|
||||||
else
|
else
|
||||||
@@ -177,7 +183,7 @@ feature {NONE} -- Implementation
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ feature -- Persistence
|
|||||||
delete_session (a_session)
|
delete_session (a_session)
|
||||||
else
|
else
|
||||||
ensure_session_folder_exists
|
ensure_session_folder_exists
|
||||||
create f.make_with_path (file_name (a_session.uuid))
|
create f.make_with_path (file_name (a_session.id))
|
||||||
if not f.exists or else f.is_writable then
|
if not f.exists or else f.is_writable then
|
||||||
f.create_read_write
|
f.create_read_write
|
||||||
a_session.data.set_expiration (a_session.expiration)
|
a_session.data.set_expiration (a_session.expiration)
|
||||||
@@ -91,7 +91,7 @@ feature -- Persistence
|
|||||||
rescued: BOOLEAN
|
rescued: BOOLEAN
|
||||||
do
|
do
|
||||||
if not rescued then
|
if not rescued then
|
||||||
create f.make_with_path (file_name (a_session.uuid))
|
create f.make_with_path (file_name (a_session.id))
|
||||||
if f.exists then
|
if f.exists then
|
||||||
f.delete
|
f.delete
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,26 +7,43 @@ note
|
|||||||
deferred class
|
deferred class
|
||||||
WSF_SESSION
|
WSF_SESSION
|
||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
|
id: READABLE_STRING_8
|
||||||
|
-- Session identifier.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
uuid: READABLE_STRING_8
|
uuid: READABLE_STRING_8
|
||||||
|
obsolete
|
||||||
|
"Use `id' which is more general [2014-03]"
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
data: WSF_SESSION_DATA
|
data: WSF_SESSION_DATA
|
||||||
|
-- Data associated with current session.
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
expiration: detachable DATE_TIME
|
expiration: detachable DATE_TIME
|
||||||
|
-- Expiration date for current session, if any.
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
expired: BOOLEAN
|
expired: BOOLEAN
|
||||||
|
-- Is current session expired now?
|
||||||
|
do
|
||||||
|
Result := expired_at (create {DATE_TIME}.make_now_utc)
|
||||||
|
end
|
||||||
|
|
||||||
|
expired_at (dt: DATE_TIME): BOOLEAN
|
||||||
|
-- Is current session expired at date and time `dt'?
|
||||||
do
|
do
|
||||||
if attached expiration as e then
|
if attached expiration as e then
|
||||||
Result := e < (create {DATE_TIME}.make_now_utc)
|
Result := e < (dt)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- status
|
feature -- status
|
||||||
|
|
||||||
is_pending: BOOLEAN
|
is_pending: BOOLEAN
|
||||||
@@ -36,27 +53,32 @@ feature -- status
|
|||||||
end
|
end
|
||||||
|
|
||||||
is_destroyed: BOOLEAN
|
is_destroyed: BOOLEAN
|
||||||
|
-- Is current session in destroyed state?
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Entries
|
feature -- Entries
|
||||||
|
|
||||||
table: TABLE_ITERABLE [detachable ANY, READABLE_STRING_32]
|
table: TABLE_ITERABLE [detachable ANY, READABLE_STRING_GENERAL]
|
||||||
|
-- Table of session data indexed by key
|
||||||
do
|
do
|
||||||
Result := data
|
Result := data
|
||||||
end
|
end
|
||||||
|
|
||||||
item (k: READABLE_STRING_GENERAL): detachable ANY
|
item alias "[]" (k: READABLE_STRING_GENERAL): detachable ANY assign remember
|
||||||
|
-- Session value associated with key `k'.
|
||||||
do
|
do
|
||||||
Result := data.item (table_key (k))
|
Result := data.item (table_key (k))
|
||||||
end
|
end
|
||||||
|
|
||||||
remember (v: detachable ANY; k: READABLE_STRING_GENERAL)
|
remember (v: detachable ANY; k: READABLE_STRING_GENERAL)
|
||||||
|
-- Remember value `v' in association with key `k'.
|
||||||
do
|
do
|
||||||
data.force (v, table_key (k))
|
data.force (v, table_key (k))
|
||||||
end
|
end
|
||||||
|
|
||||||
forget (k: READABLE_STRING_GENERAL)
|
forget (k: READABLE_STRING_GENERAL)
|
||||||
|
-- Forget about value associated with key `k'.
|
||||||
do
|
do
|
||||||
data.remove (table_key (k))
|
data.remove (table_key (k))
|
||||||
end
|
end
|
||||||
@@ -71,19 +93,30 @@ feature {NONE} -- Implementation
|
|||||||
feature -- Control
|
feature -- Control
|
||||||
|
|
||||||
destroy
|
destroy
|
||||||
|
-- Destroy current session.
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
commit
|
commit
|
||||||
|
-- Commit current session, including data associated.
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
apply_to (h: HTTP_HEADER; req: WSF_REQUEST; a_path: detachable READABLE_STRING_8)
|
apply_to (h: HTTP_HEADER_MODIFIER; req: WSF_REQUEST; a_path: detachable READABLE_STRING_8)
|
||||||
|
-- Apply current session to header `h' for request `req' and optional path `a_path'.
|
||||||
|
-- note: either use `apply_to' or `apply', not both.
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
|
apply (req: WSF_REQUEST; res: WSF_RESPONSE; a_path: detachable READABLE_STRING_8)
|
||||||
|
-- Apply current session to response `res' for request `req' and optional path `a_path'.
|
||||||
|
-- note: either use `apply' or `apply_to', not both.
|
||||||
|
do
|
||||||
|
apply_to (res.header, req, a_path)
|
||||||
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -8,7 +8,13 @@ class
|
|||||||
WSF_SESSION_DATA
|
WSF_SESSION_DATA
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
HASH_TABLE [detachable ANY, READABLE_STRING_32]
|
STRING_TABLE [detachable ANY]
|
||||||
|
rename
|
||||||
|
make as old_make,
|
||||||
|
make_caseless as make
|
||||||
|
redefine
|
||||||
|
empty_duplicate
|
||||||
|
end
|
||||||
|
|
||||||
create
|
create
|
||||||
make
|
make
|
||||||
@@ -24,4 +30,22 @@ feature -- Element change
|
|||||||
expiration := dt
|
expiration := dt
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Duplication
|
||||||
|
|
||||||
|
empty_duplicate (n: INTEGER): like Current
|
||||||
|
-- Create an empty copy of Current that can accommodate `n' items
|
||||||
|
do
|
||||||
|
create Result.make (n)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, 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
|
end
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ feature {WSF_RESPONSE} -- Output
|
|||||||
req := request
|
req := request
|
||||||
if attached req.raw_header_data as l_header then
|
if attached req.raw_header_data as l_header then
|
||||||
create s.make (l_header.count)
|
create s.make (l_header.count)
|
||||||
s.append (l_header.to_string_8)
|
s.append (l_header.to_string_8) -- Is valid as string 8, as ensured by req.raw_header_data
|
||||||
s.append_character ('%N')
|
s.append_character ('%N')
|
||||||
else
|
else
|
||||||
create s.make_empty
|
create s.make_empty
|
||||||
@@ -99,7 +99,7 @@ feature {WSF_RESPONSE} -- Output
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -1287,41 +1287,43 @@ feature {NONE} -- Cookies
|
|||||||
local
|
local
|
||||||
i,j,p,n: INTEGER
|
i,j,p,n: INTEGER
|
||||||
l_cookies: like internal_cookies_table
|
l_cookies: like internal_cookies_table
|
||||||
|
s32: READABLE_STRING_32
|
||||||
k,v,s: STRING
|
k,v,s: STRING
|
||||||
do
|
do
|
||||||
l_cookies := internal_cookies_table
|
l_cookies := internal_cookies_table
|
||||||
if l_cookies = Void then
|
if l_cookies = Void then
|
||||||
|
create l_cookies.make_equal (0)
|
||||||
if attached {WSF_STRING} meta_variable ({WSF_META_NAMES}.http_cookie) as val then
|
if attached {WSF_STRING} meta_variable ({WSF_META_NAMES}.http_cookie) as val then
|
||||||
s := val.value
|
s32 := val.value
|
||||||
create l_cookies.make_equal (5)
|
if s32.is_valid_as_string_8 then
|
||||||
from
|
s := s32.to_string_8
|
||||||
n := s.count
|
from
|
||||||
p := 1
|
n := s.count
|
||||||
i := 1
|
p := 1
|
||||||
until
|
i := 1
|
||||||
p < 1
|
until
|
||||||
loop
|
p < 1
|
||||||
i := s.index_of ('=', p)
|
loop
|
||||||
if i > 0 then
|
i := s.index_of ('=', p)
|
||||||
j := s.index_of (';', i)
|
if i > 0 then
|
||||||
if j = 0 then
|
j := s.index_of (';', i)
|
||||||
j := n + 1
|
if j = 0 then
|
||||||
k := s.substring (p, i - 1)
|
j := n + 1
|
||||||
v := s.substring (i + 1, n)
|
k := s.substring (p, i - 1)
|
||||||
|
v := s.substring (i + 1, n)
|
||||||
|
|
||||||
p := 0 -- force termination
|
p := 0 -- force termination
|
||||||
else
|
else
|
||||||
k := s.substring (p, i - 1)
|
k := s.substring (p, i - 1)
|
||||||
v := s.substring (i + 1, j - 1)
|
v := s.substring (i + 1, j - 1)
|
||||||
p := j + 1
|
p := j + 1
|
||||||
|
end
|
||||||
|
k.left_adjust
|
||||||
|
k.right_adjust
|
||||||
|
add_value_to_table (k, v, l_cookies)
|
||||||
end
|
end
|
||||||
k.left_adjust
|
|
||||||
k.right_adjust
|
|
||||||
add_value_to_table (k, v, l_cookies)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
|
||||||
create l_cookies.make_equal (0)
|
|
||||||
end
|
end
|
||||||
internal_cookies_table := l_cookies
|
internal_cookies_table := l_cookies
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ feature {NONE} -- Initialization
|
|||||||
wres: detachable WSF_WGI_DELAYED_HEADER_RESPONSE
|
wres: detachable WSF_WGI_DELAYED_HEADER_RESPONSE
|
||||||
do
|
do
|
||||||
transfered_content_length := 0
|
transfered_content_length := 0
|
||||||
create header.make
|
create internal_header.make
|
||||||
wgi_response := r
|
wgi_response := r
|
||||||
if attached {WSF_WGI_DELAYED_HEADER_RESPONSE} r as r_delayed then
|
if attached {WSF_WGI_DELAYED_HEADER_RESPONSE} r as r_delayed then
|
||||||
r_delayed.update_wsf_response (Current)
|
r_delayed.update_wsf_response (Current)
|
||||||
@@ -53,7 +53,7 @@ feature {NONE} -- Initialization
|
|||||||
do
|
do
|
||||||
transfered_content_length := 0
|
transfered_content_length := 0
|
||||||
wgi_response := res.wgi_response
|
wgi_response := res.wgi_response
|
||||||
header := res.header
|
internal_header := res.internal_header
|
||||||
set_status_code ({HTTP_STATUS_CODE}.ok) -- Default value
|
set_status_code ({HTTP_STATUS_CODE}.ok) -- Default value
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ feature {WSF_RESPONSE, WSF_RESPONSE_EXPORTER} -- Properties
|
|||||||
wgi_response: WGI_RESPONSE
|
wgi_response: WGI_RESPONSE
|
||||||
-- Associated WGI_RESPONSE.
|
-- Associated WGI_RESPONSE.
|
||||||
|
|
||||||
header: WSF_HEADER
|
internal_header: WSF_HEADER
|
||||||
-- Associated response header.
|
-- Associated response header.
|
||||||
|
|
||||||
feature {WSF_RESPONSE_EXPORTER} -- Change
|
feature {WSF_RESPONSE_EXPORTER} -- Change
|
||||||
@@ -158,7 +158,7 @@ feature {WSF_RESPONSE_EXPORTER} -- Header output operation
|
|||||||
-- commit status code and reason phrase
|
-- commit status code and reason phrase
|
||||||
wgi_response.set_status_code (status_code, status_reason_phrase)
|
wgi_response.set_status_code (status_code, status_reason_phrase)
|
||||||
-- commit header text
|
-- commit header text
|
||||||
wgi_response.put_header_text (header.string)
|
wgi_response.put_header_text (internal_header.string)
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
status_committed: status_committed
|
status_committed: status_committed
|
||||||
@@ -170,6 +170,26 @@ feature {WSF_RESPONSE_EXPORTER} -- Header output operation
|
|||||||
put_error ("Content already sent, new header text ignored!")
|
put_error ("Content already sent, new header text ignored!")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature -- Header access
|
||||||
|
|
||||||
|
header: HTTP_HEADER_MODIFIER
|
||||||
|
-- Associated header builder interface.
|
||||||
|
local
|
||||||
|
res: like internal_response_header
|
||||||
|
do
|
||||||
|
res := internal_response_header
|
||||||
|
if res = Void then
|
||||||
|
create {WSF_RESPONSE_HEADER} res.make_with_response (Current)
|
||||||
|
internal_response_header := res
|
||||||
|
end
|
||||||
|
Result := res
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Header access
|
||||||
|
|
||||||
|
internal_response_header: detachable like header
|
||||||
|
-- Cached version of `header'.
|
||||||
|
|
||||||
feature -- Header output operation
|
feature -- Header output operation
|
||||||
|
|
||||||
put_header_line (h: READABLE_STRING_8)
|
put_header_line (h: READABLE_STRING_8)
|
||||||
@@ -181,7 +201,7 @@ feature -- Header output operation
|
|||||||
if header_committed then
|
if header_committed then
|
||||||
report_content_already_sent_and_header_ignored
|
report_content_already_sent_and_header_ignored
|
||||||
else
|
else
|
||||||
header.put_header (h)
|
internal_header.put_header (h)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -194,7 +214,7 @@ feature -- Header output operation
|
|||||||
if header_committed then
|
if header_committed then
|
||||||
report_content_already_sent_and_header_ignored
|
report_content_already_sent_and_header_ignored
|
||||||
else
|
else
|
||||||
header.add_header (h)
|
internal_header.add_header (h)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -209,7 +229,7 @@ feature -- Header output operation
|
|||||||
if header_committed then
|
if header_committed then
|
||||||
report_content_already_sent_and_header_ignored
|
report_content_already_sent_and_header_ignored
|
||||||
else
|
else
|
||||||
header.put_raw_header_data (a_text)
|
internal_header.put_raw_header_data (a_text)
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
message_writable: message_writable
|
message_writable: message_writable
|
||||||
@@ -227,7 +247,7 @@ feature -- Header output operation
|
|||||||
if header_committed then
|
if header_committed then
|
||||||
report_content_already_sent_and_header_ignored
|
report_content_already_sent_and_header_ignored
|
||||||
else
|
else
|
||||||
header.append_raw_header_data (a_text)
|
internal_header.append_raw_header_data (a_text)
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
status_set: status_is_set
|
status_set: status_is_set
|
||||||
@@ -496,7 +516,7 @@ feature -- Error reporting
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
64
library/server/wsf/src/wsf_response_header.e
Normal file
64
library/server/wsf/src/wsf_response_header.e
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Interface to build the http header associated with WSF_RESPONSE.
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
WSF_RESPONSE_HEADER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
HTTP_HEADER_MODIFIER
|
||||||
|
|
||||||
|
WSF_RESPONSE_EXPORTER -- to access WSF_RESPONSE.internal_header
|
||||||
|
|
||||||
|
create
|
||||||
|
make_with_response
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make_with_response (res: WSF_RESPONSE)
|
||||||
|
do
|
||||||
|
response := res
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
response: WSF_RESPONSE
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
new_cursor: INDEXABLE_ITERATION_CURSOR [READABLE_STRING_8]
|
||||||
|
-- Fresh cursor associated with current structure.
|
||||||
|
do
|
||||||
|
Result := response.internal_header.new_cursor
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Header change: core
|
||||||
|
|
||||||
|
add_header (h: READABLE_STRING_8)
|
||||||
|
-- Add header `h'
|
||||||
|
-- if it already exists, there will be multiple header with same name
|
||||||
|
-- which can also be valid
|
||||||
|
do
|
||||||
|
response.add_header_line (h)
|
||||||
|
end
|
||||||
|
|
||||||
|
put_header (h: READABLE_STRING_8)
|
||||||
|
-- Add header `h' or replace existing header of same header name
|
||||||
|
do
|
||||||
|
response.put_header_line (h)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, 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
|
||||||
@@ -54,9 +54,9 @@ feature -- String representation
|
|||||||
|
|
||||||
feature -- Status report
|
feature -- Status report
|
||||||
|
|
||||||
debug_output: STRING
|
debug_output: STRING_32
|
||||||
do
|
do
|
||||||
Result := string_representation.as_string_8
|
Result := string_representation
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Change
|
feature -- Change
|
||||||
@@ -80,7 +80,7 @@ invariant
|
|||||||
name_attached: name /= Void
|
name_attached: name /= Void
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Eiffel Software and others"
|
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ feature -- Access
|
|||||||
has_error_implies_result_attached: has_error implies Result /= Void
|
has_error_implies_result_attached: has_error implies Result /= Void
|
||||||
end
|
end
|
||||||
|
|
||||||
as_string_representation: STRING
|
as_string_representation: STRING_32
|
||||||
-- String representation of all error(s).
|
-- String representation of all error(s).
|
||||||
require
|
require
|
||||||
has_error
|
has_error
|
||||||
@@ -269,7 +269,7 @@ feature -- Access
|
|||||||
Result := e.string_representation
|
Result := e.string_representation
|
||||||
else
|
else
|
||||||
check has_error: False end
|
check has_error: False end
|
||||||
Result := "Error occured"
|
Result := {STRING_32} "Error occured"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user