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

というのもこれに2日もはまった.

経緯

お客様から大量のファイルをアップロードを一括でアップロードできないという問い合わせが来た. これがことのはじまり.

システムの概要

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

調査その1

Web.configをいじる

とりあえず「http post limit iis」でぐぐる. 普通はWeb.configをいじればイケルらしい.

maxAllowedContentLengthでHTTPリクエストのContent-Lengthを制限出来るらしい. maxAllowedContentLengthをbyteで指定する. 1 GBまで対応したいので1*1024*1024*1024=1073741824とする.

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

maxRequestLengthでASP.NETにおいてアップロードできるファイルのサイズを制限出来るらしい. maxRequestLengthをKB単位で指定する. こっちもbyteにしてくれ 1 GBまで対応したいので1*1024*1024=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 GBに制限してみる

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

条件 結果
200 MB X
100 MB X
90 MB O
30 MB O

どうやら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

犯人はお前だったんだな... UrlScan.iniのMaxAllowedContentLengthを1073741824に設定したら問題なくファイルがアップロードできたとさ. めでたしめでたし.

まとめ

1リクエストで大量のファイルをアップロードする前にUrlScanに気をつけよう.

参考

Request Limits

httpRuntime

urlscan