diff --git a/Changes b/Changes index 3a9f7ef4..2687e764 100644 --- a/Changes +++ b/Changes @@ -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 diff --git a/lib/HTTP/Request.pm b/lib/HTTP/Request.pm index c557ff6a..dafdb6e5 100644 --- a/lib/HTTP/Request.pm +++ b/lib/HTTP/Request.pm @@ -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 diff --git a/lib/HTTP/Request/Common.pm b/lib/HTTP/Request/Common.pm index e83a51e6..2fa92f2e 100644 --- a/lib/HTTP/Request/Common.pm +++ b/lib/HTTP/Request/Common.pm @@ -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); require HTTP::Request; use Carp(); @@ -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 { @@ -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 @@ -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, C and C all work with the same parameters. +C, C, C, C and C all work with the same parameters. %data = ( title => 'something', body => something else' ); $ua = LWP::UserAgent->new(); @@ -536,11 +541,30 @@ the file is not a plain file, there will be no C 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 is calculated and the time that the last -chunk is delivered, the subroutine will C. +chunk is delivered, the subroutine will C. The C method of L 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 above, but the method in the request is C, +the safe, idempotent method with content defined by +L. +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 diff --git a/t/common-req.t b/t/common-req.t index 0e4949d6..0ff8f9a0 100644 --- a/t/common-req.t +++ b/t/common-req.t @@ -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; @@ -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', @@ -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();