WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

ダウンロードの際の拡張子 と MIME Type の指定

by WebSurfer 2. September 2010 22:42

MSDN フォーラムで、IE で xlsm をダウンロードすると zip 形式になってしまい、直接 Excel で開けないという話があったので、ちょっと調べてみました。

結局、単にそれはサーバー側の Web アプリの問題だったのですが、調査の結果、自分が知らなかったことがいろいろあったので、忘れないように書いておきます。

ブラウザは、ヘッダーの Content-Disposition: attachment; filename= で指定する拡張子と、Content-Type: で指定する MIME Type のどちらでファイルの種類を判断するでしょうか?

検証した結果は以下のとおりでした。簡単に言うと、IE8 は拡張子で判断、Opera は MIME Type で判断、Forefox は拡張子と MINE Type の指定が違う場合結果は未定義のようです。

ブラウザ Ext: xlsm
MT: xlsm
Ext: xlsm
MT: zip
Ext: zip
MT: zip
Ext: zip
MT: xlsm
IE8 Excel Excel Zip Zip
Firefox 3.6.8 Excel Zip Zip Zip
Opera 10.61 Excel Zip Zip Excel

上の表で、Ext は Content-Disposition に設定した拡張子、MT は Content-Type に設定した MIME Type です。

検証に使ったファイルは、有効な xlsm 形式のファイルで、拡張子は正しく xlsm としており、検証の間、中身も名前も一切変えていません。

クライアントの OS は Vista SP2 です。拡張子とアプリケーションの関連付けは、xlms は Excel、zip は WinZip としています。Web サーバーは Windows Server 2008 の IIS7, ASP.NET 3.5 SP1 です。

予想外の動きをしたのは Opera で、拡張子と MIME Type が異なる場合、拡張子を MIME Type に合わせて書き換えてしまいます。下の画像は、拡張子を xlsm、MIME Type を zip とした場合の例です。元のファイル名 001.xlsm が 001.zip に書き換えられています。

Opera のファイルダウンロード時のダイアログ

直リンクの場合(a 要素の href 属性にサーバーに置いた xlsm ファイルを指定した場合)、ヘッダーは以下のようになります。ブラウザは正しく判断出来るようです。

Content-Type: application/vnd.ms-excel.sheet.macroEnabled.12
Last-Modified: Thu, 02 Sep 2010 13:07:58 GMT
Accept-Ranges: bytes
ETag: "3e8647dd9f4acb1:0"
X-Powered-By: ASP.NET
Date: Thu, 02 Sep 2010 13:12:12 GMT
Content-Length: 12477

ちなみに、HTTP ハンドラーを使った場合のヘッダーは以下のようになります。

Cache-Control: private
Content-Type: application/vnd.ms-excel.sheet.macroEnabled.12
Content-Disposition: attachment; filename=001.xlsm
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET
Date: Thu, 02 Sep 2010 13:21:00 GMT
Content-Length: 12477

検証に使った HTTP ハンドラのコードを参考までにアップしておきます。

<%@ WebHandler Language="C#" Class="_045_Handler" %>

using System;
using System.Web;
using System.IO;

public class _045_Handler : IHttpHandler 
{
  public void ProcessRequest(HttpContext context)
  {
    string path = 
      context.Server.MapPath("~/Test/data/001.xlsm");

    if (!File.Exists(path))
    {
      return;
    }
        
    string type = context.Request.QueryString["type"];

    switch (type)
    {
      case "xlsm_xlsm":
        SetHeader(context, "001.xlsm", 
          "application/vnd.ms-excel.sheet.macroEnabled.12");
        break;
      case "xlsm_zip":
        SetHeader(context, "001.xlsm", 
          "application/x-zip-compressed");
        break;
      case "zip_zip":
        SetHeader(context, "001.zip", 
          "application/x-zip-compressed");
        break;
      case "zip_xlsm":
        SetHeader(context, "001.zip", 
          "application/vnd.ms-excel.sheet.macroEnabled.12");
        break;
      default:
        SetHeader(context, "001.xlsm", 
          "application/vnd.ms-excel.sheet.macroEnabled.12");
        break;                
    }
    context.Response.TransmitFile(path);
    context.Response.End();
  }
    
  public bool IsReusable
  {
    get {
      return false;
    }
  }

  protected void SetHeader(HttpContext context, string name, string type)
  {
    context.Response.AppendHeader("Content-Disposition",
      "attachment; filename=" + name);
    context.Response.ContentType = type;
  }
}

他に、今回知った新(?)事実は、Excel 2007 からファイル形式が変わったということです。何をいまさらと言われるかも知れませんが。(汗)

Excel 2007 からはファイルはバイナリではなくなり、xml 形式のテキストを zip で圧縮したものになっているそうです。確かに WinZip で xlsm ファイルを開くことができ、中身は xml 形式のテキストファイルでした。

また、xlsm は「マクロ有効ブック」というそうで、セキュリティ対策として、拡張子からマクロが含まれていることが分かるような名前の規則を作ったそうです。

------------ 2011/5/21 追記 ------------

IE8 は拡張子で判断と書きましたが、やはり IE はそのような仕様になっているようです。以下のページを参考にしてください。

ファイルのダウンロードダイアログで表示されるファイル名の命名規則

即ち、上のページの「詳細」の 1 番目に書いてあるとおり「Content-Disposition: ヘッダが存在する場合は、filename パラメータで設定されたファイル名が利用されます。」ということです。

サポートページには書いてないですが、Content-Disposition: ヘッダでファイル名が指定してあれば、Content-Type: の指定は無視されます。

2 番目の「HTTP レスポンス内に存在する、送られてきた Content-Type が、レジストリの HKEY_CLASS_ROOT\MIME\Database\Content Type 以下に存在するかどうか・・・」というのは、Content-Disposition: ヘッダの filename パラメータにファイル名の指定がない場合に限るようです。

Tags: ,

Upload Download

FileUpload が無反応

by WebSurfer 1. September 2010 14:03

FileUpload コントロールのテストをしている時、テキストボックスに文字を入力してボタンをクリックしても、入力内容によっては何の反応もないことがありました。

Fileupload

ボタンは単純に input type="submit" なので、クリックすれば、必ず form が submit されるはずなのですが・・・

何故でしょう?

不思議に思っていたんですが、MSDN フォーラムを見ていたら分かりました。XP SP2 以降に取られたセキュリティ対策だそうです。

詳しくは、マイクロソフトサポートオンラインの 文書番号:890981 に書いてありますが、ローカルや共有フォルダのファイルの完全修飾パスでないと、ファイルの送信ができないよう仕様が変更されたそうです。

ただし、あまり厳密なものではなく、それらしい形式なら submit はかかります。例えば、c は無反応ですが、c: なら OK といった具合です。

そんな程度でセキュリティ対策に効果があるのか、よく分かりません。(汗)

ちなみに、Firefox 3.6.8 の場合は、テキストボックスにフォーカスを当てると「ファイルの選択」ダイアログが開きます。要するに、テキストボックスに直接入力できないようになっています。セキュリティ対策としては、こちらの方が効果がありそうな気がします。

Tags:

Upload Download

[デバッグの停止] で止まらない

by WebSurfer 31. August 2010 16:28

Visual Studio でデバッグ

Visual Studio で ASP.NET の Web アプリケーションをデバッグしている時の話です。

表題に「止まらない」と書きましたが、正確には、デバッガは止まるものの、コードはデバッガのコントロールが外れて実行されていき、メモリが開放されて終了するまで走っていってしまうということです。

従って、DB の更新などのコードがある場合、その手前でブレークポイントを設けて実行を止め、[デバッグの停止(E)]をしても DB の更新が行われてしまいます。デバッガのバグとかではなくて、そういう仕様だそうです。

ウソだと思う人は(笑)、以下に検証するためのコードをアップしておきますので、適当なところにブレークポイントを設けて試してみてください。ブレークポイントで [デバッグの停止] をしても、その後のコードは実行され、ファイル(file1.txt ~ file3.txt)はすべて作成されるはずです。

なお、このサンプルを動作させるには、アプリケーションルート直下に Files という既存のフォルダがあり、IIS のワーカープロセスがそのフォルダに対して必要なアクセス権を持っている必要がありますので注意してください。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.IO" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
  protected void Page_Load(object sender, EventArgs e)
  {
    string path = Server.MapPath("~/Files/file1.txt");
    using (StreamWriter writer = File.CreateText(path))
    {
      writer.WriteLine("Hello World!");
    }

    path = Server.MapPath("~/Files/file2.txt");
    using (StreamWriter writer = File.CreateText(path))
    {
      writer.WriteLine("Welcome!");
    }
  }

  protected void Page_Unload(object sender, EventArgs e)
  {
    string path = Server.MapPath("~/Files/file3.txt");
    using (StreamWriter writer = File.CreateText(path))
    {
      writer.WriteLine("Goodbye!");
    }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <h1>[デバッグの停止] で止まらない?</h1>
  </div>
  </form>
</body>
</html>

デバッグが止まっても実行が止まらないのは、Visual Studio のデフォルト設定(マネージド・コード用のデバッガを使用)における仕様だそうです。

設定によってデバッグの停止と共に実行を止めることは可能です。

Web サイトプロジェクトの場合、ソリューションエクスプローラのアプリケーションルートの右クリックで表示されるコンテキストメニューから[開始オプション(O)...]を開いて、[デバッガー]のオプションで[ネイティブコード(V)]にチェックを入れてみてください。

(注: Visual Studio Community 2015 の Web サイトプロジェクトの場合、[開始オプション(O)...]⇒[デバッガー]のオプションに[ネイティブコード(V)]がありません。別の設定方法があるかもしれませんが調べ切れてません)

Web アプリケーションプロジェクトの場合は、ソリューションエクスプローラの Properties を右クリックして開き[Web]タブを選択すると[デバッガー]の項目の中に[ネイティブ コード(C)]があります。

これにより、デバッガを起動するたびにネイティブコード用デバッガが読み込まれるそうです。結果、デバッグの停止と共に実行も止まります。

ただし、 [ネイティブコード(V)]にチェックを入れた設定でデバッグを停止すると強制的に Web サーバーを停止することになるそうです。それは好ましいことではないということで、デフォルトではデバッグを停止しても実行は止まらないようになっているようです。

なので、自分の場合、Web サーバーの強制停止による好ましからぬ副作用があるとイヤなので、そういうものだ(デバッグを停止しても実行は止まらない)と理解した上で、デフォルト設定のまま使っています。

Tags:

DevelopmentTools

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  June 2020  >>
MoTuWeThFrSaSu
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

View posts in large calendar