From b541efcc8f803a9051245d4b069cd5770b2b8647 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 12 Apr 2012 11:19:41 +0200 Subject: [PATCH] Now WGI_RESPONSE.set_status_code (..) has a new argument to pass optional custom reason phrase. This is a minor breaking change (but prior to the first release, so acceptable) And then it is now possible to precise a custom reason phrase (useful for 4xx and 5xx response) At the WSF_RESPONSE level, the status code is now sent only when the header are sent. thus, it is possible to change the status code as long as no header is sent. (in the future, we should also try to delay the sending of headers) Removed WGI_RESPONSE.put_header_lines (..) which was not used, and WGI is not meant to provide such user friendly features Now this is available directly on WSF_RESPONSE --- .../http_client/src/http_client_request.e | 11 ++++ .../http_client/src/http_client_session.e | 24 ++++++++- .../libcurl/libcurl_http_client_request.e | 16 +++++- library/protocol/http/src/http_header.e | 2 +- library/protocol/http/src/http_header_names.e | 5 +- .../connectors/cgi/src/wgi_cgi_connector.e | 2 +- .../cgi/src/wgi_cgi_output_stream.e | 15 +++--- .../libfcgi/src/wgi_libfcgi_connector.e | 2 +- .../libfcgi/src/wgi_libfcgi_output_stream.e | 17 +++--- .../nino/src/wgi_nino_output_stream.e | 15 +++--- .../specification/response/wgi_response.e | 25 +++++---- .../specification/stream/wgi_output_stream.e | 5 +- .../src/implementation/wgi_response_stream.e | 28 +++------- library/server/wsf/src/wsf_response.e | 52 ++++++++++++++++--- 14 files changed, 149 insertions(+), 70 deletions(-) diff --git a/library/client/http_client/src/http_client_request.e b/library/client/http_client/src/http_client_request.e index ab331fd0..fbdc8b92 100644 --- a/library/client/http_client/src/http_client_request.e +++ b/library/client/http_client/src/http_client_request.e @@ -92,6 +92,11 @@ feature -- Authentication Result := session.credentials end + proxy: detachable TUPLE [host: READABLE_STRING_8; port: INTEGER] + do + Result := session.proxy + end + feature -- Settings timeout: INTEGER @@ -131,6 +136,12 @@ feature -- Settings Result := session.default_response_charset end + is_insecure: BOOLEAN + -- Allow connections to SSL sites without certs + do + Result := session.is_insecure + end + feature {NONE} -- Utilities append_parameters_to_url (a_url: STRING; a_parameters: detachable ARRAY [detachable TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]) diff --git a/library/client/http_client/src/http_client_session.e b/library/client/http_client/src/http_client_session.e index 24e17b32..24060d6f 100644 --- a/library/client/http_client/src/http_client_session.e +++ b/library/client/http_client/src/http_client_session.e @@ -105,6 +105,12 @@ feature -- Settings default_response_charset: detachable READABLE_STRING_8 -- Default encoding of responses. Used if no charset is provided by the host. + is_insecure: BOOLEAN + -- Allow connections to SSL sites without certs + + proxy: detachable TUPLE [host: READABLE_STRING_8; port: INTEGER] + -- Proxy information [`host' and `port'] + feature -- Access base_url: READABLE_STRING_8 @@ -132,9 +138,9 @@ feature -- Change base_url := u end - set_timeout (n: like timeout) + set_timeout (n_seconds: like timeout) do - timeout := n + timeout := n_seconds end set_connect_timeout (n: like connect_timeout) @@ -147,6 +153,11 @@ feature -- Change add_header ("User-Agent", v) end + set_is_insecure (b: BOOLEAN) + do + is_insecure := b + end + add_header (k: READABLE_STRING_8; v: READABLE_STRING_8) do headers.force (v, k) @@ -203,6 +214,15 @@ feature -- Change max_redirects := n end + set_proxy (a_host: detachable READABLE_STRING_8; a_port: INTEGER) + do + if a_host = Void then + proxy := Void + else + proxy := [a_host, a_port] + end + end + note copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/library/client/http_client/src/spec/libcurl/libcurl_http_client_request.e b/library/client/http_client/src/spec/libcurl/libcurl_http_client_request.e index 52d7602f..e346b3b3 100644 --- a/library/client/http_client/src/spec/libcurl/libcurl_http_client_request.e +++ b/library/client/http_client/src/spec/libcurl/libcurl_http_client_request.e @@ -54,6 +54,7 @@ feature -- Execution curl_easy: CURL_EASY_EXTERNALS curl_handle: POINTER ctx: like context + l_proxy: like proxy do ctx := context curl := session.curl @@ -83,7 +84,14 @@ feature -- Execution curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_header, 1) --| PROXY ... - if ctx /= Void and then attached ctx.proxy as l_proxy then + + if ctx /= Void then + l_proxy := ctx.proxy + end + if l_proxy = Void then + l_proxy := proxy + end + if l_proxy /= Void then curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_proxyport, l_proxy.port) curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_proxy, l_proxy.host) end @@ -104,6 +112,12 @@ feature -- Execution curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_followlocation, 0) end + --| SSL + if is_insecure then + curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_ssl_verifyhost, 0) + curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_ssl_verifypeer, 0) + end + if request_method.is_case_insensitive_equal ("GET") then curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpget, 1) elseif request_method.is_case_insensitive_equal ("POST") then diff --git a/library/protocol/http/src/http_header.e b/library/protocol/http/src/http_header.e index d78e63f3..6ea26e1a 100644 --- a/library/protocol/http/src/http_header.e +++ b/library/protocol/http/src/http_header.e @@ -80,7 +80,7 @@ feature {NONE} -- Initialization loop line := c.item if not line.is_empty then - if line[line.count] = '%R' then + if line [line.count] = '%R' then line.remove_tail (1) end add_header (line) diff --git a/library/protocol/http/src/http_header_names.e b/library/protocol/http/src/http_header_names.e index 73f037fd..8d679ea9 100644 --- a/library/protocol/http/src/http_header_names.e +++ b/library/protocol/http/src/http_header_names.e @@ -231,6 +231,9 @@ feature -- Request or Response header name -- Implementation-specific headers that may have various effects anywhere along the request-response chain. --| Example: Pragma: no-cache + header_status: STRING = "Status" + -- CGI program can use this to return the HTTP status code to the client. + header_via: STRING = "Via" -- Request: Informs the server of proxies through which the request was sent. -- Response: Informs the client of proxies through which the response was sent. @@ -245,7 +248,7 @@ feature -- MIME related header_content_transfer_encoding: STRING = "Content-Transfer-Encoding" note - copyright: "2011-2011, Eiffel Software and others" + copyright: "2011-2012, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/server/ewsgi/connectors/cgi/src/wgi_cgi_connector.e b/library/server/ewsgi/connectors/cgi/src/wgi_cgi_connector.e index 0384343f..b237ef81 100644 --- a/library/server/ewsgi/connectors/cgi/src/wgi_cgi_connector.e +++ b/library/server/ewsgi/connectors/cgi/src/wgi_cgi_connector.e @@ -48,7 +48,7 @@ feature -- Execution if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.exception_trace as l_trace then if res /= Void then if not res.status_is_set then - res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error) + res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void) end if res.message_writable then res.put_string ("
" + l_trace + "
") diff --git a/library/server/ewsgi/connectors/cgi/src/wgi_cgi_output_stream.e b/library/server/ewsgi/connectors/cgi/src/wgi_cgi_output_stream.e index 7fac392c..323927d3 100644 --- a/library/server/ewsgi/connectors/cgi/src/wgi_cgi_output_stream.e +++ b/library/server/ewsgi/connectors/cgi/src/wgi_cgi_output_stream.e @@ -36,21 +36,24 @@ feature {NONE} -- Initialization feature -- Status writing - put_status_line (a_code: INTEGER) - -- Put status code line for `a_code' - --| Note this is a default implementation, and could be redefined - --| for instance in relation to NPH CGI script + put_status_line (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8) + -- local s: STRING + m: detachable READABLE_STRING_8 do if a_code /= 200 then create s.make (16) s.append ("Status:") s.append_character (' ') s.append_integer (a_code) - if attached http_status_code_message (a_code) as l_status_message then + m := a_reason_phrase + if m = Void then + m := http_status_code_message (a_code) + end + if m /= Void then s.append_character (' ') - s.append_string (l_status_message) + s.append_string (m) end put_header_line (s) end diff --git a/library/server/ewsgi/connectors/libfcgi/src/wgi_libfcgi_connector.e b/library/server/ewsgi/connectors/libfcgi/src/wgi_libfcgi_connector.e index 93f70dab..08efc4a4 100644 --- a/library/server/ewsgi/connectors/libfcgi/src/wgi_libfcgi_connector.e +++ b/library/server/ewsgi/connectors/libfcgi/src/wgi_libfcgi_connector.e @@ -69,7 +69,7 @@ feature -- Execution if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.exception_trace as l_trace then if res /= Void then if not res.status_is_set then - res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error) + res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void) end if res.message_writable then res.put_string ("
" + l_trace + "
") diff --git a/library/server/ewsgi/connectors/libfcgi/src/wgi_libfcgi_output_stream.e b/library/server/ewsgi/connectors/libfcgi/src/wgi_libfcgi_output_stream.e index 349d2dab..d3b67676 100644 --- a/library/server/ewsgi/connectors/libfcgi/src/wgi_libfcgi_output_stream.e +++ b/library/server/ewsgi/connectors/libfcgi/src/wgi_libfcgi_output_stream.e @@ -40,23 +40,24 @@ feature -- Status report feature -- Status writing - put_status_line (a_code: INTEGER) - -- Put status code line for `a_code' - --| Note this is a default implementation, and could be redefined - --| for instance in relation to NPH CGI script + put_status_line (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8) + -- local s: STRING + m: detachable READABLE_STRING_8 do - --| Do not send any Status line back to the FastCGI client - --| According to http://www.fastcgi.com/docs/faq.html#httpstatus if a_code /= 200 then create s.make (16) s.append ("Status:") s.append_character (' ') s.append_integer (a_code) - if attached http_status_code_message (a_code) as l_status_message then + m := a_reason_phrase + if m = Void then + m := http_status_code_message (a_code) + end + if m /= Void then s.append_character (' ') - s.append_string (l_status_message) + s.append_string (m) end put_header_line (s) end diff --git a/library/server/ewsgi/connectors/nino/src/wgi_nino_output_stream.e b/library/server/ewsgi/connectors/nino/src/wgi_nino_output_stream.e index 1b84c0ad..9e95b69e 100644 --- a/library/server/ewsgi/connectors/nino/src/wgi_nino_output_stream.e +++ b/library/server/ewsgi/connectors/nino/src/wgi_nino_output_stream.e @@ -37,20 +37,23 @@ feature {WGI_NINO_CONNECTOR, WGI_SERVICE} -- Nino feature -- Status writing - put_status_line (a_code: INTEGER) - -- Put status code line for `a_code' - --| Note this is a default implementation, and could be redefined - --| for instance in relation to NPH CGI script + put_status_line (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8) + -- local s: STRING + m: detachable READABLE_STRING_8 do create s.make (16) s.append ({HTTP_CONSTANTS}.http_version_1_1) s.append_character (' ') s.append_integer (a_code) - if attached http_status_code_message (a_code) as l_status_message then + m := a_reason_phrase + if m = Void then + m := http_status_code_message (a_code) + end + if m /= Void then s.append_character (' ') - s.append_string (l_status_message) + s.append_string (m) end put_header_line (s) end diff --git a/library/server/ewsgi/specification/response/wgi_response.e b/library/server/ewsgi/specification/response/wgi_response.e index b9b9c7f1..3822fc82 100644 --- a/library/server/ewsgi/specification/response/wgi_response.e +++ b/library/server/ewsgi/specification/response/wgi_response.e @@ -49,15 +49,17 @@ feature -- Status setting deferred end - set_status_code (a_code: INTEGER) - -- Set response status code + set_status_code (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8) + -- Set response status code with custom `a_reason_phrase' if precised -- Should be done before sending any data back to the client require + a_code_positive: a_code > 0 status_not_set: not status_committed header_not_committed: not header_committed deferred ensure status_code_set: status_code = a_code + status_reason_phrase_set: status_reason_phrase = a_reason_phrase status_set: status_is_set end @@ -66,6 +68,13 @@ feature -- Status setting deferred end + status_reason_phrase: detachable READABLE_STRING_8 + -- Custom status reason phrase for the Response (optional) + deferred + ensure + Result /= Void implies status_is_set + end + feature -- Header output operation put_header_text (a_text: READABLE_STRING_8) @@ -79,17 +88,7 @@ feature -- Header output operation deferred ensure status_set: status_is_set - header_committed: header_committed - message_writable: message_writable - end - - put_header_lines (a_lines: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]) - require - status_set: status_is_set - header_not_committed: not header_committed - deferred - ensure - status_set: status_is_set + status_committed: status_committed header_committed: header_committed message_writable: message_writable end diff --git a/library/server/ewsgi/specification/stream/wgi_output_stream.e b/library/server/ewsgi/specification/stream/wgi_output_stream.e index 871de1d9..39d8dcd7 100644 --- a/library/server/ewsgi/specification/stream/wgi_output_stream.e +++ b/library/server/ewsgi/specification/stream/wgi_output_stream.e @@ -62,10 +62,13 @@ feature -- Specific output feature -- Status writing - put_status_line (a_code: INTEGER) + put_status_line (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8) -- Put status code line for `a_code' + -- with custom `a_reason_phrase' if precised --| Note this is a default implementation, and could be redefined --| for instance in relation to NPH CGI script + require + a_code_positive: a_code > 0 deferred end diff --git a/library/server/ewsgi/src/implementation/wgi_response_stream.e b/library/server/ewsgi/src/implementation/wgi_response_stream.e index 82c07f3b..a7610d42 100644 --- a/library/server/ewsgi/src/implementation/wgi_response_stream.e +++ b/library/server/ewsgi/src/implementation/wgi_response_stream.e @@ -54,21 +54,25 @@ feature -- Status setting status_is_set: BOOLEAN -- Is status set? do - Result := status_code /= 0 + Result := status_code > 0 end - set_status_code (a_code: INTEGER) + set_status_code (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8) -- Set response status code -- Should be done before sending any data back to the client do status_code := a_code - output.put_status_line (a_code) + status_reason_phrase := a_reason_phrase + output.put_status_line (a_code, a_reason_phrase) status_committed := True end status_code: INTEGER -- Response status + status_reason_phrase: detachable READABLE_STRING_8 + -- Custom status reason phrase for the Response (optional) + feature -- Header output operation put_header_text (a_text: READABLE_STRING_8) @@ -78,24 +82,6 @@ feature -- Header output operation header_committed := True end - put_header_lines (a_lines: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]) - local - h: STRING_8 - do - create h.make (256) - across - a_lines as c - loop - h.append (c.item.name) - h.append_character (':') - h.append_character (' ') - h.append (c.item.value) - h.append_character ('%R') - h.append_character ('%N') - end - put_header_text (h) - end - feature -- Output operation put_character (c: CHARACTER_8) diff --git a/library/server/wsf/src/wsf_response.e b/library/server/wsf/src/wsf_response.e index 9d7f8461..17ed25c1 100644 --- a/library/server/wsf/src/wsf_response.e +++ b/library/server/wsf/src/wsf_response.e @@ -56,35 +56,57 @@ feature -- Status setting status_is_set: BOOLEAN -- Is status set? do - Result := wgi_response.status_is_set + Result := status_code > 0 end set_status_code (a_code: INTEGER) -- Set response status code -- Should be done before sending any data back to the client + --| note: the status is really sent when the header are set require + a_code_valid: a_code > 0 status_not_set: not status_committed header_not_committed: not header_committed do - wgi_response.set_status_code (a_code) + status_code := a_code + status_reason_phrase := Void ensure status_code_set: status_code = a_code status_set: status_is_set end + set_status_code_with_reason_phrase (a_code: INTEGER; a_reason_phrase: READABLE_STRING_8) + -- Set response status code + -- Should be done before sending any data back to the client + --| note: the status is really sent when the header are set + require + a_code_valid: a_code > 0 + status_not_set: not status_committed + header_not_committed: not header_committed + do + set_status_code (a_code) + status_reason_phrase := a_reason_phrase + ensure + status_code_set: status_code = a_code + status_reason_phrase_set: status_reason_phrase = a_reason_phrase + status_set: status_is_set + end + status_code: INTEGER -- Response status - do - Result := wgi_response.status_code - end + + status_reason_phrase: detachable READABLE_STRING_8 + -- Custom status reason phrase (optional) feature -- Header output operation put_header_text (a_headers: READABLE_STRING_8) + -- Sent `a_headers' and just before send the status code require status_set: status_is_set header_not_committed: not header_committed do + wgi_response.set_status_code (status_code, status_reason_phrase) wgi_response.put_header_text (a_headers) ensure status_set: status_is_set @@ -93,7 +115,7 @@ feature -- Header output operation message_writable: message_writable end - put_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]]) + put_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]) -- Send headers with status `a_status', and headers from `a_headers' require status_not_committed: not status_committed @@ -107,14 +129,28 @@ feature -- Header output operation put_header_text (h.string) end ensure - header_committed: header_committed status_set: status_is_set + header_committed: header_committed message_writable: message_writable end put_header_lines (a_lines: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]) + -- Send headers from `a_lines' + local + h: STRING_8 do - wgi_response.put_header_lines (a_lines) + create h.make (256) + across + a_lines as c + loop + h.append (c.item.name) + h.append_character (':') + h.append_character (' ') + h.append (c.item.value) + h.append_character ('%R') + h.append_character ('%N') + end + put_header_text (h) end feature -- Output report