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

NAME

HTTP::Promise::Message - HTTP Message Class

SYNOPSIS

    use HTTP::Promise::Message;
    my $this = HTTP::Promise::Message->new(
        [ 'Content-Type' => 'text/plain' ],
        'Hello world'
    ) || die( HTTP::Promise::Message->error, "\n" );

VERSION

    v0.1.0

DESCRIPTION

This class represents an HTTP message, and implements methods that are common to either a request or a response. This class is inherited by HTTP::Promise::Request and HTTP::Promise::Response. It difffers from HTTP::Promise::Entity in that HTTP::Promise::Entity represents en HTTP entity which is composed of headers and a body, and this can be embedded within another entity.

Here is how it fits in overall relation with other classes.

    +-------------------------+    +--------------------------+    
    |                         |    |                          |    
    | HTTP::Promise::Request  |    | HTTP::Promise::Response  |    
    |                         |    |                          |    
    +------------|------------+    +-------------|------------+    
                 |                               |                 
                 |                               |                 
                 |                               |                 
                 |  +------------------------+   |                 
                 |  |                        |   |                 
                 +--- HTTP::Promise::Message |---+                 
                    |                        |                     
                    +------------|-----------+                     
                                 |                                 
                                 |                                 
                    +------------|-----------+                     
                    |                        |                     
                    | HTTP::Promise::Entity  |                     
                    |                        |                     
                    +------------|-----------+                     
                                 |                                 
                                 |                                 
                    +------------|-----------+                     
                    |                        |                     
                    | HTTP::Promise::Body    |                     
                    |                        |                     
                    +------------------------+                     

CONSTRUCTOR

new

This takes some parameters and instantiates a new HTTP::Promise::Message.

Accepted parameters can be one of the followings:

1. an headers object and some content as a string or scalar reference.
    my $msg = HTTP::Promise::Message->new( HTTP::Promise::Headers->new(
            Content_Type => 'text/plain',
            Content_Encoding => 'gzip',
            Host: 'www.example.org',
        ),
        "Some content",
    );

    my $str = "Some content";
    my $hdr = HTTP::Promise::Headers->new(
        Content_Type => 'text/plain',
        Content_Encoding => 'gzip',
        Host: 'www.example.org',
    );
    my $msg = HTTP::Promise::Message->new( $hdr, \$str );
2. an headers object and and HTTP::Promise::Body or HTTP::Promise::Body::Form object
    my $body = HTTP::Promise::Body::Scalar->new( "Some content" );
    my $hdr = HTTP::Promise::Headers->new(
        Content_Type => 'text/plain',
        Content_Encoding => 'gzip',
        Host: 'www.example.org',
    );
    my $msg = HTTP::Promise::Message->new( $hdr, $body );

Using the x-www-form-urlencoded class:

    my $body = HTTP::Promise::Body::Form->new({ name => '嘉納 治五郎', age => 22, city => 'Tokyo' });
    my $hdr = HTTP::Promise::Headers->new(
        Content_Type => 'text/plain',
        Content_Encoding => 'gzip',
        Host: 'www.example.org',
    );
    my $msg = HTTP::Promise::Message->new( $hdr, $body );
3. an array reference of headers field-value pairs and some content as a string or scalar reference.
    my $msg = HTTP::Promise::Message->new([
            Content_Type => 'text/plain',
            Content_Encoding => 'gzip',
            Host: 'www.example.org',
        ],
        "Some content",
    );
4. an hash reference of parameters
    my $hdr = HTTP::Promise::Headers->new(
        Content_Type => 'text/plain',
        Content_Encoding => 'gzip',
        Host: 'www.example.org',
    );
    my $msg = HTTP::Promise::Message->new({
        headers => $hdr,
        content => \$str,
        # HTP::Promise::Entity
        entity => $entity_object,
        debug => 4,
    });

In any case, you can provide additional object options by providing an hash reference as the last argument, such as:

    my $msg = HTTP::Promise::Message->new([
            Content_Type => 'text/plain',
            Content_Encoding => 'gzip',
            Host: 'www.example.org',
        ],
        "Some content",
        {
        debug => 4,
        entity => $entity_object
        },
    );

If some content is provided, a new entity in-memory body object will be initiated

It returns the new http message object, or upon error, sets an error and returns undef.

METHODS

add_content

This takes a string or a scalar reference and append it to the current body if the body object is an HTTP::Promise::Body::File or HTTP::Promise::Body::Scalar object. This does not work for HTTP::Promise::Body::Form. You would have to call yourself the class methods to add your key-value pairs.

The content thus provided is downgraded, which means it is flagged as being in perl's internal utf-8 representation. So you cannot use this method to add binary data. If you want to do so, you would need to use directly the body object methods. For example:

    my $io = $msg->entity->body->open( '>', { binmode => 'utf-8', autoflush => 1 }) ||
        die( $msg->entity->body->error );
    $io->print( $some_data ) || die( $io->error );
    $io->close;

This code works for either HTTP::Promise::Body::File or HTTP::Promise::Body::Scalar

If no entity, or body is set yet, it will create one automatically, and defaults to HTTP::Promise::Body::Scalar for the body class.

It returns the entity body object, or upon error, sets an error and returns undef.

add_content_utf8

This is the same thing as "add_content", except it will encode in utf-8 the data provided, i.e. not perl's internal representation.

add_part

By default, this will check if the HTTP message Content-Type is a multipart one, and if not, it will automatically set it to multipart/form-data and transform the current HTTP message into the first part of a multipart/form-data, and add after all the parts provided.

If the Content-Type is already a multipart one, but has no part yet and has a body content, it will parse that content to build one or more parts from it.

When used for an HTTP request, multipart/form-data is the only valid Content-Type for sending multiple data. rfc7578 in section 4.3 states: "[RFC2388] suggested that multiple files for a single form field be transmitted using a nested "multipart/mixed" part. This usage is deprecated."

See also this Stackoverflow discussion and this one too

When used for an HTTP response, one can return either a multipart/form-data or a multipart-mixed HTTP message.

If you want to make an HTTP request, then you need to provide pairs of form-name-and part object (either a HTTP::Promise::Entity or a HTTP::Promise::Message object with an HTTP::Promise::Entity set with "entity") OR a list of parts whose name attribute is set.

If you want to make an HTTP response, you can either return a multipart/form-data by providing pairs of form-name-and part object as mentioned above, or a multipart/mixed by providing a list of part object (either a HTTP::Promise::Entity or a HTTP::Promise::Message object with an HTTP::Promise::Entity set with "entity").

For example:

    $m->add_part(
        file1 => $ent1,
        file2 => $ent2,
        first_name => $ent3,
        last_name => $ent4,
        # etc...
    );

or, using the name attribute:

    $ent1->name( 'file1' );
    $ent2->name( 'file2' );
    $ent3->name( 'first_name' );
    $ent4->name( 'last_name' );
    $m->add_part( $ent1, $ent2, $ent3, $ent4 );

Note that you can always set an entity name, and it will only be used if the HTTP message Content-Type is of type multipart/form-data, unless you set yourself the Content-Disposition header value.

It returns the current object, or upon error, sets an error and returns undef.

as_string

This takes an optional end-of-line terminator and returns a scalar object representing the entire HTTP message.

The end-of-line terminator defaults to $CRLF, which is a global variable of HTTP::Promise::Message

boundary

This is a shortcut.

It returns the result returned by "boundary" in HTTP::Promise::Headers

can

This behaves like "can" in UNIVERSAL, with a twist.

Provided with a method name and this check if this is supported by HTTP::Promise::Message, or in last resort by HTTP::Promise::Headers and if the latter is true, it will alias the headers method to this namespace.

It returns the code reference of the requested method, or undef if none could be found.

clear

Clears out the headers object by calling "clear" in HTTP::Promise::Headers, empty the entity body, if any, and remove any part if any.

It does not return anything. This should be called in void context.

clone

This clones the current HTTP message and returns a new object.

content

Get or set the HTTP message body.

If one or more values are provided, they will be added to the newly created HTTP::Promise::Body object.

You can provide as values one or more instance of either a string or a scalar reference.

For example:

    $m->content( \$string, 'Hello world', \$another_string );

It returns the newly set HTTP::Promise::Body object upon success or, upon error, sets an error and returns undef.

When no argument is provided, this returns the HTTP::Promise::Body object as a scalar object.

Beware that the content returned might not be decoded if compression has been applied previously, or if compressed content was provided upon instantiation of the HTTP::Promise::Message object, such as:

    my $m = HTTP::Promise::Message->new([
        'Content-Type' => 'text/plain',
        'Content-Encoding' => 'deflate, base64',
        ],
        '80jNyclXCM8vyklRBAA='
    );
    my $content = $m->content; # 80jNyclXCM8vyklRBAA=

But even with utf-8 content, such as:

    my $m = HTTP::Promise::Message->new([
        'Content-Type' => 'text/plain; charset=utf-8',
        ],
        "\x{E3}\x{81}\x{8A}\x{E6}\x{97}\x{A9}\x{E3}\x{81}\x{86}\x{EF}\x{BC}\x{81}\x{A}",
    );
    my $content = $m->content;

$content would contain undecoded utf-8 bytes, i.e. not in perl's internal representation. Indeed, charset is never decoded. If you want the charset decoded content, use "decoded_content", which will guess the content charset to decode it into perl's internal representation. If you are sure this is utf-8, you can either call:

    my $decoded_content = $m->decoded_content( binmode => 'utf-8' );

or

    my $decoded_content = $m->decoded_content_utf8;

See "decoded_content" for more information.

content_charset

This is a convenient method that calls "content_charset" in HTTP::Promise::Entity and returns the result.

This method attempts at guessing the content charset of the entity body.

It returns a string representing the content charset, possibly empty if nothing was found, or upon error, sets an error and returns undef.

content_ref

This sets or gets the content as a scalar reference.

In assignment mode, this takes a scalar reference and pass it to "content" and returns the body object

Otherwise, this returns the content as scalar object.

If an error occurs, this sets an error and returns undef.

decodable

This gets an array object of all supported and installed decodings on the system, by calling "decodable" in HTTP::Promise::Stream

decode

This decodes the HTTP message body and return true.

If there is no Content-Encoding set, or the entity body is empty, or the entity body already has been decoded, this does nothing obviously. Otherwise, this calls "decode_body" in HTTP::Promise::Entity passing it the encodings as an array reference.

If an error occurs, this sets an error and returns undef.

decode_content

This is similar to </decode>, except that it takes an hash or hash reference of options passed to "decode_body" in HTTP::Promise::Entity, notably replace, which if true will replace the body by its decoded version and if false will return a new body version representing the decoded body.

This returns the entity body object upon success, or upon error, sets an error and returns undef.

decoded_content

This takes an hash or hash reference of options and returns the decoded representation of the body, including charset.

This calls "decode_content", passing it the options provided, to decompress the entity body if necessary. Then, unless the binmode option was provided, this calls "io_encoding" in HTTP::Promise::Entity to guess the charset encoding, and set the binmode option to it, if anything was found.

If the entity body is an xml file, any BOM (Byte Order Mark) will be removed.

This returns the content as a scalar object, or upon error, sets an error and returns undef.

Supported options are:

  • binmode

    The PerlIO encoding to apply to decode the data.

    If not provided, this will be guessed by calling "io_encoding" in HTTP::Promise::Entity

  • charset_strict

    If true, this will returns an error if there is some issues with the content charset. By default, this is false, making it lenient, especially with malformed utf-8.

  • raise_error

    When set to true, this will cause this method to die upon error. Default is false.

decoded_content_utf8

This calls "decoded_content", but this sets the binmode option to utf-8.

It returns whatever "decode_content" returns.

dump

This takes an hash or hash reference of options and either print the resulting dump on the STDOUT in void content, or returns a string representation of the HTTP message, or upon error, sets an error and returns undef.

Supported options are:

  • maxlength

    The maximum amount of body data in bytes to display.

  • no_content

    The string to use when there is no entity body data.

  • prefix

    A string to be added at the beginning of each line of the data returned.

  • preheader

    An arbitrary string to add before the HTTP headers, typically the HTTP start line

    # Returns a string
    my $dump = $msg->dump;
    # Prints on the STDOUT the result
    $msg->dump;

encode

This takes an optional list of encoding and an optional hash or hash reference of options and encode the entity body and returns true, or upon error, sets an error and returns undef.

This will return an error if it is used on a multipart message or an message/* such as message/http.

Obviously this is a no-op if no encoding was found, or if the body is empty, or if the body is already marked as encoded

Supported options are:

  • update_header

    When true, this will set the Content-Encoding with the encoding used to encode the entity body and remove the headers Content-Length and Content-MD5. Defaults to true.

entity

Sets or gets the HTTP entity object

This is a shortcut by calling "header" in HTTP::Promise::Headers

headers

Sets or gets the HTTP::Promise::Headers object.

headers_as_string

This is a shortcut to call "as_string" in HTTP::Promise::Headers

is_encoding_supported

Provided with an encoding and this returns true if the encoding is supported by HTTP::Promise::Stream

make_boundary

Returns a newly generated boundary, which is basically a uuid generated by the XS module Data::UUID

parse

Provided with a string and this will try to parse this HTTP message and returns the current message object if it was called with an HTTP message, or a new HTTP message if it was called as a class function, or upon error, sets an error and returns undef.

    my $msg = HTTP::Promise::Message->parse( $some_http_message ) ||
        die( HTTP::Promise::Message->error );
    
    $msg->parse( $some_http_message ) ||
        die( HTTP::Promise::Message->error );

parts

This returns the HTTP message entity parts as an array object and returns it, or upon error, sets an error and returns undef.

If the HTTP message has a body with content and there is no part and the mime-type top type is multipart or message, this will first parse the body into parts. Thus you could do:

    my $msg = HTTP::Promise::Message->new([
        Content_Type => 'multipart/form-data; boundary="abcd"',
        Content_Encoding => 'gzip',
        Host => 'example.org',
    ], <<EOT );
    --abcd
    Content-Disposition: form-data; name="name"

    Jigoro Kano

    --abcd
    Content-Disposition: form-data; name="birthdate"

    1860-12-10
    --abcd--
    EOT

    my $parts = $msg->parts;

protocol

Sets or gets the HTTP protocol. This is typically something like HTTP/1.0, HTTP/1.1, HTTP/2

Returns the HTTP protocol, if any was set, as a scalar object, or upon error, sets an error and returns undef.

Note that it may return undef if no protocol was set. Errors are likely to occur when assigning an improper value.

start_line

This is a no-op since it is superseded by its inheriting classes HTTP::Promise::Request and HTTP::Promise::Response

version

Sets or gets the HTTP protocol version, something like 1.0, or 1.1, or maybe 2

This returns a number object

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.