Skip to content

Commit c997233

Browse files
committed
Implement GET action also matching HEAD
1 parent 76a63e2 commit c997233

3 files changed

Lines changed: 46 additions & 5 deletions

File tree

lib/Thunderhorse.pm

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,20 @@ Action format is C<scope.method> where scope is one of C<http>, C<sse>, or
568568
C<websocket>, and method is an HTTP method for C<http> or C<sse> scope, or
569569
omitted for C<websocket>. Either part can be C<*> to match anything.
570570
571+
If a C<.get> route is created, it is automatically valid for similar C<HEAD>
572+
requests as well. If special C<HEAD> handling is required, a check can be made
573+
in handler code:
574+
575+
sub handle ($self, $ctx)
576+
{
577+
...; # set headers
578+
579+
# return empty (but defined) response if we have HEAD, full body
580+
# otherwise
581+
return '' if $ctx->req->is_head;
582+
return 'full body';
583+
}
584+
571585
Common action patterns:
572586
573587
# Match only HTTP POST requests
@@ -579,7 +593,7 @@ Common action patterns:
579593
# Match only WebSocket connections
580594
action => 'websocket'
581595
582-
# Match only Server-Sent GET Events
596+
# Match only Server-Sent GET and HEAD Events
583597
action => 'sse.get'
584598
585599
# Match any request type (default)
@@ -592,6 +606,16 @@ allowing different handlers for different request types:
592606
$router->add('/api/data' => { to => 'post_data', action => 'http.post' });
593607
$router->add('/api/data' => { to => 'stream_data', action => 'websocket' });
594608
609+
If the handler is the same for all actions, it can be achieved with a simple
610+
for loop:
611+
612+
for my $action (qw(http.get http.post websocket)) {
613+
$router->add('/api/data' => { to => 'handle_api_data', action => $action });
614+
}
615+
616+
Make sure that the order of route building is deterministic, and that C<name>
617+
(if provided) is unique.
618+
595619
=head3 PAGI compatibility
596620
597621
Thunderhorse was coded in such a way that allows it to fully integrate the PAGI

lib/Thunderhorse/Router/Location.pm

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,17 @@ sub BUILD ($self, $)
6363
sub _build_action_re ($self)
6464
{
6565
my ($scope, $method) = split /\./, $self->action;
66-
$scope = $scope eq '*' ? qr{[^.]+} : quotemeta $scope;
67-
$method = ($method // '*') eq '*' ? qr{(\.[^.]+)?} : quotemeta ".$method";
66+
$scope = $scope eq '*' ? qr{[^.]+} : quotemeta lc $scope;
67+
68+
if (($method // '*') eq '*') {
69+
$method = qr{(\.[^.]+)?};
70+
}
71+
elsif (lc $method eq 'get') {
72+
$method = '[.](get|head)';
73+
}
74+
else {
75+
$method = quotemeta lc ".$method";
76+
}
6877

6978
return qr{^$scope$method$};
7079
}

t/router-actions.t

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ package TestApp {
5858
# Test multiple routes on same path with different actions
5959
$router->add(
6060
'/multi' => {
61-
action => 'http.get',
61+
action => 'HTTP.GET',
6262
}
6363
);
6464

@@ -90,6 +90,11 @@ subtest 'should match exact scope and method' => sub {
9090
is $no_match, undef, 'ws.get did not match';
9191
};
9292

93+
subtest 'should match head with get' => sub {
94+
my $match = _get_match($router, '/exact', 'http.head');
95+
ok $match, 'route matched';
96+
};
97+
9398
subtest 'should match wildcard method' => sub {
9499
my $match = _get_match($router, '/wildcard-method', 'http.get');
95100
ok $match, 'http.get matched';
@@ -156,7 +161,10 @@ subtest 'should match no action (matches anything)' => sub {
156161

157162
subtest 'should match correct action on same path' => sub {
158163
my $match = _get_match($router, '/multi', 'http.get');
159-
is $match->location->action, 'http.get', 'http.get matched';
164+
is $match->location->action, 'HTTP.GET', 'http.get matched';
165+
166+
$match = _get_match($router, '/multi', 'http.head');
167+
is $match->location->action, 'HTTP.GET', 'http.head matched';
160168

161169
$match = _get_match($router, '/multi', 'http.post');
162170
is $match->location->action, 'http.post', 'http.post matched';

0 commit comments

Comments
 (0)