The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

HTTP::Promise::IO - I/O Handling Class for HTTP::Promise

SYNOPSIS

    use HTTP::Promise::IO;
    my $this = HTTP::Promise::IO->new( $fh ) || 
        die( HTTP::Promise::IO->error, "\n" );

VERSION

    v0.1.0

DESCRIPTION

This class implements a filehandle reader and writer with a twist.

First off, it does not rely on lines, since data stream or in general data from HTTP requests and responses do not necessarily always contain lines. Binary data are sent without necessarily any line at all.

Second, it is easy on memory by implementing "read", which uses a shared "buffer", and you can use "unread" to return data to it (they would be prepended).

Last, but not least, it implements 2 methods to read in chunks of data from the filehandle until some string pattern specified is found: "read_until" and "read_until_in_memory"

CONSTRUCTOR

new

This takes a proper filehandle and will ensure the O_NONBLOCK bit is set, so that it can timeout if there is no more data streamed from the filehandle.

It returns the newly instantiated object upon success, and upon error, sets an error and return undef

Possible optional parameters are:

buffer

You can pass some data that will set the initial read buffer, from which other methods in this class access before reading from the filehandle.

max_read_buffer

An integer. You can set this a default value for the maximum size of the read buffer.

This is used by "getline" and "read_until_in_memory" to limit how much data can be read into the buffer until it returns an error. Hopefully a line or a match specified with read_until would be found and returned before this limit is reached.

If this is greater than 0 and the amount of data loaded exceeds this limit, and error is returned.

timeout

AN integer. This is the read timeout. It defaults to 10.

METHODS

buffer

Sets or gets the buffer.

This is used by those class methods to get leftover data from the buffer, if any, or from the filehandle if necessary.

This returns a scalar object

can_read

Returns true if it can read from the filehandle or false otherwise.

It takes an optional hash or hash reference of options, of which, timeout is the only one.

close

Close the filehandle and destroys the current object.

connect

Provided with an hash or hash reference of options and this will connect to the remote server.

It returns a new HTTP::Promise::IO object, or upon error, it sets an error and returns undef

Supported options are:

All the options used for object instantiation. See "CONSTRUCTOR" and the following ones:

  • debug

    Integer representing the level of debug.

  • host

    The remote host to connect to.

  • port

    An integer representing the remote port to connect to.

  • stop_if

    A code reference that serves as a callback and that is called where there is an EINTR error. If the callback returns true, the connection attempts stop there and returns an error. This default to return false.

  • timeout

    An integer or a decimal representing a timeout to be used when resolving the host, or when making remote connection.

connect_ssl

This takes the same options has "connect", but performs an SSL connection.

Like "connect", this returns a new HTTP::Promise::IO object, or upon error, it sets an error and returns undef

connect_ssl_over_proxy

Provided with an hash or hash reference of options and this will connect to the remote server.

It returns a new HTTP::Promise::IO object, or upon error, it sets an error and returns undef

Supported options are:

All the options used for object instantiation. See "CONSTRUCTOR" and the following ones:

  • debug

    Integer representing the level of debug.

  • host

    The remote host to connect to.

  • port

    An integer representing the remote port to connect to.

  • proxy_authorization

    The proxy authorisation string to use for authentication.

  • proxy_host

    The remote proxy host to connect to.

  • proxy_port

    An integer representing the remote proxy port to connect to.

  • stop_if

    A code reference that serves as a callback and that is called where there is an EINTR error. If the callback returns true, the connection attempts stop there and returns an error. This default to return false.

  • timeout

    An integer or a decimal representing a timeout to be used when resolving the host, or when making remote connection.

filehandle

Sets or gets the filehandle being used. This is the same filehandle that was passed upon object instantiation.

getline

Reads from the buffer, if there is enough data left over, or from the filehandle and returns the first line found.

A line is a string that ends with \012 which is portable and universal. This would be the equivalent of \n.

It returns the line found, if any, or undef if there was an error that you can retrieve with error.

it takes an optional hash or hash reference of options:

chomp

If true, this will chomp any trailing sequence of \012 possibly preceded by \015

max_read_buffer

An integer that limits how much cumulative data can be read until it exceeds this allowed maximum. When that happens, an error is returned.

inactivity_timeout

Integer representing the amount of second to wait until a connection is deemed idle and closed.

last_delimiter

Sets or gets the last delimiter found. A delimiter is some pattern that is provided to "read_until" and "read_until_in_memory" with the option capture set to a true value.

This returns the last delimited found as a scalar object

make_select

Provided with an hash or hash reference of options and this "select" in perlfunc the filehandle or socket using the timeout provided.

It returns a positive integer upon success, and upon error, this sets an error and returns undef.

Supported options are:

  • timeout

    Integer representing the timeout.

  • write

    Boolean. When true, this will check the filehandle or socket for write capability, or if false for read capability.

make_select_timeout

This takes the same options as "make_select", and it will retry selecting the filehandle or socket until success or a timeout occurs. If an EINTR error occurs, it will query the callback provided with "stop_if". If the callback returns true, it will return an error, or keep trying otherwise.

Returns true upon success, and upon error, this sets an error and returns undef.

max_read_buffer

Sets or gets the maximum bytes amount of the read buffer.

This is used by "getline" and "read_until_in_memory" to limit how much data can be read into the buffer until it returns an error. Hopefully a line or a match specified with read_until would be found and returned before this limit is reached.

If this is greater than 0 and the amount of data loaded exceeds this limit, and error is returned.

print

Provided with some data to print to the underlying filehandle or socket, and this will call "write" and return true upon success, or false otherwise.

read

    my $bytes = $r->read( $buffer, $length );
    my $bytes = $r->read( $buffer, $length, $offset );

This reads $length bytes from either the internal buffer if there are leftover data, or the filehandle, or even both if the internal buffer is not big enough to meet the $length requirement.

It returns how many bytes actually were loaded into the caller's $buffer. It returns undef after having set an error if an error occurred.

Just like the perl core "read" in perlfunc function, this one too will pad with \0 the caller's buffer if the offset specified is greater than the actual size of the caller's buffer.

Note that there is no guarantee that you can read from the filehandle the desired amount of bytes in just one time, especially if the filehandle is a socket, so you may need to do:

    my $bytes;
    my $total_to_read = 102400;
    my $total_bytes;
    while( $bytes = $r->read( $buffer, $chunk_size ) )
    {
        $out-print( $buffer ) || die( $! );
        # If you want to make sure you do not read more than necessary, otherwise, you can discard this line
        $chunk_size = ( $total_to_read - $total_bytes ) if( ( $total_bytes < $total_to_read ) && ( ( $total_bytes + $chunk_size ) > $total_to_read ) );
        $total_bytes += $bytes;
        last if( $total_bytes == $total_to_read );
    }
    # Check if something bad happened
    die( "Something wrong happened: ", $r->error ) if( !defined( $bytes ) );

read_until

    my $bytes = $r->read_until( $buffer, $length, $options_hashref );
    my $bytes = $r->read_until( $buffer, $length, $offset, $options_hashref );

This is similar to "read", but will read data from either the buffer, the filehandle or a combination of both until the specified string, passed as an option, is found.

It loads data in chunks specified with the option chunk_size or by default 2048 bytes. If the specified string is not found within that buffer, it returns how many bytes where read and sets the caller's buffer with the data collected.

Upon the last call when the string is finally found, this will return the number of bytes read, but as a negative number. This will tell you it has found the match. You can consider the number is negative because those are the last n bytes.

When no more data at all can be read, this will return 0.

If an error occurred, this will set an error and return undef

The possible options that can be passed as an hash reference only are:

capture

Boolean. When set to true, this will capture the match specified with string. The resulting would then be retrievable using "last_delimiter"

chunk_size

An integer. This is the maximum bytes this will read per each iteration.

exclude

Boolean. If this is true, this will exclude the string sought from the buffer allocation.

include

Boolean. If this is true, this will set the buffer including the string sought after.

string

This is the string to read data until it is found. The string can be a simple string, or a regular expression.

read_until_in_memory

    my $data = $r->read_until_in_memory( $string );
    my $data = $r->read_until_in_memory( $string, $options_hash_or_hashref );
    die( "Error: ", $r->error ) if( !defined( $data ) );

Provided with a string to be found, this will load data from the internal buffer, the filehandle, or a combination of both into memory until the specified string is found.

Upon success, it returns the data read, which could be an empty string if nothing matched.

If an error occurred, this will set an error and return undef.

It takes the following possible options, either as an hash or hash reference:

capture

Boolean. When set to true, this will capture the match specified with string. The resulting would then be retrievable using "last_delimiter"

chunk_size

An integer. This is the maximum bytes this will read per each iteration.

exclude

Boolean. If this is true, this will exclude the string sought from the buffer allocation.

include

Boolean. If this is true, this will set the buffer including the string sought after.

ssl_opts

Sets or gets an hash reference of ssl options to be used with "start_SSL" in IO::Socket::SSL

stop_if

Sets or gets a code reference acting as a callback when an error EINTR if encountered. If the callback returns true, the method using it, will stop and return an error, otherwise, it will keep trying.

timeout

Sets or gets the timeout threshold. This returns a number object

unread

Provided with some data and this will put it back into the internal buffer, at its beginning.

This returns the current object for chaining.

write

This write to the filehandle set, and takes a buffer to write, an optional length, an optional offset, and an optional timeout value.

If no length is provided, this default to the length of the buffer.

If no offset is provided, this default to 0.

If no timeout is provided, this default to the value set with "timeout"

It returns the number of bytes written or, upon error, sets an error and returns undef

write_all

Provided with some data an an optional timeout, and this will write the data to the filehandle set.

It returns the number of bytes written or, upon error, sets an error and returns undef

AUTHOR

Jacques Deguest <jack@deguest.jp>

SEE ALSO

HTTP::Promise, HTTP::Promise::Request, HTTP::Promise::Response, HTTP::Promise::Message, HTTP::Promise::Entity, HTTP::Promise::Headers, HTTP::Promise::Body, HTTP::Promise::Body::Form, HTTP::Promise::Body::Form::Data, HTTP::Promise::Body::Form::Field, HTTP::Promise::Status, HTTP::Promise::MIME, HTTP::Promise::Parser, HTTP::Promise::IO, HTTP::Promise::Stream, HTTP::Promise::Exception

COPYRIGHT & LICENSE

Copyright(c) 2022 DEGUEST Pte. Ltd.

All rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.