Index: server/lib/gutenbach/ipp/core/request.py
===================================================================
--- server/lib/gutenbach/ipp/core/request.py	(revision 793432f59cc3f6d9a34ba213d3911b9cb3b86b05)
+++ server/lib/gutenbach/ipp/core/request.py	(revision 7c143c9bd7d05dd5dd91e0b39c94e394574d93f8)
@@ -3,7 +3,9 @@
 from .constants import AttributeTags
 from .value import Value
+from .errors import ClientErrorBadRequest
 import sys
 import struct
 import logging
+import tempfile
 
 # initialize logger
@@ -83,4 +85,8 @@
         # that file handle
         if request is not None:
+            # minimum length is
+            if length < 9:
+                raise ClientErrorBadRequest("length (%d) < 9" % length)
+            
             # read the version-number (two signed chars)
             self.version        = struct.unpack('>bb', request.read(2))
@@ -105,5 +111,5 @@
             # read in the next byte
             next_byte = struct.unpack('>b', request.read(1))[0]
-            length -=1
+            length -= 1
             logger.debug("next byte : 0x%X" % next_byte)
 
@@ -179,7 +185,12 @@
             # once we hit the end-of-attributes tag, the only thing
             # left is the data, so go ahead and read all of it
-            assert length >= 0
-            self.data = request.read(length)
-            logger.debug("data : %s" % self.data)
+            if length < 0:
+                raise ClientErrorBadRequest("length (%d) < 0" % length)
+            
+            self.data = tempfile.TemporaryFile()
+            self.data.write(request.read(length))
+            self.data.seek(0)
+            
+            logger.debug("data : %d bytes" % length)
 
         # otherwise, just set the class variables to the keyword
@@ -228,12 +239,6 @@
         end_of_attributes_tag = struct.pack('>b', AttributeTags.END)
 
-        # convert the data to binary
-        if self.data is not None:
-            data = ''.join([struct.pack('>b', x) for x in self.data])
-        else:
-            data = ''
-
         # append everything together and return it
-        return preattributes + attribute_groups + end_of_attributes_tag + data
+        return preattributes + attribute_groups + end_of_attributes_tag, self.data
 
     def __repr__(self):
Index: server/lib/gutenbach/server/printer.py
===================================================================
--- server/lib/gutenbach/server/printer.py	(revision ee8e6d08f0bd530f50e1298fc1b78a5923e5eb10)
+++ server/lib/gutenbach/server/printer.py	(revision 7c143c9bd7d05dd5dd91e0b39c94e394574d93f8)
@@ -67,5 +67,6 @@
 	self.jobs = {}
 
-	self._next_jobid = 0
+        # cups ignores jobs with id 0, so we have to start at 1
+	self._next_jobid = 1 
 
     def __getattr__(self, attr):
@@ -218,5 +219,4 @@
         self.jobs[job_id] = job
         self.active_jobs.append(job_id)
-        print self.active_jobs
         return job
 
Index: server/lib/gutenbach/server/requests.py
===================================================================
--- server/lib/gutenbach/server/requests.py	(revision ee8e6d08f0bd530f50e1298fc1b78a5923e5eb10)
+++ server/lib/gutenbach/server/requests.py	(revision 7c143c9bd7d05dd5dd91e0b39c94e394574d93f8)
@@ -41,5 +41,4 @@
 
     def __init__(self):
-        print "init"
         self.printers = {
             "test": GutenbachPrinter(name="test")
@@ -89,5 +88,5 @@
         # actually get the handler
         handler = getattr(self, handler_name)
-        logger.info("Handling request of type '%s'" % handler_name)
+        logger.info("request is '%s'" % handler_name)
 
         # try to handle the request
@@ -116,5 +115,5 @@
 
     def unknown_operation(self, request, response):
-        logger.warning("Received unknown operation 0x%x" % request.operation_id)
+        logger.warning("unknown operation 0x%x" % request.operation_id)
         response = make_empty_response(request)
         response.operation_id = ipp.StatusCodes.OPERATION_NOT_SUPPORTED
Index: server/lib/gutenbach/server/server.py
===================================================================
--- server/lib/gutenbach/server/server.py	(revision ee8e6d08f0bd530f50e1298fc1b78a5923e5eb10)
+++ server/lib/gutenbach/server/server.py	(revision 7c143c9bd7d05dd5dd91e0b39c94e394574d93f8)
@@ -5,4 +5,5 @@
 import sys
 import traceback
+import tempfile
 
 # initialize logger
@@ -13,33 +14,73 @@
 
 class GutenbachIPPServer(BaseHTTPServer.BaseHTTPRequestHandler):
+    def send_continue(self):
+        self.send_response(100, "continue")
+        self.send_header("Content-Type", "application/ipp")
+        self.end_headers()
+
+    def send_ok(self, response):
+        logger.debug(repr(response))
+        binary, data_file = response.packed_value
+            
+        self.send_response(200, "ok")
+        self.send_header("Content-Type", "application/ipp")
+        self.send_header("Connection", "close")
+        self.end_headers()
+        
+        self.wfile.write(binary)
+        if data_file is not None:
+            data = data_file.read(1024)
+            while data != '':
+                self.wfile.write(data)
+                data = data_file.read(1024)
+
+    def log_request(self, code=0, size=0):
+        logger.info("response (%s)" % code)
+
+    def log_message(self, fmt, *args):
+        logger.info(fmt % args)
+
+    def read_chunks(self):
+        size = sys.maxint
+        totalsize = 0
+
+        with tempfile.SpooledTemporaryFile() as tmp:
+            while size > 0:
+                a, b = self.rfile.read(2)
+                size = a + b
+                while not (a == "\r" and b == "\n"):
+                    a = b
+                    b = self.rfile.read(1)
+                    size += b
+                size = int(size[:-2], base=16)
+                totalsize += size
+                chunk = self.rfile.read(size)
+                clrf = self.rfile.read(2)
+                assert clrf == "\r\n"
+                tmp.write(chunk)
+
+            tmp.seek(0)
+            request = ipp.Request(request=tmp, length=totalsize)
+
+        return request
+                
     def do_POST(self):
-        # Receive a request
         length = int(self.headers.getheader('content-length', 0))
-        if length == 0:
-            logger.warning("content-length == 0")
-            return
-        request = ipp.Request(request=self.rfile, length=length)
+        expect = self.headers.getheader('expect', None)
+        encoding = self.headers.getheader('transfer-encoding', None)
+
+        logger.info("request %s (%d bytes)" % (self.command, length))
+        logger.debug(str(self.headers))
+
+        # Parse the request
+        if length == 0 and encoding == "chunked":
+            request = self.read_chunks()
+        else:
+            request = ipp.Request(request=self.rfile, length=length)
 
         # Get the handler and pass it the request and response
         # objects.  It will fill in values for the response object or
         # throw a fatal error.
-        logger.debug("Received request: %s" % repr(request))
-        try:
-            response = handler.handle(request)
-        except:
-            logger.fatal(traceback.format_exc())
-            sys.exit(1)
-
-        # Send the response across HTTP
-        logger.debug("Sending response: %s" % repr(response))
-        try:
-            binary = response.packed_value
-        except:
-            logger.fatal(traceback.format_exc())
-            sys.exit(1)
-            
-        self.send_response(200, "Gutenbach IPP Response")
-        self.send_header("Content-Type", "application/ipp")
-        self.send_header("Connection", "close")
-        self.end_headers()
-        self.wfile.write(binary)
+        logger.debug("request: %s" % repr(request))
+        response = handler.handle(request)
+        self.send_ok(response)
