curluneの日記

日々試行錯誤。雑多に、気ままに、てきとーに。HoloLens/Oculus Rift,Touchと戯れる日々。

Azure App Service で拡張子の無いファイルをダウンロードできるようにする

以前に困った事があったのでメモ。

AzureというよりはwindowsなwebサーバIISの都合での問題。

mimeが設定されていないファイルへのアクセスはブロックされるので、どうにかしないといけないというお話。

The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.

解決方法

ふつうなやり方

公開ディレクトリに下記の内容のweb.config追加すればok。

<?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <system.webServer>
            <staticContent>
                <!-- 動作が怪しい時は一旦割当を削除してみると良いかも -->
                <remove fileExtension="." />
                <!-- 拡張子無し バイナリとして割り当てる -->
                <mimeMap fileExtension="." mimeType="application/octet-stream" />
            </staticContent>
        </system.webServer>
    </configuration>

ファイルは App Service のメニュー App Service Editor (プレビュー) から作成・編集する事ができます。 f:id:curlune:20171030053601p:plain

設定の都合上、mimeはすべてのファイルで共通です。通常はこれで問題ないと思います。諸事情により別の方法も書いておきます。

へんな事をしたい場合

urlの書き換えとphpを利用するとこんな感じでもいけます。

  • web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="my file" stopProcessing="true">
                    <match url="^files/(.+)\.([^\.]+)$" />
                    <action type="Rewrite" url="/download.php?file={R:1}&amp;ext={R:2}" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
 </configuration>
<?php
$dir = 'files';

$file = @$_GET['file'];
$ext = @$_GET['ext'];
$fileName = "{$file}.{$ext}";
$parts = [__DIR__, $dir, $file];
// XXX ディレクトリトラバーサル
$filePath = implode(DIRECTORY_SEPARATOR, $parts);

if (!is_file($filePath)) {
    http_response_code(404);
    echo 'Not Found!';
    exit(1);
}

$mime = mime_content_type($filePath);
$length = filesize($filePath); // max 2GB

header("Content-Type: {$mime}");
header("Content-Disposition: inline;");
// 保存させたい場合はこちら
// header("Content-Disposition: attachment; filename='{$fileName}'");
header("Content-Length: {$length}");
readfile($filePath);
exit();

ファイルが触れないなら、触れるところから出力すればいいじゃない、という強引な方法。

こうすることで個別にmimeなどの情報を切り替えることができます。本当はファイルに拡張子を付ければよいだけなのだけれど...。

下記のようなプログラムがあって、これに近い事してごまかしたことがありました...。

  • ファイルは拡張子無しのハッシュ値名で保持
  • 拡張子は別途管理
  • アクセスは拡張子付きのリンク
  • url書き換えで実ファイルへアクセス

参考

https://support.microsoft.com/ja-jp/help/326965/iis-6-0-does-not-serve-unknown-mime-types

IIS 6.0 Web サーバーのファイルを要求した際、そのファイルの拡張子が Web サーバー上に定義済みの MIME の種類ではないと、次のエラー メッセージが表示されます。

HTTP エラー 404 - ファイルまたはディレクトリが見つかりません。

stackoverflow.com