Perl500503Syntax-OrDie

 view release on metacpan or  search on metacpan

t/corpus-stack/HTTP-Handy/lib/HTTP/Handy.pm  view on Meta::CPAN


=back

=head1 STATIC FILES, CGI, AND HTMX

HTTP::Handy can serve static files and handle dynamic routes in the same
application, making it self-contained with no external web server needed.

  my $app = sub {
      my $env = shift;
      my $path = $env->{PATH_INFO};

      # Dynamic API route (used as HTMX target)
      if ($path =~ m{^/api/}) {
          my $html_fragment = compute_fragment($env);
          return HTTP::Handy->response_html($html_fragment);
      }

      # Static files (HTML, CSS, JS)
      return HTTP::Handy->serve_static($env, './htdocs');
  };

When used with HTMX, the server simply returns HTML fragments for
C<hx-get> / C<hx-post> requests. No special support is required.

Reading POST body (equivalent to CGI's C<STDIN>):

  my $body = '';
  $env->{'psgi.input'}->read($body, $env->{CONTENT_LENGTH} || 0);
  my %post = HTTP::Handy->parse_query($body);

=head1 HTTPS

HTTP::Handy does not support HTTPS. TLS requires C<IO::Socket::SSL> and
OpenSSL, which depend on Perl 5.8+ and external C libraries.

For local personal use, this is not a problem: modern browsers treat
C<127.0.0.1> and C<localhost> as secure contexts and do not show
HTTPS warnings for HTTP on these addresses.

For LAN or internet use, place a reverse proxy in front of HTTP::Handy:

  Browser <--HTTPS--> Caddy / nginx / Apache <--HTTP--> HTTP::Handy

A minimal Caddy configuration:

  localhost {
      reverse_proxy 127.0.0.1:8080
  }

=head1 PSGI COMPATIBILITY NOTES

HTTP::Handy implements a strict I<subset> of the PSGI/1.1 specification.
The following keys defined by the PSGI spec are B<not> set in C<$env>:

  psgi.version        (PSGI requires [1,1]; not set)
  psgi.multithread    (not set; effectively false)
  psgi.multiprocess   (not set; effectively false)
  psgi.run_once       (not set; effectively false)
  psgi.nonblocking    (not set; always blocking)
  psgi.streaming      (not set; not supported)

Applications that check for these keys must treat their absence as false.
For full PSGI/1.1 compliance use L<Plack> (requires Perl 5.8+).

=head1 SECURITY

HTTP::Handy is designed for B<personal use and local development only>.
It is not hardened for production or internet-facing deployment.

=over 4

=item * B<No authentication or access control.>
Any client that can reach the listening port has unrestricted access.

=item * B<No rate limiting or DoS protection.>
A slow or malicious client can occupy the single-threaded server indefinitely.

=item * B<No HTTPS.>
All traffic is transmitted in plaintext (see L</HTTPS>).

=item * B<POST body capped at 10 MB by default.>
Requests exceeding C<max_post_size> receive a 413 response, but there is no
timeout on slow uploads.

=back

Recommended practice: bind to C<127.0.0.1> (loopback only) and place a
hardened reverse proxy in front of HTTP::Handy for any LAN or internet use.

=head1 LIMITATIONS

=over 4

=item * HTTP/1.0 only -- no Keep-Alive, no HTTP/1.1, no HTTP/2

=item * GET and POST only -- HEAD, PUT, DELETE, etc. return 405

=item * Single process, single thread -- requests are handled one at a time

=item * No HTTPS (see above)

=item * No chunked transfer encoding

=item * No streaming -- POST body and response body are fully buffered in memory

=item * Maximum POST body size: 10 MB by default (configurable via C<max_post_size>)

=item * No cookie or session management (implement in the application layer)

=back

=head1 DEMO

Run directly to start a self-contained demo server:

  perl lib/HTTP/Handy.pm           # from the distribution directory
  perl lib/HTTP/Handy.pm 9090      # on port 9090

Then open C<https://localhost:8080/> (or the port you specified) in your
browser. The demo provides three built-in pages:

=over 4

=item C</>

Top page with a GET query form and a POST form.

=item C</echo>

Echoes GET query parameters or POST form fields in a table.
Demonstrates C<parse_query> for both methods.

=item C</info>

Displays the full PSGI C<$env> hash for the current request.
Useful for understanding what HTTP::Handy provides to the application,
and for debugging routing logic.

=back

To start a minimal server after installation via C<cpan> or C<make install>:

  perl -MHTTP::Handy -e 'HTTP::Handy->run(app=>sub{[200,[],["ok"]]})'

=head1 INTERNALS -- HTTP::Handy::Input

C<HTTP::Handy::Input> is a lightweight in-memory object that acts as a
readable filehandle. It is used as the value of C<psgi.input> in the
request environment.

The reason for a custom object rather than a real filehandle is
compatibility with Perl 5.5.3: the convenient idiom
C<open my $fh, 'E<lt>', \$scalar> (opening a filehandle on an in-memory
string) was not introduced until Perl 5.6.0. C<HTTP::Handy::Input> provides
the same interface without relying on that feature.

The object is not exported and is not intended to be instantiated directly
by application code. Applications should access POST body data through
C<$env-E<gt>{'psgi.input'}> as described in L</PSGI SUBSET SPECIFICATION>.

Available methods:

  new($data)                        construct from a string
  read($buf, $length)               read up to $length bytes into $buf



( run in 0.985 second using v1.01-cache-2.11-cpan-140bd7fdf52 )