1

Sorry in advance for the length, thanks for your patience. I have an ancient production server that no one knows how it was built. It uses apache+mod_wsgi to run a Cherry Py python application to serve images. I'm recreating it to document it and start upgrading. I'm running into an issue where images with no file extension that can either be PNG or JPEG are coming through with:

Content-Type: "text/html;charset=utf-8"

the production server currently correctly returns:

Content-Type: "image/jpeg"

Info about the environment I'm recreating the server in:

Amazon Linux AMI release 2017.03 (basically CentOS 6 it feels like)
Apache/2.2.31
mod_wsgi-3.4
CherryPy 3.2.0

The production environment has the same packages installed except its running on actual Centos6 and Apache is version 2.2.17.

Files and relevant snippets:

httpd.conf

#/etc/httpd/conf/httpd.conf

LoadModule mime_magic_module modules/mod_mime_magic.so
LoadModule mime_module modules/mod_mime.so

TypesConfig /etc/mime.types

<IfModule mod_mime_magic.c>
#   MIMEMagicFile /usr/share/magic.mime                                           
   MIMEMagicFile conf/magic
</IfModule>

Include conf.sites/*.conf

# There really are no other directives or AddType calls that are relevant 
# that I can see, just standard  language and icon declarations
# if I should be more verbose here just let me know.

magic

# /etc/httpd/conf/magic
# JPEG images
0       beshort         0xffd8          image/jpeg

mime.types

# /etc/mime.types
image/jpeg                                      jpeg jpg jpe jfif

site.conf

# /etc/httpd/conf.sites/site.conf
<VirtualHost *:80>
    ServerName pic.project.com
    DocumentRoot "/srv/pic_project/html"
    RewriteEngine On                                            
    RewriteCond %{HTTP_USER_AGENT} Apache\sHttpClient [NC]
    RewriteRule . - [F,L]

    <Directory /srv/pic_project/html>
            Order allow,deny
            Allow from all
    </Directory>

    WSGIScriptAlias / /srv/pic_project/src/project.py

    <Directory /srv/pic_project/src>
            Order allow,deny
            Allow from all
    </Directory>

    ErrorLog logs/pic-error_log
    CustomLog logs/pic-access_log combined
</VirtualHost>

File that cherry py uses to serve the photo:

# /srv/pic_project/src/project.py

cherrypy.response.headers['Content-Type'] = cfile.mimetype
cherrypy.response.headers['Cherry-Py-Content-Type'] = cfile.mimetype
cherrypy.response.headers['Content-Disposition'] = 'inline; filename="12345.jpg"'

# I set two headers for debugging. Cherry-Py-Content-Type is always right
# "image/jpeg" or "image/png". "Content-Type" is always "text/html" once
# going through apache / mod_wsgi. Don't worry about "cfile", just know
# the mimetype attribute is always correct.

The url used to request is something like:

http://pic.project.com/pics/pic_type/owner_id/12345/

Additional notes:

  • The production server + my recreation have exact copies of client code, so its very unlikely the problem is in the cherry py / python code.
  • The httpd.conf, magic, mime.types, virtual host files are exact copies of what is on the production server, again not likely to be the problem.
  • The text displayed in the browser when going to the URL contains JFIF in the beginning meaning that it does find the image.

What I've done so far:

  • Set a custom response header right after the Content-Type response header is declared to confirm the application is setting the correct value, it is.
  • Triple-Checked file locations / permissions, then had another two colleagues also check.
  • Added a line at the bottom of /etc/httpd/conf/httpd.conf to force the Content-Type header: Header set Content-Type "image/jpeg", and then progressively moved it to the top of the file to see if eventually get overwritten like the application header does, but as long as that line is anywhere in the conf file it will work/not get overwritten. (remember it could be PNG or JPEG so statically setting it is not going to work).
  • Scanned production + recreation to find any .htaccess files that might be impacting, there are not any that I can find, running: sudo find / -type f -name .htaccess finds nothing.
  • confirmed all production apache modules are installed on recreation
  • confirmed no messages in error log, access log shows requests as expected, nothing in systemlog.

From what I've read in similar questions like:

One of the comments says in order for mime_magic to work, mod_mime must not find any matches, but since there is no extension it finds a bunch of matches and so mime_magic never even enters the game. Is that accurate? If so, can i force it to always use magic and never extensions? Else, what other methods for properly setting Content-Type for files with no extension based on content?

Another will say you can use a ForceType directive to match a file-pattern in a particular directory. Problem is file names are just numbers, not separated by type, so /thing/12345 and /thing/12346 one might be PNG and the other JPEG, so I can't force a pattern, I need to determine the type based on file content.

Another one was declaring a wrong Content-Type in app but i've confirmed this is not the case.

I've read dozens of other answers and tried multiple work-arounds, but I think I'm just missing something simple..

If you got this far, thank you for your time! Appreciate any suggestions. Will add any missing/helpful debug info on request!

  • 1
    Either let Apache OR CherryPy set the Response content type, not both. Since your debugging header is correct, let Cherrypy just set the response content-type. – Johan Apr 20 '17 at 12:43

1 Answers1

0

The answer to my specific issue was someone had hand-edited a generated config file on the production machine. Since the generated configs are not committed to version control and instead templates for environments are copied to be the used config based on environment, the template was not also updated. Basically, had we ran a build on the production machine it would have also had this issue. The Cherry Py config option I was missing was:

tools.encode.add_charset = False

Without this, cherry py was overwriting the Content-Type header set in the application. Turns out nothing to do with Apache / mod_mime / magic / modwsgi. Was all a Cherry Py config issue.