読者です 読者をやめる 読者になる 読者になる

たぷつきません

おなかがでてきた。もうたぷついてるやん。

動的ページのAuthSubまとめ。

 ie,chrome,firefox,safariでは動的ページのCrossdomain Cookie Injectionがようやく効くようになった。サーブレットで静的ファイルをシミュレートする手立てを以下にまとめる。
 まず、GAEの静的ファイルを扱うStaticFileFilterの動きをパケットモニタで確認した。ETagは使わず、Last-Modifiedとそれに関係する幾つかの処置が必要であることが判明。ここから適切な更新時刻さえ用意すれば良いことが分かったので、デプロイ単位の日時を紐付けるようにした。これには、データストアに ApiProxy.getEnvironment().getVersion()をキーとして対応する日時を持つエンティティを作成。エンティティ初回参照時にその日時を保存。これをサーブレットで常に返すようにした。authsubでクライアントからJSAPIを使ったloginが必要なURLに対するサーブレットに施す。動的ではあるが今回はAppsドメイン単位に内容が変化するだけなのでそもそもURLが異なる。ブラウザから見て内容が改ざんされていないことになるので変化を捉えられてしまうことはない。これで静的ファイルとして騙せるようになった。具体的には以下のレスポンスを返すようにしただけ。If-Modified-Sinceにちゃんと応答するのとLast-Modifiedが変化しないこと。Expiresがあることでブラウザがキャッシュから変化していないことが確認できるので、JSAPI(www.google.com側)から、アプリケーション(xxxx.appspot.comやらlocalhost:8080)にAuthSubのトークンをクッキーにうまく格納される(前提。operaはimg入れてるのになぜか動作しない。とりあえず諦めモード)。

private static final int LIMIT = 10 * 60; // 10分のリミット
private static String lastModified;
private static String expires;

public void beforeOutput(HttpServletRequest req, HttpServletResponse res)
        throws IOException {
    if (lastModified == null) {
        Date date = VersionBootTimeDao.INSTANCE.getDate();
        lastModified = toRFC1123Format(date.getTime());
        expires = toRFC1123Format(date.getTime() + (LIMIT * 1000));
    }
    String ifModifiedSince = req.getHeader("If-Modified-Since");
    if (ifModifiedSince != null && ifModifiedSince.equals(lastModified)) {
        res.sendError(HttpServletResponse.SC_NOT_MODIFIED, "Not modified");
        return;
    }
    res.setHeader("Last-Modified", lastModified);
    res.setHeader("Expires", expires);
    res.setHeader("Cache-Control", "public, max-age=" + LIMIT);
}

/**
 * RFC1123形式に時刻を変換する。
 * 
 * @param time
 *            1970/1/1からの経過ミリ秒
 * @return RFC1123形式の時刻文字列
 */
private static String toRFC1123Format(long time) {
    Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT-0"),
            Locale.UK);
    calendar.setTimeInMillis(time);
    // ex.) Fri, 23 Oct 2009 08:32:45 GMT
    return String.format(java.util.Locale.UK,
            "%1$ta, %1$te %1$tb %1$tY %1$tH:%1$tM:%1$tS GMT", calendar);
}

呼び出し元ではレスポンスがisCommited()でなければ(sendErrorによってcommitされる)、コンテンツを吐き出すようにしている。