]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/http-support.c
Merge changes from CUPS 1.5svn-r9198.
[thirdparty/cups.git] / cups / http-support.c
index 063756926e4c674f40769411d7d5860ed687f29a..5c1dce5d8544f20470529c7d1bd7d45526e69730 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: http-support.c 7952 2008-09-17 00:56:20Z mike $"
  *
- *   HTTP support routines for the Common UNIX Printing System (CUPS) scheduler.
+ *   HTTP support routines for CUPS.
  *
- *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
  * Include necessary headers...
  */
 
-#include "debug.h"
-#include "globals.h"
-#include <stdlib.h>
+#include "cups-private.h"
 #ifdef HAVE_DNSSD
 #  include <dns_sd.h>
+#  ifdef WIN32
+#    include <io.h>
+#  elif defined(HAVE_POLL)
+#    include <poll.h>
+#  else
+#    include <sys/select.h>
+#  endif /* WIN32 */
 #endif /* HAVE_DNSSD */
 
 
@@ -108,7 +113,7 @@ static char         *http_copy_encode(char *dst, const char *src,
                                          char *dstend, const char *reserved,
                                          const char *term, int encode);
 #ifdef HAVE_DNSSD
-static void            resolve_callback(DNSServiceRef sdRef,
+static void DNSSD_API  resolve_callback(DNSServiceRef sdRef,
                                         DNSServiceFlags flags,
                                         uint32_t interfaceIndex,
                                         DNSServiceErrorType errorCode,
@@ -129,7 +134,7 @@ static void         resolve_callback(DNSServiceRef sdRef,
  * place of traditional string functions whenever you need to create a
  * URI string.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 http_uri_status_t                      /* O - URI status */
@@ -292,7 +297,7 @@ httpAssembleURI(
       * Otherwise, just copy the host string...
       */
 
-      ptr = http_copy_encode(ptr, host, end, ":/?#[]@", NULL,
+      ptr = http_copy_encode(ptr, host, end, ":/?#[]@\\", NULL,
                              encoding & HTTP_URI_CODING_HOSTNAME);
 
       if (!ptr)
@@ -379,7 +384,7 @@ httpAssembleURI(
  * this function in place of traditional string functions whenever
  * you need to create a URI string.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 http_uri_status_t                      /* O - URI status */
@@ -459,7 +464,7 @@ httpDecode64(char       *out,               /* I - String to write to */
 /*
  * 'httpDecode64_2()' - Base64-decode a string.
  *
- * @since CUPS 1.1.21@
+ * @since CUPS 1.1.21/Mac OS X 10.4@
  */
 
 char *                                 /* O  - Decoded string */
@@ -578,7 +583,7 @@ httpEncode64(char       *out,               /* I - String to write to */
 /*
  * 'httpEncode64_2()' - Base64-encode a string.
  *
- * @since CUPS 1.1.21@
+ * @since CUPS 1.1.21/Mac OS X 10.4@
  */
 
 char *                                 /* O - Encoded string */
@@ -687,7 +692,7 @@ httpGetDateString(time_t t)         /* I - UNIX time */
 /*
  * 'httpGetDateString2()' - Get a formatted date/time string from a time value.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 const char *                           /* O - Date/time string */
@@ -726,7 +731,7 @@ httpGetDateTime(const char *s)              /* I - Date/time string */
                { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
 
 
-  DEBUG_printf(("httpGetDateTime(s=\"%s\")\n", s));
+  DEBUG_printf(("2httpGetDateTime(s=\"%s\")", s));
 
  /*
   * Extract the date and time from the formatted string...
@@ -735,8 +740,8 @@ httpGetDateTime(const char *s)              /* I - Date/time string */
   if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6)
     return (0);
 
-  DEBUG_printf(("    day=%d, mon=\"%s\", year=%d, hour=%d, min=%d, sec=%d\n",
-                day, mon, year, hour, min, sec));
+  DEBUG_printf(("4httpGetDateTime: day=%d, mon=\"%s\", year=%d, hour=%d, "
+                "min=%d, sec=%d", day, mon, year, hour, min, sec));
 
  /*
   * Convert the month name to a number from 0 to 11.
@@ -749,7 +754,7 @@ httpGetDateTime(const char *s)              /* I - Date/time string */
   if (i >= 12)
     return (0);
 
-  DEBUG_printf(("    i=%d\n", i));
+  DEBUG_printf(("4httpGetDateTime: i=%d", i));
 
  /*
   * Now convert the date and time to a UNIX time value in seconds since
@@ -762,14 +767,14 @@ httpGetDateTime(const char *s)            /* I - Date/time string */
   else
     days = normal_days[i] + day - 1;
 
-  DEBUG_printf(("    days=%d\n", days));
+  DEBUG_printf(("4httpGetDateTime: days=%d", days));
 
   days += (year - 1970) * 365 +                /* 365 days per year (normally) */
           ((year - 1) / 4 - 492) -     /* + leap days */
          ((year - 1) / 100 - 19) +     /* - 100 year days */
           ((year - 1) / 400 - 4);      /* + 400 year days */
 
-  DEBUG_printf(("    days=%d\n", days));
+  DEBUG_printf(("4httpGetDateTime: days=%d\n", days));
 
   return (days * 86400 + hour * 3600 + min * 60 + sec);
 }
@@ -804,7 +809,7 @@ httpSeparate(const char *uri,               /* I - Universal Resource Identifier */
  *
  * This function is deprecated; use the httpSeparateURI() function instead.
  *
- * @since CUPS 1.1.21@
+ * @since CUPS 1.1.21/Mac OS X 10.4@
  * @deprecated@
  */
 
@@ -829,7 +834,7 @@ httpSeparate2(const char *uri,              /* I - Universal Resource Identifier */
  * 'httpSeparateURI()' - Separate a Universal Resource Identifier into its
  *                       components.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 http_uri_status_t                      /* O - Result of separation */
@@ -1088,6 +1093,12 @@ httpSeparateURI(
       * Yes, collect the port number...
       */
 
+      if (!isdigit(uri[1] & 255))
+      {
+        *port = 0;
+        return (HTTP_URI_BAD_PORT);
+      }
+
       *port = strtol(uri + 1, (char **)&uri, 10);
 
       if (*uri != '/' && *uri)
@@ -1203,6 +1214,7 @@ httpStatus(http_status_t status)  /* I - HTTP status code */
         s = _("Bad Request");
        break;
     case HTTP_UNAUTHORIZED :
+    case HTTP_AUTHORIZATION_CANCELED :
         s = _("Unauthorized");
        break;
     case HTTP_FORBIDDEN :
@@ -1232,6 +1244,9 @@ httpStatus(http_status_t status)  /* I - HTTP status code */
     case HTTP_SERVICE_UNAVAILABLE :
         s = _("Service Unavailable");
        break;
+    case HTTP_SERVER_ERROR :
+        s = _("Internal Server Error");
+       break;
 
     default :
         s = _("Unknown");
@@ -1291,7 +1306,7 @@ _httpResolveURI(
     const char *uri,                   /* I - DNS-SD URI */
     char       *resolved_uri,          /* I - Buffer for resolved URI */
     size_t     resolved_size,          /* I - Size of URI buffer */
-    int        log)                    /* I - Log progress to stderr? */
+    int        logit)                  /* I - Log progress to stderr? */
 {
   char                 scheme[32],     /* URI components... */
                        userpass[256],
@@ -1303,8 +1318,8 @@ _httpResolveURI(
 #endif /* DEBUG */
 
 
-  DEBUG_printf(("_httpResolveURI(uri=\"%s\", resolved_uri=%p, "
-                "resolved_size=" CUPS_LLFMT ")\n", uri, resolved_uri,
+  DEBUG_printf(("4_httpResolveURI(uri=\"%s\", resolved_uri=%p, "
+                "resolved_size=" CUPS_LLFMT ")", uri, resolved_uri,
                CUPS_LLCAST resolved_size));
 
  /*
@@ -1323,11 +1338,11 @@ _httpResolveURI(
                      sizeof(resource)) < HTTP_URI_OK)
 #endif /* DEBUG */
   {
-    if (log)
-      _cupsLangPrintf(stderr, _("Bad device URI \"%s\"!\n"), uri);
+    if (logit)
+      _cupsLangPrintf(stderr, _("Bad device URI \"%s\"\n"), uri);
 
-    DEBUG_printf(("_httpResolveURI: httpSeparateURI returned %d!\n", status));
-    DEBUG_puts("_httpResolveURI: Returning NULL");
+    DEBUG_printf(("6_httpResolveURI: httpSeparateURI returned %d!", status));
+    DEBUG_puts("5_httpResolveURI: Returning NULL");
     return (NULL);
   }
 
@@ -1338,10 +1353,25 @@ _httpResolveURI(
   if (strstr(hostname, "._tcp"))
   {
 #ifdef HAVE_DNSSD
-    DNSServiceRef      ref;            /* DNS-SD service reference */
+#  ifdef WIN32
+#    pragma comment(lib, "dnssd.lib")
+#  endif /* WIN32 */
+    DNSServiceRef      ref,            /* DNS-SD master service reference */
+                       domainref,      /* DNS-SD service reference for domain */
+                       localref;       /* DNS-SD service reference for .local */
+    int                        domainsent = 0; /* Send the domain resolve? */
     char               *regtype,       /* Pointer to type in hostname */
                        *domain;        /* Pointer to domain in hostname */
     _http_uribuf_t     uribuf;         /* URI buffer */
+#ifdef HAVE_POLL
+    struct pollfd      polldata;       /* Polling data */
+#else /* select() */
+    fd_set             input_set;      /* Input set for select() */
+    struct timeval     stimeout;       /* Timeout value for select() */
+#endif /* HAVE_POLL */
+
+    if (logit)
+      fprintf(stderr, "DEBUG: Resolving \"%s\"...\n", hostname);
 
    /*
     * Separate the hostname into service name, registration type, and domain...
@@ -1362,14 +1392,10 @@ _httpResolveURI(
 
     if (regtype <= hostname)
     {
-      DEBUG_puts("_httpResolveURI: Bad hostname, returning NULL");
+      DEBUG_puts("5_httpResolveURI: Bad hostname, returning NULL");
       return (NULL);
     }
 
-    domain = regtype + strlen(regtype) - 1;
-    if (domain > regtype && *domain == '.')
-      *domain = '\0';
-
     for (domain = strchr(regtype, '.');
          domain;
         domain = strchr(domain + 1, '.'))
@@ -1384,33 +1410,114 @@ _httpResolveURI(
 
     resolved_uri[0] = '\0';
 
-    DEBUG_printf(("_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", "
+    DEBUG_printf(("6_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", "
                   "domain=\"%s\"\n", hostname, regtype, domain));
-    if (log)
+    if (logit)
     {
       fputs("STATE: +connecting-to-device\n", stderr);
-      fprintf(stderr, "DEBUG: Resolving %s, regtype=%s, domain=%s...\n",
-              hostname, regtype, domain);
-      _cupsLangPuts(stderr, _("INFO: Looking for printer...\n"));
+      fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"%s\", "
+                      "domain=\"local.\"...\n", hostname, regtype);
     }
 
-    if (DNSServiceResolve(&ref, 0, 0, hostname, regtype, domain,
-                         resolve_callback,
-                         &uribuf) == kDNSServiceErr_NoError)
+    uri = NULL;
+
+    if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError)
     {
-      if (DNSServiceProcessResult(ref) != kDNSServiceErr_NoError &&
-          resolved_uri[0])
-        uri = NULL;
-      else
-        uri = resolved_uri;
+      localref = ref;
+      if (DNSServiceResolve(&localref, kDNSServiceFlagsShareConnection, 0,
+                           hostname, regtype, "local.", resolve_callback,
+                           &uribuf) == kDNSServiceErr_NoError)
+      {
+       int     fds;                    /* Number of ready descriptors */
+       time_t  timeout,                /* Poll timeout */
+               start_time = time(NULL);/* Start time */
+
+       for (;;)
+       {
+         if (logit)
+           _cupsLangPuts(stderr, _("INFO: Looking for printer...\n"));
+
+        /*
+         * For the first minute, wakeup every 2 seconds to emit a
+         * "looking for printer" message...
+         */
+
+         timeout = (time(NULL) < (start_time + 60)) ? 2000 : -1;
+
+#ifdef HAVE_POLL
+         polldata.fd     = DNSServiceRefSockFD(ref);
+         polldata.events = POLLIN;
+
+         fds = poll(&polldata, 1, timeout);
+
+#else /* select() */
+         FD_ZERO(&input_set);
+         FD_SET(DNSServiceRefSockFD(ref), &input_set);
+
+         stimeout.tv_sec  = ((int)timeout) / 1000;
+         stimeout.tv_usec = ((int)(timeout) * 1000) % 1000000;
+
+         fds = select(DNSServiceRefSockFD(ref)+1, &input_set, NULL, NULL, 
+                      timeout < 0.0 ? NULL : &stimeout); 
+#endif /* HAVE_POLL */
+
+         if (fds < 0)
+         {
+           if (errno != EINTR && errno != EAGAIN)
+           {
+             DEBUG_printf(("5_httpResolveURI: poll error: %s", strerror(errno)));
+             break;
+           }
+         }
+         else if (fds == 0)
+         {
+          /*
+           * Wait 2 seconds for a response to the local resolve; if nothing
+           * comes in, do an additional domain resolution...
+           */
+
+           if (domainsent == 0 && strcasecmp(domain, "local."))
+           {
+             if (logit)
+               fprintf(stderr,
+                       "DEBUG: Resolving \"%s\", regtype=\"%s\", "
+                       "domain=\"%s\"...\n", hostname, regtype, domain);
+  
+             domainref = ref;
+             if (DNSServiceResolve(&domainref, kDNSServiceFlagsShareConnection, 0,
+                                   hostname, regtype, domain, resolve_callback,
+                                   &uribuf) == kDNSServiceErr_NoError)
+               domainsent = 1;
+           }
+         }
+         else
+         {
+           if (DNSServiceProcessResult(ref) == kDNSServiceErr_NoError)
+           {
+             uri = resolved_uri;
+             break;
+           }
+         }
+       }
+
+       if (domainsent)
+         DNSServiceRefDeallocate(domainref);
+
+       DNSServiceRefDeallocate(localref);
+      }
 
       DNSServiceRefDeallocate(ref);
     }
-    else
-      uri = NULL;
 
-    if (log)
+    if (logit)
+    {
+      if (uri)
+        fprintf(stderr, "DEBUG: Resolved as \"%s\"...\n", uri);
+      else
+        fputs("DEBUG: Unable to resolve URI\n", stderr);
+
       fputs("STATE: -connecting-to-device\n", stderr);
+    }
 
 #else
    /*
@@ -1420,11 +1527,11 @@ _httpResolveURI(
     uri = NULL;
 #endif /* HAVE_DNSSD */
 
-    if (log && !uri)
-      _cupsLangPuts(stderr, _("Unable to find printer!\n"));
+    if (logit && !uri)
+      _cupsLangPuts(stderr, _("Unable to find printer\n"));
   }
 
-  DEBUG_printf(("_httpResolveURI: Returning \"%s\"\n", uri));
+  DEBUG_printf(("5_httpResolveURI: Returning \"%s\"", uri));
 
   return (uri);
 }
@@ -1552,7 +1659,7 @@ http_copy_encode(char       *dst, /* O - Destination buffer */
  * 'resolve_callback()' - Build a device URI for the given service name.
  */
 
-static void
+static void DNSSD_API
 resolve_callback(
     DNSServiceRef       sdRef,         /* I - Service reference */
     DNSServiceFlags     flags,         /* I - Results flags */
@@ -1572,9 +1679,9 @@ resolve_callback(
   _http_uribuf_t       *uribuf;        /* URI buffer */
 
 
-  DEBUG_printf(("resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
+  DEBUG_printf(("7resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
                "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
-               "txtLen=%u, txtRecord=%p, context=%p)\n", sdRef, flags,
+               "txtLen=%u, txtRecord=%p, context=%p)", sdRef, flags,
                interfaceIndex, errorCode, fullName, hostTarget, port, txtLen,
                txtRecord, context));
 
@@ -1582,7 +1689,7 @@ resolve_callback(
   * Figure out the scheme from the full name...
   */
 
-  if (strstr(fullName, "._ipp"))
+  if (strstr(fullName, "._ipp") || strstr(fullName, "._fax-ipp"))
     scheme = "ipp";
   else if (strstr(fullName, "._printer."))
     scheme = "lpd";
@@ -1618,7 +1725,7 @@ resolve_callback(
   httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize, scheme,
                   NULL, hostTarget, ntohs(port), rp);
 
-  DEBUG_printf(("resolve_callback: Resolved URI is \"%s\"...\n",
+  DEBUG_printf(("8resolve_callback: Resolved URI is \"%s\"...",
                 uribuf->buffer));
 }
 #endif /* HAVE_DNSSD */