]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/request.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / request.c
index 4839bd3f1ee6de000cab2a00fd8133d86014d479..5e80fd645f60b7b1e081cc76883181fdfa1a91e7 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: request.c 5362 2006-03-31 15:26:12Z mike $"
+ * "$Id: request.c 6506 2007-05-03 18:12:35Z mike $"
  *
  *   IPP utilities for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 1997-2006 by Easy Software Products.
+ *   Copyright 1997-2007 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Easy Software Products and are protected by Federal
@@ -45,6 +45,9 @@
 #else
 #  include <unistd.h>
 #endif /* WIN32 || __EMX__ */
+#ifndef O_BINARY
+#  define O_BINARY 0
+#endif /* O_BINARY */
 
 
 /*
@@ -60,16 +63,71 @@ cupsDoFileRequest(http_t     *http, /* I - HTTP connection to server */
                   ipp_t      *request, /* I - IPP request */
                   const char *resource,        /* I - HTTP resource for POST */
                  const char *filename) /* I - File to send or NULL for none */
+{
+  ipp_t                *response;              /* IPP response data */
+  int          infile;                 /* Input file */
+
+
+  if (filename)
+  {
+    if ((infile = open(filename, O_RDONLY | O_BINARY)) < 0)
+    {
+     /*
+      * Can't get file information!
+      */
+
+      _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
+                    strerror(errno));
+
+      ippDelete(request);
+
+      return (NULL);
+    }
+  }
+  else
+    infile = -1;
+
+  response = cupsDoIORequest(http, request, resource, infile, -1);
+
+  if (infile >= 0)
+    close(infile);
+
+  return (response);
+}
+
+
+/*
+ * 'cupsDoIORequest()' - Do an IPP request with file descriptors.
+ *
+ * This function sends the IPP request to the specified server, retrying
+ * and authenticating as necessary.  The request is freed with ippDelete()
+ * after receiving a valid IPP response.
+ *
+ * If "infile" is a valid file descriptor, cupsDoIORequest() copies
+ * all of the data from the file after the IPP request message.
+ *
+ * If "outfile" is a valid file descriptor, cupsDoIORequest() copies
+ * all of the data after the IPP response message to the file.
+ *
+ * @since CUPS 1.3@
+ */
+
+ipp_t *                                        /* O - Response data */
+cupsDoIORequest(http_t     *http,      /* I - HTTP connection to server */
+                ipp_t      *request,   /* I - IPP request */
+                const char *resource,  /* I - HTTP resource for POST */
+               int        infile,      /* I - File to read from or -1 for none */
+               int        outfile)     /* I - File to write to or -1 for none */
 {
   ipp_t                *response;              /* IPP response data */
   size_t       length;                 /* Content-Length value */
   http_status_t        status;                 /* Status of HTTP request */
   int          got_status;             /* Did we get the status? */
   ipp_state_t  state;                  /* State of IPP processing */
-  FILE         *file;                  /* File to send */
   struct stat  fileinfo;               /* File information */
   int          bytes;                  /* Number of bytes read/written */
-  char         buffer[65536];          /* Output buffer */
+  char         buffer[32768];          /* Output buffer */
+  http_status_t        expect;                 /* Expect: header to use */
 
 
   DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n",
@@ -90,16 +148,16 @@ cupsDoFileRequest(http_t     *http,        /* I - HTTP connection to server */
   * See if we have a file to send...
   */
 
-  if (filename != NULL)
+  if (infile >= 0)
   {
-    if (stat(filename, &fileinfo))
+    if (fstat(infile, &fileinfo))
     {
      /*
       * Can't get file information!
       */
 
       _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
-                     strerror(errno));
+                    strerror(errno));
 
       ippDelete(request);
 
@@ -118,27 +176,24 @@ cupsDoFileRequest(http_t     *http,       /* I - HTTP connection to server */
 
       ippDelete(request);
 
-      _cupsSetError(IPP_NOT_POSSIBLE, NULL);
+      _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR));
 
       return (NULL);
     }
+  }
 
-    if ((file = fopen(filename, "rb")) == NULL)
-    {
-     /*
-      * Can't open file!
-      */
-
-      _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
-                     strerror(errno));
-
-      ippDelete(request);
+#ifdef HAVE_SSL
+ /*
+  * See if we have an auth-info attribute and are communicating over
+  * a non-local link.  If so, encrypt the link so that we can pass
+  * the authentication information securely...
+  */
 
-      return (NULL);
-    }
-  }
-  else
-    file = NULL;
+  if (ippFindAttribute(request, "auth-info", IPP_TAG_TEXT) &&
+      !httpAddrLocalhost(http->hostaddr) && !http->tls &&
+      httpEncryption(http, HTTP_ENCRYPT_REQUIRED))
+    return (NULL);
+#endif /* HAVE_SSL */
 
  /*
   * Loop until we can send the request without authorization problems.
@@ -146,6 +201,7 @@ cupsDoFileRequest(http_t     *http, /* I - HTTP connection to server */
 
   response = NULL;
   status   = HTTP_ERROR;
+  expect   = HTTP_CONTINUE;
 
   while (response == NULL)
   {
@@ -156,14 +212,21 @@ cupsDoFileRequest(http_t     *http,       /* I - HTTP connection to server */
     */
 
     length = ippLength(request);
-    if (filename)
+    if (infile >= 0)
+    {
+#ifndef WIN32
+      if (!S_ISREG(fileinfo.st_mode))
+        length = 0;                    /* Chunk when piping */
+      else
+#endif /* !WIN32 */
       length += fileinfo.st_size;
+    }
 
     httpClearFields(http);
     httpSetLength(http, length);
     httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
     httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring);
-    httpSetExpect(http, HTTP_CONTINUE);
+    httpSetExpect(http, expect);
 
     DEBUG_printf(("cupsDoFileRequest: authstring=\"%s\"\n", http->authstring));
 
@@ -217,7 +280,7 @@ cupsDoFileRequest(http_t     *http, /* I - HTTP connection to server */
     else if (httpCheck(http))
       status = httpUpdate(http);
 
-    if (status == HTTP_CONTINUE && state == IPP_DATA && filename)
+    if (status == HTTP_CONTINUE && state == IPP_DATA && infile >= 0)
     {
       DEBUG_puts("cupsDoFileRequest: file write...");
 
@@ -225,9 +288,12 @@ cupsDoFileRequest(http_t     *http,        /* I - HTTP connection to server */
       * Send the file...
       */
 
-      rewind(file);
+#ifndef WIN32
+      if (S_ISREG(fileinfo.st_mode))
+#endif /* WIN32 */
+      lseek(infile, 0, SEEK_SET);
 
-      while ((bytes = (int)fread(buffer, 1, sizeof(buffer), file)) > 0)
+      while ((bytes = (int)read(infile, buffer, sizeof(buffer))) > 0)
       {
        if (httpCheck(http))
        {
@@ -278,10 +344,15 @@ cupsDoFileRequest(http_t     *http,       /* I - HTTP connection to server */
     }
     else if (status == HTTP_ERROR)
     {
+      DEBUG_printf(("cupsDoFileRequest: http->error=%d (%s)\n", http->error,
+                    strerror(http->error)));
+
 #ifdef WIN32
-      if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH)
+      if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH &&
+          http->error != WSAETIMEDOUT)
 #else
-      if (http->error != ENETDOWN && http->error != ENETUNREACH)
+      if (http->error != ENETDOWN && http->error != ENETUNREACH &&
+          http->error != ETIMEDOUT)
 #endif /* WIN32 */
         continue;
       else
@@ -307,6 +378,14 @@ cupsDoFileRequest(http_t     *http,        /* I - HTTP connection to server */
       continue;
     }
 #endif /* HAVE_SSL */
+    else if (status == HTTP_EXPECTATION_FAILED)
+    {
+     /*
+      * Don't try using the Expect: header the next time around...
+      */
+
+      expect = (http_status_t)0;
+    }
     else if (status != HTTP_OK)
     {
       DEBUG_printf(("cupsDoFileRequest: error %d...\n", status));
@@ -328,7 +407,11 @@ cupsDoFileRequest(http_t     *http,        /* I - HTTP connection to server */
 
       response = ippNew();
 
-      if (ippRead(http, response) == IPP_ERROR)
+      while ((state = ippRead(http, response)) != IPP_DATA)
+       if (state == IPP_ERROR)
+         break;
+
+      if (state == IPP_ERROR)
       {
        /*
         * Delete the response...
@@ -342,21 +425,26 @@ cupsDoFileRequest(http_t     *http,       /* I - HTTP connection to server */
 
        break;
       }
-    }
-  }
-
- /*
-  * Close the file if needed...
-  */
-
-  if (filename != NULL)
-    fclose(file);
+      else if (outfile >= 0)
+      {
+       /*
+        * Write trailing data to file...
+       */
 
- /*
-  * Flush any remaining data...
-  */
+       while ((bytes = (int)httpRead2(http, buffer, sizeof(buffer))) > 0)
+         if (write(outfile, buffer, bytes) < bytes)
+           break;
+      }
+      else
+      {
+       /*
+        * Flush any remaining data...
+        */
 
-  httpFlush(http);
+        httpFlush(http);
+      }
+    }
+  }
 
  /*
   * Delete the original request and return the response...
@@ -463,5 +551,5 @@ _cupsSetError(ipp_status_t status,  /* I - IPP status code */
 
 
 /*
- * End of "$Id: request.c 5362 2006-03-31 15:26:12Z mike $".
+ * End of "$Id: request.c 6506 2007-05-03 18:12:35Z mike $".
  */