2011年2月23日水曜日

.NETを使った簡易HTTPサーバーの実装

C#.NETを使って簡易HTTPサーバーを立ててみようと思ったら、

static void Main(string[] args)
        {
            string root = "d:\\wwwroot\\";
            string prefix = "http://+:8080/";

            if (!HttpListener.IsSupported)
            {
                Console.WriteLine(".Net frameworkのHttpListenerクラスがサポートされていません。");
                Console.WriteLine("何かキーを押してください");
                Console.ReadKey();
                return;
            }

            HttpListener listener = new HttpListener();
            listener.Prefixes.Add(prefix);
            try
            {
                listener.Start();
            }
            catch (HttpListenerException hle)
            {
                Console.WriteLine("error:{0}", hle.Message);
                Console.WriteLine("何かキーを押してください");
                Console.ReadKey();
                return;
            }

            while(true){
                HttpListenerContext context = listener.GetContext();
                HttpListenerRequest req = context.Request;
                HttpListenerResponse res = context.Response;

                Console.WriteLine(req.RawUrl);

                string path = root + req.RawUrl.Replace("/", "\\");
                if(File.Exists(path)){
                    byte[] content = File.ReadAllBytes(path);
                    res.OutputStream.Write(content, 0, content.Length);
                }
                res.Close();
            }
        }
    }

18行目で、「HttpListenerException例外エラー」が発生する。

原因を調べてみたら、
WinOS管理者権限で「XXユーザがこのPrefixを使いますよ」と事前申請が必要なようだ。
(バックドア攻撃の予防策か、Linuxに合わせたのかどっちかかなーと思ってみたり。)

解決策はcmd.exeを管理者権限で実行して、netshコマンドを使えば良い。

まずはnetshコマンドについて調べてみた。
C:\windows\system32>netsh ?

使用法: netsh [-a エイリアス ファイル名] [-c コンテキスト] [-r リモート コンピュ
ーター名] [-u [ドメイン名\]ユーザー名] [-p パスワード | *]
              [コマンド | -f スクリプト ファイル名]

使用できるコマンドは次のとおりです:

このコンテキストのコマンド:
?              - コマンドの一覧を表示します。
add            - エントリの一覧に構成エントリを追加します。
advfirewall    - 'netsh advfirewall' コンテキストに変更します。
bridge         - 'netsh bridge' コンテキストに変更します。
delete         - エントリの一覧から構成エントリを削除します。
dhcpclient     - 'netsh dhcpclient' コンテキストに変更します。
dnsclient      - 'netsh dnsclient' コンテキストに変更します。
dump           - 構成スクリプトを表示します。
exec           - スクリプト ファイルを実行します。
firewall       - 'netsh firewall' コンテキストに変更します。
help           - コマンドの一覧を表示します。
http           - 'netsh http' コンテキストに変更します。
interface      - 'netsh interface' コンテキストに変更します。
ipsec          - 'netsh ipsec' コンテキストに変更します。
lan            - 'netsh lan' コンテキストに変更します。
mbn            - 'netsh mbn' コンテキストに変更します。
namespace      - 'netsh namespace' コンテキストに変更します。
nap            - 'netsh nap' コンテキストに変更します。
netio          - 'netsh netio' コンテキストに変更します。
p2p            - 'netsh p2p' コンテキストに変更します。
ras            - 'netsh ras' コンテキストに変更します。
rpc            - 'netsh rpc' コンテキストに変更します。
set            - 構成の設定を更新します。
show           - 情報を表示します。
trace          - 'netsh trace' コンテキストに変更します。
wcn            - 'netsh wcn' コンテキストに変更します。
wfp            - 'netsh wfp' コンテキストに変更します。
winhttp        - 'netsh winhttp' コンテキストに変更します。
winsock        - 'netsh winsock' コンテキストに変更します。
wlan           - 'netsh wlan' コンテキストに変更します。

利用できるサブコンテキストは次のとおりです:
 advfirewall bridge dhcpclient dnsclient firewall http interface ipsec lan mbn n
amespace nap netio p2p ras rpc trace wcn wfp winhttp winsock wlan

コマンドのヘルプを表示するには、コマンドの後にスペースを入れ、
 ? と入力してください。


C:\windows\system32>netsh http ?

使用できるコマンドは次のとおりです:

このコンテキストのコマンド:
?              - コマンドの一覧を表示します。
add            - テーブルに構成エントリを追加します。
delete         - テーブルから構成エントリを削除します。
dump           - 構成スクリプトを表示します。
flush          - 内部データをフラッシュします。
help           - コマンドの一覧を表示します。
show           - 情報を表示します。

コマンドのヘルプを表示するには、コマンドの後にスペースを入れ、
 ? と入力してください。


C:\windows\system32>netsh http show

使用できるコマンドは次のとおりです:

このコンテキストのコマンド:
show cacheparam - HTTP サービスのキャッシュ パラメーターを表示します。
show cachestate - キャッシュされた URI リソースとこれらの関連プロパティを一覧表
示します。
show iplisten  - IP リッスン一覧内のすべての IP アドレスを表示します。
show servicestate - HTTP サービスのスナップショットを表示します。
show sslcert   - IP アドレスおよびポートに対する SSL 証明書のバインドを表示しま
す。
show timeout   - サービスのタイムアウト値を表示します。
show urlacl    - URL 名前空間の予約を表示します。


なるほど。
覚えておけばいいのは、
 ・URL名前空間の追加:netsh http add
 ・URL名前空間の削除:netsh http delete
 ・URL名前空間の一覧:netsh http show urlacl

の3つ。

本題に戻って結論。
解決の仕方は、1つのコマンド打つだけ。
//url:使用するprefix
//user:HTTPサーバを起動するユーザ or ドメイン/ユーザ名

netsh http add urlacl url=http://+:8080/ user=eeepc

簡易HTTPサーバを起動してみると無事サーバが立ち上がる。
よかったよかった。


未検証メモ:
 URL一覧を見ると、全ユーザを許可するのは:Everyone らしい。


参考URL:
http://www.atmarkit.co.jp/fdotnet/dotnettips/695httplistener/httplistener.html
http://msdn.microsoft.com/ja-jp/library/ms733768.aspx
コメントを投稿

Androider