<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>鬼の领地 &#187; Rewrite</title>
	<atom:link href="http://blog.upsuper.org/tag/rewrite/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.upsuper.org</link>
	<description>the place where there are some ghost appearing...</description>
	<lastBuildDate>Fri, 06 Aug 2010 12:57:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>Apache 的 Rewrite 模块 Bug 一则</title>
		<link>http://blog.upsuper.org/a-bug-of-rewrite-module-in-apache/</link>
		<comments>http://blog.upsuper.org/a-bug-of-rewrite-module-in-apache/#comments</comments>
		<pubDate>Sun, 07 Mar 2010 11:20:54 +0000</pubDate>
		<dc:creator>upsuper</dc:creator>
				<category><![CDATA[探究学习]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Bug]]></category>
		<category><![CDATA[Rewrite]]></category>

		<guid isPermaLink="false">http://blog.upsuper.org/?p=1086</guid>
		<description><![CDATA[我发觉研究的东西多了，就会看到各种神奇的 Bug…… 今天写的这个 Bug 是关于 Apache 的 Rewrite 模块的。先来看一个很正常的 Rewrite 规则： 1 2 RewriteCond %{REQUEST_URI} \.u$ RewriteRule ^(.*)\.u$ $1 这个什么意思呢？用过的人一定看得出来，就是把一个 .t 结尾的请求发送到一个去掉 .t 的文件上面。比如我如果请求 upsuper.u 就会自动调用 upsuper 这个文件来返回。这没有什么疑问。 然后，我们发现，.u 文件浏览器不知道是什么，而 upsuper 这个文件在服务器上又是没有类型的，于是 Apache 不知道告诉浏览器（或者错误地告诉了一个）MIME-Type。这样即使这个文件是个网页，浏览器上也会出现下载提示或者当作纯文本直接输出。 翻阅了一下 Rewrite 模块的资料，我们了解到可以使用 T 这个标志符来强制指定 MIME-Type 类型，于是规则变成了下面这样： 1 2 RewriteCond %{REQUEST_URI} \.u$ RewriteRule ^(.*)\.u$ $1 [T=text/html] 可是无效！ Bug 开始出现了~ 在 Apache [...]]]></description>
			<content:encoded><![CDATA[<p>我发觉研究的东西多了，就会看到各种神奇的 Bug……</p>
<p>今天写的这个 Bug 是关于 Apache 的 Rewrite 模块的。先来看一个很正常的 Rewrite 规则：</p>

<div class="wp_codebox"><table><tr id="p10866"><td class="line_numbers"><pre>1
2
</pre></td><td class="code" id="p1086code6"><pre class="apache" style="font-family:monospace;"><span style="color: #00007f;">RewriteCond</span> %{REQUEST_URI} \.u$
<span style="color: #00007f;">RewriteRule</span> ^(.*)\.u$ $<span style="color: #ff0000;">1</span></pre></td></tr></table></div>

<p>这个什么意思呢？用过的人一定看得出来，就是把一个 .t 结尾的请求发送到一个去掉 .t 的文件上面。比如我如果请求 upsuper.u 就会自动调用 upsuper 这个文件来返回。这没有什么疑问。</p>
<p>然后，我们发现，.u 文件浏览器不知道是什么，而 upsuper 这个文件在服务器上又是没有类型的，于是 Apache 不知道告诉浏览器（或者错误地告诉了一个）MIME-Type。这样即使这个文件是个网页，浏览器上也会出现下载提示或者当作纯文本直接输出。</p>
<p>翻阅了一下 <a href="http://httpd.apache.org/docs/2.2/rewrite/">Rewrite 模块的资料</a>，我们了解到可以使用 T 这个标志符来强制指定 MIME-Type 类型，于是规则变成了下面这样：</p>

<div class="wp_codebox"><table><tr id="p10867"><td class="line_numbers"><pre>1
2
</pre></td><td class="code" id="p1086code7"><pre class="apache" style="font-family:monospace;"><span style="color: #00007f;">RewriteCond</span> %{REQUEST_URI} \.u$
<span style="color: #00007f;">RewriteRule</span> ^(.*)\.u$ $<span style="color: #ff0000;">1</span> [T=text/html]</pre></td></tr></table></div>

<p>可是无效！</p>
<p>Bug 开始出现了~<br />
<span id="more-1086"></span><br />
在 Apache 基金会的 Bugzilla 里面翻到了<a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=36590">关于这个 Bug 的内容</a>。然后看一看日期，OMG，2005年的 Bug，很跨10个年头没有解决！</p>
<p>看了一下，里面有一个可能是开发人员，说这一问题可能是由于引发了一个内部跳转导致的。并且提供了一种解决方法，我参照该解决方法再次修改我的 Rewrite 规则，变成下面这样：</p>

<div class="wp_codebox"><table><tr id="p10868"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p1086code8"><pre class="apache" style="font-family:monospace;"><span style="color: #00007f;">RewriteCond</span> %{REQUEST_URI} \.u$
<span style="color: #00007f;">RewriteRule</span> ^(.*)\.u$ $<span style="color: #ff0000;">1</span>
<span style="color: #00007f;">RewriteRule</span> . - [T=text/html]</pre></td></tr></table></div>

<p>成功了！泪流满面……</p>
<p>不过，有趣的还没结束~仅能变出 MIME-Type 为 text/html 本来就不是我最初的想法。我的想法更大胆一些：识别 URL 中的一部分作为 MIME-Type！</p>
<p>我发现 Rewrite 规则中，标志 E 可以修改环境变量，而且在后面的过程中还可以使用~我觉得那这个来当中间变量是一个很好的想法，于是就动手了：</p>

<div class="wp_codebox"><table><tr id="p10869"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p1086code9"><pre class="apache" style="font-family:monospace;"><span style="color: #00007f;">RewriteCond</span> %{REQUEST_URI} \.u$
<span style="color: #00007f;">RewriteRule</span> ^([a-zA-Z]+/[a-zA-Z-]+)/(.*)\.u$ $<span style="color: #ff0000;">2</span> [E=MIMETYPE:$<span style="color: #ff0000;">1</span>]
<span style="color: #00007f;">RewriteRule</span> . - [T=%{ENV:MIMETYPE}]</pre></td></tr></table></div>

<p>稍加辨别不难看出，“([a-zA-Z]+/[a-zA-Z-]+)”部分正是识别一个 MIME-Type，在而后的 [E=MIMETYPE:$1] 将这一部分存入了 MIMETYPE 这一环境变量，然后在第三行将这个环境变量的值作为 MIME-Type。</p>
<p>可是，当我们尝试访问 text/html/upsuper.u 的时候，这个文件再次被直接输出了，MIME-Type 根本没有被指定！疯了……</p>
<p>看看 RewriteLog 里面都写了些什么（已去除无关部分）：</p>

<div class="wp_codebox"><table><tr id="p108610"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="code" id="p1086code10"><pre class="text" style="font-family:monospace;">[rid#21e031f8/initial] (3) add path info postfix: ~/web/test/text -&gt; ~/web/test/text/html/upsuper.u
[rid#21e031f8/initial] (3) strip per-dir prefix: ~/web/test/text/html/upsuper.u -&gt; text/html/upsuper.u
[rid#21e031f8/initial] (3) applying pattern '^([a-zA-Z]+/[a-zA-Z-]+)/(.*)\.u$' to uri 'text/html/upsuper.u'
[rid#21e031f8/initial] (2) rewrite 'text/html/upsuper.u' -&gt; 'upsuper'
[rid#21e031f8/initial] (3) add per-dir prefix: upsuper -&gt; ~/web/test/upsuper
[rid#21e031f8/initial] (3) add path info postfix: ~/web/test/upsuper -&gt; ~/web/test/upsuper/html/upsuper.u
[rid#21e031f8/initial] (3) strip per-dir prefix: ~/web/test/upsuper/html/upsuper.u -&gt; upsuper/html/upsuper.u
[rid#21e031f8/initial] (3) applying pattern '.' to uri 'upsuper/html/upsuper.u'
[rid#21e031f8/initial] (2) remember ~/web/test/upsuper to have MIME-type 'text/html'
[rid#21e031f8/initial] (2) strip document_root prefix: ~/web/test/upsuper -&gt; /test/upsuper
[rid#21e031f8/initial] (1) internal redirect with /test/upsuper [INTERNAL REDIRECT]
[rid#21e031f8/initial] (1) force filename redirect:/test/upsuper to have MIME-type 'text/html'
[rid#21e08c80/initial/redir#1] (3) strip per-dir prefix: ~/web/test/upsuper -&gt; upsuper
[rid#21e08c80/initial/redir#1] (3) applying pattern '^([a-zA-Z]+/[a-zA-Z-]+)/(.*)\.u$' to uri 'upsuper'
[rid#21e08c80/initial/redir#1] (3) strip per-dir prefix: ~/web/test/upsuper -&gt; upsuper
[rid#21e08c80/initial/redir#1] (3) applying pattern '.' to uri 'upsuper'
[rid#21e08c80/initial/redir#1] (1) pass through ~/web/test/upsuper</pre></td></tr></table></div>

<p>注意看第9行，在这里 MIME-Type 已经被正确地设置了，但随后开始了内部重定向……orz</p>
<p>本质上说，最后这样修改和前面一次没有很大的本质不同，最后一句都是除了修改 MIME-Type 没有修改任何网址内容。可是表现却有如此大的不同，究竟是为什么呢？</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.upsuper.org/a-bug-of-rewrite-module-in-apache/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
