From 29b55f36cf7854c4eed89e441ff1c39f7958f91c Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Wed, 11 Mar 2015 14:58:13 +0100 Subject: [PATCH] Added skeleton for Eiffel Net implementation of HTTP_CLIENT solution. This is work in progress. --- library/network/http_client/README.md | 3 +- .../network/http_client/http_client-safe.ecf | 2 +- library/network/http_client/http_client.ecf | 2 +- .../http_client/src/http_client_request.e | 20 ++- .../src/spec/libcurl/libcurl_http_client.e | 7 +- .../libcurl/libcurl_http_client_request.e | 18 +- .../libcurl/libcurl_http_client_session.e | 9 +- .../src/spec/socket/net_http_client.e | 46 +++++ .../src/spec/socket/net_http_client_request.e | 45 +++++ .../src/spec/socket/net_http_client_session.e | 158 ++++++++++++++++++ 10 files changed, 285 insertions(+), 25 deletions(-) create mode 100644 library/network/http_client/src/spec/socket/net_http_client.e create mode 100644 library/network/http_client/src/spec/socket/net_http_client_request.e create mode 100644 library/network/http_client/src/spec/socket/net_http_client_session.e diff --git a/library/network/http_client/README.md b/library/network/http_client/README.md index 50dcdac3..59eb25ea 100644 --- a/library/network/http_client/README.md +++ b/library/network/http_client/README.md @@ -6,8 +6,9 @@ * Eiffel cURL library * cURL dynamic libraries in the PATH or the current directory (.dll or .so) +This means on Windows, do not forget to copy the libcurl.dll (and related) either in the same directory of the executable, or ensure the .dll are in the PATH environment. + ## Usage ## Examples - diff --git a/library/network/http_client/http_client-safe.ecf b/library/network/http_client/http_client-safe.ecf index 041fabd1..87aea4f2 100644 --- a/library/network/http_client/http_client-safe.ecf +++ b/library/network/http_client/http_client-safe.ecf @@ -11,7 +11,7 @@ - + diff --git a/library/network/http_client/http_client.ecf b/library/network/http_client/http_client.ecf index 6400022b..9913ce24 100644 --- a/library/network/http_client/http_client.ecf +++ b/library/network/http_client/http_client.ecf @@ -12,7 +12,7 @@ - + diff --git a/library/network/http_client/src/http_client_request.e b/library/network/http_client/src/http_client_request.e index 030eddf6..2d606ee0 100644 --- a/library/network/http_client/src/http_client_request.e +++ b/library/network/http_client/src/http_client_request.e @@ -14,9 +14,10 @@ inherit feature {NONE} -- Initialization - make (a_url: READABLE_STRING_8; a_session: like session; ctx: like context) + make (a_url: READABLE_STRING_8; a_request_method: like request_method; a_session: like session; ctx: like context) -- Initialize `Current'. do + request_method := a_request_method session := a_session url := a_url headers := session.headers.twin @@ -29,6 +30,8 @@ feature {NONE} -- Initialization ctx_header_set: ctx /= Void implies across ctx.headers as ctx_h all attached headers.item (ctx_h.key) as v and then v.same_string (ctx_h.item) end end +feature {NONE} -- Internal + session: HTTP_CLIENT_SESSION context: detachable HTTP_CLIENT_REQUEST_CONTEXT @@ -44,13 +47,18 @@ feature -- Status report feature -- Access request_method: READABLE_STRING_8 - deferred - end + -- Request method associated with Current request. url: READABLE_STRING_8 headers: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8] + response: HTTP_CLIENT_RESPONSE + -- Execute the request and return the response. + -- note: two consecutive calls will trigger two executions! + deferred + end + feature {HTTP_CLIENT_SESSION} -- Execution import (ctx: HTTP_CLIENT_REQUEST_CONTEXT) @@ -67,10 +75,6 @@ feature {HTTP_CLIENT_SESSION} -- Execution end end - execute: HTTP_CLIENT_RESPONSE - deferred - end - feature -- Authentication auth_type: STRING @@ -220,7 +224,7 @@ feature {NONE} -- Utilities: encoding end note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/http_client/src/spec/libcurl/libcurl_http_client.e b/library/network/http_client/src/spec/libcurl/libcurl_http_client.e index 6ff332a2..22ab6fec 100644 --- a/library/network/http_client/src/spec/libcurl/libcurl_http_client.e +++ b/library/network/http_client/src/spec/libcurl/libcurl_http_client.e @@ -1,6 +1,9 @@ note description : "[ Specific implementation of HTTP_CLIENT based on Eiffel cURL library + + WARNING: Do not forget to have the dynamic libraries libcurl (.dll or .so) + and related accessible to the executable (i.e in same directory, or in the PATH) ]" author : "$Author$" date : "$Date$" @@ -13,6 +16,7 @@ inherit HTTP_CLIENT create + default_create, make feature {NONE} -- Initialization @@ -20,6 +24,7 @@ feature {NONE} -- Initialization make -- Initialize `Current'. do + default_create end feature -- Status @@ -30,7 +35,7 @@ feature -- Status end note - copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/http_client/src/spec/libcurl/libcurl_http_client_request.e b/library/network/http_client/src/spec/libcurl/libcurl_http_client_request.e index 0dcb127a..73d9e0de 100644 --- a/library/network/http_client/src/spec/libcurl/libcurl_http_client_request.e +++ b/library/network/http_client/src/spec/libcurl/libcurl_http_client_request.e @@ -1,6 +1,9 @@ note description: "[ Specific implementation of HTTP_CLIENT_REQUEST based on Eiffel cURL library + + WARNING: Do not forget to have the dynamic libraries libcurl (.dll or .so) + and related accessible to the executable (i.e in same directory, or in the PATH) ]" date: "$Date$" revision: "$Revision$" @@ -10,9 +13,8 @@ class inherit HTTP_CLIENT_REQUEST - rename - make as make_request redefine + make, session end @@ -23,8 +25,7 @@ feature {NONE} -- Initialization make (a_url: READABLE_STRING_8; a_request_method: like request_method; a_session: like session; ctx: like context) do - make_request (a_url, a_session, ctx) - request_method := a_request_method + Precursor (a_url, a_request_method, a_session, ctx) apply_workaround end @@ -38,13 +39,10 @@ feature {NONE} -- Initialization session: LIBCURL_HTTP_CLIENT_SESSION -feature -- Access - - request_method: READABLE_STRING_8 - feature -- Execution - execute: HTTP_CLIENT_RESPONSE + response: HTTP_CLIENT_RESPONSE + -- local l_result: INTEGER l_curl_string: detachable CURL_STRING @@ -390,7 +388,7 @@ feature {NONE} -- Implementation end note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/http_client/src/spec/libcurl/libcurl_http_client_session.e b/library/network/http_client/src/spec/libcurl/libcurl_http_client_session.e index bffe43c5..b7a8b952 100644 --- a/library/network/http_client/src/spec/libcurl/libcurl_http_client_session.e +++ b/library/network/http_client/src/spec/libcurl/libcurl_http_client_session.e @@ -1,6 +1,9 @@ note description: "[ Specific implementation of HTTP_CLIENT_SESSION based on Eiffel cURL library + + WARNING: Do not forget to have the dynamic libraries libcurl (.dll or .so) + and related accessible to the executable (i.e in same directory, or in the PATH) ]" date: "$Date$" revision: "$Revision$" @@ -38,7 +41,7 @@ feature -- Custom req: HTTP_CLIENT_REQUEST do create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, a_method, Current, ctx) - Result := req.execute + Result := req.response end custom_with_upload_data (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: READABLE_STRING_8): HTTP_CLIENT_RESPONSE @@ -140,7 +143,7 @@ feature {NONE} -- Implementation end create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, a_method, Current, ctx) - Result := req.execute + Result := req.response if f /= Void then f.delete @@ -161,7 +164,7 @@ feature {LIBCURL_HTTP_CLIENT_REQUEST} -- Curl implementation ;note - copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/network/http_client/src/spec/socket/net_http_client.e b/library/network/http_client/src/spec/socket/net_http_client.e new file mode 100644 index 00000000..863451f5 --- /dev/null +++ b/library/network/http_client/src/spec/socket/net_http_client.e @@ -0,0 +1,46 @@ +note + description : "[ + Specific implementation of HTTP_CLIENT based on Eiffel NET library + + WARNING: this is work in progress + ]" + author : "$Author$" + date : "$Date$" + revision : "$Revision$" + +class + NET_HTTP_CLIENT + +inherit + HTTP_CLIENT + +create + default_create, + make + +feature {NONE} -- Initialization + + make + -- Initialize `Current'. + do + default_create + end + +feature -- Status + + new_session (a_base_url: READABLE_STRING_8): NET_HTTP_CLIENT_SESSION + do + create Result.make (a_base_url) + end + +note + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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 diff --git a/library/network/http_client/src/spec/socket/net_http_client_request.e b/library/network/http_client/src/spec/socket/net_http_client_request.e new file mode 100644 index 00000000..c9146cae --- /dev/null +++ b/library/network/http_client/src/spec/socket/net_http_client_request.e @@ -0,0 +1,45 @@ +note + description: "[ + Specific implementation of HTTP_CLIENT_REQUEST based on Eiffel NET library + ]" + date: "$Date$" + revision: "$Revision$" + +class + NET_HTTP_CLIENT_REQUEST + +inherit + HTTP_CLIENT_REQUEST + redefine + session + end + + REFACTORING_HELPER + +create + make + +feature {NONE} -- Internal + + session: NET_HTTP_CLIENT_SESSION + +feature -- Access + + response: HTTP_CLIENT_RESPONSE + -- + do + to_implement ("implementation based on EiffelNET") + (create {EXCEPTIONS}).die (0) + end + +note + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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 diff --git a/library/network/http_client/src/spec/socket/net_http_client_session.e b/library/network/http_client/src/spec/socket/net_http_client_session.e new file mode 100644 index 00000000..3f3a1ee1 --- /dev/null +++ b/library/network/http_client/src/spec/socket/net_http_client_session.e @@ -0,0 +1,158 @@ +note + description: "[ + Specific implementation of HTTP_CLIENT_SESSION based on Eiffel NET library + ]" + date: "$Date$" + revision: "$Revision$" + +class + NET_HTTP_CLIENT_SESSION + +inherit + HTTP_CLIENT_SESSION + +create + make + +feature {NONE} -- Initialization + + initialize + do + end + +feature -- Status report + + is_available: BOOLEAN = True + -- Is interface usable? + +feature -- Custom + + custom (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE + local + req: HTTP_CLIENT_REQUEST + do + create {NET_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, a_method, Current, ctx) + Result := req.response + end + + custom_with_upload_data (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: READABLE_STRING_8): HTTP_CLIENT_RESPONSE + do + Result := impl_custom (a_method, a_path, a_ctx, data, Void) + end + + custom_with_upload_file (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; fn: READABLE_STRING_8): HTTP_CLIENT_RESPONSE + do + Result := impl_custom (a_method, a_path, a_ctx, Void, fn) + end + +feature -- Helper + + get (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE + do + Result := custom ("GET", a_path, ctx) + end + + head (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE + do + Result := custom ("HEAD", a_path, ctx) + end + + post (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE + do + Result := impl_custom ("POST", a_path, a_ctx, data, Void) + end + + post_file (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE + do + Result := impl_custom ("POST", a_path, a_ctx, Void, fn) + end + + patch (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE + do + Result := impl_custom ("PATCH", a_path, a_ctx, data, Void) + end + + patch_file (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE + do + Result := impl_custom ("PATCH", a_path, a_ctx, Void, fn) + end + + put (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE + do + Result := impl_custom ("PUT", a_path, a_ctx, data, Void) + end + + put_file (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE + do + Result := impl_custom ("PUT", a_path, a_ctx, Void, fn) + end + + delete (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE + do + Result := custom ("DELETE", a_path, ctx) + end + +feature {NONE} -- Implementation + + impl_custom (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE + local + req: HTTP_CLIENT_REQUEST + ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT + f: detachable RAW_FILE + l_data: detachable READABLE_STRING_8 + do + ctx := a_ctx + if data /= Void then + if ctx = Void then + create ctx.make + end + ctx.set_upload_data (data) + end + if fn /= Void then + if ctx = Void then + create ctx.make + end + ctx.set_upload_filename (fn) + end + if ctx /= Void then + l_data := ctx.upload_data + if l_data /= Void and a_method.is_case_insensitive_equal_general ("PUT") then + --| Quick and dirty hack using real file, for PUT uploaded data + --| FIXME [2012-05-23]: better use libcurl for that purpose + + if ctx.has_upload_filename then + check put_conflict_file_and_data: False end + end + create f.make_open_write (create {FILE_NAME}.make_temporary_name) + f.put_string (l_data) + f.close + check ctx /= Void then + ctx.set_upload_data (Void) + ctx.set_upload_filename (f.path.name) + end + end + end + + create {NET_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, a_method, Current, ctx) + Result := req.response + + if f /= Void then + f.delete + end + if l_data /= Void and a_ctx /= Void then + a_ctx.set_upload_filename (Void) + a_ctx.set_upload_data (l_data) + end + end + +note + copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, 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