Index: trunk/bin/bletchley-analyze
===================================================================
--- trunk/bin/bletchley-analyze	(revision 39)
+++ trunk/bin/bletchley-analyze	(revision 40)
@@ -1,5 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
-# Requires Python 2.7+
+# Requires Python 3+
 
 '''
@@ -54,9 +54,9 @@
     sys.exit(0)
 
-input_file = sys.stdin
+input_file = sys.stdin.buffer
 if options.input_file is not None:
-    input_file = file(options.input_file, 'rb')
+    input_file = open(options.input_file, 'rb')
 
-blobs = input_file.read().rstrip('\n').replace('\r', '').split('\n')
+blobs = input_file.read().rstrip(b'\n').replace(b'\r', b'').split(b'\n')
 #print(repr(blobs))
 
@@ -81,9 +81,9 @@
     line_size = 64
     group_size *= 2 # two hex digits per byte
-    hex_blobs = map(binascii.b2a_hex, blobs)
+    hex_blobs = [binascii.b2a_hex(b) for b in blobs]
     color_map = buffertools.blockWiseColorMap(group_size, hex_blobs)
 
     for k in range(0,len(hex_blobs)):
-        hex = hex_blobs[k]
+        hex = hex_blobs[k].decode()
         
         for i in range(0,len(hex),line_size):
@@ -98,5 +98,5 @@
        
             line += '| '
-            line += repr(blobs[k][i/2:(i+line_size)/2])
+            line += repr(blobs[k][i//2:(i+line_size)//2])
         
             print(line)
@@ -136,5 +136,4 @@
         encoding = specified_encodings.pop(0)
 
-
     blobs_to_print = blobs[:options.output_lines]
     print('First %d Values:' % len(blobs_to_print))
Index: trunk/bin/bletchley-decode
===================================================================
--- trunk/bin/bletchley-decode	(revision 39)
+++ trunk/bin/bletchley-decode	(revision 40)
@@ -1,5 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
-# Requires Python 2.7+
+# Requires Python 3+
 
 '''
@@ -45,10 +45,10 @@
     sys.exit(0)
 
-input_file = sys.stdin
+input_file = sys.stdin.buffer
 if options.input_file is not None:
-    input_file = file(options.input_file, 'rb')
+    input_file = open(options.input_file, 'rb')
 
-blob = input_file.read()
+blob = input_file.read().rstrip(b'\r\n')
 
 specified_encodings = options.encoding_chain.split(',')
-sys.stdout.write(blobtools.decodeChain(specified_encodings, blob))
+sys.stdout.buffer.write(blobtools.decodeChain(specified_encodings, blob))
Index: trunk/bin/bletchley-encode
===================================================================
--- trunk/bin/bletchley-encode	(revision 39)
+++ trunk/bin/bletchley-encode	(revision 40)
@@ -1,5 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
-# Requires Python 2.7+
+# Requires Python 3+
 
 '''
@@ -46,5 +46,5 @@
     sys.exit(0)
 
-input_file = sys.stdin
+input_file = sys.stdin.buffer
 if options.input_file is not None:
     input_file = file(options.input_file, 'rb')
@@ -55,4 +55,4 @@
 specified_encodings.reverse()
 # XXX: report invalid encodings
-sys.stdout.write(blobtools.encodeChain(specified_encodings, blob))
-sys.stdout.write('\n')
+sys.stdout.buffer.write(blobtools.encodeChain(specified_encodings, blob))
+sys.stdout.buffer.write(b'\n')
Index: trunk/bin/bletchley-http2py
===================================================================
--- trunk/bin/bletchley-http2py	(revision 39)
+++ trunk/bin/bletchley-http2py	(revision 40)
@@ -1,10 +1,11 @@
-#!/usr/bin/env python
-
-# Requires Python 2.7+
+#!/usr/bin/env python3
+
+# Requires Python 3+
 
 '''
-This script reads a raw HTTP request from stdin and writes to stdout
-a Python script.  The generated script sends the same (or a very similar) 
-request using the httplib/http.client libraries.
+This script reads a raw HTTP request and writes to stdout a Python
+script.  The generated script sends the same (or a very similar) 
+request using the standard httplib/http.client library, or optionally
+using the more user friendly python-requests library.
 
 Certainly if you have a raw request, you could simply send it via TCP
@@ -34,10 +35,4 @@
 import sys
 import argparse
-try:
-    from lxml import etree
-except:
-    sys.stderr.write('ERROR: Could not import lxml module.  Ensure it is installed.\n')
-    sys.stderr.write('       Under Debian, the package name is "python-lxml"\n.')
-    sys.exit(1)
 
 parser = argparse.ArgumentParser(
@@ -48,19 +43,12 @@
     ' For more information, see: http://code.google.com/p/bletchley/wiki/Overview')
 parser.add_argument(
-    'requestfile', type=file, nargs='?', default=sys.stdin, 
+    'requestfile', type=open, nargs='?', default=sys.stdin, 
     help='A file containing an HTTP request.  Defaults to stdin if omitted.')
 parser.add_argument(
-    '--burp', action='store_true', help='Input file is a XML export from Burp.'
-    ' (First request in file is used.)')
+    '--requests', action='store_true', help='Generate a script that uses the'
+    ' python-requests module rather than httplib/http.client (experimental).')
+
 args = parser.parse_args()
-
-if args.burp:
-    safe_parser = etree.ETCompatXMLParser(resolve_entities=False)
-    root = etree.parse(args.requestfile, parser=safe_parser)
-    input_req = root.xpath('/items/item/request')[0].text
-    root = None
-else:
-    input_req = args.requestfile.read()
-
+input_req = args.requestfile.read()
 
 
@@ -79,4 +67,5 @@
 port = 80
 use_ssl = False
+protocol = 'http'
 
 headers = []
@@ -85,5 +74,5 @@
         break
     # Handle header line continuations
-    if l[0] == '\t':
+    if l[0] in ' \t':
         if len(headers) == 0:
             continue
@@ -108,20 +97,80 @@
             if port == 443:
                 use_ssl = True
+                protocol = 'https'
         else:
             host = value
 
 
-print('''#!/usr/bin/env python
+formatted_body = '\n            '.join([repr(body[i:i+40].encode()) for i in range(0,len(body),40)])
+if formatted_body == '':
+    formatted_body = "b''"
+
+
+if args.requests:
+    print('''#!/usr/bin/env python3
 
 import sys
-# function with either Python 2.7 or 3.x
 try:
-    import http.client as httpc
+    import requests
 except:
-    import httplib as httpc
+    sys.stderr.write('ERROR: Could not import requests module.  Ensure it is installed.\\n')
+    sys.stderr.write('       Under Debian, the package name is "python3-requests"\\n.')
+    sys.exit(1)
+
+
+# TODO: ensure the host, port, and SSL settings are correct.
+host = %s
+port = %s
+protocol = %s
+''' % (repr(host),repr(port),repr(protocol)))
+
+    headers = dict(headers)
+    # XXX: We don't currently support exactly formatted header
+    #      continuations with python requests, but this should be
+    #      semantically equivalent.
+    for h in headers.keys():
+        headers[h] = ' '.join(headers[h])
+
+    print('''
+session = requests.Session()
+# TODO: use "data" to supply any parameters to be included in the request
+def sendRequest(session, data=None):
+    method = %s
+    path = %s
+    headers = %s
+    url = "%%s://%%s:%%d%%s" %% (protocol,host,port,path)
+    body = (%s)
+
+    return session.request(method, url, headers=headers, data=body)
+    ''' % (repr(method), repr(path), repr(headers), formatted_body))
+
+    print('''    
+
+def fetch(data):
+    global session
+    ret_val = None
+
+    # TODO: customize code here to retrieve what you need from the response(s)
+    # For information on the response object's interface, see:
+    #   http://docs.python-requests.org/en/latest/api/#requests.Response
+    response = sendRequest(session, data)
+    print(response.headers)
+    print(repr(response.content))
+
+    return ret_val
+
+data = ''
+fetch(data)
 ''')
 
 
-print('''
+
+else:
+    print('''#!/usr/bin/env python3
+
+import sys
+import http.client as httpc
+
+
 # TODO: ensure the host, port, and SSL settings are correct.
 host = %s
@@ -130,9 +179,5 @@
 ''' % (repr(host),repr(port),repr(use_ssl)))
 
-chunked_body = '\n            '.join([repr(body[i:i+40]) for i in range(0,len(body),40)])
-if chunked_body == '':
-    chunked_body = "''"
-
-print('''
+    print('''
 # TODO: use "data" to supply any parameters to be included in the request
 def sendRequest(connection, data=None):
@@ -142,14 +187,14 @@
     
     connection.putrequest(method, path)
-    ''' % (repr(method), repr(path), chunked_body))
-
-for name,values in headers:
-    if len(values) > 1:
-        continuations = ','.join([repr(v) for v in values[1:]])
-        print('''    connection.putheader(%s, %s, %s)''' % (repr(name),repr(values[0]),continuations))
-    else:
-        print('''    connection.putheader(%s, %s)''' % (repr(name),repr(values[0])))
-
-print('''    
+    ''' % (repr(method), repr(path), formatted_body))
+
+    for name,values in headers:
+        if len(values) > 1:
+            continuations = ','.join([repr(v) for v in values[1:]])
+            print('''    connection.putheader(%s, %s, %s)''' % (repr(name),repr(values[0]),continuations))
+        else:
+            print('''    connection.putheader(%s, %s)''' % (repr(name),repr(values[0])))
+
+    print('''    
     if len(body) > 0:
         connection.putheader('Content-Length', len(body))
@@ -161,5 +206,4 @@
 
 def newConnection():
-    connection = None
     if use_ssl:
         return httpc.HTTPSConnection(host, port)
