The Power of CGI

September 19, 2007 at 7:50 am | Posted in cgi, http, python | 4 Comments

Today, with all these web application frameworks around, CGI has almost become obsolete. At least in my toolbox, it’s slid to the bottom. And whenever I stumble upon it, I have to look up the spec.

Recently a colleague of mine had the following problem: He wanted to hand out cookies to passers-by, i.e. redirect requests but making sure, the user agents have a cookie when requesting the specified location.

First idea: A job for Apache’s mod_rewrite. But there’s no way to add a Set-Cookie header with mod_rewrite alone. So mod_headers should do. But the mod_headers directives are not evaluated because mod_rewrite has already returned the redirect response.

So CGI to the rescue. But how do you set a particular response status or trigger a redirect via CGI? Tha’s what the spec says:

Parsed headers

The output of scripts begins with a small header. This header consists of text lines, in the same format as an HTTP header, terminated by a blank line (a line with only a linefeed or CR/LF). Any headers which are not server directives are sent directly back to the client. Currently, this specification defines three server directives:

  • Content-type This is the MIME type of the document you are returning.
  • Location This is used to specify to the server that you are returning a reference to a document rather than an actual document.If the argument to this is a URL, the server will issue a redirect to the client.If the argument to this is a virtual path, the server will retrieve the document specified as if the client had requested that document originally. ? directives will work in here, but # directives must be redirected back to the client.
  • Status This is used to give the server an HTTP/1.0 status line to send to the client. The format is nnn xxxxx, where nnn is the 3-digit status code, and xxxxx is the reason string, such as “Forbidden”.

Voila. Something like this does the trick:

print "Status: 302 Found"
print "Location: /"
print "Set-Cookie: key=value; path=/; expires=Wednesday, 09-Nov-07 23:12:40"
print
Advertisements

4 Comments »

RSS feed for comments on this post. TrackBack URI

  1. Despite parsed headers it appears to be necessary to send status (just got that from testing).

  2. I just tried your trick, print “Status: 500 Internal error”. Unfortunately the actual response status returned to the caller was “200 OK”; my printed status was merely content. I didn’t print anything else prior to it. So I guess I’m agreeing with Erik.
    I’m using python with Apache 2.

  3. @Lars: with the following cgi script

    #!/usr/bin/env python
    import cgi
    import sys

    print "Status: 302 Found"
    print "Location: /"
    print
    sys.exit(0)

    i got this http conversation

    http://localhost/cgi-bin/test_parsedheaders

    GET /cgi-bin/test_parsedheaders HTTP/1.1
    Host: localhost
    User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.4) Gecko/20060601 Firefox/2.0.0.4 (Ubuntu-edgy)
    Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
    Accept-Language: en-us,en;q=0.5
    Accept-Encoding: gzip,deflate
    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
    Keep-Alive: 300
    Connection: keep-alive
    Cookie: _comment_fold=; _fold=

    HTTP/1.x 302 Found
    Date: Wed, 16 Jan 2008 06:59:32 GMT
    Server: Apache/2.0.55 (Ubuntu) PHP/5.1.6 mod_webkit2/0.9.1
    Location: /
    Keep-Alive: timeout=15, max=100
    Connection: Keep-Alive
    Transfer-Encoding: chunked
    Content-Type: text/plain; charset=UTF-8
    X-Pad: avoid browser bug

    so i guess it works for me.

  4. @Lars: it also worked for status 500:

    #!/usr/bin/env python
    import cgi
    import sys

    print "Status: 500 Internal Error"
    print "Location: /"
    print
    sys.exit(0)

    returned the headers:

    Date: Wed, 16 Jan 2008 07:06:59 GMT
    Server: Apache/2.0.55 (Ubuntu) PHP/5.1.6 mod_webkit2/0.9.1
    Location: /
    Connection: close
    Transfer-Encoding: chunked
    Content-Type: text/plain; charset=UTF-8

    500 Internal Error


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.
Entries and comments feeds.

%d bloggers like this: