Name
SPVM::Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent
Description
Mojo::UserAgent class in SPVM is a full featured non-blocking I/O HTTP and WebSocket user agent, with IPv6, TLS, SNI, IDNA, HTTP proxy, UNIX domain socket, Comet (long polling), Promises/A+, keep-alive, connection pooling, timeout, cookie, multipart, gzip compression and multiple event loop support.
Usage
use Mojo::UserAgent;
# Fine grained response handling (dies on connection errors)
my $ua  = Mojo::UserAgent->new;
my $res = $ua->get("docs.mojolicious.org")->result;
if    ($res->is_success)  { say $res->body }
elsif ($res->is_error)    { say $res->message }
elsif ($res->code == 301) { say $res->headers->location }
else                      { say "Whatever..." }
# Say hello to the Unicode snowman and include an Accept header
say $ua->get("www.☃.net?hello=there" => {Accept => "*/*"})->result->body;
# IPv6 PUT request with Content-Type header and content
my $tx = $ua->put("[::1]:3000" => {"Content-Type" => "text/plain"} => "Hi!");
# Quick JSON API request with Basic authentication
my $url = (my $_ = Mojo::URL->new("https://example.com/test.json"), $_->set_userinfo("sri:☃"), $_);
my $value = $ua->get($url)->result->json;
# JSON POST (application/json) with TLS certificate authentication
my $tx = ($ua->set_cert("tls.crt"), $ua->set_key("tls.key"), $ua->post("https://example.com" => [(object)json => {top => "secret"}]));
# Form POST (application/x-www-form-urlencoded)
my $tx = $ua->post("https://metacpan.org/search" => [(object)form => {q => "mojo"}]);
# Search DuckDuckGo anonymously through Tor
$ua->proxy->http("socks://127.0.0.1:9050");
$ua->get("api.3g2upl4pq6kufc4m.onion/?q=mojolicious&format=json")->result->json;
# GET request via UNIX domain socket "/tmp/myapp.sock" (percent encoded slash)
say $ua->get("http+unix://%2Ftmp%2Fmyapp.sock/test")->result->body;
# Follow redirects to download Mojolicious from GitHub
($ua->set_max_redirects(5),
  $ua->get("https://www.github.com/mojolicious/mojo/tarball/main")
  ->result->save_to("/home/sri/mojo.tar.gz"));
Class Methods
new
static method new : Mojo::UserAgent ();
Create a new Mojo::UserAgent object, and return it.
Instance Methods
build_tx
method build_tx : Mojo::Transaction::HTTP ($method : string, $url : string|Mojo::URL, $args1 : object = undef, $args2 : object = undef);
Generate Mojo::Transaction::HTTP object with Mojo::UserAgent::Transactor#tx.
Examples:
my $tx = $ua->build_tx(GET => "example.com");
my $tx = $ua->build_tx(PUT => "http://example.com" => {Accept => "*/*"} => "Content!");
my $tx = $ua->build_tx(PUT => "http://example.com" => {Accept => "*/*"} => [(object)form => {a => "b"}]);
my $tx = $ua->build_tx(PUT => "http://example.com" => {Accept => "*/*"} => [(object)json => {a => "b"}]);
# Request with custom cookie
my $tx = $ua->build_tx(GET => "https://example.com/account");
$tx->req->cookies({name => "user", value => "sri"});
$tx = $ua->start($tx);
# Deactivate gzip compression
my $tx = $ua->build_tx(GET => "example.com");
$tx->req->headers->remove("Accept-Encoding");
$tx = $ua->start($tx);
# Interrupt response by raising an error
my $tx = $ua->build_tx(GET => "http://example.com");
$tx->res->on(progress => method ($res : Mojo::Message::Response) {
  unless (my $server = $res->headers->server) {
    return;
  }
  
  if (Re->m($server, "IIS")) {
    die "Oh noes, it is IIS!";
  }
});
$tx = $ua->start($tx);
build_websocket_tx
Not yet implemented.
delete
method delete : Mojo::Transaction::HTTP ($url : string|Mojo::URL, $args1 : object = undef, $args2 : object = undef);
Perform blocking DELETE request and return resulting Mojo::Transaction::HTTP object, takes the same arguments as "tx" in Mojo::UserAgent::Transactor (except for the DELETE method, which is implied).
Examples:
my $tx = $ua->delete("example.com");
my $tx = $ua->delete("http://example.com" => {Accept => "*/*"} => "Content!");
my $tx = $ua->delete("http://example.com" => {Accept => "*/*"} => [(object)form => {a => "b"}]);
my $tx = $ua->delete("http://example.com" => {Accept => "*/*"} => [(object)json => {a => "b"}]);
get
method get : Mojo::Transaction::HTTP ($url : string|Mojo::URL, $args1 : object = undef, $args2 : object = undef);
Perform blocking GET request and return resulting Mojo::Transaction::HTTP object, takes the same arguments as "tx" in Mojo::UserAgent::Transactor (except for the GET method, which is implied).
Examples:
my $tx = $ua->get("example.com");
my $tx = $ua->get("http://example.com" => {Accept => "*/*"} => "Content!");
my $tx = $ua->get("http://example.com" => {Accept => "*/*"} => [(object)form => {a => "b"}]);
my $tx = $ua->get("http://example.com" => {Accept => "*/*"} => [(object)json => {a => "b"}]);
head
method head : Mojo::Transaction::HTTP ($url : string|Mojo::URL, $args1 : object = undef, $args2 : object = undef);
Perform blocking HEAD request and return resulting Mojo::Transaction::HTTP object, takes the same arguments as "tx" in Mojo::UserAgent::Transactor (except for the HEAD method, which is implied).
Examples:
my $tx = $ua->head("example.com");
my $tx = $ua->head("http://example.com" => {Accept => "*/*"} => "Content!");
my $tx = $ua->head("http://example.com" => {Accept => "*/*"} => [(object)form => {a => "b"}]);
my $tx = $ua->head("http://example.com" => {Accept => "*/*"} => [(object)json => {a => "b"}]);
options
method options : Mojo::Transaction::HTTP ($url : string|Mojo::URL, $args1 : object = undef, $args2 : object = undef);
Perform blocking OPTIONS request and return resulting Mojo::Transaction::HTTP object, takes the same arguments as "tx" in Mojo::UserAgent::Transactor (except for the OPTIONS method, which is implied).
Examples:
my $tx = $ua->options("example.com");
my $tx = $ua->options("http://example.com" => {Accept => "*/*"} => "Content!");
my $tx = $ua->options("http://example.com" => {Accept => "*/*"} => [(object)form => {a => "b"}]);
my $tx = $ua->options("http://example.com" => {Accept => "*/*"} => [(object)json => {a => "b"}]);
patch
method patch : Mojo::Transaction::HTTP ($url : string|Mojo::URL, $args1 : object = undef, $args2 : object = undef);
Perform blocking PATCH request and return resulting Mojo::Transaction::HTTP object, takes the same arguments as "tx" in Mojo::UserAgent::Transactor (except for the PATCH method, which is implied).
Examples:
my $tx = $ua->patch("example.com");
my $tx = $ua->patch("http://example.com" => {Accept => "*/*"} => "Content!");
my $tx = $ua->patch("http://example.com" => {Accept => "*/*"} => [(object)form => {a => "b"}]);
my $tx = $ua->patch("http://example.com" => {Accept => "*/*"} => [(object)json => {a => "b"}]);
post
method post : Mojo::Transaction::HTTP ($url : string|Mojo::URL, $args1 : object = undef, $args2 : object = undef);
Perform blocking POST request and return resulting Mojo::Transaction::HTTP object, takes the same arguments as "tx" in Mojo::UserAgent::Transactor (except for the POST method, which is implied).
Examples:
my $tx = $ua->post("example.com");
my $tx = $ua->post("http://example.com" => {Accept => "*/*"} => "Content!");
my $tx = $ua->post("http://example.com" => {Accept => "*/*"} => [(object)form => {a => "b"}]);
my $tx = $ua->post("http://example.com" => {Accept => "*/*"} => [(object)json => {a => "b"}]);
put
method put : Mojo::Transaction::HTTP ($url : string|Mojo::URL, $args1 : object = undef, $args2 : object = undef);
Perform blocking PUT request and return resulting Mojo::Transaction::HTTP object, takes the same arguments as "tx" in Mojo::UserAgent::Transactor (except for the PUT method, which is implied).
Examples:
my $tx = $ua->put("example.com");
my $tx = $ua->put("http://example.com" => {Accept => "*/*"} => "Content!");
my $tx = $ua->put("http://example.com" => {Accept => "*/*"} => [(object)form => {a => "b"}]);
my $tx = $ua->put("http://example.com" => {Accept => "*/*"} => [(object)json => {a => "b"}]);
start
method start : Mojo::Transaction::HTTP ($tx : Mojo::Transaction::HTTP);
Perform blocking request for a custom Mojo::Transaction::HTTP object, which can be prepared manually or with "build_tx".
Examples:
my $tx = $ua->start(Mojo::Transaction::HTTP->new);
websocket
Not yet implemented.
See Also
Copyright & License
Copyright (c) 2025 Yuki Kimoto
MIT License