diff --git a/modules/printbackends/cups/gtkcupsutils.c b/modules/printbackends/cups/gtkcupsutils.c
index d7c5b7c..4ebbf1c 100644
--- a/modules/printbackends/cups/gtkcupsutils.c
+++ b/modules/printbackends/cups/gtkcupsutils.c
@@ -253,34 +253,43 @@ gtk_cups_request_free (GtkCupsRequest *request)
 }
 
 gboolean 
-gtk_cups_request_read_write (GtkCupsRequest *request)
+gtk_cups_request_read_write (GtkCupsRequest *request, gboolean connect_only)
 {
-  if (request->type == GTK_CUPS_POST)
-    post_states[request->state] (request);
-  else if (request->type == GTK_CUPS_GET)
-    get_states[request->state] (request);
+  if (connect_only && request->state != GTK_CUPS_REQUEST_START)
+    return FALSE;
 
-  if (request->attempts > _GTK_CUPS_MAX_ATTEMPTS && 
-      request->state != GTK_CUPS_REQUEST_DONE)
+  do
     {
-      /* TODO: should add a status or error code for too many failed attempts */
-      gtk_cups_result_set_error (request->result, 
-                                 GTK_CUPS_ERROR_GENERAL,
-                                 0,
-                                 0, 
-                                 "Too many failed attempts");
+      if (request->type == GTK_CUPS_POST)
+        post_states[request->state] (request);
+      else if (request->type == GTK_CUPS_GET)
+        get_states[request->state] (request);
 
-      request->state = GTK_CUPS_REQUEST_DONE;
-      request->poll_state = GTK_CUPS_HTTP_IDLE;
-    }
-    
-  if (request->state == GTK_CUPS_REQUEST_DONE)
-    {
-      request->poll_state = GTK_CUPS_HTTP_IDLE;
-      return TRUE;
+      if (request->attempts > _GTK_CUPS_MAX_ATTEMPTS &&
+          request->state != GTK_CUPS_REQUEST_DONE)
+        {
+          /* TODO: should add a status or error code for too many failed attempts */
+          gtk_cups_result_set_error (request->result,
+                                     GTK_CUPS_ERROR_GENERAL,
+                                     0,
+                                     0,
+                                     "Too many failed attempts");
+
+          request->state = GTK_CUPS_REQUEST_DONE;
+        }
+
+      if (request->state == GTK_CUPS_REQUEST_DONE)
+        {
+          request->poll_state = GTK_CUPS_HTTP_IDLE;
+          return TRUE;
+        }
     }
-  else
-    return FALSE;
+  /* We need to recheck using httpCheck if the poll_state is read, because
+   * Cups has an internal read buffer. And if this buffer is filled, we may
+   * never get a poll event again. */
+  while (request->poll_state == GTK_CUPS_HTTP_READ && request->http && httpCheck(request->http));
+
+  return FALSE;
 }
 
 GtkCupsPollState 
@@ -643,6 +652,7 @@ static void
 _connect (GtkCupsRequest *request)
 {
   request->poll_state = GTK_CUPS_HTTP_IDLE;
+  request->bytes_received = 0;
 
   if (request->http == NULL)
     {
@@ -1404,18 +1414,11 @@ _get_read_data (GtkCupsRequest *request)
 #else
   bytes = httpRead (request->http, buffer, sizeof (buffer));
 #endif /* HAVE_CUPS_API_1_2 */
+  request->bytes_received += bytes;
 
   GTK_NOTE (PRINTING,
             g_print ("CUPS Backend: %"G_GSIZE_FORMAT" bytes read\n", bytes));
-  
-  if (bytes == 0)
-    {
-      request->state = GTK_CUPS_GET_DONE;
-      request->poll_state = GTK_CUPS_HTTP_IDLE;
 
-      return;
-    }
-  
   io_status =
     g_io_channel_write_chars (request->data_io, 
                               buffer, 
@@ -1435,6 +1438,19 @@ _get_read_data (GtkCupsRequest *request)
                                  error->message);
       g_error_free (error);
     }
+
+  /* Stop if we do not expect any more data or EOF was received. */
+#if HAVE_CUPS_API_1_2
+  if (httpGetLength2 (request->http) <= request->bytes_received || bytes == 0)
+#else
+  if (httpGetLength (request->http) <= request->bytes_received || bytes == 0)
+#endif /* HAVE_CUPS_API_1_2 */
+    {
+      request->state = GTK_CUPS_GET_DONE;
+      request->poll_state = GTK_CUPS_HTTP_IDLE;
+
+      return;
+    }
 }
 
 gboolean
diff --git a/modules/printbackends/cups/gtkcupsutils.h b/modules/printbackends/cups/gtkcupsutils.h
index 2438b86..2adfc16 100644
--- a/modules/printbackends/cups/gtkcupsutils.h
+++ b/modules/printbackends/cups/gtkcupsutils.h
@@ -93,6 +93,7 @@ struct _GtkCupsRequest
 
   gint state;
   GtkCupsPollState poll_state;
+  guint64 bytes_received;
 
   gchar *password;
   gchar *username;
@@ -172,7 +173,8 @@ void                    gtk_cups_request_ipp_add_strings   (GtkCupsRequest     *
 const char            * gtk_cups_request_ipp_get_string    (GtkCupsRequest     *request,
 							    ipp_tag_t           tag,
 							    const char         *name);
-gboolean                gtk_cups_request_read_write        (GtkCupsRequest     *request);
+gboolean                gtk_cups_request_read_write        (GtkCupsRequest     *request,
+                                                            gboolean            connect_only);
 GtkCupsPollState        gtk_cups_request_get_poll_state    (GtkCupsRequest     *request);
 void                    gtk_cups_request_free              (GtkCupsRequest     *request);
 GtkCupsResult         * gtk_cups_request_get_result        (GtkCupsRequest     *request);
diff --git a/modules/printbackends/cups/gtkprintbackendcups.c b/modules/printbackends/cups/gtkprintbackendcups.c
index c7bcd6f..48dec9d 100644
--- a/modules/printbackends/cups/gtkprintbackendcups.c
+++ b/modules/printbackends/cups/gtkprintbackendcups.c
@@ -95,6 +95,7 @@ typedef struct
 
   http_t *http;
   GtkCupsRequest *request;
+  GtkCupsPollState poll_state;
   GPollFD *data_poll;
   GtkPrintBackendCups *backend;
   GtkPrintCupsResponseCallbackFunc callback;
@@ -930,11 +931,20 @@ cups_dispatch_add_poll (GSource *source)
 
   poll_state = gtk_cups_request_get_poll_state (dispatch->request);
 
+  /* Remove the old source if the poll state changed. */
+  if (poll_state != dispatch->poll_state && dispatch->data_poll != NULL)
+    {
+      g_source_remove_poll (source, dispatch->data_poll);
+      g_free (dispatch->data_poll);
+      dispatch->data_poll = NULL;
+    }
+
   if (dispatch->request->http != NULL)
     {
       if (dispatch->data_poll == NULL)
         {
 	  dispatch->data_poll = g_new0 (GPollFD, 1);
+	  dispatch->poll_state = poll_state;
 
 	  if (poll_state == GTK_CUPS_HTTP_READ)
 	    dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
@@ -1106,13 +1116,11 @@ cups_dispatch_watch_check (GSource *source)
 
   poll_state = gtk_cups_request_get_poll_state (dispatch->request);
 
-  cups_dispatch_add_poll (source);
-    
   if (poll_state != GTK_CUPS_HTTP_IDLE && !dispatch->request->need_password)
     if (!(dispatch->data_poll->revents & dispatch->data_poll->events)) 
        return FALSE;
   
-  result = gtk_cups_request_read_write (dispatch->request);
+  result = gtk_cups_request_read_write (dispatch->request, FALSE);
   if (result && dispatch->data_poll != NULL)
     {
       g_source_remove_poll (source, dispatch->data_poll);
@@ -1143,8 +1151,8 @@ cups_dispatch_watch_prepare (GSource *source,
             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
 
   *timeout_ = -1;
-  
-  result = gtk_cups_request_read_write (dispatch->request);
+
+  result = gtk_cups_request_read_write (dispatch->request, TRUE);
 
   cups_dispatch_add_poll (source);
 
@@ -1244,7 +1252,12 @@ cups_dispatch_watch_finalize (GSource *source)
       dispatch->backend = NULL;
     }
 
-  g_free (dispatch->data_poll);
+  if (dispatch->data_poll)
+    {
+      g_source_remove_poll (source, dispatch->data_poll);
+      g_free (dispatch->data_poll);
+      dispatch->data_poll = NULL;
+    }
 }
 
 static GSourceFuncs _cups_dispatch_watch_funcs = {
@@ -1273,6 +1286,7 @@ cups_request_execute (GtkPrintBackendCups              *print_backend,
 
   dispatch->request = request;
   dispatch->backend = g_object_ref (print_backend);
+  dispatch->poll_state = GTK_CUPS_HTTP_IDLE;
   dispatch->data_poll = NULL;
   dispatch->callback = NULL;
   dispatch->callback_data = NULL;
