Skip to content

Commit

Permalink
Use new io-lib. (#119)
Browse files Browse the repository at this point in the history
  • Loading branch information
floitsch authored Apr 3, 2024
1 parent ae287f7 commit ba6a3c7
Show file tree
Hide file tree
Showing 12 changed files with 308 additions and 232 deletions.
68 changes: 45 additions & 23 deletions src/chunked.toit
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,30 @@
// Use of this source code is governed by an MIT-style license that can be
// found in the LICENSE file.
import reader
import writer
import io

import .connection

// This is an adapter that converts a chunked stream (RFC 2616) to a stream of
// just the payload bytes. It takes a BufferedReader as a constructor argument,
// and acts like a Socket or TlsSocket, having one method, called read, which
// returns ByteArrays. End of stream is indicated with a null return value
// from read.
class ChunkedReader implements reader.Reader:
/**
This is an adapter that converts a chunked stream (RFC 2616) to a stream of
just the payload bytes. It takes an $io.Reader as a constructor argument,
and acts like an $io.Reader.
Deprecated for public use. Use the type $io.Reader instead.
This class will be made private in the future.
*/
class ChunkedReader extends ChunkedReader_:
constructor connection/Connection reader/io.Reader:
super connection reader

/**
This is an adapter that converts a chunked stream (RFC 2616) to a stream of
just the payload bytes. It takes an $io.Reader as a constructor argument,
and acts like an $io.Reader.
*/
class ChunkedReader_ extends io.Reader:
connection_/Connection? := null
reader_/reader.BufferedReader? := ?
reader_/io.Reader? := ?
left_in_chunk_ := 0 // How much more raw data we are waiting for before the next size line.
constructor .connection_ .reader_:
Expand All @@ -23,26 +34,29 @@ class ChunkedReader implements reader.Reader:
Returns the underlying reader, which may have buffered up data.
The ChunkedReader is unusable after a called to $detach_reader.
Deprecated.
*/
detach_reader -> reader.BufferedReader:
// TODO(florian): remove already now?
detach_reader -> io.Reader:
r := reader_
reader_ = null
return r

read -> ByteArray?:
read_ -> ByteArray?:
while true:
if not connection_:
return null
if left_in_chunk_ > 0:
result := reader_.read --max_size=left_in_chunk_
if not result: throw reader.UNEXPECTED_END_OF_READER_EXCEPTION
if not result: throw io.Reader.UNEXPECTED_END_OF_READER
left_in_chunk_ -= result.size
if left_in_chunk_ == 0:
expect_ '\r'
expect_ '\n'
return result

raw_length := reader_.read_bytes_until '\r'
raw_length := reader_.read_bytes_up_to '\r'
expect_ '\n'

left_in_chunk_ = int.parse raw_length --radix=16
Expand All @@ -55,34 +69,42 @@ class ChunkedReader implements reader.Reader:
connection_ = null

expect_ byte/int:
b := reader_.byte 0
b := reader_.peek_byte 0
if b != byte: throw "PROTOCOL_ERROR"
reader_.skip 1

class ChunkedWriter implements BodyWriter:
/**
Deprecated for public use. Use the type $io.CloseableWriter instead.
This class will be made private in the future.
*/
class ChunkedWriter extends ChunkedWriter_:
constructor connection/Connection writer/io.Writer:
super connection writer

class ChunkedWriter_ extends io.CloseableWriter:
static CRLF_ ::= "\r\n"

connection_/Connection? := null
writer_/writer.Writer
writer_/io.Writer

constructor .connection_ .writer_:

// We don't know the amount of data ahead of time, so it may already be done.
is_done -> bool:
is_done_ -> bool:
return true

constructor .connection_ .writer_:

write data -> int:
size := data.size
try_write_ data/io.Data from/int to/int -> int:
size := to - from
if size == 0: return 0
write_header_ size
writer_.write data // Always writes all data.
writer_.write data from to // Always writes all data.
// Once we've sent the data, the other side might conclude that
// they have gotten everything they need, so we don't want to throw
// an exception on writing the final CRLF.
catch: writer_.write CRLF_
return size

close -> none:
close_ -> none:
if not connection_: return
// Once we've sent the last chunk, the remaining transmitted information
// is redundant, so we don't want to throw exceptions if the other side
Expand Down
11 changes: 6 additions & 5 deletions src/client.toit
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
// Use of this source code is governed by an MIT-style license that can be
// found in the LICENSE file.
import bytes
import encoding.json
import encoding.url
import io
import net
import net.tcp
import reader
import tls

import .connection
Expand Down Expand Up @@ -207,6 +206,8 @@ class Client:
- suffixing the $host parameter with ":port", for example `localhost:8080`.
If neither is specified then the default port is used.
Deprecated. Use $(new_request method --host) instead.
*/
new_request method/string host/string --port/int?=null path/string --headers/Headers?=null -> RequestOutgoing:
parsed := ParsedUri_.private_
Expand Down Expand Up @@ -493,7 +494,7 @@ class Client:
response := null
try_to_reuse_ parsed: | connection |
request := connection.new_request POST parsed.path headers
request.body = bytes.Reader data
request.body = io.Reader data
response = request.send

if follow_redirects and is_regular_redirect_ response.status_code:
Expand Down Expand Up @@ -606,7 +607,7 @@ class Client:
return post_form_ map parsed --headers=headers --follow_redirects=follow_redirects

url_encode_ map/Map -> ByteArray:
buffer := bytes.Buffer
buffer := io.Buffer
first := true
map.do: | key value |
if key is not string: throw "WRONG_OBJECT_TYPE"
Expand Down Expand Up @@ -680,7 +681,7 @@ class Client:
ensure_connection_ location/ParsedUri_ -> bool:
if connection_ and connection_.is_open_:
if location.can_reuse_connection connection_.location_:
connection_.drain // Remove any remnants of previous requests.
connection_.drain_ // Remove any remnants of previous requests.
return true
// Hostname etc. didn't match so we need a new connection.
connection_.close
Expand Down
Loading

0 comments on commit ba6a3c7

Please sign in to comment.