]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/http-support.c
Merge changes from CUPS 1.5svn-r9641
[thirdparty/cups.git] / cups / http-support.c
index a2d227e531759d1d31a3205c9c0eae3d722c92a6..1d73f7d4887e8767cbfbb71ff56508a103a682aa 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-2011 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -36,6 +36,7 @@
  *   httpStatus()         - Return a short string describing a HTTP status code.
  *   _cups_hstrerror()    - hstrerror() emulation function for Solaris and
  *                          others...
+ *   _httpDecodeURI()     - Percent-decode a HTTP request URI.
  *   _httpEncodeURI()     - Percent-encode a HTTP request URI.
  *   _httpResolveURI()    - Resolve a DNS-SD URI.
  *   http_copy_decode()   - Copy and decode a URI.
  * 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 +114,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,
@@ -292,7 +298,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)
@@ -726,7 +732,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 +741,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 +755,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 +768,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);
 }
@@ -915,7 +921,9 @@ httpSeparateURI(
 
     for (ptr = scheme, end = scheme + schemelen - 1;
          *uri && *uri != ':' && ptr < end;)
-      if (isalnum(*uri & 255) || *uri == '-' || *uri == '+' || *uri == '.')
+      if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                 "abcdefghijklmnopqrstuvwxyz"
+                "0123456789-+.", *uri) != NULL)
         *ptr++ = *uri++;
       else
         break;
@@ -939,7 +947,7 @@ httpSeparateURI(
     *port = 80;
   else if (!strcmp(scheme, "https"))
     *port = 443;
-  else if (!strcmp(scheme, "ipp"))
+  else if (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps"))
     *port = 631;
   else if (!strcasecmp(scheme, "lpd"))
     *port = 515;
@@ -1088,6 +1096,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 +1217,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 +1247,15 @@ 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;
+    case HTTP_PKI_ERROR :
+        s = _("SSL/TLS Negotiation Error");
+       break;
+    case HTTP_WEBIF_DISABLED :
+        s = _("Web Interface is Disabled");
+       break;
 
     default :
         s = _("Unknown");
@@ -1268,6 +1292,22 @@ _cups_hstrerror(int error)               /* I - Error number */
 #endif /* !HAVE_HSTRERROR */
 
 
+/*
+ * '_httpDecodeURI()' - Percent-decode a HTTP request URI.
+ */
+
+char *                                 /* O - Decoded URI or NULL on error */
+_httpDecodeURI(char       *dst,                /* I - Destination buffer */
+               const char *src,                /* I - Source URI */
+              size_t     dstsize)      /* I - Size of destination buffer */
+{
+  if (http_copy_decode(dst, src, (int)dstsize, NULL, 1))
+    return (dst);
+  else
+    return (NULL);
+}
+
+
 /*
  * '_httpEncodeURI()' - Percent-encode a HTTP request URI.
  */
@@ -1291,7 +1331,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 +1343,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 +1363,11 @@ _httpResolveURI(
                      sizeof(resource)) < HTTP_URI_OK)
 #endif /* DEBUG */
   {
-    if (log)
-      _cupsLangPrintf(stderr, _("Bad device URI \"%s\"!\n"), uri);
+    if (logit)
+      _cupsLangPrintFilter(stderr, "ERROR", _("Bad device-uri \"%s\"."), 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 +1378,26 @@ _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? */
+                       offline = 0;    /* offline-report state set? */
     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 +1418,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 +1436,125 @@ _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)
+           _cupsLangPrintFilter(stderr, "INFO", _("Looking for printer."));
+
+        /*
+         * 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;
+           }
+
+          /*
+           * If it hasn't resolved within 5 seconds set the offline-report
+           * printer-state-reason...
+           */
+
+           if (logit && offline == 0 && time(NULL) > (start_time + 5))
+           {
+             fputs("STATE: +offline-report\n", stderr);
+             offline = 1;
+           }
+         }
+         else
+         {
+           if (DNSServiceProcessResult(ref) == kDNSServiceErr_NoError)
+           {
+             uri = resolved_uri;
+             break;
+           }
+         }
+       }
+
+       if (domainsent)
+         DNSServiceRefDeallocate(domainref);
+
+       DNSServiceRefDeallocate(localref);
+      }
 
       DNSServiceRefDeallocate(ref);
     }
-    else
-      uri = NULL;
 
-    if (log)
-      fputs("STATE: -connecting-to-device\n", stderr);
+    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,offline-report\n", stderr);
+    }
 
 #else
    /*
@@ -1420,11 +1564,11 @@ _httpResolveURI(
     uri = NULL;
 #endif /* HAVE_DNSSD */
 
-    if (log && !uri)
-      _cupsLangPuts(stderr, _("Unable to find printer!\n"));
+    if (logit && !uri)
+      _cupsLangPrintFilter(stderr, "ERROR", _("Unable to find printer."));
   }
 
-  DEBUG_printf(("_httpResolveURI: Returning \"%s\"\n", uri));
+  DEBUG_printf(("5_httpResolveURI: Returning \"%s\"", uri));
 
   return (uri);
 }
@@ -1552,7 +1696,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 +1716,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 +1726,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 +1762,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 */