简体   繁体   中英

Simple Perl Proxy

We store a large amount of files on Amazon S3 that we want website visitors to be able to access via AJAX but we don't want the actual file locations disclosed to visitors.

To accomplish this what I'm hoping to do is to make an AJAX request to a very simple perl script that would simply act as a proxy and return the file to the browser. I already have the script setup to authenticate that the user is logged in and do a database query to figure out the correct url to access the file on S3 but I'm not sure the best way to return the file to the vistor's browser in the most efficient manner.

Any suggestions on the best way to accomplish this would be greatly appreciated. Thanks!

The best way is to use the sendfile system call . If you're opening and reading the file from disk manually and then again write it blockwise to the "sink" end of your Web framework, then you're very wasteful because the data have to travel through the RAM, possibly including buffering.

What you describe in your question is a very common pattern, therefore many solutions already exist around the idea of just setting a special HTTP header , then letting the Web stack below your application deal with it efficiently.

Employ the XSendfile middleware in Plack to set the appropriate header. The following minimal program will DTRT and take advantage of the system call where possible.

use IO::File::WithPath qw();
use Plack::Builder qw(builder enable);
builder {
    enable 'Plack::Middleware::XSendfile';
    sub {
        return [200, [], IO::File::WithPath->new('/usr/src/linux/COPYING')];
    }
};

Ok. There's example how to implement this using Mojolicious framework. I suppose you run this script as daemon. Script catches all requests to /json_dir/.*, this request to Stackoverflow API and returns response. You may run this script as ./example.pl daemon and then try http://127.0.0.1:3000/json_dir/perl

In response you should be able to find your own question titled 'Simple Perl Proxy'. This code could be used as standalone daemon that listen on certain port and as CGI script (first preferred).

#!/usr/bin/env perl
use Mojolicious::Lite;

get '/json_dir/(.filename)' => sub {
    my $self = shift;

    my $filename = $self->stash('filename');
    my $url = "http://api.stackoverflow.com/1.1/questions?tagged=" . $filename;

    $self->ua->get(
        $url => sub {
            my ($client, $tx) = @_;
            json_response($self, $tx);
        }
    );

    $self->render_later;
};

sub json_response {
    my ($self, $tx) = @_;
    if (my $res = $tx->success) {
        $self->tx->res($res);
    }
    else {
        $self->render_not_found;
    }
    $self->rendered;
}

app->start;

__DATA__

@@ not_found.html.ep
<!doctype html><html>
  <head><title>Not Found</title></head>
  <body>File not found</body>
</html>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM