Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

mod_rewriteで503

ちょっと気になったので。。。


最初、ここら辺のすべての処理をmod_rewriteだけで実現できるかなと思ったのですが、残念ながら、mod_rewriteでは300番系のエラーを出すことができますが、503のエラーは出せないようなのでさくっと簡単なものを作るの「には」便利とかいわれてるPHPで、さくっと、503を出すことにしました。

mod_rewriteのRフラグではステータスコードを一緒に指定できます。mod_rewrite - Apache HTTP Server Version 2.2にも


'redirect|R [=code]' (force redirect)
Prefix Substitution with http://thishost[:thisport]/ (which makes the new URL a URI) to force a external redirection. If no code is given, a HTTP response of 302 (MOVED TEMPORARILY) will be returned. If you want to use other response codes in the range 300-400, simply specify the appropriate number or use one of the following symbolic names: temp (default), permanent, seeother. Use this for rules to canonicalize the URL and return it to the client - to translate ``/~'' into ``/u/'', or to always append a slash to /u/user, etc.

と「300〜400の範囲で任意のステータスコードを指定できる」とあります。
が、「300〜400の範囲だけ」とは書いてないし、「ソースはどうなってんの?」ということで、ちょっと追ってみました。


これ以降、Apache2.2.4での話です。Apache1.3系・2.0系では確認していません。


以下はApache2.2.4のmodules/mappers/mod_rewrite.cの抜粋です。最初のcaseは3297行目で、設定内容を解析しているコードの一部分です。

static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg,
                                           char *key, char *val)
{
       :
    case 'r':
    case 'R':
        if (!*key || !strcasecmp(key, "edirect")) {        /* redirect */
            int status = 0;

            cfg->flags |= RULEFLAG_FORCEREDIRECT;
            if (strlen(val) > 0) {
                if (strcasecmp(val, "permanent") == 0) {
                    status = HTTP_MOVED_PERMANENTLY;
                }
                else if (strcasecmp(val, "temp") == 0) {
                    status = HTTP_MOVED_TEMPORARILY;
                }
                else if (strcasecmp(val, "seeother") == 0) {
                    status = HTTP_SEE_OTHER;
                }
                else if (apr_isdigit(*val)) {
                    status = atoi(val);
                    if (status != HTTP_INTERNAL_SERVER_ERROR) {
                        int idx =
                            ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);

                        if (ap_index_of_response(status) == idx) {
                            return apr_psprintf(p, "RewriteRule: invalid HTTP "
                                                   "response code '%s' for "
                                                   "flag 'R'",
                                                val);
                        }
                    }
                    if (!ap_is_HTTP_REDIRECT(status)) {
                        cfg->flags |= (RULEFLAG_STATUS | RULEFLAG_NOSUB);
                    }
                }
                cfg->forced_responsecode = status;
            }
        }
        else {
            ++error;
        }
        break;
       :
}

apr_isdigit以下が

[R=503]

のようにステータスコードを数字で指定したときの処理になりますが、基本的に指定されたステータスコードの有効性だけチェックして、HTTP_INTERNAL_SERVER_ERRORの場合だけ特殊扱いしてる感じです(間違いがあれば指摘して下さい :-))。
ということで、動作確認してみました。設定は適当w

RewriteEngine On
RewriteLog logs/rewrite_log
RewriteCond %{QUERY_STRING} rewrite
RewriteRule '' '' [R=503,L]

apache graceful後、ブラウザから確認。

Service Temporarily Unavailable

The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.

おおーっ!動くんじゃん。HTTPレスポンスヘッダは以下のような感じ。

HTTP/1.x 503 Service Temporarily Unavailable
Date: Mon, 09 Jul 2007 06:27:47 GMT
Server: Apache/2.2.4 (Unix) mod_ssl/2.2.4 OpenSSL/0.9.7a PHP/5.2.3
Content-Length: 433
Connection: close
Content-Type: text/html; charset=iso-8859-1

ついでに、

RewriteRule '' '' [R=501,L]

で確認。

Method Not Implemented

GET to / not supported.

おおーっ!初めて見たよ、このメッセージ!w
もう一つついでに、

RewriteRule '' '' [R=500,L]

で確認。

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator, xxxx@xxxxxx.xxx and inform them of the time the error occurred, and anything you might have done that may have caused the error.

More information about this error may be available in the server error log.

なんだ、いけんじゃん。。。
あとは、ErrorDocumentディレクティブを

ErrorDocument 503 /path/to/sorry.html

のような感じで設定してやればOKです。

追記(2007/07/09 16:20)

Apache2.0.59のmod_rewrite.cのソース(836行目)を見てみました。こちらは「リダイレクト系のステータスコードのみ」に限定してますね。

static const char *cmd_rewriterule_setflag(apr_pool_t *p,
                                           rewriterule_entry *cfg,
                                           char *key, char *val)
{
    int status = 0;
    int i;

    if (   strcasecmp(key, "redirect") == 0
        || strcasecmp(key, "R") == 0       ) {
        cfg->flags |= RULEFLAG_FORCEREDIRECT;
        if (strlen(val) > 0) {
            if (strcasecmp(val, "permanent") == 0) {
                status = HTTP_MOVED_PERMANENTLY;
            }
            else if (strcasecmp(val, "temp") == 0) {
                status = HTTP_MOVED_TEMPORARILY;
            }
            else if (strcasecmp(val, "seeother") == 0) {
                status = HTTP_SEE_OTHER;
            }
            else if (apr_isdigit(*val)) {
                status = atoi(val);
            }
            if (!ap_is_HTTP_REDIRECT(status)) {
                return "RewriteRule: invalid HTTP response code "
                       "for flag 'R'";
            }
            cfg->forced_responsecode = status;
        }
    }