My goal is to:
$tx->req->to_string
The re-use program looks like this:
use Mojo::Util qw/dumper/;
use Mojo::File qw/path/;
use Mojo::UserAgent;
use Mojo::Message::Request;
use Mojo::Transaction::HTTP;
my $req_string = path($ARGV[0])->slurp;
my $ua = Mojo::UserAgent->new;
my $tx = Mojo::Transaction::HTTP->new;
$tx->req->parse($req_string);
print dumper $tx->req; # seems to print a valid Mojo::Message::Request object
$tx = $ua->start($tx);
# this fails with Can't call method "server" on an undefined value at /home/me/perl5/perlbrew/perls/perl-5.30.2/lib/site_perl/5.30.2/Mojo/Server/Daemon.pm line 55.
print dumper $tx->res->body;
which fails at line 16 with
Can't call method "server" on an undefined value at /home/me/perl5/perlbrew/perls/perl-5.30.2/lib/site_perl/5.30.2/Mojo/Server/Daemon.pm line 55.
In general, this seems to fail:
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;
my $tx = Mojo::Transaction::HTTP->new;
# more transaction defining stuff
$tx = $ua->start($tx);
print $tx->res->body; # success!
my $txt = $tx->req->to_string;
$tx = Mojo::Transaction::HTTP->new;
$tx->req->parse($txt);
$tx = $ua->start($tx); # failure!
print $tx->res->body;
What am I doing wrong?
I have no idea whether this is a bug or not. This seems to fix the problem:
$tx = 'Mojo::Transaction::HTTP'->new;
$tx->req->parse($txt);
$tx->req->url($tx->req->url->to_abs);
$tx = $ua->start($tx); # No more failures!
Why does this help?
If you added Carp::Always, you'd see that the error comes from line 317 in Mojo::UserAgent:
if (!$url->is_abs && (my $server = $self->server)) {
my $base = $loop == $self->ioloop ? $server->url : $server->nb_url; # <- LINE 317.
$url->scheme($base->scheme)->host($base->host)->port($base->port);
}
How comes the $url is not absolute? Becuase in Mojo::URL, is_abs
is defined as
sub is_abs { !!shift->scheme }
And if we inspect the url coming from the request, it indeed doesn't have a scheme:
#! /usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
use Mojo::Message::Request;
use Mojo::URL;
my $url1 = 'Mojo::URL'->new('http://example.com');
say $url1->to_string, ' ', $url1->is_abs ? 'abs' : '!abs'; # Is absolute.
my $txt = join "\r\n", 'GET / HTTP/1.1', 'Host: example.com', "", "";
my $url2 = 'Mojo::Message::Request'->new->parse($txt)->url;
say $url2->to_string, ' ', $url2->is_abs ? 'abs' : '!abs'; # Isn't absolute!
print Dumper $url1, $url2;
You can see the difference in the Data::Dumper output:
$VAR1 = bless( {
'query' => bless( {
'pairs' => [],
'charset' => 'UTF-8'
}, 'Mojo::Parameters' ),
'path' => bless( {
'parts' => [],
'leading_slash' => '',
'charset' => 'UTF-8',
'trailing_slash' => ''
}, 'Mojo::Path' ),
'scheme' => 'http',
'host' => 'example.com'
}, 'Mojo::URL' );
$VAR1 = bless( {
'path' => bless( {
'charset' => 'UTF-8',
'path' => '/'
}, 'Mojo::Path' ),
'query' => bless( {
'charset' => 'UTF-8',
'pairs' => []
}, 'Mojo::Parameters' ),
'base' => bless( {
'scheme' => 'http',
'host' => 'example.com'
}, 'Mojo::URL' )
}, 'Mojo::URL' );
That's also why the hack above fixes the problem: it sets the missing scheme (and host) in the second URL.
Let's now wait for someone more Mojo-savvy to explain all this to us.