65.9K
CodeProject 正在变化。 阅读更多。
Home

MiniHttpd:HTTP Web 服务器库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (51投票s)

2005年8月18日

14分钟阅读

viewsIcon

2052755

downloadIcon

9875

一个用100%托管C#编写的、可移植且灵活的HTTP Web服务器库。

引言

MiniHttpd 是一个独立的 HTTP 和 Web 服务器库。它可以作为 Web 服务器使用,也可以在部署 IIS 或 Apache 等完整 Web 服务器不可行的情况下用作 HTTP 侦听器。

创建 MiniHttpd 的初衷之一是为 Windows Media Player 创建一个 Web 界面,以便我能够通过手机或 Pocket PC 控制 Media Player 并下载曲目。其中一个程序叫做 PlayerPal,截至 3.0 版本,它使用了功能相似但已不再开发的 Cassini 库。

另一个动机是制作一个替代的文件服务器,供朋友之间使用。无论有多少种发送文件的方式——MSN、IRC、FTP、电子邮件……有时它们都行不通!

MiniHttpd 尚未完成,肯定会有更多功能和改进。如果您有任何建议或问题,我将很高兴听到。如果您在实际中使用 MiniHttpd,我建议将其隔离在具有有限权限的独立操作系统帐户中。一如既往,我感谢您发现 bug——目前这是一个一人项目,我独自一人能做的事情有限。非常感谢那些查看过代码的人。

下载

为了演示服务器,我在朋友的电脑上设置了一个 MiniHttpd 服务器,托管着演示应用程序的二进制文件。您可以通过 此链接 下载 MiniHttpdApp。

与其他 Web 服务器的比较

这是 MiniHttpd 与其他常见 Web 服务器的功能比较。此列表仅限于我的知识范围,如果您发现有遗漏的重要内容,请告知我。

Apache IIS XSP Cassini MiniHttpd
兼容 Windows          
兼容 *NIX/BSD/OS X          
兼容 .NET Compact framework         可能在未来
Standalone          
可移植库          
支持 ASPX 通过 Mod-Mono       从 1.1 版本开始
支持 PHP          
适用于商业用途          
可编程性 PHP/CGI ASP/ASPX ASPX ASPX ASPX、IFile/IDirectory
支持断点续传          
支持 SSL (HTTPS)         但愿很快

使用代码

基本设置

最少,设置一个 Web 服务器只需要几行代码。此示例初始化一个 Web 服务器,它使用您的 C 驱动器作为根目录。

// Create a server object on the
// default HTTP web port (80)
HttpWebServer server = new HttpWebServer();

// Set the root directory to C (don't try this at home)
server.Root = new DriveDirectory(@"c:\");

// Start the server
server.Start();

Console.ReadLine();

// Stop the server (note that you must stop the listener
// explicitly either by calling Stop or Dispose, or by
// wrapping the server in a 'using' block)
server.Stop();

就这样!您可以在您喜欢的浏览器中访问您的本地地址,它应该会显示一个目录列表,或者如果存在的话,会显示一个 index.htm/index.html 页面。您可以在构造函数中指定不同的侦听端口,或者通过设置 Port 属性来更改。

虚拟目录

虚拟目录是您可以以编程方式填充的目录,而不是通过反射物理目录。默认情况下,HttpWebServer 实例在创建时会将 root 设置为一个空的虚拟目录。您可以选择使用这个虚拟目录,或者创建自己的。此示例创建了一个虚拟目录,添加了一些文件和文件夹,并删除了几个。

// Create a new virtual directory
// and set the root to it
VirtualDirectory root = new VirtualDirectory();
server.Root = root;

// Add a few files
root.AddFile("notepad.exe");
root.AddFile("autoexec.bat");

// Add a directory
root.AddDirectory(@"c:\windows");

// Remove a file
root.Remove(@"autoexec.bat");

// Add a virtual subdirectory
root.AddDirectory(new VirtualDirectory("virtual", root));

ASP.NET 支持

ASPX 通过扩展 DriveDirectoryHttpWebServer,以及 AspxAppDirAspxWebServer 来实现。两者都具有与其基类相同的构造函数,因此设置过程就像替换所有实例一样简单。

不幸的是,没有虚拟 ASPX 目录,因为 ASP.NET 要求文件在磁盘上有绝对路径。我会关注是否有解决方法——能够将 ASPX 应用程序存储在程序集中会非常好。

ASPX 代码包含在 MiniHttpd 程序集中,以避免弄乱分发版。如果您出于任何原因根本不想要 ASPX,只需从项目中排除 Aspx 文件夹并重新编译即可。

版本 1.1 尚未实现某些功能;我知道尚未实现的功能是 HTTP 处理程序和 HTTPS。

请注意,MiniHttpd 会在您用作 ASPX 目录的任何文件夹中留下带有 MiniHttpd.dllBin 文件夹。从 1.2.0 版本开始,MiniHttpd 在处置时会删除该文件,如果文件夹为空,也会删除该文件夹。

PHP 支持

PHP 的实现方式与 ASPX 类似,PhpAppDirectoryPhpWebServer 继承自 DriveDirectoryHttpWebServer。目前,PHP 支持比 ASPX 更基础,仅接受具有文本输出且没有请求/响应头的脚本。

您需要三个程序集才能在 MiniHttpd 中使用 PHP

  • MiniHttpd.Php.dll - 您可以从文章顶部的链接下载此文件及其源代码。
  • php4app.dll - 该文件包含在项目中,但您也可以从 此处 下载。
  • php5ts.dll - 由于这是一个相当大的文件(4 MB),我已将其托管在 此处。您也可以在 PHP Windows 二进制文件中找到它,您可以从 此处 下载。

感谢 Daaron Dwyer 向我演示了 MiniHttpd 上的 PHP,并完成了 MiniHttpd.Php 的大部分工作!

索引页

库中内置的索引页目前只是一个非常无聊的文件夹文件列表。您可以通过替换 HttpWebServer.IndexPage 属性来覆盖此行为。可选地,您可以覆盖 IndexPage 类,该类提供了一个 BuildPath 方法,您可以使用该方法确定目录的相对路径。

此外,从 1.2.0 版本开始,有一个稍微花哨一点的索引页叫做 IndexPageEx。您可以通过创建一个新的 IndexPageEx 对象并将其分配给 HttpWebServer.IndexPage 来使用它。您可以通过设置 IndexPageEx.Columns 属性中的 ResourceColumn 值数组来指定要显示的列和列的顺序。默认值为 Modified, Size, Name。对于大型目录,IndexPageEx 可能会变慢,因此请仔细决定是否使用它。(我猜测当 MSH 和/或 Vista 发布时,这种情况在几个月内会有所改变。)

HttpServer

HttpServer 及其附属类实现了 HTTP/1.1 协议的基本工作原理。HttpWebServer 继承自此类。您可以使用此类手动处理 HTTP 事务,而无需使用 HttpWebServer 提供的目录结构。但是,在 .NET 2.0 Framework 中引入了一个类似的类 System.Net.HttpListener,如果您只需要一个 HTTP 侦听器,您可能想使用该类。

日志记录

服务器将日志消息写入 HttpServer.Log 指定的 TextWriter。默认情况下,它会写入控制台,除非没有可用的控制台(例如在 Pocket PC 上)。您可以通过将 LogConnectionsLogRequests 设置为 false 来禁用此功能,并且可以通过设置 Log 属性将输出重定向到其他 TextWriter

身份验证

从 1.2.0 版本开始,MiniHttpd 支持通过 IAuthenticator 接口进行非常简单的身份验证(登录名和密码)。MiniHttpd 中实现了两个 IAuthenticatorBasicAuthenticatorLdapAuthenticator。您可以通过将 HttpServer.RequireAuthentication 设置为 true 来启用它。默认值为 BasicAuthenticator,但您也可以通过将新的 LdapAuthenticator 分配给 HttpServer.Authenticator 来轻松启用 LdapAuthenticator

BasicAuthenticator 仅维护一个包含用户名/密码对的 Hashtable。密码存储为 MD5 哈希,以便于序列化和存储在磁盘上。LdapAuthenticator 使用客户端提供的用户名和密码与 Active Directory 服务器进行身份验证。

目前,身份验证还比较基础;访问是整个服务器范围的。另外请注意,这不是 HTTPS,因此密码和事务不是加密的。

再次感谢 Daaron Dwyer 为我演示了 MiniHttpd 上的 LDAP 和身份验证。

IDirectory 和 IFile

HttpWebServer 文件树中的所有对象都由 IDirectoryIFile 的实现来描述。IDirectoryIFile 都继承自 IResource,它提供了标识文件或目录的属性。内部,IDirectoryDriveDirectory 实现以引用物理目录,由 VirtualDirectory 实现以引用内存中的目录(包含其他 IDirectoryIFile)。IFileDriveFile 实现以引用磁盘上的文件。

IDirectoryIFile 可用于创建动态内容。任何树形文件结构都可以由 IDirectory 对象表示;例如,Windows Media Player 中的媒体库。IFile 可用于发送从重定向到视频流的任何内容。到目前为止,IDirectory/IFile 接口已用于一些很棒的项目:

  • “我的 IP 是什么”图像生成器
  • 网络摄像头馈送,在快照之前自动打开车库灯
  • 视频流到支持 Web 的电视设备

ASPX 无法做的事情,IFile/IDirectory 也能做到,因此它们在 ASPX 不可用的情况下最为突出。但此时,MiniHttpd 不兼容任何没有 ASPX 的操作系统。如果有任何兴趣,我将尝试恢复 Compact Framework 的兼容性,以便它可以作为 Pocket PC 和智能手机的可编程 Web 服务器。我很想看到它运行在 SPOT OS(用于 SPOT 手表和 Windows Vista 的 Auxiliary Displays)上,如果他们将来向公众开放用于电子爱好者和机器人项目的话。让我们希望他们会这样做!

实现 IDirectory

实现 IDirectory 相当直接。一个 IDirectory 对象通常包含一个子目录和子文件的集合。只需要三个步骤:

  • 创建一个构造函数,它接受目录的名称和父目录,并将它们存储起来供 NameParent 属性返回(请参阅下面的 IFile 示例)。
  • 实现 IResource.NameIResource.Parent 属性,通过返回构造函数中传递的值来获取。
  • 实现所有 IDirectory.Get...() 函数。它们的用法在 FileSystem/IDirectory.cs 的 XML 文档中有描述。

确保在删除所有子目录和文件时调用 Dispose(),并在 Dispose 函数中也进行调用。

实现 IFile

实现 IFile 稍微复杂一些,尽管从程序员的角度来看,我觉得它在概念上比 ASPX 网页更容易理解(但这可能只是我个人的看法)。

IDirectory 类似,第一步是创建一个构造函数,它接受名称和父目录作为参数,并将它们存储起来供 NameParent 属性返回。

然后实现 ContentType。内容类型(也称为 MIME 类型)是 Web 用来描述资源类型的方式,就像 Windows 通过文件名扩展名识别文件类型一样。.txt 文件称为“text/plain”,.jpg 文件称为“image/jpeg”,.html/.htm 文件称为“text/html”。通常,您可以使用 ContentTypes.GetExtensionType() 来检索常见文件扩展名的 MIME 等效项。

最后但同样重要的是,实现 OnFileRequested 方法。request 提供了操作请求的所有属性和方法,而 directory 提供了文件的父目录。在大多数情况下,Response 属性是唯一重要的,特别是 Response 属性的 ResponseContent 属性。您可以将任何类型的流分配给 ResponseContent 流,只要它支持读取、查找并且具有确定的长度。

一个发送文本“Hello, world!”到客户端的 IFile 实现可能看起来像这样:

public class HelloWorldFile : IFile
{
   public HelloWorldFile(string name, IDirectory parent)
   {
      this.name = name;
      this.parent = parent;
   }

   string name;
   IDirectory parent;

   public void OnFileRequested(HttpRequest request, 
                               IDirectory directory)
   {
      // Assign a MemoryStream to hold the response content.
      request.Response.ResponseContent = new MemoryStream();

      // Create a StreamWriter to which we
      // can write some text, and write to it.
      StreamWriter writer = 
        new StreamWriter(request.Response.ResponseContent);

      writer.WriteLine("Hello, world!");

      // Don't forget to flush!
      writer.Flush();
   }

   public string ContentType
   {
      get { return ContentTypes.GetExtensionType(".txt"); }
   }
   public string Name
   {
      get { return name; }
   }

   public IDirectory Parent
   {
      get { return parent; }
   }

   public void Dispose()
   {
   }
}

分块响应

由于 HTTP 通常要求您在头部提供资源的大小,MiniHttpd 使用分配给 HttpResponse.ResponseStream 的流的 Length 属性来获取此信息。但是,有些数据形式没有确定的长度——例如动态网页和视频/音频流。HTTP/1.1 协议提供了一种机制来实现这一点,称为分块传输编码(HTTP/1.0 在每次传输后通过断开连接来隐式表示传输结束)。您可以通过调用 BeginChunkedOutput() 而不是将流分配给 HttpResponse.ResponseStream 来启用它(该函数会为您处理)。

MiniHttpdApp 演示项目

MiniHttpdApp

MiniHttpdApp 是一个 Web 服务器示例应用程序,演示了 MiniHttpd 库。尽管 GUI 看起来几乎相同,但我为 1.2.0 版本从头开始重写了它,以解决它的一些崩溃问题,这些问题源于其粗糙的设计和缺乏线程安全考虑。现在它应该足够稳定,可以作为您 Windows 系统托盘中的永久驻留程序。

指定一个端口,如果您的网络在路由器或其他 NAT 设备后面,还可以选择指定主机名,然后单击 Server -> Start。左侧的属性网格中有更多选项,其中大多数是不言自明的。

在左侧窗格的 Directories 部分中,将 RootType 设置为 Drive,您可以在 RootFolder 框中指定要共享的文件夹。将 RootType 设置为 Virtual,您可以拖放文件和文件夹进行共享,并右键单击或按 Delete 键进行删除。设置将保存到 MiniHttpdAppSettings.xml

MiniHttpdConsole

MiniHttpdConsole 是一个命令行演示项目,我主要用它来尝试在 Linux 上运行 MiniHttpd。界面比较原始,带有一个有点怀旧的文本菜单系统(对 Unix 用户来说可能不那么怀旧)和命令行参数输入。输入“?”会列出可用的菜单项,输入“h”会列出可用的命令行参数。

除了 VirtualDirectory 格式(由于 .NET 1.1 不完整的 XML 序列化实现,它是一个 base-64 编码的根 VirtualDirectory 的二进制序列化),您可以使用与 MiniHttpdApp 相同的配置文件运行 MiniHttpdConsole。设置好所有设置后,您可以在后台运行 MiniHttpdConsole,如下所示:

mono MiniHttpdConsole.exe -s -l &

-s 表示静默模式(无输出,无菜单);-l 开启文件日志记录到 MiniHttpd.log

请注意,MiniHttpdConsole 需要 .NET 2.0Mono 1.1.10

MSH 很棒

微软正在为 Longhorn Server(以及可能的 Vista)开发一个新的命令行 shell,名为 Microsoft Shell (Monad),这是一个 .NET 驱动的 shell,具有类型安全的管道,其语法借鉴了函数式语言、SQL 和 Unix shell。我忍不住分享了我在 Monad 中尝试 MiniHttpd 的事实。请注意,我是在 shell 中直接这样做的,但这很容易制作成一个函数(称为 cmdlet)并保存到 cmdlet 文件中。

> [Reflection.Assembly]::LoadFile($(combine-path 
                         $(get-location) "minihttpd.dll"))

GAC    Version        Location
---    -------        --------
False  v1.1.4322      C:\Documents and Settings\Rei Miyasaka\
                      My Documents\Visual Studio Proj...


>$server = new-object MiniHttpd.HttpWebServer
>$server.Root = new-object MiniHttpd.DriveDirectory($(get-location))
>$server.Start()
Server: MiniHttpd/1.2.0.92
CLR: 2.0.50727.42
Server running at http://rei/

这不酷吗?!

法律声明

我将根据 Creative Commons Attribution 2.5 许可协议来约束 MiniHttpd,该协议一言以蔽之:您可以出于任何目的、以任何方式(包括商业用途,但无保修)使用 MiniHttpd,只要您将原始作品的功劳归于我。

另一方面,我是一名大学生,而在温哥华的编程工作虽然稀少但薪水并不高。以我的处境,很难证明投入时间去做任何不能给我带来至少一点回报的事情。因此,如果您发现 MiniHttpd 的商业用途,我将非常感谢您的小额捐款,以鼓励我。

另外,**请** 告诉我您是否在项目中使用 MiniHttpd。这对我的简历会很有帮助 :)

未来的更新

这些是未来版本的想法,不分先后顺序,也没有确切的截止日期。每次进行破坏性更改时,我都会增加一个次要版本号(1.x)。

  • web.config 注册 HTTP 处理程序。
  • 修复 .NET Compact Framework 兼容性。
  • 增加调试,尤其是 ASPX。
  • HTTPS 支持。
  • 权限和密码。
  • 每目录 MIME 类型和其他设置。
  • 上传上限/配额控制。
  • 分块 POST 数据。
  • 改进 PHP 支持。
  • 尝试使用多路复用而不是异步 IO(请参阅 Alexey Popov 的文章)。
  • Windows 服务。
  • 自定义错误页面。
  • 为更好的 ASPX 和 PHP 设计请求处理程序。
  • 想一个更好的名字。
  • 在 .NET 2.0 中使用 XML 序列化 MiniHttpdApp。
  • 使用 W3C 扩展日志格式
  • 远程管理页面。
  • Spec# 为 .NET 2.0 重写整个程序。

链接

历史

  • 2004.12.20 - 项目开始。
  • 2005.08.18 - 首次发布 - 版本 1.0.0。
  • 2005.08.18 - 版本 1.0.1 - 我把昨晚遗留的一些调试代码留下了……它会转储请求的所有头部!已修复。
  • 2005.08.18 - 版本 1.0.2 - 服务器现在侦听所有地址(包括 localhost),除非在构造函数或 LocalAddress 属性中另有指定。
  • 2005.08.20 - 版本 1.0.4 - MiniHttpdApp 现在默认启动为 Virtual 模式。一个非常严重的 bug——我忘了实现最大 POST 大小限制!抱歉。我检查了所有其他上传限制;其他一切应该都没问题。
  • 2005.08.22 - 版本 1.0.5 - 修复了一个**严重**的缺陷,用户可以通过输入 URL 编码的反斜杠来访问根文件夹,以及其他类似的滥用行为。如果您使用的是之前的任何版本,**请**下载此版本。进行了一些小的改进。
  • 2005.09.17 - 版本 1.1.1 - 添加了 ASPX 支持,修复了几个小故障,并进行了微小的改进。在 MiniHttpdApp 中添加了传输监视器。
  • 2005.12.12 - 版本 1.2.0
    • 修复了几个 bug。
    • IResource 现在继承 IDisposable;所有 IDirectory 都应调用 Dispose 来处理其包含的资源。
    • 高级索引页。
    • MiniHttpdApp 示例应用程序重写,修复了 bug 并进行了一些改进。
    • 支持日志到文件。
    • 添加了 MiniHttpdConsole 示例应用程序。
    • 除关键 bug 修复外,所有未来版本都将移植到 Visual Studio 2005 和 .NET 2.0。
    • 基本身份验证。
    • 基本 PHP 支持。
© . All rights reserved.