diff --git a/lib/DBDefs/Default.pm b/lib/DBDefs/Default.pm index ead739e71c6..a972ea9a502 100644 --- a/lib/DBDefs/Default.pm +++ b/lib/DBDefs/Default.pm @@ -351,6 +351,10 @@ sub INTERNET_ARCHIVE_IA_METADATA_PREFIX { 'https://archive.org/metadata' } sub COVER_ART_ARCHIVE_DOWNLOAD_PREFIX { '//coverartarchive.org' } sub EVENT_ART_ARCHIVE_DOWNLOAD_PREFIX { '//eventartarchive.org' } +# Required in order to use the `/ssssss` endpoint. See the +# `MusicBrainz::Server::Controller::SSSSSSProxy` module for more information. +sub SSSSSS_SERVER { 'http://localhost:5050' } + # Mapbox access token must be set to display area/place maps. sub MAPBOX_MAP_ID { 'mapbox/streets-v11' } sub MAPBOX_ACCESS_TOKEN { '' } diff --git a/lib/MusicBrainz/Server/Controller/SSSSSSProxy.pm b/lib/MusicBrainz/Server/Controller/SSSSSSProxy.pm new file mode 100644 index 00000000000..da47165887e --- /dev/null +++ b/lib/MusicBrainz/Server/Controller/SSSSSSProxy.pm @@ -0,0 +1,112 @@ +package MusicBrainz::Server::Controller::SSSSSSProxy; +use strict; +use warnings; + +use HTTP::Request; +use LWP::UserAgent; +use Moose; +use MooseX::MethodAttributes; +use namespace::autoclean; +use URI; + +use DBDefs; + +extends 'Catalyst::Controller'; + +__PACKAGE__->config( namespace => 'ssssss' ); + +sub _get_content : Private { + my ($self, $c) = @_; + my %content = %{ $c->req->body_parameters }; + for my $upload_key (keys %{ $c->req->uploads }) { + my $upload = $c->req->uploads->{$upload_key}; + $content{$upload_key} = [ + $upload->tempname, + $upload->filename, + 'Content-Type' => $upload->type, + ]; + } + return %content; +} + +sub ssssss : Path('/ssssss') { + my ($self, $c) = @_; + + unless (DBDefs->DB_STAGING_TESTING_FEATURES) { + $c->res->status(403); + $c->res->body(''); + $c->detach; + } + + my $proxy_uri = URI->new(DBDefs->SSSSSS_SERVER); + $proxy_uri->path_query( + $c->req->uri->path_query =~ s{^/ssssss}{}r, + ); + + my $req_headers = $c->req->headers->clone; + $req_headers->remove_header('Content-Length'); + + my $lwp = LWP::UserAgent->new; + my $method = lc $c->req->method; + my $proxy_res; + + if ($method eq 'options') { + $proxy_res = $lwp->get(HTTP::Request->new( + 'OPTIONS', + $proxy_uri, + $req_headers, + )); + } elsif ($method eq 'delete' || $method eq 'get') { + $proxy_res = $lwp->$method($proxy_uri, $req_headers->flatten); + } elsif ($method eq 'post' || $method eq 'put') { + my %content = $self->_get_content($c); + if (%content) { + $req_headers->header('Content-Type', 'form-data'); + } + $proxy_res = $lwp->$method( + $proxy_uri, + $req_headers->flatten, + %content ? (Content => \%content) : (), + ); + } + + $c->res->status($proxy_res->code); + $c->res->headers($proxy_res->headers->clone); + $c->res->body($proxy_res->content); +} + +1; + +=pod + +=head1 NAME + +MusicBrainz::Server::Controller::SSSSSSProxy - proxy for contrib/ssssss.psgi + +=head1 DESCRIPTION + +This endpoint acts as a proxy between the client's browser and +contrib/ssssss.psgi. It's generally only useful in pseudo-production +environments, like test.musicbrainz.org, where it negates the need to expose +ssssss over a public gateway. + +It's expected that `SSSSSS_SERVER` points to the internal host and port which +ssssss.psgi is listening on; and that `INTERNET_ARCHIVE_UPLOAD_PREFIXER` +points to `SSSSSS_SERVER` as follows: + + sub INTERNET_ARCHIVE_UPLOAD_PREFIXER { + my ($self, $bucket) = @_; + return $self->SSSSSS_SERVER . "/$bucket"; + } + +The endpoint is disabled unless `DB_STAGING_TESTING_FEATURES` is on. + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2023 MetaBrainz Foundation + +This file is part of MusicBrainz, the open internet music database, +and is licensed under the GPL version 2, or (at your option) any +later version: http://www.gnu.org/licenses/gpl-2.0.txt + +=cut diff --git a/lib/MusicBrainz/Server/Controller/WS/js.pm b/lib/MusicBrainz/Server/Controller/WS/js.pm index 617f65309f3..a97606c08c0 100644 --- a/lib/MusicBrainz/Server/Controller/WS/js.pm +++ b/lib/MusicBrainz/Server/Controller/WS/js.pm @@ -542,8 +542,20 @@ sub _art_upload { my $expiration = gmtime() + 3600; $s3_policy{expiration} = $expiration->datetime . '.000Z'; + my $action = URI->new(DBDefs->INTERNET_ARCHIVE_UPLOAD_PREFIXER($bucket)); + # On test servers using contrib/ssssss.psgi, have the client send uploads + # to `MusicBrainz::Server::Controller::SSSSSSProxy`. + if (DBDefs->DB_STAGING_TESTING_FEATURES) { + my $ssssss_server = URI->new(DBDefs->SSSSSS_SERVER); + if ($action->authority eq $ssssss_server->authority) { + $action->scheme($c->req->uri->scheme); + $action->authority(DBDefs->WEB_SERVER); + $action->path('/ssssss' . $action->path); + } + } + my $data = { - action => DBDefs->INTERNET_ARCHIVE_UPLOAD_PREFIXER($bucket), + action => $action->as_string, image_id => "$id", formdata => $art_archive_model->post_fields($bucket, $gid, $id, \%s3_policy), nonce => $nonce,