Bug 36590 - mod_rewrite type|T force mime type option doesn't work
Summary: mod_rewrite type|T force mime type option doesn't work
Status: RESOLVED FIXED
Alias: None
Product: Apache httpd-2
Classification: Unclassified
Component: Documentation (show other bugs)
Version: 2.2.3
Hardware: All All
: P2 normal with 2 votes (vote)
Target Milestone: ---
Assignee: HTTP Server Documentation List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-09-10 14:38 UTC by Richard Antony Burton
Modified: 2010-03-07 12:36 UTC (History)
1 user (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Richard Antony Burton 2005-09-10 14:38:31 UTC
Using the following rule:
RewriteCond %{QUERY_STRING} (.+)
RewriteRule ^(.*\.html)$ $1@%1 [T=text/html]

To convert some urls like this:
http://example.com/index.html?image.jpg
to access files like this (produced by a batch downloading tool):
index.html@image.jpg
the rewrite rule needs the T option because otherwise apache will send a jpg
mime type, based on the file name.

The log for this rewrite is:
[rid#aa1218/initial] (3) [per-dir /tmp/www/] strip per-dir prefix:
/tmp/www/test/index.html -> test/index.html
[rid#aa1218/initial] (3) [per-dir /tmp/www/] applying pattern '^(.*\.html)$' to
uri 'test/index.html'
[rid#aa1218/initial] (2) [per-dir /tmp/www/] rewrite test/index.html ->
test/index.html@image.jpg
[rid#aa1218/initial] (3) [per-dir /tmp/www/] add per-dir prefix:
test/index.html@image.jpg -> /tmp/www/test/index.html@image.jpg
[rid#aa1218/initial] (2) [per-dir /tmp/www/] remember
/tmp/www/test/index.html@image.jpg to have MIME-type 'text/html'
[rid#aa1218/initial] (2) [per-dir /tmp/www/] strip document_root prefix:
/tmp/www/test/index.html@image.jpg -> /hcStore/8x10/index.html@image.jpg
[rid#aa1218/initial] (1) [per-dir /tmp/www/] internal redirect with
/hcStore/8x10/index.html@image.jpg [INTERNAL REDIRECT]
[rid#ab0208/initial/redir#1] (3) [per-dir /tmp/www/] strip per-dir prefix:
/tmp/www/test/index.html@image.jpg -> test/index.html@image.jpg
[rid#ab0208/initial/redir#1] (3) [per-dir /tmp/www/] applying pattern
'^(.*\.html)$' to uri 'test/index.html@image.jpg'
[rid#ab0208/initial/redir#1] (1) [per-dir /tmp/www/] pass through
/tmp/www/test/index.html@image.jpg

Note the lack of a log entry indicating that the forced mime type is actually
being set, which should be in the redir#1 block. livehttpheaders confirmed the
forced mime type did not find its way to the browser.

A couple of extra log points in hook_mimetype showed that it wasn't finding the
force mime type note for the request. This is probably because we are on a new
request second time through (the internal redirect), and so we should be using
r->prev->notes instead of r->notes. Potentially the forced mime type could be a
couple of redirects back, so all previous requests should probably(?) be checked
until one is found, or we have been through them all.

I'd suggest something like this as a possible fix (works fine for me):
static int hook_mimetype(request_rec *r)
{
    const char *t;
    request_rec *p = r;

    /* now check if we have to force a MIME-type */
    while (p) {
        t = apr_table_get(p->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR);
        if (t != NULL) {
            rewritelog(r, 1, "force filename %s to have MIME-type '%s'",
                       r->filename, t);
            ap_set_content_type(r, t);
            return OK;
        }
        p = p->prev;
    }
    return DECLINED;
}

Richard.
Comment 1 André Malo 2005-09-10 14:55:37 UTC
Whether this is a bug or not depends on the point of view. It may be desired
that the internal redirect is run without a memory.
I'd leave the behavior as is, because otherwise it could break many existing
stuff out there.

I suggest you setup a second rule, which matches for the 'html@' stuff and
forces the mime type then (without changing the url so no redirect occurs).
Note that your problem doesn't happen, when the rules are executed in server
context, because there no redirect happens at all.
Comment 2 Richard Antony Burton 2005-09-10 15:28:20 UTC
From the point of view of mod_rewrite working as documented it is definitely a bug.

This memory effect would only be for setting the mime type based on a previous
rewrite having taken place. And only where a user supplied rewrite rule has
explicitly requested this mime type override. It doesn't cause any memory for
any other part of an internal redirect processing. Can you suggest anywhere this
change could be a problem? I can't think of one, though I obviously don't know
it as well as you do.

If you still think the risk in fixing this is too high, perhaps it could be
changed in 2.1?

Or even failing that this bug should be passed to Documentation because the
manual is wrong. Even the example php source rewrite rule in the doc doesn't
work if used in a .htaccess file. If this feature is not available and needs to
be worked around for per directory config it needs to be explained in the
documentation.
Comment 3 Jan Pazdziora 2006-06-11 06:15:40 UTC
> If you still think the risk in fixing this is too high, perhaps it could be
> changed in 2.1?

The problem is still present in version 2.2.2. Any idea how this issue
could be resolved?

We'd either need a fix of code, or a fix of documentation stating that
if the Rewrite Rule changes the file name or URI, leading to an internal
redirect, the forced MIME-Type will be lost.
Comment 4 Anthony L. Awtrey 2007-03-17 05:38:22 UTC
Would it be possible to leave T|type and add a FT|ForceType that is remembered
after redirection? It would be really handy, since we store uploads as UUID
strings and keep meta-data, like original filename and mimetype, in a database.
Having the ability to do a rewrite to the UUID file whilst preserving the
mimetype and original filename would be a valuable feature.
Comment 5 Arnaud LB 2007-08-15 19:00:12 UTC
I'm according with Richard Antony Burton, from the point of view of mod_rewrite 
working as documented it is definitely a bug.

Additionally the solution André Malo's solution does not work for me:

<Directory />
RewriteEngine On
RewriteRule (.+\.html)$ $1.gz
RewriteRule . - [T=text/html,L]
</Directory>

Result:
Content-Type: application/x-gzip

Expected result:
Content-Type: test/html

Last RewriteLog line:
force filename redirect:/dir/file.html.gz to have MIME-type 'text/html'
Comment 6 Sigfried Arnold 2010-01-13 00:39:44 UTC
Changed to Version 2.2.3 - Problem still exists here too (Red Hat)

Testcase:

AddHandler php5-script .css
RewriteEngine On
RewriteRule ^(.+\.css)$ $1 [T=text/css]

Result:
Content-Type: text/html

Expected:
Content-Type: text/css
Comment 7 quanxunzhen 2010-03-07 10:50:23 UTC
This bug is also trouble me.

If I use the following rule:
RewriteCond %{REQUEST_URI} \.t$
RewriteRule ^(.*)\.t$ $1 [T=text/html]

The flag T will never work. But when I modify it to the following rule:
RewriteCond %{REQUEST_URI} \.t$
RewriteRule ^(.*)\.t$ $1
RewriteRule . - [T=text/html]

Then, the Content-Type in header is set properly.

But now, I need a more flexible rewrite rule that I can set the MIME-Type in the request url, so I modify it again to:
RewriteCond %{REQUEST_URI} \.t$
RewriteRule ^([a-zA-Z]+/[a-zA-Z-]+)/(.*)\.t$ $2 [E=MIMETYPE:$1]
RewriteRule . - [T=%{ENV:MIMETYPE}]

But it doesn't work anymore.

According to your explanation above, the last rule should not lead to a internal redirect because it changes nothing but the mimetype like the previous one. But they behave quite differently!
Comment 8 Eric Covener 2010-03-07 12:18:14 UTC
> If I use the following rule:
> RewriteCond %{REQUEST_URI} \.t$
> RewriteRule ^(.*)\.t$ $1 [T=text/html]
> 
> The flag T will never work. But when I modify it to the following rule:

That's because you're in per-directory context and by changing the URL you've asked Apache to recalculate all of this.

> RewriteCond %{REQUEST_URI} \.t$
> RewriteRule ^(.*)\.t$ $1
> RewriteRule . - [T=text/html]
> 
> Then, the Content-Type in header is set properly.
> 
> But now, I need a more flexible rewrite rule that I can set the MIME-Type in
> the request url, so I modify it again to:
> RewriteCond %{REQUEST_URI} \.t$
> RewriteRule ^([a-zA-Z]+/[a-zA-Z-]+)/(.*)\.t$ $2 [E=MIMETYPE:$1]
> RewriteRule . - [T=%{ENV:MIMETYPE}]

The condition looks completely unnecessary, which makes me think you'd benefit from discussing your config, with a rewritelog, on the users list.


> 
> But it doesn't work anymore.
> 
> According to your explanation above, the last rule should not lead to a
> internal redirect because it changes nothing but the mimetype like the previous
> one. But they behave quite differently!

It could be failing to do what you want for any number of reasons.  Primarily, you need to make sure that T= rule runs in a round of rewrite processing that on the whole does not do a substitution -- not just in the one rule with the T=.
Comment 9 Eric Covener 2010-03-07 12:36:38 UTC
This was already documented in trunk and is now documented in 2.2.x.   I enhanced it a bit.

Configuration assistance is available via the users mailing list, not bugzilla.