Fessのテーマ配信とHTTPエラー応答を改善する

FessのStaticテーマ配信で、公開を禁止したファイルのチェックを見直しました。あわせて、エラーページのHTTPステータスと、壊れたリクエストパラメーターへの応答を修正しています。テーマを運用する際の安全性と、障害を判断しやすい応答に関わる変更です。

パスを解決した後に公開可否を判定する

テーマのtheme.ymlやREADME、ドットで始まるファイルなどは、配信時の拒否リストで公開を防いでいます。しかし従来は生のリクエストURIで判定していたため、重複スラッシュ、ドットのパス、パーセントエンコードなどの表記と、サーブレットコンテナが解決したファイルのパスが一致しない場合がありました。

今回、コンテナが解決したパスでテーマの配信経路を判断し、拒否対象のファイル名を確認します。非アクティブなテーマに属するファイルでも、拒否リストの対象なら404を返します。通常のJavaScriptやCSSなどのアセットは引き続き配信します。

拒否リストはすべてのドキュメントを非公開にする機能ではありません。例えばDESIGN.mdのようにリストにない名前は対象外です。テーマ内に公開すべきでないファイルを置く場合は、配信対象の確認も必要です。

エラーページとHTTPステータスを一致させる

従来は/error/404や/error/not_foundでもHTTP 500を返す場合がありました。数値コードと名前の表記を整理し、例えば次のように応答します。

パスHTTPステータス
/error/404404
/error/not_found404
/error/400400
/error/502502

専用の画面がないコードでもHTTPステータスは維持し、近いエラーページを表示します。例えば401ではアクセス拒否の画面、502ではサーバーエラーの画面を使います。不明な名前などは従来どおり500です。

読み取れないパラメーターを400として扱う

不正なパーセントエンコードなどを含むパラメーターは、サーバー内部の不具合とは区別してHTTP 400を返すようにしました。API v2ではinvalid_requestのエラー形式を使い、他の画面では通常の400応答にします。フォームのサイズ制限を超えた場合は413を返します。

これにより、監視で500を数えている環境でも、壊れたリンクや不正な入力と、アプリケーションの障害を区別しやすくなります。他の例外まで400に変換するものではありません。

今回の対応を含むビルドを適用した後は、テーマの通常画面とアセットに加えて、404などの応答も確認するとよいと思います。

関連PR

FessのWebクロールでHTTPヘッダーの文字コードを反映する

Shift_JISやEUC-JPのページをFessでクロールしたとき、ブラウザーでは読めるのに検索結果のタイトルや本文が文字化けすることがあります。HTTPヘッダーだけで文字コードを指定しているページを正しく扱うため、fess-crawlerのHTTPクライアントとHTML解析処理を修正しました。

HTTPヘッダーのcharsetを使う

従来は文字コードをContent-Encodingから読み取っていました。このヘッダーはgzipなどの圧縮方式を表すもので、文字コードの指定ではありません。修正後はContent-Typeのcharsetを読み取り、HTML側に文字コード指定がない場合も解析処理へ引き継ぎます。HttpClient 4と5の両方が対象です。

Content-Type: text/html; charset=Shift_JIS

例えば実際の本文がShift_JISで、HTMLにmeta charsetがなく、上記のヘッダーだけがあるページが対象になります。EUC-JPも同じ考え方です。新しい有効化設定は追加されていません。

初期値と優先順位

HTML内のmeta charsetがある場合は、その指定が従来どおり優先されます。meta指定がなければクライアントが報告した文字コードを使います。HTTP応答のcharsetが未指定、未対応、または不正な名前の場合の初期値はUTF-8です。文字コードを自動推定する機能ではないので、何も宣言していないShift_JISのページは引き続き文字化けします。

HtmlTransformerのdefaultEncodingは、クライアントからも文字コードが報告されていない場合だけ使われます。HTTPクライアントは未指定時もUTF-8を報告するため、defaultEncodingだけでHTTPページの未指定文字コードを上書きできるとは考えないでください。

クロール先で確認すること

文字化けがあれば、まず応答ヘッダーとHTMLのmeta charset、実際のファイルの文字コードを照合します。ヘッダーもmetaもないページには正しい指定を追加し、本文を再取得してインデックスを更新します。誤ったcharsetを送るサーバーも、ヘッダーが尊重されるようになるため修正が必要です。

ファイル、FTP、SMB、S3、GCS経由のHTMLにも、meta指定がない場合はクライアントの設定charsetが引き継がれます。これらの初期値もUTF-8です。この変更はHTML標準に合わせてヘッダーをmetaより優先する変更ではなく、既存の優先順位を維持しています。

関連PR

Fessの文書レポートとインデックス統計でファイルを整理する

ファイルサーバーをクロールし続けると、重複した資料や長く更新されていない文書がたまってきます。Fessの管理画面に文書レポート、fess-kopfに文書インデックスの統計画面が追加され、整理対象を調べやすくなりました。

重複と休眠文書を調べる

Fessの「システム情報」>「文書レポート」で、重複と休眠文書のタブを切り替えます。smb://server/share/などのURL接頭辞で対象を絞り、CSVで取り出せます。管理ロールはadmin-docreport、閲覧専用はadmin-docreport-viewです。

fess_config.propertiesの初期値は次のとおりです。

docreport.duplicate.group.size=100
docreport.duplicate.docs.size=10
docreport.duplicate.export.page.size=10000
docreport.dormant.days=365

画面は最大100の重複グループ、各グループ10文書を表示します。重複判定には本文のMinHash署名content_minhash_bitsを使うので、完全一致だけでなく近い内容も含み得ます。ファイルのバイナリーが同一であることを保証する判定ではありません。トークンのない本文は誤った巨大グループになるため除外します。

通常のマッピングでは既存の署名を使い、署名のためだけの再インデックスは不要です。cloudやawsのマッピングでは署名を計算しないため、重複レポートを利用できません。大きなインデックスでは画面の集計が見落とす組み合わせもあり、全体確認にはページングで取得するCSVを使います。

休眠文書は初期値で365日以上更新されていない文書です。最終更新日時のない文書は含めません。「検索結果から一度も開かれていない」条件はクリック数が正でない文書を対象にします。画面のページングには結果ウィンドウの上限があるため、それを超える確認はCSVで行います。

インデックスの全体像を見る

fess-kopfのdocuments画面では、ファイル種別、MIMEタイプ、ホスト、ラベル、所有者、最終更新者の上位20件と、その他・値なしの件数を表示します。サイズ分布、更新年、インデックス登録年、最大サイズの10文書も確認できます。

fess.searchエイリアスがある環境で文書タブを表示します。インデックスのメニューから過去の世代を指定することもできます。画面を開くときと更新時に取得し、クラスターポーリングごとの集計は行いません。

数字の読み方と制限

createdは元ファイルの作成日ではなくFessへ登録した時刻です。ファイルの年齢を見るときはlast_modifiedを使います。年の集計は閲覧側のタイムゾーンに従い、サイズはバイナリー単位です。

古いインデックスのフィールド型によっては集計できない項目があります。利用可能な.keywordが全ての対象インデックスにある場合は代用し、それ以外は集計不能と表示します。fess-kopf側にはCSV出力と定期レポート機能はありません。

両画面とも調査のための読み取り機能です。重複や休眠というだけで不要と判断せず、原本や保管義務、実際の利用状況を確認してからファイル整理へつなげてください。

利用できるバージョン

Fess 15.9.0に含まれる予定の機能になります。現時点では、まだ、リリースしていないので、今後のテストで変更される可能性もあります。

関連PR