「サーバーエラーのふり」を見抜く方法?

政治家の橋本聖子さんの事務所のサイトが「アクセス集中」によるサーバー負荷が原因で閲覧できなくなっているという話題を見つけました。

こちらのツイートが発端のようです:https://twitter.com/nyupy/status/502395108151394304

もう指摘された方もきっといらっしゃるとは思いますが、一応。HTTP レスポンスが返って来たから真正のエラーではない、と判断することはできません。エラーかどうかはレスポンスボディではなくてステータスコードで判断することになっています。

Web アプリケーション側でエラーが発生して処理を打ち切ったら、HTTP サーバー側で適切なレスポンスを返すこともあるでしょう (500 Internal Server Error 等)。あるいは (もしあれば) ロードバランサ側で 502 Bad Gateway のようなレスポンスを返すこともあるでしょう。レスポンスボディの内容はもちろんカスタマイズできるので、ステータスコードを見ないことにはエラーか否か判断できません。

じゃあ橋本聖子さんの事務所のサイトの HTTP レスポンスはどうなんだと言うと…

HTTP/1.1 200 OK
Date: Fri, 22 Aug 2014 01:14:59 GMT
Server: Apache/1.3.42 Ben-SSL/1.60 (Unix) PHP/4.4.9 with Suhosin-Patch
Last-Modified: Wed, 20 Aug 2014 14:53:19 GMT
ETag: "3f8f891-245-53f4b65f"
Accept-Ranges: bytes
Content-Length: 581
Connection: close
Content-Type: text/html; charset=shift_jis

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis" />
<title></title>
<style type="text/css">
.center {
	text-align: center;
}
</style>
</head>

<body>
<p class="center">&nbsp;</p>
<p class="center">&nbsp;</p>
<p class="center">只今アクセスが集中しており、ページを表示することができません。
<p class="center">しばらくたってから、アクセスいただきますようお願いいたします。
</body>
</html>

1行目がステータスコードです。200 OK は「何ら問題なく正常にリクエストを処理した」ことを示します。なので、「只今アクセスが集中しており、ページを表示することができません。」というのはちょっと違います。でも、このページを表示しないと本当にサイトが過負荷で火を吹く可能性はあるでしょう (どのようなサイト構成なのかによりますが)。

レスポンスヘッダで他に注目したいのは、Server: Apache/1.3.42 Ben-SSL/1.60 (Unix) PHP/4.4.9 でしょうか。なかなかクラシックなサーバーです。Apache 1.3.42 リリースのアナウンスがポストされたのは Wed, 03 Feb 2010 00:03:34 GMT、php 4.4.9 は 07 Aug 2008 です。

Last-Modified はこの日時に index.html が編集された、ということです。なぜ index.html かというと、デタラメな URI をリクエストすると index.html にリダイレクトされ、上の HTML が返ってくるからです。転送には mod_rewrite (あるいは mod_alias) を使っているんでしょう。なお、Apache 1 系列の mod_rewrite の正規表現は文字クラスの省略記法が使えない等、注意が必要なようです:http://stackoverflow.com/questions/1223754/diff-in-mod-rewrite-on-apache-1-3-and-2-2

さて、これは他人事ではありません。自社の顧客のサイトが炎上して似たような対応を求められることもあるかもしれません。どうすればもっともらしいレスポンスが返せるでしょう?ということで、Perl の PSGI を使ってウソエラー生成器を作ってみました:

# vim: syntax=perl:

use 5.020;
use utf8;
use Encode;

my $app = sub {
  my ($env) = @_;

  [
    503,
    [
      'Server' => 'Apache',
      'Content-Type' => 'text/html; charset=UTF-8',
    ],
    [encode('utf8', <<EOF )],
<!doctype html>
<html>
  <head>
    <title>503 Service Unavailable</title>
  </head>
  <body>
    <h1>503 Service Unavailable</h1>
    <p>ただいまアクセスが集中しているため、サイトが表示できません。</p>
  </body>
</html>
EOF
  ];
};

上のスクリプトを Starman 等の PSGI 対応の HTTP サーバーで動かします (シェルで starman foo.psgi を実行するだけ)。Starman にアクセスするとこうなります:

HTTP/1.1 503 Service Unavailable
Server: Apache
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 22 Aug 2014 02:09:24 GMT
Connection: keep-alive

fb
<!doctype html>
<html>
  <head>
    <title>503 Service Unavailable</title>
  </head>
  <body>
    <h1>503 Service Unavailable</h1>
    <p>ただいまアクセスが集中しているため、サイトが表示できません。</p>
  </body>
</html>

0

どんなリクエスト URI を指定しても上のようなレスポンスが返ります。ウソエラーを返すという目的には好都合です。が、レスポンスヘッダはもうちょっと凝った方が良いかも?あと、POST リクエストには違うエラーを返したり、リクエストヘッダに Accept 等がなければ反応しなかったり、そういう工夫もしないと「本物らしさ」が出ないかもしれません。

ともあれ、こういう事態には巻き込まれたくないものです。しみじみ。

(コウヅ)