From 2ed362f5d39ec2278ad3e87fced982ec11b60eb2 Mon Sep 17 00:00:00 2001 From: Colin Adams Date: Mon, 12 Aug 2013 09:27:00 +0100 Subject: [PATCH] refactored to allow etags to work properly when multiple representations are available --- .../src/resource/order_handler.e | 12 +- library/server/wsf/router/wsf_delete_helper.e | 16 ++- library/server/wsf/router/wsf_get_helper.e | 16 ++- library/server/wsf/router/wsf_method_helper.e | 122 +++++++++++------- library/server/wsf/router/wsf_post_helper.e | 13 +- library/server/wsf/router/wsf_put_helper.e | 9 +- .../server/wsf/router/wsf_skeleton_handler.e | 89 ++++++++----- 7 files changed, 172 insertions(+), 105 deletions(-) diff --git a/examples/restbucksCRUD/src/resource/order_handler.e b/examples/restbucksCRUD/src/resource/order_handler.e index 8a24693f..ece4c63e 100644 --- a/examples/restbucksCRUD/src/resource/order_handler.e +++ b/examples/restbucksCRUD/src/resource/order_handler.e @@ -152,7 +152,7 @@ feature -- Access end end - etag (req: WSF_REQUEST; a_media_type, a_language_type, a_character_type, a_compression_type: READABLE_STRING_8): detachable READABLE_STRING_8 + etag (req: WSF_REQUEST): detachable READABLE_STRING_8 -- Optional Etag for `req' in the requested variant local l_etag_utils: ETAG_UTILS @@ -228,14 +228,14 @@ feature -- Execution feature -- GET/HEAD content - ensure_content_available (req: WSF_REQUEST; - a_media_type, a_language_type, a_character_type, a_compression_type: READABLE_STRING_8) + ensure_content_available (req: WSF_REQUEST) -- Commence generation of response text (entity-body). -- If not chunked, then this will create the entire entity-body so as to be available -- for a subsequent call to `content'. -- If chunked, only the first chunk will be made available to `next_chunk'. If chunk extensions -- are used, then this will also generate the chunk extension for the first chunk. -- We save the text in `req.execution_variable ("GENERATED_CONTENT")' + -- We ignore the results of content negotiation, as there is only one possible combination. do check attached {ORDER} req.execution_variable ("ORDER") as l_order then -- precondition get_or_head and postcondition order_saved_only_for_get_head of `check_resource_exists' and @@ -250,7 +250,7 @@ feature -- GET/HEAD content attached {READABLE_STRING_8} req.execution_variable ("GENERATED_CONTENT") end - content (req: WSF_REQUEST; a_media_type, a_language_type, a_character_type, a_compression_type: READABLE_STRING_8): READABLE_STRING_8 + content (req: WSF_REQUEST): READABLE_STRING_8 -- Non-chunked entity body in response to `req'; -- We only call this for GET/HEAD in this example. do @@ -260,7 +260,7 @@ feature -- GET/HEAD content end end - next_chunk (req: WSF_REQUEST; a_media_type, a_language_type, a_character_type, a_compression_type: READABLE_STRING_8): TUPLE [a_check: READABLE_STRING_8; a_extension: detachable READABLE_STRING_8] + next_chunk (req: WSF_REQUEST): TUPLE [a_chunk: READABLE_STRING_8; a_extension: detachable READABLE_STRING_8] -- Next chunk of entity body in response to `req'; -- The second field of the result is an optional chunk extension. do @@ -269,7 +269,7 @@ feature -- GET/HEAD content Result := ["", Void] end - generate_next_chunk (req: WSF_REQUEST; a_media_type, a_language_type, a_character_type, a_compression_type: READABLE_STRING_8) + generate_next_chunk (req: WSF_REQUEST) -- Prepare next chunk (including optional chunk extension) of entity body in response to `req'. -- This is not called for the first chunk. do diff --git a/library/server/wsf/router/wsf_delete_helper.e b/library/server/wsf/router/wsf_delete_helper.e index 77baf03d..751e0adf 100644 --- a/library/server/wsf/router/wsf_delete_helper.e +++ b/library/server/wsf/router/wsf_delete_helper.e @@ -14,15 +14,19 @@ inherit feature {NONE} -- Implementation - send_response (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER; a_header: HTTP_HEADER; - a_media_type, a_language_type, a_character_type, a_compression_type: detachable READABLE_STRING_8; a_new_resource: BOOLEAN) - -- Write response to deletion of resource named by `req' into `res' in accordance with `a_media_type' etc. + send_response (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER; a_header: HTTP_HEADER; a_new_resource: BOOLEAN) + -- Write response to deletion of resource named by `req' into `res'. + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" local l_dt: STRING do a_handler.delete (req) if a_handler.includes_response_entity (req) then - a_handler.ensure_content_available (req, a_media_type, a_language_type, a_character_type, a_compression_type) + a_handler.ensure_content_available (req) a_header.put_content_length (a_handler.content_length (req).as_integer_32) -- we don't bother supporting chunked responses for DELETE. else @@ -36,12 +40,12 @@ feature {NONE} -- Implementation if a_handler.delete_queued (req) then res.set_status_code ({HTTP_STATUS_CODE}.accepted) res.put_header_text (a_header.string) - res.put_string (a_handler.content (req, a_media_type, a_language_type, a_character_type, a_compression_type)) + res.put_string (a_handler.content (req)) elseif a_handler.deleted (req) then if a_handler.includes_response_entity (req) then res.set_status_code ({HTTP_STATUS_CODE}.ok) res.put_header_text (a_header.string) - res.put_string (a_handler.content (req, a_media_type, a_language_type, a_character_type, a_compression_type)) + res.put_string (a_handler.content (req)) else res.set_status_code ({HTTP_STATUS_CODE}.no_content) res.put_header_text (a_header.string) diff --git a/library/server/wsf/router/wsf_get_helper.e b/library/server/wsf/router/wsf_get_helper.e index 7200f6f1..c5e7a8cb 100644 --- a/library/server/wsf/router/wsf_get_helper.e +++ b/library/server/wsf/router/wsf_get_helper.e @@ -14,14 +14,18 @@ inherit feature {NONE} -- Implementation - send_response (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER; a_header: HTTP_HEADER; - a_media_type, a_language_type, a_character_type, a_compression_type: detachable READABLE_STRING_8; a_new_resource: BOOLEAN) + send_response (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER; a_header: HTTP_HEADER; a_new_resource: BOOLEAN) -- Write response to `req' into `res' in accordance with `a_media_type' etc. + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" local l_chunked, l_ok: BOOLEAN l_dt: STRING do - a_handler.ensure_content_available (req, a_media_type, a_language_type, a_character_type, a_compression_type) + a_handler.ensure_content_available (req) l_chunked := a_handler.is_chunking (req) if l_chunked then a_header.put_transfer_encoding_chunked @@ -39,15 +43,15 @@ feature {NONE} -- Implementation else write_error_response (req, res) end - if attached a_handler.etag (req, a_media_type, a_language_type, a_character_type, a_compression_type) as l_etag then + if attached a_handler.etag (req) as l_etag then a_header.put_header_key_value ({HTTP_HEADER_NAMES}.header_etag, l_etag) end res.put_header_text (a_header.string) if l_ok then if l_chunked then - send_chunked_response (req, res, a_handler, a_header, a_media_type, a_language_type, a_character_type, a_compression_type) + send_chunked_response (req, res, a_handler, a_header) else - res.put_string (a_handler.content (req, a_media_type, a_language_type, a_character_type, a_compression_type)) + res.put_string (a_handler.content (req)) end end end diff --git a/library/server/wsf/router/wsf_method_helper.e b/library/server/wsf/router/wsf_method_helper.e index ca527161..899e28b0 100644 --- a/library/server/wsf/router/wsf_method_helper.e +++ b/library/server/wsf/router/wsf_method_helper.e @@ -36,15 +36,19 @@ feature -- Basic operations execute_new_resource (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER) -- Write response to non-existing resource requested by `req.' into `res'. -- Policy routines are available in `a_handler'. - -- This default implementation does not apply for PUT requests. - -- The behaviour for POST requests depends upon a policy. + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" + -- An HTTP_HEADER is also available as the execution variable "NEGOTIATED_HTTP_HEADER". + -- It includes the Vary header (if any) require req_attached: req /= Void res_attached: res /= Void a_handler_attached: a_handler /= Void local l_locs: LIST [URI] - h: HTTP_HEADER do if a_handler.resource_previously_existed (req) then if a_handler.resource_moved_permanently (req) then @@ -54,26 +58,35 @@ feature -- Basic operations l_locs := a_handler.previous_location (req) handle_redirection_error (req, res, l_locs, {HTTP_STATUS_CODE}.found) else - create h.make + check attached {HTTP_HEADER} req.execution_variable ("NEGOTIATED_HTTP_HEADER") as h then + -- postcondition header_attached of `handle_content_negotiation' + h.put_content_type_text_plain + h.put_current_date + h.put_content_length (0) + res.set_status_code ({HTTP_STATUS_CODE}.gone) + res.put_header_lines (h) + end + end + else + check attached {HTTP_HEADER} req.execution_variable ("NEGOTIATED_HTTP_HEADER") as h then + -- postcondition header_attached of `handle_content_negotiation' h.put_content_type_text_plain h.put_current_date h.put_content_length (0) - res.set_status_code ({HTTP_STATUS_CODE}.gone) + res.set_status_code ({HTTP_STATUS_CODE}.not_found) res.put_header_lines (h) end - else - create h.make - h.put_content_type_text_plain - h.put_current_date - h.put_content_length (0) - res.set_status_code ({HTTP_STATUS_CODE}.not_found) - res.put_header_lines (h) end end execute_existing_resource (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER) -- Write response to existing resource requested by `req' into `res'. -- Policy routines are available in `a_handler'. + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" require req_attached: req /= Void res_attached: res /= Void @@ -127,19 +140,28 @@ feature -- Basic operations end end if not l_failed then - handle_content_negotiation (req, res, a_handler, False) + check attached {HTTP_HEADER} req.execution_variable ("NEGOTIATED_HTTP_HEADER") as h then + -- postcondition header_attached of `handle_content_negotiation' + send_response (req, res, a_handler, h, False) + end end end end end -feature {NONE} -- Implementation +feature -- Content negotiation - handle_content_negotiation (req: WSF_REQUEST; res: WSF_RESPONSE; - a_handler: WSF_SKELETON_HANDLER; a_new_resource: BOOLEAN) + handle_content_negotiation (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER) -- Negotiate acceptable content for, then write, response requested by `req' into `res'. -- Policy routines are available in `a_handler'. - -- This default version applies to GET and HEAD. + -- + -- Either a 406 Not Acceptable error is sent, or upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" + -- An HTTP_HEADER is also saved as the execution variable "NEGOTIATED_HTTP_HEADER". + -- It includes the Vary header (if any) require req_attached: req /= Void res_attached: res /= Void @@ -182,6 +204,7 @@ feature {NONE} -- Implementation else if attached l_lang.language_type as l_language_type then h.put_content_language (l_language_type) + req.set_execution_variable ("NEGOTIATED_LANGUAGE", l_language_type) end l_charsets := a_handler.charsets_supported (req) l_charset := l_conneg.charset_preference (l_charsets, req.http_accept_charset) @@ -191,8 +214,14 @@ feature {NONE} -- Implementation if not l_charset.is_acceptable then handle_not_acceptable ("None of the requested character encodings were acceptable", l_charsets, req, res) else - if attached l_media.media_type as l_media_type and attached l_charset.character_type as l_character_type then - h.put_content_type (l_media_type + "; charset=" + l_character_type) + if attached l_media.media_type as l_media_type then + if attached l_charset.character_type as l_character_type then + h.put_content_type (l_media_type + "; charset=" + l_character_type) + req.set_execution_variable ("NEGOTIATED_CHARSET", l_charset) + else + h.put_content_type (l_media_type) + end + req.set_execution_variable ("NEGOTIATED_MEDIA_TYPE", l_media_type) end l_encodings := a_handler.encodings_supported (req) l_encoding := l_conneg.encoding_preference (l_encodings, req.http_accept_encoding) @@ -204,48 +233,51 @@ feature {NONE} -- Implementation else if attached l_encoding.compression_type as l_compression_type then h.put_content_encoding (l_compression_type) + req.set_execution_variable ("NEGOTIATED_ENCODING", l_compression_type) end - -- We do not support multiple choices, so - send_response (req, res, a_handler, h, - l_media.media_type, l_lang.language_type, l_charset.character_type, l_encoding.compression_type, a_new_resource) end end end end + req.set_execution_variable ("NEGOTIATED_HTTP_HEADER", h) + ensure + header_attached: attached {HTTP_HEADER} req.execution_variable ("NEGOTIATED_HTTP_HEADER") end - send_response (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER; a_header: HTTP_HEADER; - a_media_type, a_language_type, a_character_type, a_compression_type: detachable READABLE_STRING_8; a_new_resource: BOOLEAN) - -- Write response to `req' into `res' in accordance with `a_media_type' etc. +feature {NONE} -- Implementation + + send_response (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER; a_header: HTTP_HEADER; a_new_resource: BOOLEAN) + -- Write response to `req' into `res'. + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" require req_attached: req /= Void res_attached: res /= Void a_handler_attached: a_handler /= Void a_header_attached: a_header /= Void - a_media_type_attached: a_media_type /= Void - a_language_type_attached: a_language_type /= Void - a_character_type_attached: a_character_type /= Void - a_compression_type_attached: a_compression_type /= Void deferred end - send_chunked_response (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER; a_header: HTTP_HEADER; - a_media_type, a_language_type, a_character_type, a_compression_type: READABLE_STRING_8) - -- Write response in chunks to `req' into `res' in accordance with `a_media_type' etc. + send_chunked_response (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER; a_header: HTTP_HEADER) + -- Write response in chunks to `req'. + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" require req_attached: req /= Void res_attached: res /= Void a_handler_attached: a_handler /= Void - a_media_type_attached: a_media_type /= Void - a_language_type_attached: a_language_type /= Void - a_character_type_attached: a_character_type /= Void - a_compression_type_attached: a_compression_type /= Void local l_chunk: TUPLE [a_chunk: READABLE_STRING_8; a_extension: detachable READABLE_STRING_8] do from if a_handler.response_ok (req) then - l_chunk := a_handler.next_chunk (req, a_media_type, a_language_type, a_character_type, a_compression_type) + l_chunk := a_handler.next_chunk (req) res.put_chunk (l_chunk.a_chunk, l_chunk.a_extension) else write_error_response (req, res) @@ -253,9 +285,9 @@ feature {NONE} -- Implementation until a_handler.finished (req) or not a_handler.response_ok (req) loop - a_handler.generate_next_chunk (req, a_media_type, a_language_type, a_character_type, a_compression_type) + a_handler.generate_next_chunk (req) if a_handler.response_ok (req) then - l_chunk := a_handler.next_chunk (req, a_media_type, a_language_type, a_character_type, a_compression_type) + l_chunk := a_handler.next_chunk (req) res.put_chunk (l_chunk.a_chunk, l_chunk.a_extension) else write_error_response (req, res) @@ -464,6 +496,11 @@ feature -- Error reporting handle_not_modified (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER) -- Write a Not Modified response to `res'. + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" require req_attached: req /= Void res_attached: res /= Void @@ -474,12 +511,7 @@ feature -- Error reporting create h.make h.put_content_type_text_plain h.put_content_length (0) - if attached a_handler.etag (req, "", "", "", "") as l_etag then - -- FIXME: We aren't strictly conformant here, as we have not conducted content negotiation yet, - -- so we might not get an identical etag as for a successful (200 OK) request. - -- So we should conduct content negotiation at this point (and if not acceptable, we don't include an etag). - -- Add add any Vary header that might result. - -- Also, when we add support for the Content-Location header in responses, we need to send that here too. + if attached a_handler.etag (req) as l_etag then h.put_header_key_value ({HTTP_HEADER_NAMES}.header_etag, l_etag) end generate_cache_headers (req, a_handler, h, create {DATE_TIME}.make_now_utc) diff --git a/library/server/wsf/router/wsf_post_helper.e b/library/server/wsf/router/wsf_post_helper.e index 41c54a64..f3d4d44c 100644 --- a/library/server/wsf/router/wsf_post_helper.e +++ b/library/server/wsf/router/wsf_post_helper.e @@ -22,7 +22,10 @@ feature -- Basic operations -- Policy routines are available in `a_handler'. do if a_handler.allow_post_to_missing_resource (req) then - handle_content_negotiation (req, res, a_handler, True) + check attached {HTTP_HEADER} req.execution_variable ("NEGOTIATED_HTTP_HEADER") as h then + -- postcondition header_attached of `handle_content_negotiation' + send_response (req, res, a_handler, h, True) + end else res.send (create {WSF_NOT_FOUND_RESPONSE}.make(req)) end @@ -31,9 +34,13 @@ feature -- Basic operations feature {NONE} -- Implementation - send_response (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER; a_header: HTTP_HEADER; - a_media_type, a_language_type, a_character_type, a_compression_type: detachable READABLE_STRING_8; a_new_resource: BOOLEAN) + send_response (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER; a_header: HTTP_HEADER; a_new_resource: BOOLEAN) -- Write response to `req' into `res' in accordance with `a_media_type' etc. as a new URI. + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" local l_code: NATURAL do diff --git a/library/server/wsf/router/wsf_put_helper.e b/library/server/wsf/router/wsf_put_helper.e index 6adedbbf..02b26f0d 100644 --- a/library/server/wsf/router/wsf_put_helper.e +++ b/library/server/wsf/router/wsf_put_helper.e @@ -24,15 +24,16 @@ feature -- Basic operations if a_handler.treat_as_moved_permanently (req) then handle_redirection_error (req, res, a_handler.previous_location (req), {HTTP_STATUS_CODE}.moved_permanently) else - handle_content_negotiation (req, res, a_handler, True) + check attached {HTTP_HEADER} req.execution_variable ("NEGOTIATED_HTTP_HEADER") as h then + -- postcondition header_attached of `handle_content_negotiation' + send_response (req, res, a_handler, h, True) + end end end - feature {NONE} -- Implementation - send_response (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER; a_header: HTTP_HEADER; - a_media_type, a_language_type, a_character_type, a_compression_type: detachable READABLE_STRING_8; a_new_resource: BOOLEAN) + send_response (req: WSF_REQUEST; res: WSF_RESPONSE; a_handler: WSF_SKELETON_HANDLER; a_header: HTTP_HEADER; a_new_resource: BOOLEAN) -- Write response to `req' into `res' in accordance with `a_media_type' etc. as a new URI. local l_code: NATURAL diff --git a/library/server/wsf/router/wsf_skeleton_handler.e b/library/server/wsf/router/wsf_skeleton_handler.e index 33a71d51..b246af4c 100644 --- a/library/server/wsf/router/wsf_skeleton_handler.e +++ b/library/server/wsf/router/wsf_skeleton_handler.e @@ -109,14 +109,15 @@ feature -- Access deferred end - etag (req: WSF_REQUEST; a_media_type, a_language_type, a_character_type, a_compression_type: READABLE_STRING_8): detachable READABLE_STRING_8 - -- Optional Etag for `req' in the requested variant + etag (req: WSF_REQUEST): detachable READABLE_STRING_8 + -- Optional Etag for response entity to `req'; + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" require req_attached: req /= Void - a_media_type_attached: a_media_type /= Void - a_language_type_attached: a_language_type /= Void - a_character_type_attached: a_character_type /= Void - a_compression_type_attached: a_compression_type /= Void deferred end @@ -216,20 +217,23 @@ feature -- DELETE feature -- GET/HEAD content - ensure_content_available (req: WSF_REQUEST; - a_media_type, a_language_type, a_character_type, a_compression_type: READABLE_STRING_8) + ensure_content_available (req: WSF_REQUEST) -- Commence generation of response text (entity-body). -- If not chunked, then this will create the entire entity-body so as to be available -- for a subsequent call to `content'. -- If chunked, only the first chunk will be made available to `next_chunk'. If chunk extensions -- are used, then this will also generate the chunk extension for the first chunk. + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" + -- If you support etags, and you have more than one possible representation + -- for the resource (so that your etag depends upon the particular representation), + -- then you will probably have already created the response entity in `check_resource_exists'. require req_attached: req /= Void get_or_head_or_delete: req.is_get_head_request_method or req.is_delete_request_method - a_media_type_attached: a_media_type /= Void - a_language_type_attached: a_language_type /= Void - a_character_type_attached: a_character_type /= Void - a_compression_type_attached: a_compression_type /= Void deferred end @@ -243,45 +247,48 @@ feature -- GET/HEAD content last_error_set: Result = not req.error_handler.has_error end - content (req: WSF_REQUEST; a_media_type, a_language_type, a_character_type, a_compression_type: READABLE_STRING_8): READABLE_STRING_8 - -- Non-chunked entity body in response to `req' + content (req: WSF_REQUEST): READABLE_STRING_8 + -- Non-chunked entity body in response to `req'; + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" require req_attached: req /= Void head_get_or_delete: req.is_get_head_request_method or req.is_delete_request_method no_error: response_ok (req) not_chunked: not is_chunking (req) - a_media_type_attached: a_media_type /= Void - a_language_type_attached: a_language_type /= Void - a_character_type_attached: a_character_type /= Void - a_compression_type_attached: a_compression_type /= Void deferred end - generate_next_chunk (req: WSF_REQUEST; a_media_type, a_language_type, a_character_type, a_compression_type: READABLE_STRING_8) + generate_next_chunk (req: WSF_REQUEST) -- Prepare next chunk (including optional chunk extension) of entity body in response to `req'. -- This is not called for the first chunk. + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" require req_attached: req /= Void no_error: response_ok (req) chunked: is_chunking (req) - a_media_type_attached: a_media_type /= Void - a_language_type_attached: a_language_type /= Void - a_character_type_attached: a_character_type /= Void - a_compression_type_attached: a_compression_type /= Void deferred end - next_chunk (req: WSF_REQUEST; a_media_type, a_language_type, a_character_type, a_compression_type: READABLE_STRING_8): TUPLE [a_check: READABLE_STRING_8; a_extension: detachable READABLE_STRING_8] + next_chunk (req: WSF_REQUEST): TUPLE [a_check: READABLE_STRING_8; a_extension: detachable READABLE_STRING_8] -- Next chunk of entity body in response to `req'; -- The second field of the result is an optional chunk extension. + -- Four execution variables are set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" require req_attached: req /= Void no_error: response_ok (req) chunked: is_chunking (req) - a_media_type_attached: a_media_type /= Void - a_language_type_attached: a_language_type /= Void - a_character_type_attached: a_character_type /= Void - a_compression_type_attached: a_compression_type /= Void deferred end @@ -427,14 +434,17 @@ feature -- Execution res_attached: res /= Void a_helper_attached: a_helper /= Void do - check_resource_exists (req, a_helper) - if a_helper.resource_exists then - a_helper.execute_existing_resource (req, res, Current) - else - if attached req.http_if_match as l_if_match and then l_if_match.same_string ("*") then - a_helper.handle_precondition_failed (req, res) + a_helper.handle_content_negotiation (req, res, Current) + if not res.status_is_set or else res.status_code /= {HTTP_STATUS_CODE}.Not_acceptable then + check_resource_exists (req, a_helper) + if a_helper.resource_exists then + a_helper.execute_existing_resource (req, res, Current) else - a_helper.execute_new_resource (req, res, Current) + if attached req.http_if_match as l_if_match and then l_if_match.same_string ("*") then + a_helper.handle_precondition_failed (req, res) + else + a_helper.execute_new_resource (req, res, Current) + end end end end @@ -442,6 +452,15 @@ feature -- Execution check_resource_exists (req: WSF_REQUEST; a_helper: WSF_METHOD_HELPER) -- Call `a_helper.set_resource_exists' to indicate that `req.path_translated' -- is the name of an existing resource. + -- Upto four execution variables may be set on `req': + -- "NEGOTIATED_MEDIA_TYPE" + -- "NEGOTIATED_LANGUAGE" + -- "NEGOTIATED_CHARSET" + -- "NEGOTIATED_ENCODING" + -- If you support etags, and you have more than one possible representation + -- for the resource (so that your etag depends upon the particular representation), + -- then you will probably need to create the response entity at this point, rather + -- than in `ensure_content_available'. require req_attached: req /= Void a_helper_attached: a_helper /= Void