CloudFront Functions でサポートされているランタイムについて調べてみた
2021-05-13CloudFront Functions でサポートされているランタイムは現時点で JavaScript (ECMAScript 5.1 準拠) となっていますが、「ECMAScript 5.1 !? いつの規格やねん、解散。」 となる前にあらためて公式ドキュメントを読んで詳細を確認してみます。
なお、内容については 2021/05/13 時点のものです。
目次
はじめに
今回の内容は、下記の公式ドキュメントの内容を自分なりにまとめたものになります。公式ドキュメント以上の内容はありません。
ECMAScript 5.1 compliant
CloudFront Functions の発表に歓喜したものの、サポートされているランタイムが JavaScript のみで且つ ECMAScript 5.1 compliant となっていて、残念に思った方は少なくないと思います。ただし、公式ドキュメントには下記のように書かれています。
The CloudFront Functions JavaScript runtime environment is compliant with ECMAScript (ES) version 5.1 and also supports some features of ES versions 6 through 9.
つまり ベースは ECMAScript 5.1 (2011/06)1 ですが、 ES 6 (2015)2 から ES 9 (2018)3 に含まれる一部の機能もサポートしており、さらに ES の仕様に含まれない非標準のメソッドも提供されています。
なので、 ES 5.1 以降の仕様で何が含まれているのか、非標準のメソッドって具体的に何が含まれているのか、気になったところを見ていきます。
ちなみに、 コンソールや AWS CLI などからランタイムを指定する場合は cloudfront-js-1.0 という名前になっています。
Core features
ES のコアとなる仕様についてです。
式と演算子
ES 5.1 のすべての演算子に加えて、 ES 7 に含まれる べき乗演算子 **
がサポートされています。
var side = 4;
var square = side ** 2;
console.log(square);
// 16
文と宣言
下記のステートメントがサポートされています。
宣言
var
※ let
および const
はサポートされていません (ES 6)
制御フロー
break
continue
if...else
switch
try...catch [finally]
throw
反復処理
for
for...in
while
do...while
その他
label
関数
ES 5.1 のすべての機能に加えて、 ES 6 に含まれる arrow function 、 rest parameter (残余引数) がサポートされています。
var sum = (...args) => {
var total = 0;
for (var i in args) {
total += args[i];
}
return total;
}
console.log(sum(2,4,6));
// 12
Primitive objects
Object
ES 5.1 の Object メソッド (一部) に加えて、 ES 6 および ES 8 に含まれる下記のメソッドがサポートされています。
-
assign
(ES 6)var curry = {source: 'ポーク', spicy: '2辛'}; var rice = {origin: '新潟', quantity: '400g'}; var curryRice = Object.assign(rice, curry); console.log(curry); console.log(rice); console.log(curryRice); // {source:'ポーク',spicy:'2辛'} // {origin:'新潟',quantity:'400g',source:'ポーク',spicy:'2辛'} // {origin:'新潟',quantity:'400g',source:'ポーク',spicy:'2辛'}
-
is
(ES 6)var rice = {origin: '新潟', quantity: '400g'}; var thaiRice = {origin: 'タイ', quantity: '400g'}; console.log(Object.is(rice, thaiRice)); console.log(Object.is(rice.quantity, thaiRice.quantity)); // false // true
-
prototype.setPrototypeOf
(ES 6) -
entries
(ES 8)var curryRice = {origin: '新潟', quantity: '400g', source: 'ポーク', spicy: '2辛'}; console.log(Object.entries(curryRice)); // [['origin','新潟'],['quantity','400g'],['source','ポーク'],['spicy','2辛']]
-
values
(ES 8)var curryRice = {origin: '新潟', quantity: '400g', source: 'ポーク', spicy: '2辛'}; console.log(Object.values(curryRice)); // ['新潟','400g','ポーク','2辛']
String
ES 5.1 の String メソッド (一部) に加えて、 ES 6、 ES 8、 ES 9 に含まれる下記のメソッドがサポートされています。
fromCodePoint
prototype.codePointAt
(ES 6)prototype.endsWith
(ES 6)prototype.includes
(ES 6)prototype.repeat
(ES 6)prototype.startsWith
(ES 6)prototype.padStart
(ES 8)prototype.padEnd
(ES 8)prototype.trimStart
(ES 9)prototype.trimEnd
(ES 9)
更に、下記の非標準メソッドもサポートされています。
prototype.bytesFrom(array | string, encoding)
prototype.fromBytes(start[, end])
prototype.fromUTF8(start[, end])
prototype.toBytes(start[, end])
prototype.toUTF8(start[, end])
用途がパッと思いつかなかったんですが、公式の example では JWT の検証として String.bytesFrom()
を使ってました。
Validate a simple token in the request - Amazon CloudFront
Number
ES 5.1 のすべての Number メソッドと、 ES 6 に含まれる下記のメソッド/定数がサポートされています。
isFinite
isInteger
isNaN
isSafeInteger
parseFloat
parseInt
prototype.toExponential
prototype.toFixed
prototype.toPrecision
EPSILON
MAX_SAFE_INTEGER
MAX_VALUE
MIN_SAFE_INTEGER
MIN_VALUE
NEGATIVE_INFINITY
NaN
POSITIVE_INFINITY
Built-in objects
Date
ES 5.1 の Date
の機能がすべてサポートされていますが、下記の制限があります。
セキュリティの観点から、 Date
のメソッドで返却される現在時刻は実行される Function のライフタイム内で常に一定で、その値は Function が起動した時点の時刻となります。
つまり、関数の開始と終了時点でそれぞれの時刻を取得して、その差分から関数の実行時間を取得するようなことはできません。
var start = Date.now();
/**
* 何かしらの処理
*/
var end = Date.now();
console.log(`${start}\n${end}`);
// 1620857555194
// 1620857555194
Function
Function constructors はサポートされていません。
var hello = new Function('return "Hello";');
console.log(hello());
// Error Message: The CloudFront function associated with the CloudFront distribution is invalid or could not run. TypeError: function constructor is disabled in "safe" mode
var bye = function() {return 'Bye';};
console.log(bye());
// bye
(safe じゃないモードなら使えるのか…?)
Regular expressions
ES 5.1 のすべての RegExp の機能に加えて、 ES 9 に含まれる named capture groups がサポートされています。
var CURRY_RICE_RE = /ソース:(?<source>.*) 辛さ:(?<spicy>.*) ご飯の量:(?<rice>.*)/;
var menu = 'ソース:ポーク 辛さ:2辛 ご飯の量:300g';
var matched = CURRY_RICE_RE.exec(menu);
console.log(matched.groups.source);
console.log(matched.groups.spicy);
console.log(matched.groups.rice);
// ポーク
// 2辛
// 300g
Array
ES 5.1 の Array メソッド (一部) に加えて、 ES 6 および ES 7 に含まれる下記のメソッドがサポートされています。
of
(ES 6)prototype.copyWithin
(ES 6)prototype.fill
(ES 6)prototype.find
(ES 6)prototype.findIndex
(ES 6)prototype.includes
(ES 7)
var currySource = Array.of('ポーク', 'ビーフ');
console.log(currySource);
// ['ポーク','ビーフ']
console.log(currySource.copyWithin(0, 1, 2));
// ['ビーフ','ビーフ']
console.log(currySource.fill('ハヤシ', 1, 2));
// ['ビーフ','ハヤシ']
console.log(currySource.find(element => element = 'ビーフ'));
// ビーフ
console.log(currySource.findIndex(element => element = 'ビーフ'));
// 0
console.log(currySource.includes('キーマ'));
// false
Typed arrays
ES 6 に含まれる 型付き配列 がサポートされています。
Int8Array
Uint8Array
Uint8ClampedArray
Int16Array
Uint16Array
Int32Array
Uint32Array
Float32Array
Float64Array
var int8array = new Int8Array(2);
int8array[0] = 0;
console.log(int8array);
int8array[1] = 'string';
console.log(int8array);
int8array[1] = 1;
console.log(int8array);
// Int8Array [0,0]
// Int8Array [0,0]
// Int8Array [0,1]
Built-in modules
Built-in modules として crypto
と querystring
がサポートされており、それぞれ require
で読み込むことで使用できます。
Crypto (hash and HMAC)
crypto
モジュールでは、標準的なハッシュおよびハッシュベースのメッセージ認証コード (HMAC) のヘルパが提供されています。下記のメソッドがサポートされており、それぞれ Node.js の対応するメソッド4 と同じ挙動となります。
Hashing methods
crypto.createHash(algorithm)
hash.update(data)
hash.digest([encoding])
var crypto = require('crypto');
var text = 'I love curry.';
var hash = crypto.createHash('sha256'); // or md5, sha1
hash.update(text);
var digest = hash.digest('hex'); // or base64, base64url
console.log(`${text}\n${digest}`);
// I love curry.
// 74dc57666d14c957cf622ad110f1c8d88c0f3390ee057333e97bcaf0c50ac82a
HMAC methods
crypto.createHmac(algorithm, secret key)
hmac.update(data)
hmac.digest([encoding])
var crypto = require('crypto');
var text = 'I love curry.';
var hmac = crypto.createHmac('sha256', 'secret key hoge'); // or md5, sha1
hmac.update(text);
var digest = hmac.digest('hex'); // or base64, base64url
console.log(`${text}\n${digest}`);
// I love curry.
// 2e3ef82b9c4265d77b977ab9d778663e240da3737e0059ca82c0f93b49f4ddd1
Query string
querystring
モジュールでは、 URL 内のクエリ文字列を解析して操作するためのメソッドが提供されています。下記のメソッドがサポートされており、それぞれ Node.js の対応するメソッド5 と同じ挙動となります。
ただ、 CloudFront Functions に渡されるイベントオブジェクトは自動的にパースされるので、このモジュールを使う場面はほぼないです。
querystring.escape(string)
- 通常は
querystring.stringify()
経由で実行されるため、直接使用することはない
- 通常は
querystring.parse(string[, separator[, equal[, options]]])
querystring.stringify(object[, separator[, equal[, options]]])
querystring.unescape(string)
- 通常は
querystring.parse()
経由で実行されるため、直接使用することはない
- 通常は
var qs = require('querystring');
var queryString = 'source=beef&rice=300&topping=egg&topping=garlic';
var parsed = qs.parse(queryString);
console.log(JSON.stringify(parsed, null, 2));
// {
// "source": "beef",
// "rice": "300",
// "topping": [
// "egg",
// "garlic"
// ]
// }
var params = {
source: 'pork',
rice: '500',
topping: [
'seafood'
]
}
var paramsString = qs.stringify(params);
console.log(paramsString);
// source=pork&rice=500topping=seafood
まとめ
CloudFront Functions でサポートされているランタイムについて、公式ドキュメントの内容を読んでみた話でした。
ベースは ECMAScript 5.1 ですが それ以降の ES 9 までの内容も含まれているので、 ECMAScript 5.1 という文字だけで気を落とすのは早そうです。そもそも CloudFront Functions では外部ネットワーク接続できなかったりメモリや実行時間の制限が厳しいこともあり、古い仕様でもなんとかなっているのかなと思いました。とはいえ var
で変数宣言するのはちょっと気持ち悪いです。
今後ランタイムは更新されているかもしれませんが、現状では諸々の制限の中で処理を実装する上では ECMAScript 5.1 準拠であっても困ることはなさそうです。
comments powered by Disqus