Better implementation to get http header for http_client, and to get list of header entries by key,value
This commit is contained in:
@@ -15,8 +15,9 @@ feature {NONE} -- Initialization
|
|||||||
make
|
make
|
||||||
-- Initialize `Current'.
|
-- Initialize `Current'.
|
||||||
do
|
do
|
||||||
|
--| Default values
|
||||||
status := 200
|
status := 200
|
||||||
raw_headers := ""
|
create {STRING_8} raw_header.make_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Status
|
feature -- Status
|
||||||
@@ -35,37 +36,96 @@ feature {HTTP_CLIENT_REQUEST} -- Status setting
|
|||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
status: INTEGER assign set_status
|
status: INTEGER assign set_status
|
||||||
|
-- Status code of the response.
|
||||||
|
|
||||||
raw_headers: READABLE_STRING_8
|
raw_header: READABLE_STRING_8
|
||||||
|
-- Raw http header of the response.
|
||||||
|
|
||||||
headers: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
|
headers: LIST [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]]
|
||||||
|
-- Computed table of http headers of the response.
|
||||||
local
|
local
|
||||||
tb: like internal_headers
|
tb: like internal_headers
|
||||||
|
pos, l_start, l_end, n, c: INTEGER
|
||||||
|
h: like raw_header
|
||||||
|
k: STRING_8
|
||||||
do
|
do
|
||||||
tb := internal_headers
|
tb := internal_headers
|
||||||
if tb = Void then
|
if tb = Void then
|
||||||
create tb.make (3)
|
create tb.make (3)
|
||||||
|
h := raw_header
|
||||||
|
from
|
||||||
|
pos := 1
|
||||||
|
n := h.count
|
||||||
|
until
|
||||||
|
pos = 0 or pos > n
|
||||||
|
loop
|
||||||
|
l_start := pos
|
||||||
|
--| Left justify
|
||||||
|
from until not h[l_start].is_space loop
|
||||||
|
l_start := l_start + 1
|
||||||
|
end
|
||||||
|
pos := h.index_of ('%N', l_start)
|
||||||
|
if pos > 0 then
|
||||||
|
l_end := pos - 1
|
||||||
|
elseif l_start < n then
|
||||||
|
l_end := n + 1
|
||||||
|
else
|
||||||
|
-- Empty line
|
||||||
|
l_end := 0
|
||||||
|
end
|
||||||
|
if l_end > 0 then
|
||||||
|
--| Right justify
|
||||||
|
from until not h[l_end].is_space loop
|
||||||
|
l_end := l_end - 1
|
||||||
|
end
|
||||||
|
c := h.index_of (':', l_start)
|
||||||
|
if c > 0 then
|
||||||
|
k := h.substring (l_start, c - 1)
|
||||||
|
k.right_adjust
|
||||||
|
c := c + 1
|
||||||
|
from until c <= n and not h[c].is_space loop
|
||||||
|
c := c + 1
|
||||||
|
end
|
||||||
|
tb.force ([k, h.substring (c, l_end)])
|
||||||
|
else
|
||||||
|
check header_has_colon: c > 0 end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
pos := pos + 1
|
||||||
|
end
|
||||||
internal_headers := tb
|
internal_headers := tb
|
||||||
end
|
end
|
||||||
Result := tb
|
Result := tb
|
||||||
end
|
end
|
||||||
|
|
||||||
body: detachable READABLE_STRING_8 assign set_body
|
body: detachable READABLE_STRING_8 assign set_body
|
||||||
|
-- Content of the response
|
||||||
|
|
||||||
feature -- Change
|
feature -- Change
|
||||||
|
|
||||||
set_status (s: INTEGER)
|
set_status (s: INTEGER)
|
||||||
|
-- Set response `status' code to `s'
|
||||||
do
|
do
|
||||||
status := s
|
status := s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
set_raw_header (h: READABLE_STRING_8)
|
||||||
|
-- Set http header `raw_header' to `h'
|
||||||
|
do
|
||||||
|
raw_header := h
|
||||||
|
--| Reset internal headers
|
||||||
|
internal_headers := Void
|
||||||
|
end
|
||||||
|
|
||||||
set_body (s: like body)
|
set_body (s: like body)
|
||||||
|
-- Set `body' message to `s'
|
||||||
do
|
do
|
||||||
body := s
|
body := s
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
internal_headers: detachable like headers
|
internal_headers: detachable ARRAYED_LIST [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]]
|
||||||
|
-- Internal cached value for the headers
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ feature -- Execution
|
|||||||
curl: CURL_EXTERNALS
|
curl: CURL_EXTERNALS
|
||||||
curl_easy: CURL_EASY_EXTERNALS
|
curl_easy: CURL_EASY_EXTERNALS
|
||||||
curl_handle: POINTER
|
curl_handle: POINTER
|
||||||
l_response : HTTP_CLIENT_RESPONSE
|
|
||||||
do
|
do
|
||||||
curl := session.curl
|
curl := session.curl
|
||||||
curl_easy := session.curl_easy
|
curl_easy := session.curl_easy
|
||||||
@@ -166,7 +165,6 @@ feature -- Execution
|
|||||||
l_headers as curs
|
l_headers as curs
|
||||||
loop
|
loop
|
||||||
p := curl.slist_append (p, curs.key + ": " + curs.item)
|
p := curl.slist_append (p, curs.key + ": " + curs.item)
|
||||||
-- curl_easy.setopt_slist (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpheader, p)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -197,10 +195,8 @@ feature -- Execution
|
|||||||
else
|
else
|
||||||
Result.status := 0
|
Result.status := 0
|
||||||
end
|
end
|
||||||
l_response := populate_response ( l_curl_string.string)
|
|
||||||
Result.headers.copy (l_response.headers)
|
|
||||||
Result.body := l_response.body
|
|
||||||
|
|
||||||
|
set_header_and_body_to (l_curl_string.string, Result)
|
||||||
else
|
else
|
||||||
Result.set_error_occurred (True)
|
Result.set_error_occurred (True)
|
||||||
end
|
end
|
||||||
@@ -209,41 +205,28 @@ feature -- Execution
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
populate_response ( curl_response: STRING) : HTTP_CLIENT_RESPONSE
|
set_header_and_body_to (a_source: READABLE_STRING_8; res: HTTP_CLIENT_RESPONSE)
|
||||||
-- parse curl_response
|
-- Parse `a_source' response
|
||||||
-- if the header exist, extract header fields
|
-- and set `header' and `body' from HTTP_CLIENT_RESPONSE `res'
|
||||||
-- and body and return an HTTP_CLIENT_RESPONSE
|
|
||||||
local
|
local
|
||||||
l_response : LIST[detachable STRING]
|
pos, l_start : INTEGER
|
||||||
l_b: BOOLEAN
|
|
||||||
pos : INTEGER
|
|
||||||
do
|
do
|
||||||
create Result.make
|
l_start := a_source.substring_index ("%R%N", 1)
|
||||||
if curl_response.has_substring ("%R%N%R%N") then -- has header
|
if l_start > 0 then
|
||||||
l_response := curl_response.split ('%R')
|
--| Skip first line which is the status line
|
||||||
from
|
--| ex: HTTP/1.1 200 OK%R%N
|
||||||
l_response.start
|
l_start := l_start + 2
|
||||||
until
|
end
|
||||||
l_response.after or l_b
|
if l_start < a_source.count and then a_source[l_start] = '%R' and a_source[l_start + 1] = '%N' then
|
||||||
loop
|
res.set_body (a_source)
|
||||||
if attached {STRING} l_response.item as l_item then
|
|
||||||
if l_item.has (':') then
|
|
||||||
pos := l_item.index_of (':', 1)
|
|
||||||
Result.headers.put (l_item.substring (pos+1, l_item.count), l_item.substring (2, pos-1))
|
|
||||||
elseif l_item.starts_with ("%N") and then l_item.count = 1 then
|
|
||||||
l_b := true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
l_response.forth
|
|
||||||
if l_b then
|
|
||||||
if attached {STRING} l_response.item as l_item then
|
|
||||||
l_item.remove_head (1)
|
|
||||||
Result.body := l_item
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
Result.body := curl_response
|
pos := a_source.substring_index ("%R%N%R%N", l_start)
|
||||||
|
if pos > 0 then
|
||||||
|
res.set_raw_header (a_source.substring (l_start, pos + 1)) --| Keep the last %R%N
|
||||||
|
res.set_body (a_source.substring (pos + 4, a_source.count))
|
||||||
|
else
|
||||||
|
res.set_body (a_source)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
88
library/client/http_client/tests/test_http_client.e
Normal file
88
library/client/http_client/tests/test_http_client.e
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Eiffel tests that can be executed by testing tool.
|
||||||
|
]"
|
||||||
|
author: "EiffelStudio test wizard"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
testing: "type/manual"
|
||||||
|
|
||||||
|
class
|
||||||
|
TEST_HTTP_CLIENT
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EQA_TEST_SET
|
||||||
|
|
||||||
|
feature -- Test routines
|
||||||
|
|
||||||
|
test_http_client
|
||||||
|
-- New test routine
|
||||||
|
local
|
||||||
|
sess: LIBCURL_HTTP_CLIENT_SESSION
|
||||||
|
h: STRING_8
|
||||||
|
do
|
||||||
|
create sess.make ("http://www.google.com")
|
||||||
|
if attached sess.get ("/search?q=eiffel", Void) as res then
|
||||||
|
create h.make_empty
|
||||||
|
if attached res.headers as hds then
|
||||||
|
across
|
||||||
|
hds as c
|
||||||
|
loop
|
||||||
|
h.append (c.item.key + ": " + c.item.value + "%R%N")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if attached res.body as l_body then
|
||||||
|
|
||||||
|
end
|
||||||
|
assert ("same headers", h.same_string (res.raw_header))
|
||||||
|
else
|
||||||
|
assert ("Not found", False)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test_headers
|
||||||
|
local
|
||||||
|
res: HTTP_CLIENT_RESPONSE
|
||||||
|
h: STRING
|
||||||
|
do
|
||||||
|
create res.make
|
||||||
|
create h.make_empty
|
||||||
|
h.append ("normal: NORMAL%R%N")
|
||||||
|
h.append ("concat: ABC%R%N")
|
||||||
|
h.append ("concat: DEF%R%N")
|
||||||
|
h.append ("key1: KEY%R%N")
|
||||||
|
h.append (" key2 : KEY%R%N")
|
||||||
|
h.append (" %T key3 : KEY%R%N")
|
||||||
|
h.append ("value1:VALUE%R%N")
|
||||||
|
h.append ("value2: VALUE%R%N")
|
||||||
|
h.append ("value3: VALUE%R%N")
|
||||||
|
h.append ("value4: VALUE %R%N")
|
||||||
|
h.append (" %Tfoo : BAR%T %R%N")
|
||||||
|
res.set_raw_header (h)
|
||||||
|
create h.make_empty
|
||||||
|
if attached res.headers as hds then
|
||||||
|
across
|
||||||
|
hds as c
|
||||||
|
loop
|
||||||
|
h.append (c.item.key + ": " + c.item.value + "%N")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert ("Expected headers map", h.same_string ("[
|
||||||
|
normal: NORMAL
|
||||||
|
concat: ABC
|
||||||
|
concat: DEF
|
||||||
|
key1: KEY
|
||||||
|
key2: KEY
|
||||||
|
key3: KEY
|
||||||
|
value1: VALUE
|
||||||
|
value2: VALUE
|
||||||
|
value3: VALUE
|
||||||
|
value4: VALUE
|
||||||
|
foo: BAR
|
||||||
|
|
||||||
|
]"))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user