/data.cgi
#!/usr/bin/env python
"""
data.cgi - Data URI Resolver
Author: Sean B. Palmer, inamidst.com
@@ Autodetect whether to use GET or POST
"""
import sys, os, cgi, urllib
allowed = frozenset(['text/plain', 'text/html', 'image/svg+xml',
'application/xhtml+xml'])
PATH_INFO = os.environ.get('PATH_INFO', '')
QUERY_STRING = os.environ.get('QUERY_STRING', '')
SCRIPT_NAME = os.environ.get('SCRIPT_NAME', '')
REQUEST_URI = os.environ.get('REQUEST_URI', '')
REQUEST_METHOD = os.environ.get('REQUEST_METHOD', '')
script = REQUEST_URI.split('?')[0]
def serve(status, headers, body):
sys.stdout.write("Status: %s\r\n" % status)
for header in headers.iteritems():
sys.stdout.write("%s: %s\r\n" % header)
sys.stdout.write("\r\n")
sys.stdout.write(str(body))
sys.exit()
def ok(mime, body):
serve(200, {'Content-Type': mime}, body)
def redirect(uri, temp=False):
if not uri.startswith('http:'):
from urlparse import urljoin
domain = os.environ.get('SERVER_NAME', 'localhost')
uri = urljoin('http://' + domain + REQUEST_URI, uri)
status = (301, 307)[temp]
headers = {'Location': uri, 'Content-Type': 'text/html'}
body = '<a href="%s">Go!</a>' % uri
serve(status, headers, body)
def error(msg):
body = '<p>%s</p>' % cgi.escape(msg)
serve(501, {'Content-Type': 'text/html'}, body)
def query():
form = cgi.FieldStorage()
form.__call__ = lambda s: form[s].value
if not form.has_key('data'):
error('Form must have key "data".')
uridata = urllib.quote(form('data'))
# Commas, as metachars, need encoding: <mime>,<data>
uridata = uridata.replace(',', '%2C')
# @@ It should be done with slashes too, but that breaks Apache...
# uridata = uridata.replace('/', '%2F')
if form.has_key('mime'):
mime = form('mime')
if mime != 'text/html':
uridata = mime + ',' + uridata
redirect(script + uridata)
def homepage():
import textwrap
ok('text/html', textwrap.dedent("""\
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Data URI Resolver - Paste 'n' Go</title>
<link rel="stylesheet" type="text/css" href="/trove/simple.css" />
<style type="text/css">
body { margin: 2.3em 3em; }
h1 { font-size: 1.8em; color: #353f3f; }
h1 img { margin-bottom: -8px; }
form { margin-left: 0.25em; }
input[type="text"] { border: 2px solid #9bc; }
textarea { border: 2px solid #9bc;
margin-bottom: 0.25em;
padding: 0.1em 0.2em; }
select { border: 2px solid #eaa; }
input[type="submit"] {
margin-left: 0.25em; margin-right: 0.25em;
border: 2px solid #9ba;
background-color: #f3faf5;
}
h1 { border-top: 2px solid #9bc;
margin-top: 0.75em;
padding-top: 0.5em;
margin-bottom: 0em;
padding-bottom: 0.5em; }
address { font-style: normal; }
p { margin-right: 3em; }
</style>
<script type="text/javascript">
<!--
function usepost() {
document.data.setAttribute('method', 'post');
document.data.submitter.setAttribute('value', 'POST');
switcher = document.getElementById('switcher');
switcher.style.display = 'none';
}
window.onload = function(){
setTimeout("document.data.data.focus();", 5);
}
// -->
</script>
</head>
<body>
<div class="nav">
</div>
<form method="get" action="" name="data">
<div><textarea name="data" rows="17" cols="79"></textarea></div>
<div>Media Type:
<select name="mime">
<option>text/html</option>
<option>text/plain</option>
<option>image/svg+xml</option>
<option>application/xhtml+xml</option>
</select>
<input type="submit" name="submitter" value="GET" />
<span id="switcher">
(<a href="javascript:void(0);" onclick="usepost()">Use POST</a>)
</span>
</div>
</form>
<p>The form above uses GET by default but only allows up to 2,048 bytes.
By switching to POST you won't get a bookmarkable URI, but you will be
able to send up to 51,200 bytes.</p>
<h1>
<a href="/"><img src="/trove/logo" alt="inamidst.com" /></a>
Data URI Resolver
</h1>
<address>
By <a href="http://inamidst.com/sbp/">Sean B. Palmer</a>.
See the <a href="/inside/data/">script</a> for details.
</address>
</body>
</html>
"""))
def post():
form = cgi.FieldStorage()
form.__call__ = lambda s: form[s].value
if not form.has_key('data'):
error('Form must have key "data".')
uridata = urllib.quote(form('data'))
data('/' + uridata)
def data(path):
# path = REQUEST_URI[5:] # len(SCRIPT_NAME.rsplit('/', 1)[0]):]
if path.startswith('/'):
path = path[1:]
if ',' in path:
mime, uridata = path.split(',', 1)
else: mime, uridata = 'text/html', path
if mime.endswith(';base64'):
import base64
mime = mime[:-7]
uridata = base64.b64decode(uridata)
if mime not in allowed:
uridata = mime + ',' + uridata
mime = 'text/html'
# error('MIME type "%s" is not allowed.' % mime)
import urllib
# @@ Should probably do this above
uridata = urllib.unquote(uridata)
if (REQUEST_METHOD == 'GET') and (len(uridata) >= 2048):
error('Data length must be less than 2048 bytes.')
elif (REQUEST_METHOD == 'POST') and (len(uridata) >= 51200):
error('Data length must be less than 51,200 bytes.')
ok(mime, uridata)
def main():
import cgitb
cgitb.enable()
if REQUEST_METHOD == 'GET':
if QUERY_STRING: query()
elif PATH_INFO == '/': homepage()
elif not PATH_INFO:
redirect(REQUEST_URI + '/')
else: data(PATH_INFO)
else: post()
if __name__=="__main__":
main()