my ($id, $prev);
my $next_arg = $ctx->{next_arg} = [ $ctx->{mid}, \$id, \$prev ];
- my $smsg = $ctx->{smsg} = $over->next_by_mid(@$next_arg) or
- return; # undef == 404
-
+ my $smsg = $ctx->{smsg} = $over->next_by_mid(@$next_arg);
+ if (!$smsg && $ctx->{mid} =~ /\A\<(.+)\>\z/ and
+ ($next_arg->[0] = $1) and
+ ($over->next_by_mid(@$next_arg))) {
+ return PublicInbox::WWW::r301($ctx, undef, $next_arg->[0]);
+ }
+ $smsg or return; # undef=404
# allow user to easily browse the range around this message if
# they have ->over
$ctx->{-t_max} = $smsg->{ts};
$res = $cb->(GET(q{/test/?q=%22s'more%22&x=A}));
is $res->code, 200, 'single quote inside phrase';
+
+ $res = $cb->(GET("/test/<$mid>/"));
+ is $res->code, 301, "redirect for raw `<' and `>' in msgid";
+ like $res->header('location'), qr!/test/\Q$mid\E/\z!,
+ "redirected to URL without raw `<' and `>'";
+
+ $res = $cb->(GET("/test/%3c$mid%3e/"));
+ is $res->code, 301, "redirect for escaped `<' and `>' in msgid";
+ like $res->header('location'), qr!/test/\Q$mid\E/\z!,
+ "redirected to URL without escaped `<' and `>'";
+
# TODO: more tests and odd cases
});