From 0bd2d16c12b2237263690efb764e805910f933b9 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 13 Apr 2012 16:33:49 +0200 Subject: [PATCH] Made WGI_CHUNKED_INPUT_STREAM inherits from WGI_INPUT_STREAM Merged REQUEST.input and REQUEST.chunked_input Now REQUEST.input handles directly the chunked transfer encoding, or the non chunked. Kept REQUEST.is_chunked_input since it matters that Content-Length is 0 even if there are input (chunked) data. --- .../ewsgi/specification/request/wgi_request.e | 10 +- .../stream/wgi_chunked_input_stream.e | 209 ++++++++++++------ .../implementation/wgi_request_from_table.e | 17 +- .../wsf/src/support/wsf_mime_handler_helper.e | 36 +-- library/server/wsf/src/wsf_request.e | 11 +- 5 files changed, 171 insertions(+), 112 deletions(-) diff --git a/library/server/ewsgi/specification/request/wgi_request.e b/library/server/ewsgi/specification/request/wgi_request.e index 1beecf6c..d2b8cba9 100644 --- a/library/server/ewsgi/specification/request/wgi_request.e +++ b/library/server/ewsgi/specification/request/wgi_request.e @@ -77,8 +77,7 @@ feature -- Access: Input input: WGI_INPUT_STREAM -- Server input channel - require - is_not_chunked_input: not is_chunked_input + --| Could also be Chunked input, but this is transparent deferred end @@ -87,13 +86,6 @@ feature -- Access: Input deferred end - chunked_input: detachable WGI_CHUNKED_INPUT_STREAM - -- Chunked server input channel - require - is_chunked_input: is_chunked_input - deferred - end - feature -- Access: CGI meta variables meta_variable (a_name: READABLE_STRING_8): detachable READABLE_STRING_8 diff --git a/library/server/ewsgi/specification/stream/wgi_chunked_input_stream.e b/library/server/ewsgi/specification/stream/wgi_chunked_input_stream.e index 42db419f..411c71ac 100644 --- a/library/server/ewsgi/specification/stream/wgi_chunked_input_stream.e +++ b/library/server/ewsgi/specification/stream/wgi_chunked_input_stream.e @@ -1,12 +1,14 @@ note description: "Summary description for {WGI_CHUNKED_INPUT_STREAM}." - author: "" date: "$Date$" revision: "$Revision$" class WGI_CHUNKED_INPUT_STREAM +inherit + WGI_INPUT_STREAM + create make @@ -14,90 +16,177 @@ feature {NONE} -- Implementation make (an_input: like input) do + create last_string.make_empty + create last_chunk.make_empty + last_chunk_size := 0 + index := 0 + chunk_lower := 0 + chunk_upper := 0 create tmp_hex_chunk_size.make_empty input := an_input end feature -- Input - data: STRING_8 - local - d: like internal_data + read_character + -- Read the next character in input stream. + -- Make the result available in `last_character' do - d := internal_data - if d = Void then - d := fetched_data - internal_data := d + index := index + 1 + if index > chunk_upper then + read_chunk + if last_chunk = Void then + read_trailer + end end - Result := d + last_character := last_chunk.item (index) end + read_string (nb: INTEGER) + -- Read the next `nb' characters and + -- make the string result available in `last_string' + local + i: like index + do + last_string.wipe_out + if last_chunk_size = 0 then + read_chunk + end + from + index := index + 1 + i := index + until + i - index + 1 = nb or last_chunk_size = 0 + loop + if i + nb - 1 <= chunk_upper then + last_string.append (last_chunk.substring (i, i + nb - 1)) + i := i + nb - 1 + else + -- Need to read new chunk + -- first get all available data from current chunk + if i <= chunk_upper then + last_string.append (last_chunk.substring (i, chunk_upper)) + i := chunk_upper + end + -- then continue + read_chunk + end + end + if last_chunk_size = 0 then + read_trailer + end + index := i + end + +feature -- Access + + last_string: STRING_8 + -- Last string read. + -- + -- Note: this query *might* return the same object. + -- Therefore a clone should be used if the result + -- is to be kept beyond the next call to this feature. + -- However `last_string' is not shared between file objects.) + + last_character: CHARACTER_8 + -- Last item read. + +feature -- Status report + + is_open_read: BOOLEAN + -- Can items be read from input stream? + do + Result := input.is_open_read + end + + end_of_input: BOOLEAN + -- Has the end of input stream been reached? + do + Result := input.end_of_input + end + +--feature -- Input + +-- data: STRING_8 +-- local +-- d: like internal_data +-- do +-- d := internal_data +-- if d = Void then +-- d := fetched_data +-- internal_data := d +-- end +-- Result := d +-- end + feature {NONE} -- Parser - internal_data: detachable STRING_8 + index, chunk_lower, chunk_upper: INTEGER + last_chunk_size: INTEGER + last_chunk: STRING_8 + +-- internal_data: detachable STRING_8 tmp_hex_chunk_size: STRING_8 - last_chunk_size: INTEGER - last_chunk: detachable STRING_8 - fetched_data: STRING_8 - -- Read all the data in a chunked stream. - -- Make the result available in `last_chunked'. - -- Chunked-Body = *chunk - -- last-chunk - -- trailer - -- CRLF - -- chunk = chunk-size [ chunk-extension ] CRLF - -- chunk-data CRLF - -- chunk-size = 1*HEX - -- last-chunk = 1*("0") [ chunk-extension ] CRLF - -- chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) - -- chunk-ext-name = token - -- chunk-ext-val = token | quoted-string - -- chunk-data = chunk-size(OCTET) - -- trailer = *(entity-header CRLF) - local - eoc: BOOLEAN - s: STRING_8 - do - from - create s.make (1024) - until - eoc - loop - read_chunk - if attached last_chunk as l_last_chunk then - s.append (l_last_chunk) - else - eoc := True - end - if last_chunk_size = 0 then - eoc := True - end - end +-- fetched_data: STRING_8 +-- -- Read all the data in a chunked stream. +-- -- Make the result available in `last_chunked'. +-- -- Chunked-Body = *chunk +-- -- last-chunk +-- -- trailer +-- -- CRLF +-- -- chunk = chunk-size [ chunk-extension ] CRLF +-- -- chunk-data CRLF +-- -- chunk-size = 1*HEX +-- -- last-chunk = 1*("0") [ chunk-extension ] CRLF +-- -- chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) +-- -- chunk-ext-name = token +-- -- chunk-ext-val = token | quoted-string +-- -- chunk-data = chunk-size(OCTET) +-- -- trailer = *(entity-header CRLF) +-- local +-- eoc: BOOLEAN +-- s: STRING_8 +-- do +-- from +-- create s.make (1024) +-- until +-- eoc +-- loop +-- read_chunk +-- if attached last_chunk as l_last_chunk then +-- s.append (l_last_chunk) +-- else +-- eoc := True +-- end +-- if last_chunk_size = 0 then +-- eoc := True +-- end +-- end - read_trailer +-- read_trailer - Result := s - end - - reset_chunk - do - last_chunk := Void - last_chunk_size := 0 - end +-- Result := s +-- end read_chunk do - reset_chunk + chunk_lower := chunk_upper + 1 + last_chunk.wipe_out + last_chunk_size := 0 read_chunk_size if last_chunk_size > 0 then + chunk_upper := chunk_upper + last_chunk_size read_chunk_data end + ensure + attached last_chunk as l_last_chunk implies l_last_chunk.count = chunk_upper - chunk_lower end read_chunk_data require + last_chunk.is_empty last_chunk_size > 0 local l_input: like input @@ -105,12 +194,6 @@ feature {NONE} -- Parser l_input := input l_input.read_string (last_chunk_size) last_chunk := l_input.last_string - - -- read CRLF - l_input.read_character - if l_input.last_character = '%R' then - l_input.read_character - end ensure last_chunk_attached: attached last_chunk as el_last_chunk last_chunk_size_ok: el_last_chunk.count = last_chunk_size diff --git a/library/server/ewsgi/src/implementation/wgi_request_from_table.e b/library/server/ewsgi/src/implementation/wgi_request_from_table.e index 827a3542..29dec9d2 100644 --- a/library/server/ewsgi/src/implementation/wgi_request_from_table.e +++ b/library/server/ewsgi/src/implementation/wgi_request_from_table.e @@ -27,9 +27,18 @@ feature {NONE} -- Initialization input := a_input set_meta_variables (a_vars) update_path_info - if attached http_transfer_encoding as l_transfer_encoding and then l_transfer_encoding.same_string ("chunked") then + update_input + end + + update_input + -- Update input, depending on Transfer-Encoding value. + do + if + attached http_transfer_encoding as l_transfer_encoding and then + l_transfer_encoding.same_string (once "chunked") + then is_chunked_input := True - create chunked_input.make (a_input) + create {WGI_CHUNKED_INPUT_STREAM} input.make (input) end end @@ -40,9 +49,7 @@ feature -- Access: Input input: WGI_INPUT_STREAM -- Server input channel - - chunked_input: detachable WGI_CHUNKED_INPUT_STREAM - -- Chunked server input channel + --| Could be a chunked input as well feature -- EWSGI access diff --git a/library/server/wsf/src/support/wsf_mime_handler_helper.e b/library/server/wsf/src/support/wsf_mime_handler_helper.e index ae5e146e..8802b6dc 100644 --- a/library/server/wsf/src/support/wsf_mime_handler_helper.e +++ b/library/server/wsf/src/support/wsf_mime_handler_helper.e @@ -11,44 +11,30 @@ feature {NONE} -- Implementation full_input_data (req: WSF_REQUEST): READABLE_STRING_8 do - if req.is_chunked_input then - if attached req.chunked_input as l_chunked_input then - Result := l_chunked_input.data - else - check has_chunked_input: False end - Result := "" - end - else - Result := read_input_data (req.input, req.content_length_value) - end + Result := read_input_data (req.input) end - read_input_data (a_input: WGI_INPUT_STREAM; nb: NATURAL_64): STRING_8 + read_input_data (a_input: WGI_INPUT_STREAM): STRING_8 -- All data from input form local - nb32: INTEGER - n64: NATURAL_64 n: INTEGER t: STRING do from - n64 := nb - nb32 := n64.to_integer_32 - create Result.make (nb32) - n := nb32 - if n > 1_024 then - n := 1_024 - end + n := 1_024 + create Result.make (n) until - n64 <= 0 + n = 0 loop a_input.read_string (n) t := a_input.last_string - Result.append_string (t) - if t.count < n then - n64 := 0 + if t.count = 0 then + n := 0 else - n64 := n64 - t.count.as_natural_64 + if t.count < n then + n := 0 + end + Result.append_string (t) end end end diff --git a/library/server/wsf/src/wsf_request.e b/library/server/wsf/src/wsf_request.e index fe2be820..1b4b8910 100644 --- a/library/server/wsf/src/wsf_request.e +++ b/library/server/wsf/src/wsf_request.e @@ -157,26 +157,17 @@ feature -- Access: Input input: WGI_INPUT_STREAM -- Server input channel - require - is_not_chunked_input: not is_chunked_input do Result := wgi_request.input end is_chunked_input: BOOLEAN -- Is request using chunked transfer-encoding? + -- If True, the Content-Length has no meaning do Result := wgi_request.is_chunked_input end - chunked_input: detachable WGI_CHUNKED_INPUT_STREAM - -- Server input channel - require - is_chunked_input: is_chunked_input - do - Result := wgi_request.chunked_input - end - feature -- Helper is_request_method (m: READABLE_STRING_8): BOOLEAN