Security Advisories (10)
CPANSA-Mojolicious-2022-03 (2022-12-10)

Mojo::DOM did not correctly parse <script> tags.

CPANSA-Mojolicious-2021-02 (2021-06-01)

Small sessions could be used as part of a brute-force attack to decode the session secret.

CVE-2021-47208 (2021-03-16)

A bug in format detection can potentially be exploited for a DoS attack.

CVE-2018-25100 (2018-02-13)

Mojo::UserAgent::CookieJar leaks old cookies because of the missing host_only flag on empty domain.

CPANSA-Mojolicious-2015-01 (2015-02-02)

Directory traversal on Windows

CPANSA-Mojolicious-2018-03 (2018-05-19)

Mojo::UserAgent was not checking peer SSL certificates by default.

CPANSA-Mojolicious-2018-02 (2018-05-11)

GET requests with embedded backslashes can be used to access local files on Windows hosts

CPANSA-Mojolicious-2014-01 (2014-10-07)

Context sensitivity of method param could lead to parameter injection attacks.

CVE-2011-1589 (2011-04-05)

Directory traversal vulnerability in Path.pm in Mojolicious before 1.16 allows remote attackers to read arbitrary files via a %2f..%2f (encoded slash dot dot slash) in a URI.

CVE-2024-58134 (2025-05-03)

Mojolicious versions from 0.999922 for Perl uses a hard coded string, or the application's class name, as a HMAC session secret by default. These predictable default secrets can be exploited to forge session cookies. An attacker who knows or guesses the secret could compute valid HMAC signatures for the session cookie, allowing them to tamper with or hijack another user's session.

NAME

Mojo::UserAgent - Async IO HTTP 1.1 And WebSocket User Agent

SYNOPSIS

use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;

# Grab the latest Mojolicious release :)
my $latest = 'http://latest.mojolicio.us';
print $ua->max_redirects(3)->get($latest)->res->body;

# Quick JSON request
my $trends = 'http://search.twitter.com/trends.json';
print $ua->get($trends)->res->json->{trends}->[0]->{name};

# Extract data from HTML and XML resources
print $ua->get('mojolicio.us')->res->dom->at('title')->text;

# Scrape the latest headlines from a news site
my $news = 'http://digg.com';
$ua->max_redirects(3);
$ua->get($news)->res->dom('h3 > a.story-title')->each(sub {
  print shift->text . "\n";
});

# Form post with exception handling
my $cpan   = 'http://search.cpan.org/search';
my $search = {q => 'mojo'};
my $tx     = $ua->post_form($cpan => $search);
if (my $res = $tx->success) { print $res->body }
else {
  my ($message, $code) = $tx->error;
  print "Error: $message";
}

# TLS certificate authentication
$ua->cert('tls.crt')->key('tls.key')->get('https://mojolicio.us');

# Websocket request
$ua->websocket('ws://websockets.org:8787' => sub {
  my $tx = pop;
  $tx->on_finish(sub { Mojo::IOLoop->stop });
  $tx->on_message(sub {
    my ($tx, $message) = @_;
    print "$message\n";
    $tx->finish;
  });
  $tx->send_message('hi there!');
});
Mojo::IOLoop->start;

DESCRIPTION

Mojo::UserAgent is a full featured async io HTTP 1.1 and WebSocket user agent with IPv6, TLS, epoll and kqueue support.

Optional modules IO::KQueue, IO::Epoll, IO::Socket::IP and IO::Socket::SSL are supported transparently and used if installed.

ATTRIBUTES

Mojo::UserAgent implements the following attributes.

app

my $app = $ua->app;
$ua     = $ua->app(MyApp->new);

A Mojo application to associate this user agent with. If set, local requests will be processed in this application.

cert

my $cert = $ua->cert;
$ua      = $ua->cert('tls.crt');

Path to TLS certificate file.

my $cookie_jar = $ua->cookie_jar;
$ua            = $ua->cookie_jar(Mojo::CookieJar->new);

Cookie jar to use for this user agents requests, by default a Mojo::CookieJar object.

http_proxy

my $proxy = $ua->http_proxy;
$ua       = $ua->http_proxy('http://sri:secret@127.0.0.1:8080');

Proxy server to use for HTTP and WebSocket requests.

https_proxy

my $proxy = $ua->https_proxy;
$ua       = $ua->https_proxy('http://sri:secret@127.0.0.1:8080');

Proxy server to use for HTTPS and WebSocket requests.

ioloop

my $loop = $ua->ioloop;
$ua      = $ua->ioloop(Mojo::IOLoop->new);

Loop object to use for blocking io operations, by default a Mojo::IOLoop object will be used.

keep_alive_timeout

my $keep_alive_timeout = $ua->keep_alive_timeout;
$ua                    = $ua->keep_alive_timeout(15);

Timeout in seconds for keep alive between requests, defaults to 15.

key

my $key = $ua->key;
$ua     = $ua->key('tls.crt');

Path to TLS key file.

log

my $log = $ua->log;
$ua     = $ua->log(Mojo::Log->new);

A Mojo::Log object used for logging, by default the application log will be used.

max_connections

my $max_connections = $ua->max_connections;
$ua                 = $ua->max_connections(5);

Maximum number of keep alive connections that the user agent will retain before it starts closing the oldest cached ones, defaults to 5.

max_redirects

my $max_redirects = $ua->max_redirects;
$ua               = $ua->max_redirects(3);

Maximum number of redirects the user agent will follow before it fails, defaults to 0.

name

my $name = $ua->name;
$ua      = $ua->name('Mojolicious');

Value for User-Agent request header, defaults to Mojolicious (Perl).

no_proxy

my $no_proxy = $ua->no_proxy;
$ua          = $ua->no_proxy(['localhost', 'intranet.mojolicio.us']);

Domains that don't require a proxy server to be used. Note that this attribute is EXPERIMENTAL and might change without warning!

on_start

my $cb = $ua->on_start;
$ua    = $ua->on_start(sub {...});

Callback to be invoked whenever a new transaction is about to start, this includes automatically prepared proxy CONNECT requests and followed redirects.

$ua->on_start(sub {
  my ($ua, $tx) = @_;
  $tx->req->headers->header('X-Bender', 'Bite my shiny metal ass!');
});

websocket_timeout

my $websocket_timeout = $ua->websocket_timeout;
$ua                   = $ua->websocket_timeout(300);

Timeout in seconds for WebSockets to be idle, defaults to 300.

METHODS

Mojo::UserAgent inherits all methods from Mojo::Base and implements the following new ones.

build_form_tx

my $tx = $ua->build_form_tx('http://kraih.com/foo' => {test => 123});
my $tx = $ua->build_form_tx(
  'http://kraih.com/foo',
  'UTF-8',
  {test => 123}
);
my $tx = $ua->build_form_tx(
  'http://kraih.com/foo',
  {test => 123},
  {Connection => 'close'}
);
my $tx = $ua->build_form_tx(
  'http://kraih.com/foo',
  'UTF-8',
  {test => 123},
  {Connection => 'close'}
);
my $tx = $ua->build_form_tx(
  'http://kraih.com/foo',
  {file => {file => '/foo/bar.txt'}}
);
my $tx = $ua->build_form_tx(
  'http://kraih.com/foo',
  {file => {content => 'lalala'}}
);
my $tx = $ua->build_form_tx(
  'http://kraih.com/foo',
  {myzip => {file => $asset, filename => 'foo.zip'}}
);

Versatile Mojo::Transaction::HTTP builder for forms.

my $tx = $ua->build_form_tx('http://kraih.com/foo' => {test => 123});
$tx->res->body(sub { print $_[1] });
$ua->start($tx);

build_tx

my $tx = $ua->build_tx(GET => 'mojolicio.us');
my $tx = $ua->build_tx(POST => 'http://mojolicio.us');
my $tx = $ua->build_tx(
  GET => 'http://kraih.com' => {Connection => 'close'}
);
my $tx = $ua->build_tx(
  POST => 'http://kraih.com' => {Connection => 'close'} => 'Hi!'
);

Versatile general purpose Mojo::Transaction::HTTP builder.

# Streaming response
my $tx = $ua->build_tx(GET => 'http://mojolicio.us');
$tx->res->body(sub { print $_[1] });
$ua->start($tx);

# Custom socket
my $tx = $ua->build_tx(GET => 'http://mojolicio.us');
$tx->connection($socket);
$ua->start($tx);

build_websocket_tx

my $tx = $ua->build_websocket_tx('ws://localhost:3000');

Versatile Mojo::Transaction::HTTP builder for WebSocket handshakes. An upgrade to Mojo::Transaction::WebSocket will happen automatically after a successful handshake is performed.

delete

my $tx = $ua->delete('http://kraih.com');
my $tx = $ua->delete('http://kraih.com' => {Connection => 'close'});
my $tx = $ua->delete(
  'http://kraih.com' => {Connection => 'close'} => 'Hi!'
);

Perform blocking HTTP DELETE request. You can also append a callback to perform requests non-blocking.

$ua->delete('http://kraih.com' => sub {
  print shift->res->body;
  Mojo::IOLoop->stop;
});
Mojo::IOLoop->start;

detect_proxy

$ua = $ua->detect_proxy;

Check environment variables HTTP_PROXY, http_proxy, HTTPS_PROXY, https_proxy, NO_PROXY and no_proxy for proxy information.

get

my $tx = $ua->get('http://kraih.com');
my $tx = $ua->get('http://kraih.com' => {Connection => 'close'});
my $tx = $ua->get(
  'http://kraih.com' => {Connection => 'close'} => 'Hi!'
);

Perform blocking HTTP GET request. You can also append a callback to perform requests non-blocking.

$ua->get('http://kraih.com' => sub {
  print shift->res->body;
  Mojo::IOLoop->stop;
});
Mojo::IOLoop->start;
my $tx = $ua->head('http://kraih.com');
my $tx = $ua->head('http://kraih.com' => {Connection => 'close'});
my $tx = $ua->head(
  'http://kraih.com' => {Connection => 'close'} => 'Hi!'
);

Perform blocking HTTP HEAD request. You can also append a callback to perform requests non-blocking.

$ua->head('http://kraih.com' => sub {
  print shift->res->body;
  Mojo::IOLoop->stop;
});
Mojo::IOLoop->start;

need_proxy

my $need_proxy = $ua->need_proxy('intranet.mojolicio.us');

Check if request for domain would use a proxy server. Note that this method is EXPERIMENTAL and might change without warning!

post

my $tx = $ua->post('http://kraih.com');
my $tx = $ua->post('http://kraih.com' => {Connection => 'close'});
my $tx = $ua->post(
  'http://kraih.com' => {Connection => 'close'} => 'Hi!'
);

Perform blocking HTTP POST request. You can also append a callback to perform requests non-blocking.

$ua->post('http://kraih.com' => sub {
  print shift->res->body;
  Mojo::IOLoop->stop;
});
Mojo::IOLoop->start;

post_form

my $tx = $ua->post_form('http://kraih.com/foo' => {test => 123});
my $tx = $ua->post_form(
  'http://kraih.com/foo'
  'UTF-8',
  {test => 123}
);
my $tx  = $ua->post_form(
  'http://kraih.com/foo',
  {test => 123},
  {Connection => 'close'}
);
my $tx  = $ua->post_form(
  'http://kraih.com/foo',
  'UTF-8',
  {test => 123},
  {Connection => 'close'}
);
my $tx = $ua->post_form(
  'http://kraih.com/foo',
  {file => {file => '/foo/bar.txt'}}
);
my $tx= $ua->post_form(
  'http://kraih.com/foo',
  {file => {content => 'lalala'}}
);
my $tx = $ua->post_form(
  'http://kraih.com/foo',
  {myzip => {file => $asset, filename => 'foo.zip'}}
);

Perform blocking HTTP POST request with form data. You can also append a callback to perform requests non-blocking.

$ua->post_form('http://kraih.com' => {q => 'test'} => sub {
  print shift->res->body;
  Mojo::IOLoop->stop;
});
Mojo::IOLoop->start;

put

my $tx = $ua->put('http://kraih.com');
my $tx = $ua->put('http://kraih.com' => {Connection => 'close'});
my $tx = $ua->put(
  'http://kraih.com' => {Connection => 'close'} => 'Hi!'
);

Perform blocking HTTP PUT request. You can also append a callback to perform requests non-blocking.

$ua->put('http://kraih.com' => sub {
  print shift->res->body;
  Mojo::IOLoop->stop;
});
Mojo::IOLoop->start;

start

$ua = $ua->start($tx);
$ua = $ua->start($tx => sub {...});

Process blocking transaction. You can also append a callback to perform transactions non-blocking.

$ua->start($tx => sub {
  print shift->res->body;
  Mojo::IOLoop->stop;
});
Mojo::IOLoop->start;

test_server

my $port = $ua->test_server;
my $port = $ua->test_server('https');

Starts a test server for app if necessary and returns the port number. Note that this method is EXPERIMENTAL and might change without warning!

websocket

$ua->websocket('ws://localhost:3000' => sub {...});
$ua->websocket(
  'ws://localhost:3000' => {'User-Agent' => 'Agent 1.0'} => sub {...}
);

Open a non-blocking WebSocket connection with transparent handshake.

$ua->websocket('ws://localhost:3000' => sub {
  my $tx = pop;
  $tx->on_finish(sub { Mojo::IOLoop->stop });
  $tx->on_message(sub { say pop });
  $tx->send_message('Hi!');
});
Mojo::IOLoop->start;

SEE ALSO

Mojolicious, Mojolicious::Guides, http://mojolicio.us.