HTTP::...Parser(3pm)

πŸ’… HTTP::...Parser(3pm) β€” like, the whole manual, but make it make sense

Okay bestie, so this is the man page for HTTP::Entity::Parser (perl, section 3pm), and I'm gonna walk you through it like we're texting at 2am. Grab a πŸ“ snack, this is gonna slay.


✨ NAME ✨

HTTP::Entity::Parser β€” PSGI compliant HTTP Entity Parser. That's it, that's the whole vibe. It parses HTTP entities, and it plays nice with PSGI. πŸ‘‘


🌸 SYNOPSIS 🌸

Here's the little intro snippet, copy it exactly, no cap:

use HTTP::Entity::Parser;

my $parser = HTTP::Entity::Parser->new;
$parser->register('application/x-www-form-urlencoded','HTTP::Entity::Parser::UrlEncoded');
$parser->register('multipart/form-data','HTTP::Entity::Parser::MultiPart');
$parser->register('application/json','HTTP::Entity::Parser::JSON');

sub app {
    my $env = shift;
    my ( $params, $uploads) = $parser->parse($env);
}

That's the whole glow-up in five lines πŸ’–


πŸ¦‹ DESCRIPTION πŸ¦‹

So HTTP::Entity::Parser is a PSGI-compliant HTTP Entity parser, fr fr. And here's the cute part β€” it's also compatible with HTTP::Body 🫢

But unlike HTTP::Body, this one reads HTTP entities straight out of PSGI's environment, specifically $env->{'psgi.input'}, and parses that. No middleman, no drama. ✨

And what formats does it support? I'm so glad you asked:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • application/json

Three icons, all serving πŸ’…


πŸŽ€ METHODS πŸŽ€

new( buffer_length => $length:Intger)

Creates the instance. Baby's first parser ✨

buffer_length

The buffer length that HTTP::Entity::Parser reads from psgi.input. Default is 16384. That's the number, don't come for me. πŸ‘‘

register($content_type:String, $class:String, $opts:HashRef)

Registers a parser class. You literally just hand it a content type and a class and it's like "say less" πŸ”₯

$parser->register('application/x-www-form-urlencoded','HTTP::Entity::Parser::UrlEncoded');
$parser->register('multipart/form-data','HTTP::Entity::Parser::MultiPart');
$parser->register('application/json','HTTP::Entity::Parser::JSON');

If the request's content_type matches a registered type, HTTP::Entity::Parser uses the registered parser class. Iconic matching behaviour tbh.

And if content_type does not match any registered type? HTTP::Entity::Parser::OctetStream gets used. It's the default bestie, always showing up for you 🫢

parse($env:HashRef)

Parses HTTP entities from PSGI's env. The main character method, lowkey πŸ’œ

my ( $params:ArrayRef, $uploads:ArrayRef) = $parser->parse($env);

$param is a key-value pair list. (Yes, the doc says $param there, and the examples say $params β€” I'm just relaying the messages, don't shoot the messenger 😭)

my ( $params, $uploads) = $parser->parse($env);
my $body_parameters = Hash::MultiValue->new(@$params);

$uploads is an ArrayRef of HashRef. And the shape of one of those hashrefs is chef's kiss, look:

my ( $params, $uploads) = $parser->parse($env);
warn Dumper($uploads->[0]);
{
    "name" => "upload", #field name
    "headers" => [
        "Content-Type" => "application/octet-stream",
        "Content-Disposition" => "form-data; name=\"upload\"; filename=\"hello.pl\""
    ],
    "size" => 78, #size of upload content
    "filename" => "hello.png", #original filename in the client
    "tempname" => "/tmp/XXXXX", # path to the temporary file where uploaded file is saved
}

Every key got a lil comment explaining itself, we love a self-documenting hash. 🧚

And when you use it with Plack::Request::Upload, it goes a little like this:

my ( $params, $uploads) = $parser->parse($env);
 my $upload_hmv = Hash::MultiValue->new();
 while ( my ($k,$v) = splice @$uploads, 0, 2 ) {
     my %copy = %$v;
     $copy{headers} = HTTP::Headers::Fast->new(@{$v->{headers}});
     $upload_hmv->add($k, Plack::Request::Upload->new(%copy));
 }

(Yes I kept the indentation exactly as the original had it. Fidelity queen. πŸ’…)


🌈 PARSERS 🌈

Here's the whole squad, one by one:

  • OctetStream β€” the default parser. This one does not parse the entity, and always returns an empty list. It's the "I'm just here" parser and honestly? Respect. πŸ’€
  • UrlEncoded β€” for application/x-www-form-urlencoded. It's used for HTTP POST without file upload. Simple, effective, ate. ⭐
  • MultiPart β€” for multipart/form-data. It's used for HTTP POST that contains file upload. Big upload energy.

The MultiPart parser uses HTTP::MultiPartParser. 🧚

  • JSON β€” for application/json. This parser decodes the JSON body automatically. And ngl, it's genuinely convenient to use with Ajax forms. Obsessed. πŸ”₯

🌟 WHAT'S DIFFERENT FROM HTTP::Body 🌟

Okay so the whole "why is this a separate module" tea:

  • HTTP::Entity::Parser accepts PSGI's env and reads the body from it. 🌸
  • HTTP::Entity::Parser is able to choose parsers by the instance β€” meanwhile HTTP::Body requires you to modify global variables 😭 which, yeah, no thank you.

That's the difference. Periodt. πŸ’…


πŸ‘‘ SEE ALSO πŸ‘‘

Go check these out, they're all in the group chat:

  • HTTP::Body
  • HTTP::MultiPartParser
  • Plack::Request
  • WWW::Form::UrlEncoded β€” HTTP::Entity::Parser uses this for parsing application/x-www-form-urlencoded. iykyk πŸ’œ

πŸŽ€ LICENSE πŸŽ€

Copyright (C) Masahiro Nagano.

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


πŸ’– AUTHOR πŸ’–

  • Masahiro Nagano <kazeburo@gmail.com>
  • Tokuhiro Matsuno <tokuhirom@gmail.com>

This module is based on tokuhirom's code, see <https://github.com/plack/Plack/pull/434> ✨


Okay so real talk: this whole page is from perl v5.42.0, dated 2020-11-29 β€” that's the version and date, and yes I'm mentioning them because the footer said so, and because we respect the metadata in this house πŸ‘‘βœ¨

Stay parsed, bestie πŸ’…πŸ¦‹πŸŒΈ

πŸ“¦ where this page comes from