Wednesday, March 28, 2012

Decoding Base64 Encoded Strings with CherryPy

I wanted to write a simple web app for decoding base64 encoded strings.  I wanted something that was very easy to use that wouldn't require a large amount of up front learning.  I've done some stuff with Google App Engine Python SDK before and thought about using that (and I might still do that) but decided to look at some other frameworks.  I came across CherryPy which I had heard of before but never really looked at.  To get a basic Hello World app working was very quick and easy and I liked that it has a built in web server so I wouldn't have to configure Apache or some web server to get it working.  It's so minimal that it just looks like python code with embedded html and if you use something like Mako templates it looks even cleaner but it does add a little more complexity.  Mako templates are very easy to use however and if you are building larger scale applications they are well worth it.

Below is the code I came up with.  It is a simple website with 2 pages. The first is for decoding base64 encoded strings and gives you the result as a file to download.  The second is for encoding files and has a file upload form that gives you the resulting base64 encoded string as a result.

To run it, you need python and cherrypy installed (I'm using python 2.6.4 and cherrypy 3.2.2). Save the below code as base64Decoder.py and use the following command to run it:

python base64Decoder.py

And then view it in your favourite browser at http://localhost:8064/

import base64
import cherrypy
from cherrypy.lib.static import serve_file

class base64Decoder(object):
    def index(self):
        return """
        <html>
        <head><title>Base 64 Decoder</title></head>
        <body>
            <h2>Base 64 Decoder</h2> 
            <a href="encoder">Switch to Encoder</a>
            <h2>Paste in the base 64 encoded string</h2>
            <form action="decode" method="post" enctype="multipart/form-data" target="_blank">
            <textarea id="textToDecode" name="textToDecode" rows="5" cols="40"></textarea>
            Name of output file: 
            <input type="text" id="fileName" name="fileName" />
            <input type="submit" value="decode"/>
            </form>
        </body></html>
        """
    index.exposed = True

    def encoder(self):
        return """
        <html>
        <head><title>Base 64 Encoder</title></head>
        <body>
            <h2>Base 64 Encoder</h2> 
            <a href="decoder">Switch to Decoder</a>
            <h2>Upload a file to encode</h2>
            <form action="encode" method="post" enctype="multipart/form-data" target="_blank">
            filename: <input type="file" name="myFile" />
            <input type="submit" value="encode"/>
            </form>
        </body></html>
        """
    encoder.exposed = True

    def encode(self, myFile):
        cherrypy.response.headers['Content-Type'] = 'text/plain'
        data = myFile.file.read()
        return base64.encodestring(data)
    encode.exposed = True

    def decode(self, textToDecode, fileName):
        cherrypy.response.headers['Content-Type'] = 'application/octet-stream'
        dis = 'attachment; filename="%s"' % fileName
        cherrypy.response.headers['Content-Disposition'] = dis
        outstr = base64.decodestring(textToDecode)
        return outstr
    decode.exposed = True

    decoder = index

cherrypy.server.socket_port = 8064
cherrypy.quickstart(base64Decoder(), '/')