Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Revision history for HTTP-Message

{{$NEXT}}
- add RFC 10008 HTTP QUERY method (GH#225) (Daniel Böhmer),
see https://datatracker.ietf.org/doc/rfc10008/

7.03 2026-07-21 20:45:16Z
- Fix max_body_size for Content-Encoding: br, which made every brotli
Expand Down
3 changes: 2 additions & 1 deletion lib/HTTP/Request.pm
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ This constructs a new request object by parsing the given string.
=item $r->method( $val )
This is used to get/set the method attribute. The method should be a
short string like "GET", "HEAD", "PUT", "PATCH" or "POST".
short string like "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST",
"PUT" or "QUERY".
=item $r->uri
Expand Down
34 changes: 29 additions & 5 deletions lib/HTTP/Request/Common.pm
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ our $READ_BUFFER_SIZE = 8192;

use Exporter 5.57 'import';

our @EXPORT =qw(GET HEAD PUT PATCH POST OPTIONS);
our @EXPORT_OK = qw($DYNAMIC_FILE_UPLOAD DELETE);
our @EXPORT = qw(GET HEAD OPTIONS PATCH POST PUT);
our @EXPORT_OK = qw($DYNAMIC_FILE_UPLOAD DELETE QUERY);

@oalders oalders Jul 23, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

🤖 Posted by Claude Code (model: Claude Opus 4.8, claude-opus-4-8) on behalf of @oalders


require HTTP::Request;
use Carp();
Expand All @@ -22,10 +22,11 @@ my $CRLF = "\015\012"; # "\r\n" is not portable
sub GET { _simple_req('GET', @_); }
sub HEAD { _simple_req('HEAD', @_); }
sub DELETE { _simple_req('DELETE', @_); }
sub OPTIONS { request_type_with_data('OPTIONS', @_); }
sub PATCH { request_type_with_data('PATCH', @_); }
sub POST { request_type_with_data('POST', @_); }
sub PUT { request_type_with_data('PUT', @_); }
sub OPTIONS { request_type_with_data('OPTIONS', @_); }
sub QUERY { request_type_with_data('QUERY', @_); }

sub request_type_with_data
{
Expand Down Expand Up @@ -316,6 +317,10 @@ __END__
$ua->request(PUT 'http://somewhere/foo', foo => bar, bar => foo);
$ua->request(OPTIONS 'http://somewhere/foo', foo => bar, bar => foo);

use HTTP::Request::Common qw(DELETE QUERY);
$ua->request(DELETE 'http://somewhere/foo', foo => bar, bar => foo);
$ua->request(QUERY 'http://somewhere/foo', foo => bar, bar => foo);

=head1 DESCRIPTION

This module provides functions that return newly created C<HTTP::Request>
Expand Down Expand Up @@ -417,7 +422,7 @@ This was added in version 6.21, so you should require that in your code:

=item POST $url, Header => Value,..., Content => $content

C<POST>, C<PATCH> and C<PUT> all work with the same parameters.
C<OPTIONS>, C<POST>, C<PATCH>, C<PUT> and C<QUERY> all work with the same parameters.

%data = ( title => 'something', body => something else' );
$ua = LWP::UserAgent->new();
Expand Down Expand Up @@ -536,11 +541,30 @@ the file is not a plain file, there will be no C<Content-Length> header
defined for the request. Not all servers (or server
applications) like this. Also, if the file(s) change in size between
the time the C<Content-Length> is calculated and the time that the last
chunk is delivered, the subroutine will C<Croak>.
chunk is delivered, the subroutine will C<croak>.

The C<post(...)> method of L<LWP::UserAgent> exists as a shortcut for
C<< $ua->request(POST ...) >>.

=item QUERY $url

=item QUERY $url, Header => Value,...

=item QUERY $url, $form_ref, Header => Value,...

=item QUERY $url, Header => Value,..., Content => $form_ref

=item QUERY $url, Header => Value,..., Content => $content

The same as C<POST> above, but the method in the request is C<QUERY>,
the safe, idempotent method with content defined by
L<RFC 10008|https://www.rfc-editor.org/rfc/rfc10008.html>.
This function is not exported by default.

This was added in version 7.04, so you should require that in your code:

use HTTP::Request::Common 7.04 qw(QUERY);

=back

=head1 SEE ALSO
Expand Down
28 changes: 26 additions & 2 deletions t/common-req.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use Test::More;
use File::Spec;
use File::Temp qw(tempfile);
use HTTP::Request::Common;
use HTTP::Request::Common qw(QUERY);

my $r = GET 'http://www.sn.no/';
note $r->as_string;
Expand Down Expand Up @@ -72,6 +73,23 @@ $r = PATCH "http://www.sn.no",
{ foo => "bar" };
is($r->content, "foo=bar");

$r = QUERY "http://www.sn.no",
Content => 'foo';
note $r->as_string, "\n";

is($r->method, "QUERY");
is($r->uri->host, "www.sn.no");

ok(!defined($r->header("Content")));

is(${$r->content_ref}, "foo");
is($r->content, "foo");
is($r->content_length, 3);

$r = QUERY "http://www.sn.no",
{ foo => "bar" };
is($r->content, "foo=bar");

#--- Test POST requests ---

$r = POST "http://www.sn.no", [foo => 'bar;baz',
Expand Down Expand Up @@ -262,15 +280,21 @@ $r = HTTP::Request::Common::DELETE 'http://www.example.com';
is($r->method, "DELETE");

$r = HTTP::Request::Common::PUT 'http://www.example.com',
'Content-Type' => 'application/octet-steam',
'Content-Type' => 'application/octet-stream',
'Content' => 'foobarbaz',
'Content-Length' => 12; # a slight lie
is($r->header('Content-Length'), 9);

$r = HTTP::Request::Common::PATCH 'http://www.example.com',
'Content-Type' => 'application/octet-steam',
'Content-Type' => 'application/octet-stream',
'Content' => 'foobarbaz',
'Content-Length' => 12; # a slight lie
is($r->header('Content-Length'), 9);

$r = HTTP::Request::Common::QUERY 'http://www.example.com',
'Content-Type' => 'application/octet-stream',
'Content' => 'foobarbaz',
'Content-Length' => 12;
is($r->header('Content-Length'), 9, 'Content-Length is recalculated, not taken from the header');

done_testing();
Loading