本手册旨在描述 Subversion 1.4。如果您运行的是更新版本的 Subversion,我们强烈建议您访问 https://svnbook.subversion.org.cn/ 并参考与您的 Subversion 版本相匹配的版本手册。
Apache HTTP 服务器是一个“重型”网络服务器,Subversion 可以利用它。通过自定义模块,httpd 使 Subversion 仓库可以通过 WebDAV/DeltaV 协议访问,该协议是 HTTP 1.1 的扩展(更多信息请参见 http://www.webdav.org/)。该协议基于全球通用的 HTTP 协议,该协议是万维网的核心,并增加了写入功能,特别是版本化写入功能。结果是一个标准化的、健壮的系统,它方便地打包为 Apache 2.0 软件的一部分,受到众多操作系统和第三方产品的支持,并且不需要网络管理员打开另一个自定义端口。[44] 虽然 Apache-Subversion 服务器比 svnserve 拥有更多功能,但设置起来也稍微困难一些。灵活性和复杂性往往是相辅相成的。
以下大部分讨论包括对 Apache 配置指令的引用。虽然提供了一些使用这些指令的示例,但对它们的完整描述超出了本章的范围。Apache 团队在其网站上发布了优秀的文档,可在 https://httpd.apache.ac.cn 公开获取。例如,配置指令的一般参考位于 https://httpd.apache.ac.cn/docs-2.0/mod/directives.html。
此外,当您对 Apache 设置进行更改时,很可能在某个步骤中会出错。如果您不熟悉 Apache 的日志记录子系统,那么您应该了解它。在您的 httpd.conf
文件中,有指令指定 Apache 生成的访问日志和错误日志的磁盘位置(分别是 CustomLog
和 ErrorLog
指令)。Subversion 的 mod_dav_svn 也使用 Apache 的错误日志记录接口。您可以随时浏览这些文件的内容,以查找可能揭示问题根源的信息,而这些信息在其他情况下并不明显。
要通过 HTTP 网络化您的仓库,您基本上需要四个组件,这四个组件包含在两个包中。您将需要 Apache httpd 2.0、随附的 mod_dav DAV 模块、Subversion 以及与 Subversion 一起发布的 mod_dav_svn 文件系统提供程序模块。一旦您拥有了所有这些组件,网络化您的仓库的过程就简单地如下所示
让 httpd 2.0 与 mod_dav 模块一起运行,
将 mod_dav_svn 插件安装到 mod_dav 中,该插件使用 Subversion 的库访问仓库,以及
配置您的 httpd.conf
文件以导出(或公开)仓库。
您可以通过编译 httpd 和 Subversion 源代码来完成前两个步骤,也可以在您的系统上安装它们的预构建二进制包。有关如何编译 Subversion 以与 Apache HTTP 服务器一起使用以及如何为此目的编译和配置 Apache 本身的最新信息,请参阅 Subversion 源代码树顶层中的 INSTALL
文件。
一旦您在系统上安装了所有必要的组件,剩下的就是通过 httpd.conf
文件配置 Apache。使用 LoadModule
指令指示 Apache 加载 mod_dav_svn 模块。此指令必须位于任何其他与 Subversion 相关的配置项之前。如果您的 Apache 是使用默认布局安装的,那么您的 mod_dav_svn 模块应该已安装在 Apache 安装位置(通常是 /usr/local/apache2
)的 modules
子目录中。LoadModule
指令语法简单,将命名模块映射到磁盘上的共享库位置
LoadModule dav_svn_module modules/mod_dav_svn.so
请注意,如果 mod_dav 是作为共享对象(而不是静态链接到 httpd 二进制文件)编译的,那么您也需要类似的 LoadModule
语句。确保它位于 mod_dav_svn 行之前
LoadModule dav_module modules/mod_dav.so LoadModule dav_svn_module modules/mod_dav_svn.so
在配置文件的后面,您现在需要告诉 Apache 您在哪里保存 Subversion 仓库(或仓库)。Location
指令具有类似 XML 的表示法,以一个开始标记开头,以一个结束标记结束,中间包含各种其他配置指令。Location
指令的目的是指示 Apache 在处理指向特定 URL 或其子 URL 的请求时执行特殊操作。在 Subversion 的情况下,您希望 Apache 将指向版本化资源的 URL 的支持简单地传递给 DAV 层。您可以指示 Apache 将所有路径部分(URL 中服务器名称和可选端口号后面的部分)以 /repos/
开头的 URL 的处理委托给仓库位于 /absolute/path/to/repository
的 DAV 提供程序,使用以下 httpd.conf
语法
<Location /repos> DAV svn SVNPath /absolute/path/to/repository </Location>
如果您计划支持多个 Subversion 仓库,这些仓库将驻留在本地磁盘上的同一个父目录中,您可以使用另一种指令 SVNParentPath
指令来指示该公共父目录。例如,如果您知道您将在 /usr/local/svn
目录中创建多个 Subversion 仓库,这些仓库将通过 URL(例如 http://my.server.com/svn/repos1
、http://my.server.com/svn/repos2
等)访问,您可以使用以下示例中的 httpd.conf
配置语法
<Location /svn> DAV svn # any "/svn/foo" URL will map to a repository /usr/local/svn/foo SVNParentPath /usr/local/svn </Location>
使用以前的语法,Apache 将将所有路径部分以 /svn/
开头的 URL 的处理委托给 Subversion DAV 提供程序,然后该提供程序将假定 SVNParentPath
指令指定的目录中的任何项目实际上都是 Subversion 仓库。这种语法特别方便,因为与使用 SVNPath
指令不同,您不必重新启动 Apache 就可以创建和网络化新的仓库。
请确保在定义新的 Location
时,它不与其他导出的 Location 重叠。例如,如果您的主 DocumentRoot
被导出到 /www
,请不要在 <Location /www/repos>
中导出 Subversion 仓库。如果收到对 URI /www/repos/foo.c
的请求,Apache 将不知道是应该在 DocumentRoot
中查找文件 repos/foo.c
,还是应该委托 mod_dav_svn 从 Subversion 仓库返回 foo.c
。结果通常是服务器返回的错误,格式为 301 Moved Permanently
。
在此阶段,您应该认真考虑权限问题。如果您已经将 Apache 作为常规 web 服务器运行了一段时间,那么您可能已经拥有了一系列内容,即网页、脚本等。这些项目已经配置了一组权限,允许它们与 Apache 配合使用,或者更准确地说,允许 Apache 与这些文件配合使用。Apache 在用作 Subversion 服务器时,也需要正确的权限才能读取和写入您的 Subversion 仓库。
您需要确定一个权限系统设置,以满足 Subversion 的要求,同时不会弄乱任何以前存在的网页或脚本安装。这可能意味着更改 Subversion 仓库的权限以匹配 Apache 为您服务的其他项目的权限,或者它可能意味着使用 User
和 Group
指令在 httpd.conf
中指定 Apache 应该以拥有 Subversion 仓库的用户和组的身份运行。没有一种单一的正确方法来设置您的权限,每个管理员都有不同的原因来以某种方式进行设置。只需注意,权限相关的问题可能是配置 Subversion 仓库以与 Apache 配合使用时最常见的疏忽。
在此阶段,如果您将 httpd.conf
配置为包含以下内容
<Location /svn> DAV svn SVNParentPath /usr/local/svn </Location>
…那么您的仓库对全世界“匿名”可访问。在您配置一些身份验证和授权策略之前,您通过 Location
指令提供的 Subversion 仓库将对所有人普遍可访问。换句话说,
任何人都可以使用他们的 Subversion 客户端检出一个仓库 URL(或其任何子目录)的工作副本,
任何人都可以通过将他们的 web 浏览器指向仓库 URL 来交互式地浏览仓库的最新修订版,以及
任何人都可以提交到仓库。
当然,您可能已经设置了一个 pre-commit
钩子脚本以防止提交(请参见 名为“实现仓库钩子”的部分)。但正如您将在后面看到,您还可以使用 Apache 的内置方法以特定方式限制访问。
验证客户端最简单的方法是使用 HTTP Basic 认证机制,该机制只需使用用户名和密码来验证用户是否为其自称的身份。Apache 提供了 htpasswd 实用程序来管理可接受的用户名和密码列表。让我们授予 Sally 和 Harry 提交访问权限。首先,我们需要将它们添加到密码文件中。
$ ### First time: use -c to create the file $ ### Use -m to use MD5 encryption of the password, which is more secure $ htpasswd -cm /etc/svn-auth-file harry New password: ***** Re-type new password: ***** Adding password for user harry $ htpasswd -m /etc/svn-auth-file sally New password: ******* Re-type new password: ******* Adding password for user sally $
接下来,您需要在 httpd.conf
文件的 Location
块中添加一些额外的 httpd.conf
指令,以告诉 Apache 如何处理新的密码文件。 AuthType
指令指定要使用的认证系统类型。在本例中,我们要指定 Basic
认证系统。 AuthName
是您为认证域指定的任意名称。当浏览器向用户查询其用户名和密码时,大多数浏览器会在弹出对话框中显示此名称。最后,使用 AuthUserFile
指令指定使用 htpasswd 创建的密码文件的位置。
添加了这三个指令后,您的 <Location>
块应该看起来像这样
<Location /svn> DAV svn SVNParentPath /usr/local/svn AuthType Basic AuthName "Subversion repository" AuthUserFile /etc/svn-auth-file </Location>
此 <Location>
块尚未完成,也不会执行任何有用的操作。它只是告诉 Apache,当需要授权时,Apache 应该从 Subversion 客户端获取用户名和密码。但是,这里缺少的是告诉 Apache 哪些 类型的客户端请求需要授权的指令。无论在何处需要授权,Apache 都将要求进行身份验证。最简单的方法是保护所有请求。添加 Require valid-user
告诉 Apache 所有请求都需要经过身份验证的用户
<Location /svn> DAV svn SVNParentPath /usr/local/svn AuthType Basic AuthName "Subversion repository" AuthUserFile /etc/svn-auth-file Require valid-user </Location>
务必阅读下一节(名为“授权选项”的部分),以了解有关 Require
指令和设置授权策略的其他方法的更多详细信息。
需要注意的是:HTTP Basic Auth 密码几乎以纯文本形式通过网络传输,因此极不安全。如果您担心密码被窃取,最好使用某种 SSL 加密,以便客户端通过 https://
而不是 http://
进行身份验证;至少,您可以配置 Apache 使用自签名服务器证书。 [45] 请查阅 Apache 文档(和 OpenSSL 文档)以了解如何执行此操作。
需要公开其存储库以供公司防火墙外部访问的企业应该意识到,未经授权的方可能会“嗅探”他们的网络流量。SSL 使这种不必要的关注不太可能导致敏感数据泄露。
如果 Subversion 客户端被编译为使用 OpenSSL,那么它将获得通过 https://
URL 与 Apache 服务器通信的能力。Subversion 客户端使用的 Neon 库不仅能够验证服务器证书,还可以在受到挑战时提供客户端证书。当客户端和服务器交换了 SSL 证书并成功相互验证后,所有后续通信都将通过会话密钥加密。
描述如何生成客户端和服务器证书以及如何配置 Apache 使用这些证书超出了本书的范围。许多其他书籍(包括 Apache 自己的文档)描述了此任务。但这里可以介绍的是如何从普通的 Subversion 客户端管理服务器和客户端证书。
当通过 https://
与 Apache 通信时,Subversion 客户端可以接收两种不同类型的信息
服务器证书
对客户端证书的要求
如果客户端收到服务器证书,则需要验证是否信任该证书:服务器是否真的是它声称的身份?OpenSSL 库通过检查服务器证书的签名者或 证书颁发机构 (CA) 来执行此操作。如果 OpenSSL 无法自动信任 CA,或者出现其他问题(例如证书过期或主机名不匹配),Subversion 命令行客户端将询问您是否要仍然信任服务器证书
$ svn list https://host.example.com/repos/project Error validating server certificate for 'https://host.example.com:443': - The certificate is not issued by a trusted authority. Use the fingerprint to validate the certificate manually! Certificate information: - Hostname: host.example.com - Valid: from Jan 30 19:23:56 2004 GMT until Jan 30 19:23:56 2006 GMT - Issuer: CA, example.com, Sometown, California, US - Fingerprint: 7d:e1:a9:34:33:39:ba:6a:e9:a5:c4:22:98:7b:76:5c:92:a0:9c:7b (R)eject, accept (t)emporarily or accept (p)ermanently?
此对话应该很熟悉;它本质上与您可能从 Web 浏览器(它只是像 Subversion 一样的另一个 HTTP 客户端)看到的相同。如果您选择 (p)ermanent 选项,服务器证书将被缓存到您的私有运行时 auth/
区域中,就像您的用户名和密码被缓存一样(参见 名为“客户端凭据缓存”的部分)。如果已缓存,Subversion 将在将来的协商中自动信任此证书。
您的运行时 servers
文件还允许您使 Subversion 客户端自动信任特定的 CA,无论是全局还是按主机进行。只需将 ssl-authority-files
变量设置为以分号分隔的 PEM 编码 CA 证书列表即可
[global] ssl-authority-files = /path/to/CAcert1.pem;/path/to/CAcert2.pem
许多 OpenSSL 安装还预定义了一组“默认”CA,这些 CA 几乎被普遍信任。要使 Subversion 客户端自动信任这些标准颁发机构,请将 ssl-trust-default-ca
变量设置为 true
。
当与 Apache 通信时,Subversion 客户端也可能会收到对客户端证书的挑战。Apache 要求客户端进行身份验证:客户端是否真的是它声称的身份?如果一切顺利,Subversion 客户端会发送回由 Apache 信任的 CA 签名的私有证书。客户端证书通常以加密格式存储在磁盘上,受本地密码保护。当 Subversion 收到此挑战时,它会询问您证书路径和保护它的密码
$ svn list https://host.example.com/repos/project Authentication realm: https://host.example.com:443 Client certificate filename: /path/to/my/cert.p12 Passphrase for '/path/to/my/cert.p12': ******** …
请注意,客户端证书是“p12”文件。要使用 Subversion 的客户端证书,它必须采用 PKCS#12 格式,这是一个可移植的标准。大多数 Web 浏览器已经能够以这种格式导入和导出证书。另一种选择是使用 OpenSSL 命令行工具将现有证书转换为 PKCS#12。
同样,运行时 servers
文件允许您按主机自动执行此挑战。这两条信息都可以或任选其一在运行时变量中描述
[groups] examplehost = host.example.com [examplehost] ssl-client-cert-file = /path/to/my/cert.p12 ssl-client-cert-password = somepassword
一旦您设置了 ssl-client-cert-file
和 ssl-client-cert-password
变量,Subversion 客户端就可以自动响应客户端证书挑战,而无需提示您。 [46]
此时,您已经配置了身份验证,但没有配置授权。Apache 能够向客户端发出挑战并确认身份,但它尚未被告知如何允许或限制对拥有这些身份的客户端的访问。本节描述了两种控制对存储库访问的策略。
最简单的访问控制形式是授权某些用户对存储库进行只读访问,或对存储库进行读/写访问。
您可以通过在 <Location>
块中添加 Require valid-user
指令来限制对所有存储库操作的访问。使用我们之前的示例,这意味着只有声称自己是 harry
或 sally
并且为其各自用户名提供了正确密码的客户端才能对 Subversion 存储库执行任何操作
<Location /svn> DAV svn SVNParentPath /usr/local/svn # how to authenticate a user AuthType Basic AuthName "Subversion repository" AuthUserFile /path/to/users/file # only authenticated users may access the repository Require valid-user </Location>
有时您不需要运行如此严格的系统。例如,Subversion 自己的源代码存储库 http://svn.collab.net/repos/svn 允许世界上任何人都执行只读存储库任务(例如检出工作副本和使用 Web 浏览器浏览存储库),但将所有写操作限制为经过身份验证的用户。要执行这种选择性限制,您可以使用 Limit
和 LimitExcept
配置指令。与 Location
指令一样,这些块也有开始和结束标签,您需要将它们嵌套到 <Location>
块中。
Limit
和 LimitExcept
指令中包含的参数是受该块影响的 HTTP 请求类型。例如,如果您想禁止对存储库的所有访问,除了当前支持的只读操作之外,您将使用 LimitExcept
指令,并传递 GET
、PROPFIND
、OPTIONS
和 REPORT
请求类型参数。然后,前面提到的 Require valid-user
指令将被放置到 <LimitExcept>
块中,而不是仅放置到 <Location>
块中。
<Location /svn> DAV svn SVNParentPath /usr/local/svn # how to authenticate a user AuthType Basic AuthName "Subversion repository" AuthUserFile /path/to/users/file # For any operations other than these, require an authenticated user. <LimitExcept GET PROPFIND OPTIONS REPORT> Require valid-user </LimitExcept> </Location>
这些只是一些简单的示例。有关 Apache 访问控制和 Require
指令的更多深入信息,请查看 Apache 文档教程集合中的 Security
部分,网址为 https://httpd.apache.ac.cn/docs-2.0/misc/tutorials.html。
可以使用第二个 Apache httpd 模块 mod_authz_svn 设置更细粒度的权限。此模块获取从客户端传递到服务器的各种不透明 URL,要求 mod_dav_svn 对其进行解码,然后可能会根据配置中定义的访问策略拒绝请求文件。
如果您是从源代码构建了 Subversion,那么 mod_authz_svn 会自动与 mod_dav_svn 一起构建和安装。许多二进制发行版也会自动安装它。要验证它是否已正确安装,请确保它在 httpd.conf
中的 mod_dav_svn 的 LoadModule
指令之后立即出现
LoadModule dav_module modules/mod_dav.so LoadModule dav_svn_module modules/mod_dav_svn.so LoadModule authz_svn_module modules/mod_authz_svn.so
要激活此模块,您需要将 Location
块配置为使用 AuthzSVNAccessFile
指令,该指令指定一个包含存储库中路径的权限策略的文件。(稍后,我们将讨论该文件的格式。)
Apache 很灵活,因此您可以选择以三种基本模式之一来配置您的块。首先,选择其中一种基本配置模式。(以下示例非常简单;请查看 Apache 自己的文档,以了解有关 Apache 身份验证和授权选项的更多详细信息。)
最简单的块是允许每个人开放访问。在这种情况下,Apache 永远不会发送身份验证挑战,因此所有用户都被视为“匿名”。
示例 6.1. 匿名访问的示例配置。
<Location /repos> DAV svn SVNParentPath /usr/local/svn # our access control policy AuthzSVNAccessFile /path/to/access/file </Location>
在偏执程度的另一端,您可以将块配置为向所有人要求身份验证。所有客户端都必须提供凭据来识别自己。您的块无条件地要求通过 Require valid-user
指令进行身份验证,并定义了一种进行身份验证的方法。
示例 6.2. 经过身份验证的访问的示例配置。
<Location /repos> DAV svn SVNParentPath /usr/local/svn # our access control policy AuthzSVNAccessFile /path/to/access/file # only authenticated users may access the repository Require valid-user # how to authenticate a user AuthType Basic AuthName "Subversion repository" AuthUserFile /path/to/users/file </Location>
第三种非常流行的模式是允许经过身份验证和匿名访问的组合。例如,许多管理员希望允许匿名用户读取某些存储库目录,但只想让经过身份验证的用户读取(或写入)更敏感的区域。在此设置中,所有用户都以匿名方式开始访问存储库。如果您的访问控制策略在任何时候都需要真实的用户名,Apache 将要求客户端进行身份验证。要执行此操作,您需要同时使用 Satisfy Any
和 Require valid-user
指令。
示例 6.3. 混合身份验证/匿名访问的示例配置。
<Location /repos> DAV svn SVNParentPath /usr/local/svn # our access control policy AuthzSVNAccessFile /path/to/access/file # try anonymous access first, resort to real # authentication if necessary. Satisfy Any Require valid-user # how to authenticate a user AuthType Basic AuthName "Subversion repository" AuthUserFile /path/to/users/file </Location>
一旦您确定了这三种基本 httpd.conf
模板之一,您就需要创建包含存储库中特定路径的访问规则的文件。这在 名为“基于路径的授权”的部分 中进行了描述。
模块 mod_dav_svn 会进行大量工作,以确保您标记为“不可读” 的数据不会意外泄露。这意味着它需要密切监控所有由 svn checkout 或 svn update 等命令返回的路径和文件内容。如果这些命令遇到根据某些授权策略不可读的路径,则该路径通常会被完全忽略。在历史记录或重命名跟踪的情况下,例如在很久以前重命名的文件上运行类似 svn cat -r OLD foo.c 的命令,如果确定对象的先前名称之一被限制读取,则重命名跟踪将简单地停止。
所有这些路径检查有时会非常昂贵,尤其是在 svn log 的情况下。检索修订版本列表时,服务器会查看每个修订版本中的每个更改的路径,并检查其可读性。如果发现不可读路径,则将其从修订版本更改路径列表中省略(通常使用 --verbose
选项显示),并且整个日志消息会被抑制。不用说,这在影响大量文件的修订版本上可能非常耗时。这是安全的代价:即使您根本没有配置 mod_authz_svn 等模块,mod_dav_svn 模块仍然要求 Apache httpd 对每个路径运行授权检查。 mod_dav_svn 模块不知道已安装哪些授权模块,因此它所能做的就是要求 Apache 调用可能存在的任何模块。
另一方面,也存在一种类似于“逃生门”的机制,它允许您以速度换取安全性。如果您没有强制执行任何类型的按目录授权(即不使用 mod_authz_svn 或类似的模块),那么您可以禁用所有这些路径检查。在您的 httpd.conf
文件中,使用 SVNPathAuthz
指令
默认情况下,SVNPathAuthz
指令处于“开启”状态。设置为“关闭”时,将禁用所有基于路径的授权检查;mod_dav_svn 会停止对发现的每个路径调用授权检查。
我们已经涵盖了 Apache 和 mod_dav_svn 的大多数身份验证和授权选项。但是,Apache 还提供了其他一些不错的功能。
将 Apache/WebDAV 配置用于您的 Subversion 仓库的最大好处之一是,版本控制文件的最新修订版本和目录可以通过常规的网络浏览器立即查看。由于 Subversion 使用 URL 来标识版本控制的资源,因此用于基于 HTTP 的仓库访问的 URL 可以直接在 Web 浏览器中输入。您的浏览器将针对该 URL 发出 HTTP GET
请求,根据该 URL 是否代表版本控制的目录或文件,mod_dav_svn 将响应目录列表或文件内容。
由于 URL 不包含您希望查看的资源的哪个版本的任何信息,因此 mod_dav_svn 将始终使用最新版本进行响应。此功能具有一个奇妙的副作用,您可以将 Subversion URL 传递给您的同行作为文档的引用,并且这些 URL 将始终指向该文档的最新版本。当然,您甚至可以将这些 URL 用作其他网站上的超链接。
浏览 Subversion 仓库时,网络浏览器会通过查看 Apache 响应 HTTP GET
请求时返回的 Content-Type:
标头来获得如何呈现文件内容的提示。此标头的值是某种 MIME 类型。默认情况下,Apache 会告诉网络浏览器所有仓库文件都是“默认” MIME 类型,通常是 text/plain
。但是,如果用户希望仓库文件以更具意义的方式呈现,这可能会令人沮丧,例如,如果用户希望仓库中的 foo.html
文件在浏览时实际上呈现为 HTML,这可能就很好。
要实现这一点,您只需要确保您的文件具有正确的 svn:mime-type
设置。这将在 名为“File Content Type”的章节 中详细介绍,您甚至可以将客户端配置为自动将正确的 svn:mime-type
属性附加到第一次进入仓库的文件;请参阅 名为“Automatic Property Setting”的章节。
因此,在我们的示例中,如果将 svn:mime-type
属性设置为 text/html
,用于文件 foo.html
,那么 Apache 将正确地告诉您的网络浏览器将该文件呈现为 HTML。也可以将正确的 image/*
MIME 类型属性附加到图像,并通过这样做,最终可以从仓库中直接查看整个网站!通常,这样做不会有问题,只要网站不包含任何动态生成的的内容即可。
您通常会更多地使用版本控制文件的 URL,毕竟,有趣的内容往往就在那里。但您可能需要浏览 Subversion 目录列表,您会很快注意到,用于显示该列表的生成的 HTML 非常基础,当然不是为了美观(甚至不有趣)。为了能够自定义这些目录显示,Subversion 提供了一个 XML 索引功能。在您仓库的 httpd.conf
文件的 Location
块中添加单个 SVNIndexXSLT
指令,将指示 mod_dav_svn 在显示目录列表时生成 XML 输出,并引用您选择的 XSLT 样式表
<Location /svn> DAV svn SVNParentPath /usr/local/svn SVNIndexXSLT "/svnindex.xsl" … </Location>
使用 SVNIndexXSLT
指令和一个创意 XSLT 样式表,您可以使您的目录列表与网站其他部分中使用的配色方案和图像相匹配。或者,如果您愿意,您可以使用 Subversion 源代码分发包的 tools/xslt/
目录中提供的示例样式表。请记住,提供给 SVNIndexXSLT
目录的路径实际上是 URL 路径,浏览器需要能够读取您的样式表才能使用它们!
如果您通过 SVNParentPath
指令从单个 URL 提供多个仓库,那么也可以让 Apache 将所有可用仓库显示给网络浏览器。只需激活 SVNListParentPath
指令
<Location /svn> DAV svn SVNParentPath /usr/local/svn SVNListParentPath on … </Location>
如果用户现在将她的网络浏览器指向 URL http://host.example.com/svn/
,她将看到位于 /usr/local/svn
中的所有 Subversion 仓库列表。显然,这可能是一个安全问题,因此默认情况下此功能处于关闭状态。
由于 Apache 本质上是一个 HTTP 服务器,因此它包含非常灵活的日志记录功能。讨论所有日志记录配置方式超出了本书的范围,但我们应该指出,即使是最通用的 httpd.conf
文件也会使 Apache 生成两个日志:error_log
和 access_log
。这些日志可能出现在不同的位置,但通常是在 Apache 安装的日志记录区域中创建的。(在 Unix 上,它们通常位于 /usr/local/apache2/logs/
中。)
error_log
描述了 Apache 在工作时遇到的任何内部错误。 access_log
文件记录了 Apache 收到的每个传入的 HTTP 请求。这使得查看以下信息变得容易,例如,Subversion 客户端来自哪些 IP 地址,特定客户端使用服务器的频率,哪些用户正确地进行了身份验证,以及哪些请求成功或失败。
不幸的是,由于 HTTP 是一种无状态协议,即使是最简单的 Subversion 客户端操作也会生成多个网络请求。查看 access_log
并推断客户端正在执行的操作非常困难,大多数操作看起来像是一系列神秘的 PROPPATCH
、GET
、PUT
和 REPORT
请求。更糟糕的是,许多客户端操作会发送几乎完全相同的请求序列,因此更难将它们区分开来。
但是,mod_dav_svn
可以提供帮助。通过激活“操作日志记录”功能,您可以要求 mod_dav_svn
创建一个单独的日志文件,描述您的客户端正在执行哪些类型的顶级操作。
为此,您需要使用 Apache 的 CustomLog
指令(在 Apache 自身的文档中有更详细的说明)。确保在您的 Subversion Location
块的 外部 调用此指令
<Location /svn> DAV svn … </Location> CustomLog logs/svn_logfile "%t %u %{SVN-ACTION}e" env=SVN-ACTION
在此示例中,我们要求 Apache 在标准 Apache logs
目录中创建一个特殊日志文件 svn_logfile
。 %t
和 %u
变量分别由请求的时间和用户名替换。真正重要的部分是 SVN-ACTION
的两个实例。当 Apache 看到该变量时,它会用 SVN-ACTION
环境变量的值进行替换,该值由 mod_dav_svn
在检测到顶级客户端操作时自动设置。
因此,您不必像这样解释传统的 access_log
[26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc/!svn/vcc/default HTTP/1.1" 207 398 [26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc/!svn/bln/59 HTTP/1.1" 207 449 [26/Jan/2007:22:25:29 -0600] "PROPFIND /svn/calc HTTP/1.1" 207 647 [26/Jan/2007:22:25:29 -0600] "REPORT /svn/calc/!svn/vcc/default HTTP/1.1" 200 607 [26/Jan/2007:22:25:31 -0600] "OPTIONS /svn/calc HTTP/1.1" 200 188 [26/Jan/2007:22:25:31 -0600] "MKACTIVITY /svn/calc/!svn/act/e6035ef7-5df0-4ac0-b811-4be7c823f998 HTTP/1.1" 201 227 …
… 相反,您可以查看更易于理解的 svn_logfile
,如下所示
[26/Jan/2007:22:24:20 -0600] - list-dir '/' [26/Jan/2007:22:24:27 -0600] - update '/' [26/Jan/2007:22:25:29 -0600] - remote-status '/' [26/Jan/2007:22:25:31 -0600] sally commit r60
Apache 作为强大的 Web 服务器,提供了一些功能,这些功能也可以被用于提升 Subversion 的功能或安全性。Subversion 通过 Neon 与 Apache 通信,Neon 是一个通用的 HTTP/WebDAV 库,支持 SSL(安全套接层,之前已讨论过)等机制。如果您的 Subversion 客户端支持 SSL,则可以使用 https://
访问 Apache 服务器。
Apache 和 Subversion 之间关系的另一个有用功能是,可以指定自定义端口(而不是默认的 HTTP 端口 80)或 Subversion 存储库应访问的虚拟域名,或者通过 HTTP 代理访问存储库。这些功能都由 Neon 支持,因此 Subversion 可以免费获得这些支持。
最后,由于 mod_dav_svn 正在使用 WebDAV/DeltaV 协议的子集,因此可以通过第三方 DAV 客户端访问存储库。大多数现代操作系统(Win32、OS X 和 Linux)都具有将 DAV 服务器作为标准网络共享挂载的内置功能。这是一个复杂的主题;有关详细信息,请阅读 附录 C,WebDAV 和自动版本控制。