ReactPHP 1.2のLoopと開始時のエラー

ReactPHP のバージョン1.2からイベントループをわざわざ作成しなくても良くなったようだ。
代わりにLoopクラスのstatic関数を使う。

<?php
use React\EventLoop\Loop;

Loop::addPeriodicTimer(1, function () {
    static $count = 0;
    echo ++$count . "\n";
});

$loop->run()さえもないが、Loopクラスがshutdown関数を登録して、プログラムの最後にrun()が実行される。

作ったイベントループインスタンスを引き回さなくてよくて便利になった。ただ、プログラム本体がshutdown関数の中で実行されることになるので他のshutdown関数との実行順序が問題になるかもしれない。(これは実装時のレビューでも指摘されたようだ。)
明示的にループを実行することで回避できる。

<?php
use React\EventLoop\Loop;

Loop::addPeriodicTimer(1, function () {
    static $count = 0;
    echo ++$count . "\n";
});
Loop::run(); // Loopクラスが登録するshutdown関数はループを実行済みとしてなにもしない

本題だが、イベントループの準備後に問題が起きてプログラムを開始できないケースというのもある。

<?php
use React\EventLoop\Loop;

Loop::addPeriodicTimer(1, function () {
    static $count = 0;
    echo ++$count . "\n";
});
if ('failed') { // 問題発生
    echo "セットアップ中のエラー\n";
    exit(1);
}
Loop::run();

この場合、単にexitしたいにも関わらず、やはりループが実行されてしまう。
準備が中途半端な状態で実行されてしまうのは困る。

対策としては2つある。一つはtrigger_errorを呼ぶか、catchされない例外を投げる。

<?php
use React\EventLoop\Loop;

Loop::addPeriodicTimer(1, function () {
    static $count = 0;
    echo ++$count . "\n";
});
if ('failed') { // 問題発生
    trigger_error("セットアップ中のエラー", E_USER_ERROR); // noticeやwarningでは実行停止しないのでダメ
    // または throw new \RuntimeException("セットアップ中のエラー");
}
Loop::run();

この方法は自分でexitできないので任意の終了ステータスが指定できない。
もう一つは、最初にループを止めておく方法。

<?php
use React\EventLoop\Loop;

Loop::stop();
Loop::addPeriodicTimer(1, function () {
    static $count = 0;
    echo ++$count . "\n";
});
if ('failed') { // 問題発生
    echo "セットアップ中のエラー\n";
    exit(1);
}
Loop::run();

こちらは終了ステータスを指定できる。

そもそもイベントループの自動実行は必要なのだろうか?

Let's Encryptで--preferred-chain 'DST Root CA X3'で証明書を発行してきていた。その間、他のサーバでは中間証明書は毎回更新せず固定で送っていたところなど、チェーンが切れたところも目にしたが、いよいよ期限となってきた。
オプション指定はもう消してもいいのかどうかと思い、Let's Encryptの認証局の話を少し調べていたら、acme.shスクリプトのデフォルト認証局がLet's EncryptからスポンサーのZeroSSLに変わるという話を見つけた。
あそこはワイルドカードとか有料だったからそれなら他を使うだろう、と思っていたし、このスレッドでも指摘している人はいた。
しかし読んでみる限りではどうもACME経由なら全部料金なしでできるらしい。


それはそれとして、Let's Encryptなのだが、--preferred-chainで選べるチェーンは2通り

Subscriber Cert <-- R3 <-- ISRG Root X1 <-- DST Root CA X3 (self-signed)
Subscriber Cert <-- R3 <-- ISRG Root X1 (self-signed)

2番目がAndroid 7.1.1未満で有効と認識されないという問題が1番目(新たなデフォルト)で解決されたという話。ところが裏技的な1番目はOpenSSL 1.0.0-1.0.2等の古いTLS実装では認識されないらしい。
Windows/macOSではOKということで、むしろ機械的アクセスの方の懸念になる。OpenSSL 1.0系にはバックポートされていないのだろうか? リリースノートを見てみてもどの変更のことなのかが解らない。

reCAPTCHAのtimeout-or-duplicateは無視してはいけない

フォームにreCAPTCHA v3を置いたときに、発行したトークンが2分でタイムアウトしてしまう。そのためエラー理由にtimeout-or-duplicateが返ってきた場合にも成功扱いにする、という回避策があるらしい。
しかしこのエラーコードは名前の通り、トークン重複利用の場合でも返ってくる。
要は一回人間が操作したときのreCAPTCHAのフォーム値が再利用できるようになるということで、いくらでもbotが通過できるようになり、reCAPTCHAが無意味になる。
timeout-or-duplicateエラーはエラーとして扱わないといけない。エラーは無視してはいけない。いや、何を当たり前のことを。

このエラーの発生を防ぐためには、reCAPTCHA v3についてはユーザアクション時(例えばフォーム送信時)にトークン発行することをドキュメントでは勧めている。
v2でもinvisibleタイプなら同様にできる。

Firefox 80でアドレスバーから検索できない

Firefox 80にアップデートしてから、アドレスバーでの検索ができなくなった。
Ctrl-Kでアドレスバーにフォーカスして「? キーワード」と入力しても「アドレスが正しくないようです」と出る。
もちろん検索エンジンは設定されている。オプションで検索バーを表示してそちらに入力すれば検索できるし、検索候補の表示はどちらでもできる。セーフモード(Shift押下起動)でも変化なし。

ちょろっと検索しても原因が判らなかったので放置していたのだが、80.0.1でも解消しなかったので改めて調べてみた。
about:config の keyword.enabled を false から true (デフォルト) にしたら解消する。
(参考:Address Bar doesn't search with google after messing with settings)

アップデートまで普通に動作していたし、アップデート後アプリを再起動してすぐに異常に気づいたので、その時に「勝手に」何か変わったのは間違いないと思うのだが。

ある動画サービスのストリーミングをHTTPS経由で見ていたら、決まった場所でデコードに起因するとみられるブロックノイズと異音が入る。解像度を変えてみると入らないのでソースの問題ではないし、AACエンコーダもどれだけバグってもここまでの大音量なノイズは発生させないと思う*1のでストレージか転送時の破損と思う。
HTTPSなので原理的には整合性チェックがHTTPよりまともに働くため、転送時に破損したままというのはあり得ない。しかし高負荷のサーバの場合フロントにロードバランサやプロキシ、そこからバックエンドで負荷分散、というのはよくやる。クライアントと直接話すフロントのサーバのみHTTPSでLAN内をHTTP接続にしてしまうと、LAN内で壊れたもののたまたまTCP等でのチェックサムが通ったデータというのがそのままフロントからクライアントに流れたりキャッシュされたりしまうことも十分起こりうる、と思う。
HTTPSでも暗号化を行わないcipher suiteにしてセッションキャッシュすれば速度的にも見劣りしないと思うが、世にあるお手軽ハウツーブログではプロキシはHTTP接続ばかりで、HTTPSは見たことがない気がする。

*1:後で考えたらそんなこともない