fix: guard async responses with local flag

This commit is contained in:
2025-12-29 15:08:26 +01:00
parent 15f082fcdc
commit e2c4916565
2 changed files with 28 additions and 8 deletions

View File

@@ -6,11 +6,14 @@ use Urupam::Utils qw(sanitize_input get_error_status sanitize_error_message);
sub shorten { sub shorten {
my $c = shift; my $c = shift;
$c->render_later; $c->render_later;
my $responded = 0;
my $url_service = $c->url_service; my $url_service = $c->url_service;
my $validator = $c->validator; my $validator = $c->validator;
my $json = $c->req->json; my $json = $c->req->json;
unless ( defined $json && ref $json eq 'HASH' ) { unless ( defined $json && ref $json eq 'HASH' ) {
return if $responded;
$responded = 1;
$c->render( $c->render(
json => { error => 'Invalid JSON format' }, json => { error => 'Invalid JSON format' },
status => 400 status => 400
@@ -21,6 +24,8 @@ sub shorten {
my $original_url = sanitize_input( $json->{url} || '' ); my $original_url = sanitize_input( $json->{url} || '' );
unless ($original_url) { unless ($original_url) {
return if $responded;
$responded = 1;
$c->render( $c->render(
json => { error => 'URL is required' }, json => { error => 'URL is required' },
status => 400 status => 400
@@ -38,7 +43,8 @@ sub shorten {
)->then( )->then(
sub { sub {
my $short_code = shift; my $short_code = shift;
return if $c->rendered; return if $responded;
$responded = 1;
my $short_url = $c->url_for("/$short_code")->to_abs; my $short_url = $c->url_for("/$short_code")->to_abs;
$c->render( $c->render(
json => { json => {
@@ -52,7 +58,8 @@ sub shorten {
)->catch( )->catch(
sub { sub {
my $err = shift; my $err = shift;
return if $c->rendered; return if $responded;
$responded = 1;
$c->app->log->error("API URL validation/creation error: $err"); $c->app->log->error("API URL validation/creation error: $err");
my $status = get_error_status($err); my $status = get_error_status($err);
my $sanitized_error = sanitize_error_message($err); my $sanitized_error = sanitize_error_message($err);
@@ -67,11 +74,14 @@ sub shorten {
sub get_url { sub get_url {
my $c = shift; my $c = shift;
$c->render_later; $c->render_later;
my $responded = 0;
my $short_code = $c->param('short_code') // ''; my $short_code = $c->param('short_code') // '';
my $url_service = $c->url_service; my $url_service = $c->url_service;
my $validator = $c->validator; my $validator = $c->validator;
unless ( $short_code && $validator->validate_short_code($short_code) ) { unless ( $short_code && $validator->validate_short_code($short_code) ) {
return if $responded;
$responded = 1;
$c->render( $c->render(
json => { error => 'Invalid short code format' }, json => { error => 'Invalid short code format' },
status => 400 status => 400
@@ -82,7 +92,8 @@ sub get_url {
return $url_service->get_original_url($short_code)->then( return $url_service->get_original_url($short_code)->then(
sub { sub {
my $original_url = shift; my $original_url = shift;
return if $c->rendered; return if $responded;
$responded = 1;
if ($original_url) { if ($original_url) {
my $short_url = $c->url_for("/$short_code")->to_abs; my $short_url = $c->url_for("/$short_code")->to_abs;
$c->render( $c->render(
@@ -104,7 +115,8 @@ sub get_url {
)->catch( )->catch(
sub { sub {
my $err = shift; my $err = shift;
return if $c->rendered; return if $responded;
$responded = 1;
$c->app->log->error("API URL retrieval error: $err"); $c->app->log->error("API URL retrieval error: $err");
my $status = get_error_status($err); my $status = get_error_status($err);
my $sanitized_error = sanitize_error_message($err); my $sanitized_error = sanitize_error_message($err);

View File

@@ -43,9 +43,11 @@ sub startup {
cb => sub { cb => sub {
my $c = shift; my $c = shift;
$c->render_later; $c->render_later;
my $responded = 0;
$c->db->ping->then( $c->db->ping->then(
sub { sub {
return if $c->rendered; return if $responded;
$responded = 1;
$c->render( $c->render(
json => { json => {
status => 'ok', status => 'ok',
@@ -56,7 +58,8 @@ sub startup {
)->catch( )->catch(
sub { sub {
my $err = shift; my $err = shift;
return if $c->rendered; return if $responded;
$responded = 1;
$c->app->log->error("Health check DB error: $err"); $c->app->log->error("Health check DB error: $err");
$c->render( $c->render(
json => { json => {
@@ -96,6 +99,7 @@ sub startup {
cb => sub { cb => sub {
my $c = shift; my $c = shift;
$c->render_later; $c->render_later;
my $responded = 0;
my $short_code = $c->param('short_code') // ''; my $short_code = $c->param('short_code') // '';
my $url_service = $c->url_service; my $url_service = $c->url_service;
my $validator = $c->validator; my $validator = $c->validator;
@@ -103,6 +107,8 @@ sub startup {
unless ( $short_code unless ( $short_code
&& $validator->validate_short_code($short_code) ) && $validator->validate_short_code($short_code) )
{ {
return if $responded;
$responded = 1;
$c->render( $c->render(
template => '404', template => '404',
status => 404 status => 404
@@ -113,7 +119,8 @@ sub startup {
return $url_service->get_original_url($short_code)->then( return $url_service->get_original_url($short_code)->then(
sub { sub {
my $original_url = shift; my $original_url = shift;
return if $c->rendered; return if $responded;
$responded = 1;
if ($original_url) { if ($original_url) {
$c->redirect_to($original_url); $c->redirect_to($original_url);
} }
@@ -127,7 +134,8 @@ sub startup {
)->catch( )->catch(
sub { sub {
my $err = shift; my $err = shift;
return if $c->rendered; return if $responded;
$responded = 1;
$c->app->log->error("Redirect lookup error: $err"); $c->app->log->error("Redirect lookup error: $err");
$c->render( $c->render(
template => '500', template => '500',