Files
EWF/library/network/protocol/http/src/http_header.e

427 lines
9.3 KiB
Plaintext

note
description: "[
The class represents a HTTP header, and it provides simple routine
to build it.
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$"
class
HTTP_HEADER
inherit
ITERABLE [READABLE_STRING_8]
HTTP_HEADER_MODIFIER
create
make,
make_with_count,
make_from_array,
make_from_header,
make_from_raw_header_data
convert
make_from_array ({ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]]}),
string: {READABLE_STRING_8, STRING_8}
feature {NONE} -- Initialization
make
-- Initialize current
do
make_with_count (3)
end
make_with_count (n: INTEGER)
-- Make with a capacity of `n' header entries
do
create {ARRAYED_LIST [READABLE_STRING_8]} headers.make (n)
end
make_from_array (a_headers: ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]])
-- Create HEADER from array of pair (key,value)
do
if a_headers.is_empty then
make_with_count (0)
else
make_with_count (a_headers.count)
append_array (a_headers)
end
end
make_from_header (a_header: HTTP_HEADER)
-- Create Current from existing HEADER `a_header'
do
make_with_count (a_header.headers.count)
append_header_object (a_header)
end
make_from_raw_header_data (h: READABLE_STRING_8)
-- Create Current from raw header data
do
make
append_raw_header_data (h)
end
feature -- Recycle
recycle
-- Recycle current object
do
headers.wipe_out
end
feature -- Access
count: INTEGER
-- Number of header items.
do
Result := headers.count
end
is_empty: BOOLEAN
-- Is empty?
do
Result := count = 0
end
headers: ARRAYED_LIST [READABLE_STRING_8]
-- Header's lines.
string: STRING_8
-- String representation of the header entries.
local
n: like count
do
n := count
if n = 0 then
create Result.make_empty
else
create Result.make (n * 32)
append_string_to (Result)
end
ensure
result_has_ending_cr_lf: Result.count >= 2 implies Result.substring (Result.count - 1, Result.count).same_string ("%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
feature -- Conversion
to_name_value_iterable: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]
-- Iterable representation of the header entries.
local
res: ARRAYED_LIST [TUPLE [READABLE_STRING_8, READABLE_STRING_8]]
do
create res.make (headers.count)
across
headers as c
loop
if attached header_name_value (c.item) as tu then
res.extend (tu)
end
end
Result := res
end
feature --
append_string_to (a_result: STRING_8)
-- Append current as string representation to `a_result'
local
l_headers: like headers
do
l_headers := headers
if not l_headers.is_empty then
across
l_headers as c
loop
append_line_to (c.item, a_result)
end
end
end
feature -- Access
new_cursor: INDEXABLE_ITERATION_CURSOR [READABLE_STRING_8]
-- Fresh cursor associated with current structure.
do
Result := headers.new_cursor
end
feature -- Header: adding
append_raw_header_data (h: READABLE_STRING_8)
-- Append raw header data `h' to Current
local
line : detachable STRING
lines: LIST [READABLE_STRING_8]
do
lines := h.split ('%N')
headers.grow (headers.count + lines.count)
across
lines as c
loop
line := c.item
if not line.is_empty then
if line [line.count] = '%R' then
line.remove_tail (1)
end
if not line.is_empty then
add_header (line)
end
end
end
end
append_array (a_headers: ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]])
-- Append array of key,value headers
do
headers.grow (headers.count + a_headers.count)
across
a_headers as c
loop
add_header_key_value (c.item.key, c.item.value)
end
end
append_header_object (h: HTTP_HEADER)
-- Append headers from `h'
do
headers.grow (headers.count + h.headers.count)
across
h.headers as c
loop
add_header (c.item.string)
end
end
feature -- Header: merging
put_raw_header_data (h: READABLE_STRING_8)
-- Append raw header data `h' to Current
-- Overwrite existing header with same name
local
line : detachable STRING
lines: LIST [READABLE_STRING_8]
do
lines := h.split ('%N')
headers.grow (headers.count + lines.count)
across
lines as c
loop
line := c.item
if not line.is_empty then
if line [line.count] = '%R' then
line.remove_tail (1)
end
put_header (line)
end
end
end
put_array (a_headers: ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]])
-- Append array of key,value headers
-- Overwrite existing header with same name
do
headers.grow (headers.count + a_headers.count)
across
a_headers as c
loop
put_header_key_value (c.item.key, c.item.value)
end
end
put_header_object (h: HTTP_HEADER)
-- Append headers from `h'
-- Overwrite existing header with same name
do
headers.grow (headers.count + h.headers.count)
across
h.headers as c
loop
put_header (c.item.string)
end
end
feature -- Removal
remove_header_named (a_name: READABLE_STRING_8)
-- Remove any header line related to name `a_name'.
local
lst: like headers
do
from
lst := headers
lst.start
until
lst.after
loop
if has_same_header_name (lst.item, a_name) then
-- remove
lst.remove
else
lst.forth
end
end
ensure
removed: not has_header_named (a_name)
end
feature -- Header change: general
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
headers.force (h)
end
put_header (h: READABLE_STRING_8)
-- Add header `h' or replace existing header of same header name
do
force_header_by_name (header_name_colon (h), h)
end
feature -- Redirection
remove_location
-- Remove any location header line.
do
remove_header_named ({HTTP_HEADER_NAMES}.header_location)
end
feature {NONE} -- Implementation: Header change
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'
require
h_has_name_n: (n /= Void and attached header_name_colon (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
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
-- If any, header's name with colon
--| ex: for "Foo-bar: something", this will return "Foo-bar:"
local
s: detachable STRING_8
i,n: INTEGER
c: CHARACTER
do
from
i := 1
n := h.count
create s.make (10)
until
i > n or c = ':' or s = Void
loop
c := h[i]
inspect c
when ':' then
s.extend (c)
when '-', 'a' .. 'z', 'A' .. 'Z' then
s.extend (c)
else
s := Void
end
i := i + 1
end
Result := s
end
header_name_value (h: READABLE_STRING_8): detachable TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]
-- If any, header's [name,value]
--| ex: for "Foo-bar: something", this will return ["Foo-bar", "something"]
local
s: detachable STRING_8
i,n: INTEGER
c: CHARACTER
do
from
i := 1
n := h.count
create s.make (10)
until
i > n or c = ':' or s = Void
loop
c := h[i]
inspect c
when ':' then
when '-', 'a' .. 'z', 'A' .. 'Z' then
s.extend (c)
else
s := Void
end
i := i + 1
end
if s /= Void then
Result := [s, h.substring (i, n)]
end
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