1リクエストで大量のファイルをアップロード出来ない問題を解決するのが大変だった話

ASP.NET

表題の通り 1 リクエストで大量のファイルをアップロードできない問題を解決するのが大変だったので経緯とどう解決したかを紹介します。

スポンサーリンク

経緯

とあるシステムについてお客様から大量のファイルをアップロードを一括でアップロードできないという問い合わせが来ました。
これがことのはじまりでした。


システムの概要

アプリは ASP.NET MVC で Web サーバーは IIS です。


調査その1

Web.config を編集する

とりあえず「http post limit iis」でぐぐります。
普通は Web.config をいじれば解決するみたいです。

maxAllowedContentLength で HTTP リクエストの Content-Length を制限出来るみたいなので maxAllowedContentLength を byte で指定します。
今回は 1 GB まで対応したいので 110241024*1024 = 1073741824 とします。

<configuration>
    <system.webServer>
        <security>
          <requestFiltering>
            <requestLimits maxAllowedContentLength="1073741824" />
          </requestFiltering>
        </security>
    <system.webServer>
</configuration>    

maxRequestLength で ASP.NET においてアップロードできるファイルのサイズを制限出来るようなので maxRequestLength を KB 単位で指定します。
こっちもbyteにしてくれ
1 GB まで対応したいので 110241024 = 1048576 とします。

<configuration>
    <system.web>
        <httpRuntime maxRequestLength="1048576" />
    </system.web>
<configuration>  

Web.config を編集したが問題は解決しませんでした。


問題の原因を探る

Web.config の設定が効いてるのか不安になったので色々条件を変えてアップロードしてみました。


30 MB に制限してみる

1 GB とたいそれたことは言わないで 30 MBに制限して試してみました。
結果 30 MB まではファイルをアップロードでき、それを超える場合はアップロード出来ませんでした。
Web.config が効いていることが判明しました。


もう 1 回 1 GB に制限してみる

1 GB に制限して色々な条件でファイルをアップロードしてみました。

条件結果
200 MBX
100 MBX
90 MBO
30 MBO

100 MB 未満ならアップロード出来ることが判明しました。


考察

アプリケーションにリクエストが届く前に何かフィルターがかかっている?

スポンサー

調査その2

エラーの詳細を見るために色々設定しました。


トレースを有効にする

IIS にトレース機能が追加されていない場合はサーバーマネージャーで IIS にトレースを追加します。
IIS マネージャで対象のサイトを選択した後、失敗した要求のトレースをクリックし、トレースを有効にします。


トレース規則を設定する

IIS マネージャで対象のサイトを選択し、機能ビューの失敗した要求のトレースの規則をダブルクリックします。
追加→すべてのコンテンツ→状態コード(今回は403、404)→プロバイダーを全て選択で規則を設定します。


エラーを発生させる

大量のファイルをアップロードします。
エラーが「C:\inetpub\logs\FailedReqLogFiles\W3SVC1」に xml で出力されます。


エラーの内容を見る

見てみると気になる内容が…

FILTER_START FilterName="C:\Windows\system32\inetsrv\urlscan\urlscan.dll"

FILTER_SET_REQ_HEADER HeaderName="URLSCAN-STATUS-HEADER:"、HeaderValue="Content-length-too-long"

GENERAL_REQUEST_HEADERS Headers="Cache-Control: no-cache

Connection: close
Content-Length: 0
Content-Type: multipart/form-data; boundary=---------------------------7e21c9181f09b6
Accept: text/html、application/xhtml+xml、*/*
Accept-Encoding: gzip、deflate
Accept-Language: ja-JP
URLSCAN-STATUS-HEADER: Content-length-too-long

urlscan???
Content-length-too-long???

とりあえず Content-Length が長すぎって怒られているようです。
urlscan なるものが動いていそうだということがわかりました。

スポンサー

urlscan についてぐぐる

「urlscan iis」でぐぐりました。

URLScan v3.1 は、インターネット インフォメーション サービス (IIS) が処理する HTTP 要求の種類を制限するセキュリティ ツールです。


urlscan のログを見る

「%WINDIR%\system32\inetsrv\urlscan\logs」にログが出力されるようなので見てみます。

#Software: Microsoft UrlScan 3.1
#Version: 1.0
#Date: 2018-06-07 06:30:42
#Fields: Date Time c-ip s-siteid cs-method cs-uri x-action x-reason x-context cs-data x-control
2018-06-07 06:31:24 10.94.33.151 1 POST /example/fileupload Rejected Content+length+too+long Content-Length: 203675502 100000000

ありました!!!!!!!!!
これで urlscan が原因だと確定しました。
urlscan でどう制限しているのかぐぐります。


urlscan の設定をいじる

「urlscan iis content-length」でぐぐりました。
すると「%WINDIR%\system32\inetsrv\urlscan\」にUrlScan.iniなる設定ファイルがあるようです。

[RequestLimits]

;
; The entries in this section impose limits on the length
; of allowed parts of requests reaching the server.
;
; It is possible to impose a limit on the length of the
; value of a specific request header by prepending "Max-" to the
; name of the header.  For example、the following entry would
; impose a limit of 100 bytes to the value of the
; 'Content-Type' header:
;
;   Max-Content-Type=100
;
; Any headers not listed in this section will not be checked for
; length limits.
;
; There are 3 special case limits:
;
;   - MaxAllowedContentLength specifies the maximum allowed
;     numeric value of the Content-Length request header.  For
;     example、setting this to 1000 would cause any request
;     with a content length that exceeds 1000 to be rejected.
;     The default is 30000000.
;
;   - MaxUrl specifies the maximum length of the request URL,
;     not including the query string. The default is 260 (which
;     is equivalent to MAX_PATH).
;
;   - MaxQueryString specifies the maximum length of the query
;     string.  The default is 2048.
;

MaxAllowedContentLength=100000000
MaxUrl=26000
MaxQueryString=2048000

UriScan.ini の MaxAllowedContentLength を 1073741824 に設定したら問題なくファイルがアップロードでき流ようになりました。


まとめ

1リクエストで大量のファイルをアップロードする前に urlscan に気をつけましょう。


参考

Request Limits


httpRuntime


urlscan


関連情報

C# や ASP.NET に関連する記事を以下にまとめています。

テレワークしている方には以下の記事がおすすめです。
私のお気に入りは REALFORCE と R&F BELX のルイボスティーです。

エンジニア初心者向けに本当に使えるツールを紹介しています。
特に Notion はタスク管理に本当に便利です。

タイトルとURLをコピーしました