view release on metacpan or search on metacpan
0.0.40 2023-07-09T17:55:20Z
- Perl 5.38.0 is released
- Perl 5.36.1 is released
0.0.39 2022-11-20T18:56:48Z
- update dependency modules
0.0.38 2022-11-13T05:40:29Z
- fix Untagged opnames warnings, closes https://github.com/shogo82148/p5-aws-lambda/issues/97
- Off load perlstrip to AWS Lambda.
- add fallback to content-type
0.0.37 2022-10-08T13:28:41Z
- arm64 compatible layers are now available on 12 additional regions
- Africa (Cape Town) af-south-1
- Asia Pacific (Seoul) ap-northeast-2
- Asia Pacific (Jakarta) ap-southeast-3
- Asia Pacific (Hong Kong) ap-east-1
- Asia Pacific (Osaka) ap-northeast-3
- Canada (Central) ca-central-1
- Europe (Paris) eu-west-3
"file" : "lib/AWS/Lambda/ResponseWriter.pm"
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "https://github.com/shogo82148/p5-aws-lambda/issues"
},
"homepage" : "https://github.com/shogo82148/p5-aws-lambda",
"repository" : {
"type" : "git",
"url" : "https://github.com/shogo82148/p5-aws-lambda.git",
"web" : "https://github.com/shogo82148/p5-aws-lambda"
}
},
"version" : "0.9.0",
"x_contributors" : [
"ICHINOSE Shogo <shogo82148@gmail.com>",
"Jose Luis Martinez <jlmartinez@capside.com>",
"Mohammad S Anwar <mohammad.anwar@yahoo.com>",
"dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
perl -MAWS::Lambda -e 'AWS::Lambda::print_runtime_arn_al2023("5.38", "us-east-1")'
perl -MAWS::Lambda -e 'AWS::Lambda::print_paws_arn_al2023("5.38", "us-east-1")'
The list of all layer ARNs is available on [AWS::Lambda::AL2023](https://metacpan.org/pod/AWS%3A%3ALambda%3A%3AAL2023).
## Use Pre-built Zip Archives
1. Login to your AWS Account and go to the Lambda Console.
2. Create a new layer and give it a name.
3. For the "Code entry type" selection, select **Upload a file from Amazon S3**.
4. In the "License" section, input [https://github.com/shogo82148/p5-aws-lambda/blob/main/LICENSE](https://github.com/shogo82148/p5-aws-lambda/blob/main/LICENSE).
5. Click **Create** button.
6. Use the layer created. For detail, see Use Prebuilt Public Lambda Layer section.
URLs for Zip archives are here.
`https://shogo82148-lambda-perl-runtime-$REGION.s3.amazonaws.com/perl-$VERSION-runtime-al2023-$ARCHITECTURE.zip`
## Use Pre-built Docker Images
author/build-paws-al2023.sh view on Meta::CPAN
ARCH=arm64;;
*)
echo "unknown architecture: $(uname -m)"
esac
cd /opt
unzip "/var/task/.perl-layer/dist/perl-$TAG-runtime-al2023-$ARCH.zip"
/opt/bin/cpanm --notest --no-man-pages "Paws@$PAWS_VERSION"
# remove pods
find /opt/lib/perl5/site_perl -type f -a -name '*.pod' -delete
author/build-paws-layer-al2023.sh view on Meta::CPAN
esac
docker run \
-v "$ROOT:/var/task" \
-v "$OPT-$PLATFORM/lib/perl5/site_perl:/opt/lib/perl5/site_perl" \
-v "$OPT-$PLATFORM/lib:/opt-lib" \
--platform "$DOCKER_PLATFORM" \
"public.ecr.aws/sam/build-provided.al2023:1-$PLATFORM" \
./author/build-paws-al2023.sh "$TAG"
find "$OPT-$PLATFORM" -type f -a -name '*.pm' -print0 | parallel -0 -j 32 "$ROOT/author/perlstrip.sh"
cd "$OPT-$PLATFORM"
mkdir -p "$DIST"
zip -9 -r "$DIST/perl-$TAG-paws-al2023-$PLATFORM.zip" .
author/perl-stripper/perl-stripper/cpanfile.snapshot view on Meta::CPAN
PPI::Token::Magic 1.276
PPI::Token::Number 1.276
PPI::Token::Number::Binary 1.276
PPI::Token::Number::Exp 1.276
PPI::Token::Number::Float 1.276
PPI::Token::Number::Hex 1.276
PPI::Token::Number::Octal 1.276
PPI::Token::Number::Version 1.276
PPI::Token::Operator 1.276
PPI::Token::Pod 1.276
PPI::Token::Prototype 1.276
PPI::Token::Quote 1.276
PPI::Token::Quote::Double 1.276
PPI::Token::Quote::Interpolate 1.276
PPI::Token::Quote::Literal 1.276
PPI::Token::Quote::Single 1.276
PPI::Token::QuoteLike 1.276
PPI::Token::QuoteLike::Backtick 1.276
PPI::Token::QuoteLike::Command 1.276
PPI::Token::QuoteLike::Readline 1.276
PPI::Token::QuoteLike::Regexp 1.276
author/perl-stripper/perl-stripper/handler.pl view on Meta::CPAN
);
my $app = sub {
my $env = shift;
my $req = Plack::Request->new($env);
my $code = do { local $/; my $body = $req->body; <$body> };
my $stripped = $stripper->strip($code);
my $res = $req->new_response(200);
$res->content_type('text/plain');
$res->body($stripped);
return $res->finalize;
};
my $func = AWS::Lambda::PSGI->wrap($app);
sub handle($payload, $context) {
return $func->($payload);
}
author/publish-perl-runtime-archives.pl view on Meta::CPAN
for my $zip(glob "$FindBin::Bin/../.perl-layer/dist/perl-*-$suffix-$arch.zip") {
chomp(my $sha256 = `openssl dgst -sha256 -r "$zip" | cut -d" " -f1`);
my $name = basename($zip, '.zip');
next unless $name =~ /^perl-([0-9]+)-([0-9]+)-/;
my $perl_version = "$1.$2";
head_or_put("$name/$sha256.zip", $zip);
my $metadata = encode_json({
url => "https://shogo82148-lambda-perl-runtime-us-east-1.s3.amazonaws.com/$name/$sha256.zip",
});
run_command("echo '$metadata' | aws --region 'us-east-1' s3 cp --content-type application/json - s3://shogo82148-lambda-perl-runtime-us-east-1/$name.json");
}
}
if ($force) {
say STDERR "FORCE TO DEPLOY";
} else {
say STDERR "DRY RUN";
}
publish("runtime-al2023", "x86_64");
author/update-aws-lambda-al.pl view on Meta::CPAN
chomp(my $module_version = `cat $FindBin::Bin/../META.json | jq -r .version`);
my $latest_perl = $versions->[0];
my $latest_perl_layer = $latest_perl =~ s/[.]/-/r;
my $latest_runtime_arn = $layers->{$latest_perl}{'us-east-1'}{runtime_arn};
my $latest_runtime_version = $layers->{$latest_perl}{'us-east-1'}{runtime_version};
my $latest_paws_arn = $layers->{$latest_perl}{'us-east-1'}{paws_arn};
my $latest_paws_version = $layers->{$latest_perl}{'us-east-1'}{paws_version};
open my $fh, '>', "$FindBin::Bin/../lib/AWS/Lambda/AL.pm" or die "$!";
sub printfh :prototype($) {
my $contents = shift;
$contents =~ s/\@\@VERSION\@\@/$module_version/g;
$contents =~ s/\@\@LATEST_PERL\@\@/$latest_perl/g;
$contents =~ s/\@\@LATEST_PERL_LAYER\@\@/$latest_perl_layer/g;
$contents =~ s/\@\@LATEST_RUNTIME_ARN\@\@/$latest_runtime_arn/g;
$contents =~ s/\@\@LATEST_RUNTIME_VERSION\@\@/$latest_runtime_version/g;
$contents =~ s/\@\@LATEST_PAWS_ARN\@\@/$latest_paws_arn/g;
$contents =~ s/\@\@LATEST_PAWS_VERSION\@\@/$latest_paws_version/g;
print $fh $contents;
}
author/update-aws-lambda-al2.pl view on Meta::CPAN
chomp(my $module_version = `cat $FindBin::Bin/../META.json | jq -r .version`);
my $latest_perl = $versions_al2->[0];
my $latest_perl_layer = $latest_perl =~ s/[.]/-/r;
my $latest_runtime_arn = $layers_al2->{$latest_perl}{'us-east-1'}{x86_64}{runtime_arn};
my $latest_runtime_version = $layers_al2->{$latest_perl}{'us-east-1'}{x86_64}{runtime_version};
my $latest_paws_arn = $layers_al2->{$latest_perl}{'us-east-1'}{x86_64}{paws_arn};
my $latest_paws_version = $layers_al2->{$latest_perl}{'us-east-1'}{x86_64}{paws_version};
open my $fh, '>', "$FindBin::Bin/../lib/AWS/Lambda/AL2.pm" or die "$!";
sub printfh :prototype($) {
my $contents = shift;
$contents =~ s/\@\@VERSION\@\@/$module_version/g;
$contents =~ s/\@\@LATEST_PERL\@\@/$latest_perl/g;
$contents =~ s/\@\@LATEST_PERL_LAYER\@\@/$latest_perl_layer/g;
$contents =~ s/\@\@LATEST_RUNTIME_ARN\@\@/$latest_runtime_arn/g;
$contents =~ s/\@\@LATEST_RUNTIME_VERSION\@\@/$latest_runtime_version/g;
$contents =~ s/\@\@LATEST_PAWS_ARN\@\@/$latest_paws_arn/g;
$contents =~ s/\@\@LATEST_PAWS_VERSION\@\@/$latest_paws_version/g;
print $fh $contents;
}
author/update-aws-lambda-al2023.pl view on Meta::CPAN
chomp(my $module_version = `cat $FindBin::Bin/../META.json | jq -r .version`);
my $latest_perl = $versions_al2023->[0];
my $latest_perl_layer = $latest_perl =~ s/[.]/-/r;
my $latest_runtime_arn = $layers_al2023->{$latest_perl}{'us-east-1'}{x86_64}{runtime_arn};
my $latest_runtime_version = $layers_al2023->{$latest_perl}{'us-east-1'}{x86_64}{runtime_version};
my $latest_paws_arn = $layers_al2023->{$latest_perl}{'us-east-1'}{x86_64}{paws_arn};
my $latest_paws_version = $layers_al2023->{$latest_perl}{'us-east-1'}{x86_64}{paws_version};
open my $fh, '>', "$FindBin::Bin/../lib/AWS/Lambda/AL2023.pm" or die "$!";
sub printfh :prototype($) {
my $contents = shift;
$contents =~ s/\@\@VERSION\@\@/$module_version/g;
$contents =~ s/\@\@LATEST_PERL\@\@/$latest_perl/g;
$contents =~ s/\@\@LATEST_PERL_LAYER\@\@/$latest_perl_layer/g;
$contents =~ s/\@\@LATEST_RUNTIME_ARN\@\@/$latest_runtime_arn/g;
$contents =~ s/\@\@LATEST_RUNTIME_VERSION\@\@/$latest_runtime_version/g;
$contents =~ s/\@\@LATEST_PAWS_ARN\@\@/$latest_paws_arn/g;
$contents =~ s/\@\@LATEST_PAWS_VERSION\@\@/$latest_paws_version/g;
print $fh $contents;
}
examples/cgi/WwwCounter/readme.html view on Meta::CPAN
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">
<title>WwwCounter Ver3.15å©ç¨ã¡ã¢ - ã¨ã»ã»ã®WWWå
¥é</title>
<style type="text/css">
<!--
BODY {
color: #333333;
}
H2 {
width: 100%;
font-weight: bold;
color: #ffffff;
background-color: #8484ee;
border: 1px none #8888f8;
examples/cgi/WwwCounter/sample.html view on Meta::CPAN
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>WwwCounterãµã³ãã« - ã¨ã»ã»ã®WWWå
¥é</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<style>
.i { margin-left: 1rem; }
</style>
</head>
<body>
examples/cgi/WwwCounter/style3.css view on Meta::CPAN
*/
/* Font */
body {
/* font-family: verdana, 'Meiryo UI', 'ã¡ã¤ãªãª', 'ï¼ï¼³ ï¼°ã´ã·ãã¯', 'ãã©ã®ãè§ã´ã·ãã¯', sans-selif; */
font-family: 'Meiryo UI', 'ã¡ã¤ãªãª', 'ï¼ï¼³ ï¼°ã´ã·ãã¯', 'ãã©ã®ãè§ã´ã·ãã¯', sans-selif;
}
pre, code {
font-family: Consolas, 'Meiryo UI', 'ã¡ã¤ãªãª', 'ï¼ï¼³ ï¼°ã´ã·ãã¯', 'ãã©ã®ãè§ã´ã·ãã¯', sans-selif;
}
.teletype, .tt {
font-family: Consolas, 'Courier New', 'ï¼ï¼³ ã´ã·ãã¯', monospace;
}
.notbold, .nb {
font-weight: normal;
}
.meiryo, .mr {
font-family: 'Meiryo UI';
}
/* Color */
examples/cgi/WwwCounter/style3.css view on Meta::CPAN
}
.mt1 {
margin-top: 1em;
}
.mb1 {
margin-bottom: 1em;
}
/* List */
.nomark {
list-style-type: none;
margin-top: 0;
margin-left: -1em;
}
.dl1 dt {
margin-top: 1em;
font-weight: bold;
}
.dl1 dd {
margin-left: 1em;
}
examples/cgi/WwwCounter/wwwcount.cgi view on Meta::CPAN
# ã«ã¦ã³ã¿ã¼æåå(ä¾:000123)ãå¾ã
if ($g_figure != 0) {
$count_str = sprintf(sprintf("%%0%dld", $g_figure), $count);
} else {
$count_str = sprintf("%ld", $count);
}
# ããã¹ãã¢ã¼ã
if ($g_mode eq "text") {
printf("Content-type: text/html\n");
printf("\n");
printf("$count_str\n");
# GIFã¢ã¼ã
} elsif ($g_mode eq "gif") {
printf("Content-type: image/gif\n");
printf("\n");
@files = ();
for (my $i = 0; $i < length($count_str); $i++) {
$n = substr($count_str, $i, 1);
push(@files, "$n.gif");
}
require "./gifcat.pl";
binmode(STDOUT);
print gifcat'gifcat(@files);
# é ãã«ã¦ã³ã¿ã¼ã¢ã¼ã
} elsif ($g_mode eq "hide") {
printf("Content-type: image/gif\n");
printf("\n");
$size = -s $g_gif_file;
open(IN, $g_gif_file);
binmode(IN);
binmode(STDOUT);
read(IN, $buf, $size);
print $buf;
close(IN);
}
}
examples/cgi/WwwCounter/wwwcount.cgi view on Meta::CPAN
sub unlockLock {
if ($g_lock_flag) {
rmdir($g_file_lock);
}
}
#
# CGIã使ç¨ã§ããããã¹ããè¡ãã
#
sub test {
print "Content-type: text/html\n";
print "\n";
print "<!doctype html>\n";
print "<html>\n";
print "<head>\n";
print "<meta charset='utf-8'>\n";
print "<title>Test</title>\n";
print "</head>\n";
print "<body>\n";
print "<p>OK. CGIã¹ã¯ãªããã¯æ£å¸¸ã«åãã¦ãã¾ãã</p>\n";
if ($g_mailto ne "") {
if (! -f $g_sendmail) {
print "<p>ERROR: $g_sendmail ãåå¨ãã¾ããã</p>\n";
examples/s3-get-object/handler.pl view on Meta::CPAN
use 5.30.0;
use lib "$ENV{'LAMBDA_TASK_ROOT'}/extlocal/lib/perl5";
use Paws;
use Try::Tiny;
use URI::Escape;
my $obj = Paws->service('S3', region => 'ap-northeast-1');
sub handle {
my $payload = shift;
# Get the object from the event and show its content type
my $bucket = $payload->{Records}[0]{s3}{bucket}{name};
my $key = uri_unescape($payload->{Records}[0]{s3}{object}{key} =~ s/\+/ /gr);
my $resp = try {
$obj->GetObject(
Bucket => $bucket,
Key => $key,
);
} catch {
print STDERR "$_\n";
my $message = "Error getting object $key from bucket $bucket. Make sure they exist and your bucket is in the same region as this function.";
lib/AWS/Lambda.pm view on Meta::CPAN
=item 1
Login to your AWS Account and go to the Lambda Console.
=item 2
Create a new layer and give it a name.
=item 3
For the "Code entry type" selection, select B<Upload a file from Amazon S3>.
=item 4
In the "License" section, input L<https://github.com/shogo82148/p5-aws-lambda/blob/main/LICENSE>.
=item 5
Click B<Create> button.
=item 6
lib/AWS/Lambda/Bootstrap.pm view on Meta::CPAN
sub lambda_response_streaming {
my $self = shift;
my ($response, $context) = @_;
my $runtime_api = $self->{runtime_api};
my $api_version = $self->{api_version};
my $request_id = $context->aws_request_id;
my $url = "http://${runtime_api}/${api_version}/runtime/invocation/${request_id}/response";
my $writer = undef;
try {
$response->(sub {
my $content_type = shift;
$writer = AWS::Lambda::ResponseWriter->new(
response_url => $url,
http => $self->{http},
);
$writer->_request($content_type);
return $writer;
});
} catch {
my $err = $_;
print STDERR "$err";
if ($writer) {
$writer->_close_with_error($err);
} else {
$self->lambda_error($err, $context);
}
lib/AWS/Lambda/Bootstrap.pm view on Meta::CPAN
}
}
sub lambda_error {
my $self = shift;
my ($error, $context) = @_;
my $runtime_api = $self->{runtime_api};
my $api_version = $self->{api_version};
my $request_id = $context->aws_request_id;
my $url = "http://${runtime_api}/${api_version}/runtime/invocation/${request_id}/error";
my $type = blessed($error) // "Error";
my $resp = $self->{http}->post($url, {
content => encode_json({
errorMessage => "$error",
errorType => "$type",
}),
});
if (!$resp->{success}) {
die "failed to send error of execution: $resp->{status} $resp->{reason}";
}
}
sub lambda_init_error {
my $self = shift;
my $error = shift;
my $runtime_api = $self->{runtime_api};
my $api_version = $self->{api_version};
my $url = "http://${runtime_api}/${api_version}/runtime/init/error";
my $type = blessed($error) // "Error";
my $resp = $self->{http}->post($url, {
content => encode_json({
errorMessage => "$error",
errorType => "$type",
}),
});
if (!$resp->{success}) {
die "failed to send error of execution: $resp->{status} $resp->{reason}";
}
}
1;
__END__
lib/AWS/Lambda/PSGI.pm view on Meta::CPAN
use warnings;
use URI::Escape;
use Plack::Util;
use bytes ();
use MIME::Base64;
use JSON::Types;
use Encode;
use Try::Tiny;
use Plack::Middleware::ReverseProxy;
use AWS::Lambda;
use Scalar::Util qw(reftype);
use JSON::XS qw(encode_json);
sub new {
my $proto = shift;
my $class = ref $proto || $proto;
my $self;
if (@_ == 1 && ref $_[0] eq 'HASH') {
$self = bless {%{$_[0]}}, $class;
} else {
lib/AWS/Lambda/PSGI.pm view on Meta::CPAN
my $singleValueHeaders = {};
my $multiValueHeaders = {};
Plack::Util::header_iter($headers, sub {
my ($k, $v) = @_;
$singleValueHeaders->{lc $k} = string $v;
push @{$multiValueHeaders->{lc $k} //= []}, string $v;
});
my $content = '';
if (reftype($body) eq 'ARRAY') {
$content = join '', grep defined, @$body;
} else {
local $/ = \4096;
while (defined(my $buf = $body->getline)) {
$content .= $buf;
}
$body->close;
}
my $type = $singleValueHeaders->{'content-type'} // 'application/octet-stream';
my $isBase64Encoded = $type !~ m(^text/.*|application/(:?json|javascript|xml))i;
if ($isBase64Encoded) {
$content = encode_base64 $content, '';
} else {
$content = try {
# is valid utf-8 string? try to decode as utf-8.
decode_utf8($content, Encode::FB_CROAK | Encode::LEAVE_SRC);
} catch {
# it looks not utf-8 encoding. fallback to base64 encoding.
$isBase64Encoded = 1;
encode_base64 $content, '';
lib/AWS/Lambda/PSGI.pm view on Meta::CPAN
isBase64Encoded => bool $isBase64Encoded,
headers => $singleValueHeaders,
multiValueHeaders => $multiValueHeaders,
statusCode => number $status,
body => string $content,
}
}
sub _handle_response_stream {
my ($self, $response) = @_;
if (reftype($response) ne "CODE") {
my $orig = $response;
$response = sub {
my $responder = shift;
$responder->($orig);
};
}
return sub {
my $lambda_responder = shift;
my $psgi_responder = sub {
lib/AWS/Lambda/PSGI.pm view on Meta::CPAN
my $writer = $lambda_responder->("application/vnd.awslambda.http-integration-response");
my $prelude = encode_json($self->_format_response_stream($status, $headers));
$prelude .= "\x00\x00\x00\x00\x00\x00\x00\x00";
$writer->write($prelude) or die "failed to write prelude: $!";
# write the body.
if (!defined $body) {
# the caller will write the body.
return $writer;
}
if (reftype($body) eq 'ARRAY') {
# array-ref
for my $chunk (@$body) {
$writer->write($chunk) or die "failed to write chunk: $!";
}
} else {
# IO::Handle-like object
local $/ = \4096;
while (defined(my $chunk = $body->getline)) {
$writer->write($chunk) or die "failed to write chunk: $!";
}
lib/AWS/Lambda/ResponseWriter.pm view on Meta::CPAN
my $class = ref $proto || $proto;
my %args;
if (@_ == 1 && ref $_[0] eq 'HASH') {
%args = %{$_[0]};
} else {
%args = @_;
}
my $http = $args{http} // HTTP::Tiny->new;
my $response_url = $args{response_url} // die '$LAMBDA_TASK_ROOT is not found';
my $content_type = $args{content_type} // 'application/json';
my $self = bless +{
response_url => $response_url,
http => $http,
handle => undef,
closed => 0,
}, $class;
return $self;
}
sub _request {
my ($self, $content_type) = @_;
my $response_url = $self->{response_url};
my $http = $self->{http};
my ($scheme, $host, $port, $path_query, $auth) = $http->_split_url($response_url);
my $host_port = ($port == $DefaultPort{$scheme} ? $host : "$host:$port");
my $request = {
method => "POST",
scheme => $scheme,
host => $host,
port => $port,
host_port => $host_port,
uri => $path_query,
headers => {
"host" => $host_port,
"content-type" => $content_type,
"transfer-encoding" => "chunked",
"trailer" => "Lambda-Runtime-Function-Error-Type, Lambda-Runtime-Function-Error-Body",
"lambda-runtime-function-response-mode" => "streaming",
},
header_case => {
"host" => "Host",
"content-type" => "Content-Type",
"transfer-encoding" => "Transfer-Encoding",
"trailer" => "Trailer",
"lambda-runtime-function-response-mode" => "Lambda-Runtime-Function-Response-Mode",
},
};
my $peer = $host;
# We remove the cached handle so it is not reused in the case of redirect.
# reuse for the same scheme, host and port
my $handle = delete $http->{handle};
lib/AWS/Lambda/ResponseWriter.pm view on Meta::CPAN
sub _close_with_error {
my ($self, $error) = @_;
if ($self->{closed}) {
# already closed
return;
}
$self->{closed} = 1;
my $handle = $self->{handle};
$handle->write("0\x0D\x0A");
my $type = blessed($error) // "Error";
return $handle->write_header_lines({
"lambda-runtime-function-error-type" => "$type",
"lambda-runtime-function-error-body" => encode_base64("$error", ""),
}, {
"lambda-runtime-function-error-type" => "Lambda-Runtime-Function-Error-Type",
"lambda-runtime-function-error-body" => "Lambda-Runtime-Function-Error-Body",
});
}
1;
t/15_lambda_response_streaming.t view on Meta::CPAN
my $env = shift;
my $req = Plack::Request->new($env);
my $headers = $req->headers;
my $body = slurp($req->body);
is $req->method, "POST", "http method is POST";
is $headers->header('Lambda-Runtime-Function-Response-Mode'), "streaming", "streaming is enabled";
is $body, '{"key1":"a","key2":"b","key3":"c"}', "response body is correct";
my $res = $req->new_response(200);
$res->content_type("application/json");
$res->body('{}');
$res->finalize;
};
$server->run($app, {
port => $port, host => '127.0.0.1',
});
},
max_wait => 10, # seconds
);
t/20_psgi.t view on Meta::CPAN
is $req->query_string, 'query=hoge&query=fuga', 'query string';
is $req->header('Header-Name'), 'Value1, Value2', 'header';
ok !$req->env->{'psgi.streaming'}, 'psgi.streaming';
};
subtest "API Gateway POST Request" => sub {
my $input = slurp_json("testdata/apigateway-post-request.json");
my $output = $app->format_input($input);
my $req = Plack::Request->new($output);
is $req->method, 'POST', 'method';
is $req->content_type, 'application/json', 'content-type';
my $content;
warning_is { $content = slurp_fh($req->input) } undef, 'no warning';
is $content, '{"hello":"ããã«ã¡ã¯ä¸ç"}', 'content';
is $req->request_uri, '/', 'request uri';
is $req->path_info, '/', 'path info';
is $req->query_string, '', 'query string';
ok !$req->env->{'psgi.streaming'}, 'psgi.streaming';
};
subtest "API Gateway Base64 encoded POST Request" => sub {
my $input = slurp_json("testdata/apigateway-base64-request.json");
my $output = $app->format_input($input);
my $req = Plack::Request->new($output);
is $req->method, 'POST', 'method';
# You have to add 'application/octet-stream' to binary media types.
# https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings-configure-with-console.html
is $req->content_type, 'application/octet-stream', 'content-type';
my $content;
warning_is { $content = slurp_fh($req->input) } undef, 'no warning';
is $content, '{"hello":"world"}', 'content';
is $req->request_uri, '/', 'request uri';
is $req->path_info, '/', 'path info';
is $req->query_string, '', 'query string';
ok !$req->env->{'psgi.streaming'}, 'psgi.streaming';
};
subtest "API Gateway v2 GET Request" => sub {
t/20_psgi.t view on Meta::CPAN
is $req->query_string, 'query=hoge&query=fuga', 'query string';
is $req->header('Header-Name'), 'Value1, Value2', 'header';
ok !$req->env->{'psgi.streaming'}, 'psgi.streaming';
};
subtest "ALB POST Request" => sub {
my $input = slurp_json("testdata/alb-post-request.json");
my $output = $app->format_input($input);
my $req = Plack::Request->new($output);
is $req->method, 'POST', 'method';
is $req->content_type, 'application/json', 'content-type';
is slurp_fh($req->input), '{"hello":"ããã«ã¡ã¯ä¸ç"}', 'content';
is $req->request_uri, '/', 'request uri';
is $req->path_info, '/', 'path info';
is $req->query_string, '', 'query string';
ok !$req->env->{'psgi.streaming'}, 'psgi.streaming';
};
subtest "ALB POST Base64 Request" => sub {
my $input = slurp_json("testdata/alb-base64-request.json");
my $output = $app->format_input($input);
my $req = Plack::Request->new($output);
is $req->method, 'POST', 'method';
is $req->content_type, 'application/octet-stream', 'content-type';
is slurp_fh($req->input), '{"hello":"world"}', 'content';
is $req->request_uri, '/foo/bar', 'request uri';
is $req->path_info, '/foo/bar', 'path info';
is $req->query_string, '', 'query string';
ok !$req->env->{'psgi.streaming'}, 'psgi.streaming';
};
subtest "Function URLs GET Request" => sub {
my $input = slurp_json("testdata/function-urls-get-request.json");
my $output = $app->format_input($input);
t/20_psgi.t view on Meta::CPAN
is $req->query_string, 'parameter1=value1¶meter1=value2¶meter2=value', 'query string';
is $req->header('header1'), 'value1,value2', 'header';
ok !$req->env->{'psgi.streaming'}, 'psgi.streaming';
};
subtest "Function URLs POST Request" => sub {
my $input = slurp_json("testdata/function-urls-post-request.json");
my $output = $app->format_input($input);
my $req = Plack::Request->new($output);
is $req->method, 'POST', 'method';
is $req->content_type, 'application/json', 'content-type';
is slurp_fh($req->input), '{"hello":"world"}', 'content';
is $req->request_uri, '/my/path', 'request uri';
is $req->path_info, '/my/path', 'path info';
is $req->query_string, '', 'query string';
ok !$req->env->{'psgi.streaming'}, 'psgi.streaming';
};
subtest "Function URLs POST Base64 Request" => sub {
my $input = slurp_json("testdata/function-urls-post-base64-request.json");
my $output = $app->format_input($input);
my $req = Plack::Request->new($output);
is $req->method, 'POST', 'method';
is $req->content_type, 'application/octet-stream', 'content-type';
is slurp_fh($req->input), '{"hello":"world"}', 'content';
is $req->request_uri, '/my/path', 'request uri';
is $req->path_info, '/my/path', 'path info';
is $req->query_string, '', 'query string';
ok !$req->env->{'psgi.streaming'}, 'psgi.streaming';
};
subtest "plain text response" => sub {
my $response = [
200,
t/20_psgi.t view on Meta::CPAN
[
"Hello",
"World",
encode_utf8("ããã«ã¡ã¯ä¸ç"),
]
];
my $res = $app->format_output($response);
cmp_deeply $res, {
isBase64Encoded => bool 0,
headers => {
'content-type' => 'text/plain',
'header-name' => 'value2',
},
multiValueHeaders => {
'content-type' => ['text/plain'],
'header-name' => ['value1', 'value2'],
},
statusCode => 200,
body => "HelloWorldããã«ã¡ã¯ä¸ç",
};
diag encode_json $res;
};
subtest "binary response" => sub {
my $response = [
t/20_psgi.t view on Meta::CPAN
'Content-Type' => 'application/octet-stream',
],
[
'{"hello":"world"}',
]
];
my $res = $app->format_output($response);
cmp_deeply $res, {
isBase64Encoded => bool 1,
headers => {
'content-type' => 'application/octet-stream',
},
multiValueHeaders => {
'content-type' => ['application/octet-stream'],
},
statusCode => 200,
body => "eyJoZWxsbyI6IndvcmxkIn0=",
};
diag encode_json $res;
};
subtest "IO::Handle-like response" => sub {
open my $f, "<", \"HelloWorld";
my $response = [
200,
[
'Content-Type' => 'text/plain',
],
$f,
];
my $res = $app->format_output($response);
cmp_deeply $res, {
isBase64Encoded => bool 0,
headers => {
'content-type' => 'text/plain',
},
multiValueHeaders => {
'content-type' => ['text/plain'],
},
statusCode => 200,
body => "HelloWorld",
};
diag encode_json $res;
};
subtest "EUC-JP encoded response" => sub {
my $response = [
200,
t/20_psgi.t view on Meta::CPAN
'Content-Type' => 'text/plain',
],
[
"\xC8\xFE\xC6\xFD",
]
];
my $res = $app->format_output($response);
cmp_deeply $res, {
isBase64Encoded => bool 1,
headers => {
'content-type' => 'text/plain',
},
multiValueHeaders => {
'content-type' => ['text/plain'],
},
statusCode => 200,
body => "yP7G/Q==",
};
diag encode_json $res;
};
subtest "query string enconding" => sub {
my $input = slurp_json("testdata/apigateway-get-request.json");
$input->{queryStringParameters} = {
t/21_psgi_response_streaming.t view on Meta::CPAN
sub slurp_fh {
my $fh = $_[0];
local $/;
my $v = <$fh>;
defined $v ? decode_utf8($v) : '';
}
my $app = AWS::Lambda::PSGI->new;
subtest "array reference" => sub {
my $content_type = undef;
my $buf = "";
my $res = $app->_handle_response_stream([200, ["Content-Type" => "text/plain"], ["hello"]]);
my $responder = sub {
$content_type = shift;
open my $fh, ">", \$buf or die "failed to open: $!";
return $fh;
};
$res->($responder);
is $content_type, "application/vnd.awslambda.http-integration-response", "content type";
my ($prelude, $body) = split /\x00\x00\x00\x00\x00\x00\x00\x00/, $buf;
cmp_deeply decode_json($prelude), {
statusCode => 200,
headers => {
"content-type" => "text/plain",
},
cookies => [],
}, "prelude";
is $body, "hello", "body";
};
subtest "IO::Handle-like object" => sub {
my $content_type = undef;
open my $fh, "<", \"hello" or die "failed to open: $!";
my $buf = "";
my $res = $app->_handle_response_stream([200, ["Content-Type" => "text/plain"], $fh]);
my $responder = sub {
$content_type = shift;
open my $fh, ">", \$buf or die "failed to open: $!";
return $fh;
};
$res->($responder);
is $content_type, "application/vnd.awslambda.http-integration-response", "content type";
my ($prelude, $body) = split /\x00\x00\x00\x00\x00\x00\x00\x00/, $buf;
cmp_deeply decode_json($prelude), {
statusCode => 200,
headers => {
"content-type" => "text/plain",
},
cookies => [],
}, "prelude";
is $body, "hello", "body";
};
subtest "streaming response" => sub {
my $content_type = undef;
my $buf = "";
my $res = $app->_handle_response_stream(sub {
my $responder = shift;
my $writer = $responder->([200, ["Content-Type" => "text/plain"]]);
$writer->write("hello");
$writer->close;
});
my $responder = sub {
$content_type = shift;
open my $fh, ">", \$buf or die "failed to open: $!";
return $fh;
};
$res->($responder);
is $content_type, "application/vnd.awslambda.http-integration-response", "content type";
my ($prelude, $body) = split /\x00\x00\x00\x00\x00\x00\x00\x00/, $buf;
cmp_deeply decode_json($prelude), {
statusCode => 200,
headers => {
"content-type" => "text/plain",
},
cookies => [],
}, "prelude";
is $body, "hello", "body";
};
done_testing;
t/testdata/alb-base64-request.json view on Meta::CPAN
"elb": {
"targetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/lambda-target/a8d0882e91e66540"
}
},
"httpMethod": "POST",
"path": "/foo/bar",
"queryStringParameters": {},
"headers": {
"accept": "*/*",
"content-length": "17",
"content-type": "application/octet-stream",
"host": "lambda-test-1234567890.ap-northeast-1.elb.amazonaws.com",
"user-agent": "curl/7.54.0",
"x-amzn-trace-id": "Root=1-5c0f091f-56087f0297986bc017de21bc",
"x-forwarded-for": "192.0.2.1",
"x-forwarded-port": "80",
"x-forwarded-proto": "http"
},
"body": "eyJoZWxsbyI6IndvcmxkIn0=",
"isBase64Encoded": true
}
t/testdata/alb-post-request.json view on Meta::CPAN
"elb": {
"targetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/lambda-target/a8d0882e91e66540"
}
},
"httpMethod": "POST",
"path": "/",
"queryStringParameters": {},
"headers": {
"accept": "*/*",
"content-length": "17",
"content-type": "application/json",
"host": "lambda-test-1234567890.ap-northeast-1.elb.amazonaws.com",
"user-agent": "curl/7.54.0",
"x-amzn-trace-id": "Root=1-5c0f08ec-8a00ddf3c79b53a01fa905ba",
"x-forwarded-for": "192.0.2.1",
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
},
"body": "{\"hello\":\"ããã«ã¡ã¯ä¸ç\"}",
"isBase64Encoded": false
}
t/testdata/apigateway-base64-request.json view on Meta::CPAN
{
"resource": "/",
"path": "/",
"httpMethod": "POST",
"headers": {
"accept": "*/*",
"content-type": "application/octet-stream",
"Host": "xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com",
"User-Agent": "curl/7.54.0",
"X-Amzn-Trace-Id": "Root=1-5c0f0502-7611e42628aee5c8cce21a72",
"X-Forwarded-For": "192.0.2.1",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"multiValueHeaders": {
"accept": [
"*/*"
],
"content-type": [
"application/octet-stream"
],
"Host": [
"xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com"
],
"User-Agent": [
"curl/7.54.0"
],
"X-Amzn-Trace-Id": [
"Root=1-5c0f0502-7611e42628aee5c8cce21a72"
t/testdata/apigateway-post-request.json view on Meta::CPAN
{
"resource": "/",
"path": "/",
"httpMethod": "POST",
"headers": {
"accept": "*/*",
"content-type": "application/json",
"Host": "xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com",
"User-Agent": "curl/7.54.0",
"X-Amzn-Trace-Id": "Root=1-5c0f033a-32eff4c8b894f0d4f8fa213c",
"X-Forwarded-For": "192.0.2.1",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"multiValueHeaders": {
"accept": [
"*/*"
],
"content-type": [
"application/json"
],
"Host": [
"xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com"
],
"User-Agent": [
"curl/7.54.0"
],
"X-Amzn-Trace-Id": [
"Root=1-5c0f033a-32eff4c8b894f0d4f8fa213c"
t/testdata/apigateway-v2-base64-request.json view on Meta::CPAN
{
"version": "2.0",
"routeKey": "$default",
"rawPath": "/my/path",
"rawQueryString": "",
"headers": {
"accept": "*/*",
"content-length": "17",
"content-type": "application/octet-stream",
"host": "xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com",
"user-agent": "curl/7.64.1",
"x-amzn-trace-id": "Root=1-5e8a9b8c-5fd89a5053994a40c1343990",
"x-forwarded-for": "192.0.2.1",
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
},
"requestContext": {
"accountId": "123456789012",
"apiId": "xxxxxxxxxx",
t/testdata/apigateway-v2-post-request.json view on Meta::CPAN
{
"version": "2.0",
"routeKey": "$default",
"rawPath": "/my/path",
"rawQueryString": "",
"headers": {
"accept": "*/*",
"content-length": "17",
"content-type": "application/json",
"host": "xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com",
"user-agent": "curl/7.64.1",
"x-amzn-trace-id": "Root=1-5e8a9af6-43dfdbb5896d7684515eb0ba",
"x-forwarded-for": "192.0.2.1",
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
},
"requestContext": {
"accountId": "123456789012",
"apiId": "xxxxxxxxxx",
t/testdata/function-urls-post-base64-request.json view on Meta::CPAN
{
"body": "eyJoZWxsbyI6IndvcmxkIn0=",
"headers": {
"accept": "*/*",
"content-type": "application/octet-stream",
"host": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws",
"user-agent": "curl/7.79.1",
"x-amzn-trace-id": "Root=1-62577702-3f59d86f1830be3f76a10c1e",
"x-forwarded-for": "192.0.2.1",
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
},
"isBase64Encoded": true,
"rawPath": "/my/path",
"rawQueryString": "",