Skip to content

Commit 41a0a6b

Browse files
Respect HTTP request method casing
While weird, mixed-case or lower-cased methods are totally legal, and some symbols are permitted too. The ABNF is here: https://www.rfc-editor.org/rfc/rfc9110#appendix-A
1 parent 990d344 commit 41a0a6b

File tree

13 files changed

+46
-33
lines changed

13 files changed

+46
-33
lines changed

lib/Mojo/Message/Request.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ sub _start_line {
216216
$path = "/$path" unless $path =~ m!^/!;
217217

218218
# CONNECT
219-
my $method = uc $self->method;
219+
my $method = $self->method;
220220
if ($method eq 'CONNECT') {
221221
my $port = $url->port // ($url->protocol eq 'https' ? '443' : '80');
222222
$path = $url->ihost . ":$port";

lib/Mojo/Transaction/HTTP.pm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ sub client_read {
88

99
# Skip body for HEAD request
1010
my $res = $self->res;
11-
$res->content->skip_body(1) if uc $self->req->method eq 'HEAD';
11+
$res->content->skip_body(1) if $self->req->method eq 'HEAD';
1212
return undef unless $res->parse($chunk)->is_finished;
1313

1414
# Unexpected 1xx response
@@ -20,7 +20,7 @@ sub client_read {
2020

2121
sub client_write { shift->_write(0) }
2222

23-
sub is_empty { !!(uc $_[0]->req->method eq 'HEAD' || $_[0]->res->is_empty) }
23+
sub is_empty { !!($_[0]->req->method eq 'HEAD' || $_[0]->res->is_empty) }
2424

2525
sub keep_alive {
2626
my $self = shift;

lib/Mojo/UserAgent.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ sub _finish {
245245
}
246246

247247
# CONNECT requests always have a follow-up request
248-
$self->_reuse($id, $close) unless uc $old->req->method eq 'CONNECT';
248+
$self->_reuse($id, $close) unless $old->req->method eq 'CONNECT';
249249
$res->error({message => $res->message, code => $res->code}) if $res->is_error;
250250
$c->{cb}($self, $old) unless $self->_redirect($c, $old);
251251
}

lib/Mojo/UserAgent/Transactor.pm

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ sub proxy_connect {
9494

9595
# Already a CONNECT request
9696
my $req = $old->req;
97-
return undef if uc $req->method eq 'CONNECT';
97+
return undef if $req->method eq 'CONNECT';
9898

9999
# No proxy
100100
return undef unless (my $proxy = $req->proxy) && $req->via_proxy;
@@ -122,7 +122,7 @@ sub redirect {
122122

123123
# CONNECT requests cannot be redirected
124124
my $req = $old->req;
125-
return undef if uc $req->method eq 'CONNECT';
125+
return undef if $req->method eq 'CONNECT';
126126

127127
# Fix location without authority and/or scheme
128128
return undef unless my $location = $res->headers->every_header('Location')->[0];
@@ -138,7 +138,7 @@ sub redirect {
138138
$new->req($clone);
139139
}
140140
else {
141-
my $method = uc $req->method;
141+
my $method = $req->method;
142142
$method = $code == 303 || $method eq 'POST' ? 'GET' : $method;
143143
$new->req->method($method)->content->headers(my $headers = $req->headers->clone);
144144
$headers->remove($_) for grep {/^content-/i} @{$headers->names};
@@ -229,7 +229,7 @@ sub _form {
229229
}
230230

231231
# Query parameters or urlencoded
232-
my $method = uc $req->method;
232+
my $method = $req->method;
233233
my @form = map { $_ => $form->{$_} } sort keys %$form;
234234
if ($method eq 'GET' || $method eq 'HEAD') { $req->url->query->merge(@form) }
235235
else {

lib/Mojolicious/Command/routes.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ sub _walk {
3535

3636
# Methods
3737
my $methods = $route->methods;
38-
push @$row, !$methods ? '*' : uc join ',', @$methods;
38+
push @$row, !$methods ? '*' : join ',', @$methods;
3939

4040
# Name
4141
my $name = $route->name;

lib/Mojolicious/Routes.pm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ sub match {
6565
else { $path = $req->url->path->to_route }
6666

6767
# Method (HEAD will be treated as GET)
68-
my $method = uc $req->method;
68+
my $method = $req->method;
6969
my $override = $req->url->query->clone->param('_method');
70-
$method = uc $override if $override && $method eq 'POST';
71-
$method = 'GET' if $method eq 'HEAD';
70+
$method = $override if $override && $method eq 'POST';
71+
$method = 'GET' if $method eq 'HEAD';
7272

7373
# Check cache
7474
my $ws = $c->tx->is_websocket ? 1 : 0;

lib/Mojolicious/Routes/Route.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ sub is_websocket { !!shift->{websocket} }
6161
sub methods {
6262
my $self = shift;
6363
return $self->{methods} unless @_;
64-
my $methods = [map uc($_), @{ref $_[0] ? $_[0] : [@_]}];
64+
my $methods = [@{ref $_[0] ? $_[0] : [@_]}];
6565
$self->{methods} = $methods if @$methods;
6666
return $self;
6767
}

lib/Mojolicious/resources/templates/mojo/debug.html.ep

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@
240240
<pre><%= ' ' x $depth %><%= $unparsed %></pre>
241241
</td>
242242
<td class="value">
243-
<pre><%= uc(join ',', @{$route->methods // []}) || '*' %></pre>
243+
<pre><%= (join ',', @{$route->methods // []}) || '*' %></pre>
244244
</td>
245245
<td class="value">
246246
% my $name = $route->name;

lib/Test/Mojo.pm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ sub _request_ok {
471471
$self->tx($self->ua->start($tx));
472472
my $err = $self->tx->error;
473473
Test::More::diag $err->{message} if !(my $ok = !$err->{message} || $err->{code}) && $err;
474-
return $self->test('ok', $ok, _desc("@{[uc $tx->req->method]} $url"));
474+
return $self->test('ok', $ok, _desc("@{[$tx->req->method]} $url"));
475475
}
476476

477477
sub _sse_ok {
@@ -499,7 +499,7 @@ sub _sse_ok {
499499
);
500500
Mojo::IOLoop->start;
501501

502-
return $self->test('ok', $ok, _desc("SSE connection established: @{[uc $tx->req->method]} $url"));
502+
return $self->test('ok', $ok, _desc("SSE connection established: @{[$tx->req->method]} $url"));
503503
}
504504

505505
sub _sse_wait {

t/mojo/request.t

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,11 +1149,24 @@ subtest 'Build HTTP 1.1 start-line and header (with clone and changes)' => sub {
11491149
is $clone->headers->host, '127.0.0.1', 'right "Host" value';
11501150
};
11511151

1152+
subtest 'method case and symbols are preserved' => sub {
1153+
my $req = Mojo::Message::Request->new;
1154+
my $finished = undef;
1155+
$req->on(finish => sub { $finished = shift->is_finished });
1156+
$req->method('P0$t!!');
1157+
$req->url->parse('http://127.0.0.1/foo/bar');
1158+
$req = Mojo::Message::Request->new->parse($req->to_string);
1159+
ok $req->is_finished, 'request is finished';
1160+
is $req->method, 'P0$t!!', 'right method, including weird casing';
1161+
ok $finished, 'finish event has been emitted';
1162+
ok $req->is_finished, 'request is finished';
1163+
};
1164+
11521165
subtest 'Build full HTTP 1.1 request' => sub {
11531166
my $req = Mojo::Message::Request->new;
11541167
my $finished = undef;
11551168
$req->on(finish => sub { $finished = shift->is_finished });
1156-
$req->method('get');
1169+
$req->method('GET');
11571170
$req->url->parse('http://127.0.0.1/foo/bar');
11581171
$req->headers->expect('100-continue');
11591172
$req->body("Hello World!\n");
@@ -1184,7 +1197,7 @@ subtest 'Build HTTP 1.1 request parts with progress' => sub {
11841197
$progress += $offset;
11851198
}
11861199
);
1187-
$req->method('get');
1200+
$req->method('GET');
11881201
$req->url->parse('http://127.0.0.1/foo/bar');
11891202
$req->headers->expect('100-continue');
11901203
$req->body("Hello World!\n");
@@ -1211,7 +1224,7 @@ subtest 'Build full HTTP 1.1 request (with clone)' => sub {
12111224
my $req = Mojo::Message::Request->new;
12121225
my $finished = undef;
12131226
$req->on(finish => sub { $finished = shift->is_finished });
1214-
$req->method('get');
1227+
$req->method('GET');
12151228
$req->url->parse('http://127.0.0.1/foo/bar');
12161229
$req->headers->expect('100-continue');
12171230
$req->body("Hello World!\n");

0 commit comments

Comments
 (0)