8

This question is related to this one. I was having no problems while printing raw binary data from a CGI script in Python 2, for example:

#!/usr/bin/env python2

import os

if __name__ == '__main__':
    with open(os.path.abspath('test.png'), 'rb') as f:
        print "Content-Type: image/png\n"
        print f.read()

Here are the relevant response headers:

> GET /cgi-bin/plot_string2.py HTTP/1.1
> User-Agent: curl/7.32.0
> Host: 0.0.0.0:8888
> Accept: */*
> 
* HTTP 1.0, assume close after body
< HTTP/1.0 200 Script output follows
< Server: SimpleHTTP/0.6 Python/3.3.2
< Date: Fri, 13 Sep 2013 16:21:25 GMT
< Content-Type: image/png

and the result is interpreted as an image, as expected. However, if I try to make a translation to Python 3:

#!/usr/bin/env python

import os
import sys

if __name__ == '__main__':
    with open(os.path.abspath('test.png'), 'rb') as f:
        print("Content-Type: image/png\n")
        sys.stdout.buffer.write(f.read())

Nothing is returned, and here are the headers:

> GET /cgi-bin/plot_string3.py HTTP/1.1
> User-Agent: curl/7.32.0
> Host: 0.0.0.0:8888
> Accept: */*
> 
* HTTP 1.0, assume close after body
< HTTP/1.0 200 Script output follows
< Server: SimpleHTTP/0.6 Python/3.3.2
< Date: Fri, 13 Sep 2013 16:22:13 GMT
< �PNG
< 

I cannot do print(f.read()) anymore because that will print something like b'\x89PNG\r\n\x1a\n\x00.... The question I linked gives a solution, but apparently doesn't work in this environment.

Thoughts?

Added: Note for the future:

This also means print is no good for CGI any more.

Share a link to this question
CC BY-SA 3.0
19

Use sys.stdout.flush to force the header printed before the body:

import os
import sys

if __name__ == '__main__':
    with open(os.path.abspath('test.png'), 'rb') as f:
        print("Content-Type: image/png\n")
        sys.stdout.flush() # <---
        sys.stdout.buffer.write(f.read())

Or remove print, and use sys.stdout.buffer.write only:

import os
import sys

if __name__ == '__main__':
    with open(os.path.abspath('test.png'), 'rb') as f:
        sys.stdout.buffer.write(b"Content-Type: image/png\n\n") # <---
        sys.stdout.buffer.write(f.read())

NOTE

f.read() could cause a problem if the file is huge. To prevent that, use shutil.copyfileobj:

import os
import shutil
import sys

if __name__ == '__main__':
    with open(os.path.abspath('test.png'), 'rb') as f:
        sys.stdout.buffer.write(b"Content-Type: image/png\n\n")
        shutil.copyfileobj(f, sys.stdout.buffer)
Share a link to this answer
CC BY-SA 3.0
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.