]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Merge HTTP and JSON changes from libcups v3, including httpConnectURI API.
authorMichael R Sweet <msweet@msweet.org>
Mon, 9 Sep 2024 20:49:18 +0000 (16:49 -0400)
committerMichael R Sweet <msweet@msweet.org>
Mon, 9 Sep 2024 20:49:18 +0000 (16:49 -0400)
cups/http.c
cups/http.h
cups/json.c

index 124530a9dff21af2a7660e7a68c3b265a9c67a9c..c0716f1dbf97c3df8ee1620def3ee8c93c14d678 100644 (file)
@@ -553,6 +553,114 @@ httpConnectEncrypt(
 }
 
 
+//
+// 'httpConnectURI()' - Connect to a HTTP service using a URI.
+//
+// This function creates a connection to a HTTP server.  The "uri" argument
+// specifies a "http", "https", "ipp", or "ipps" URI for the service.
+//
+// The resource path for the service is returned in the buffer pointed to by
+// the "resource" argument of size "rsize".
+//
+// The "msec" argument specifies how long to try to connect to the server or `0`
+// to just create an unconnected `http_t` object.  The "cancel" argument
+// specifies an integer variable that can be set to a non-zero value to cancel
+// the connection process.
+//
+// The "require_ca" argument specifies whether to verify that the service
+// connection is using a CA-signed X.509 certificate.
+//
+// @since CUPS 2.5@
+//
+
+http_t *                               // O - New HTTP connection
+httpConnectURI(const char *uri,                // I - Service to connect to
+               char       *host,       // I - Host name buffer (`NULL` for don't care)
+               size_t     hsize,       // I - Size of host name buffer
+               int        *port,       // O - Port number (`NULL` for don't care)
+               char       *resource,   // I - Resource path buffer (`NULL` for don't care)
+               size_t     rsize,       // I - Size of resource path buffer
+               bool       blocking,    // I - `true` for blocking connection, `false` for non-blocking
+               int        msec,                // I - Connection timeout in milliseconds, `0` means don't connect
+               int        *cancel,     // I - Pointer to "cancel" variable or `NULL` for none
+               bool       require_ca)  // I - `true` to require a CA-signed X.509 certificate
+{
+  http_t       *http;                  // New HTTP connection
+  char         scheme[32],             // URI scheme
+               userpass[32],           // URI username:password
+               lhost[256],             // URI host (local copy)
+               lresource[256];         // URI resource (local copy)
+  int          lport;                  // URI port (local copy)
+  http_encryption_t encryption;                // Type of encryption to use
+
+
+  DEBUG_printf("httpConnectURI(uri=\"%s\", host=%p, hsize=%u, port=%p, resource=%p, rsize=%u, blocking=%d, msec=%d, cancel=%p, require_ca=%s)", uri, (void *)host, (unsigned)hsize, (void *)port, (void *)resource, (unsigned)rsize, blocking, msec, (void *)cancel, require_ca ? "true" : "false");
+
+  // Range check input...
+  if (!uri)
+  {
+    if (host)
+      *host = '\0';
+
+    if (port)
+      *port = 0;
+
+    if (resource)
+      *resource = '\0';
+
+    return (NULL);
+  }
+
+  if (!host)
+  {
+    host  = lhost;
+    hsize = sizeof(lhost);
+  }
+
+  if (!port)
+    port = &lport;
+
+  if (!resource)
+  {
+    resource = lresource;
+    rsize    = sizeof(lresource);
+  }
+
+  // Get the URI components...
+  if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, hsize, port, resource, rsize) < HTTP_URI_STATUS_OK)
+    return (NULL);
+
+  DEBUG_printf("1httpConnectURI: scheme=\"%s\", host=\"%s\", port=%d, resource=\"%s\"", scheme, host, *port, resource);
+
+  if (!strcmp(scheme, "https") || !strcmp(scheme, "ipps") || *port == 443)
+    encryption = HTTP_ENCRYPTION_ALWAYS;
+  else
+    encryption = HTTP_ENCRYPTION_IF_REQUESTED;
+
+  http = httpConnect2(host, *port, /*addrlist*/NULL, AF_UNSPEC, encryption, blocking, msec, cancel);
+
+  if (httpIsEncrypted(http) && require_ca)
+  {
+    // Validate trust with service...
+    char       *creds;                 // Peer credentials...
+    http_trust_t trust;                        // Trust in credentials...
+
+    creds = httpCopyPeerCredentials(http);
+    trust = cupsGetCredentialsTrust(/*path*/NULL, host, creds, require_ca);
+
+    free(creds);
+
+    if (trust != HTTP_TRUST_OK)
+    {
+      httpClose(http);
+      http = NULL;
+    }
+  }
+
+  return (http);
+}
+
+
 //
 // 'httpDelete()' - Send a DELETE request to the server.
 //
index 71a01fdb9d9405829f991d10759ee21ff2874763..6cc06ce0fff24992337ae8834b25d83a2d87e9a1 100644 (file)
@@ -406,6 +406,7 @@ extern http_t               *httpConnect(const char *host, int port) _CUPS_DEPRECATED_MSG("Us
 extern http_t          *httpConnect2(const char *host, int port, http_addrlist_t *addrlist, int family, http_encryption_t encryption, int blocking, int msec, int *cancel) _CUPS_PUBLIC;
 extern bool            httpConnectAgain(http_t *http, int msec, int *cancel) _CUPS_PUBLIC;
 extern http_t          *httpConnectEncrypt(const char *host, int port, http_encryption_t encryption) _CUPS_DEPRECATED_MSG("Use httpConnect2 instead.");
+extern http_t          *httpConnectURI(const char *uri, char *host, size_t hsize, int *port, char *resource, size_t rsize, bool blocking, int msec, int *cancel, bool require_ca) _CUPS_PUBLIC;
 extern int             httpCopyCredentials(http_t *http, cups_array_t **credentials) _CUPS_DEPRECATED_MSG("Use httpCopyPeerCredentials instead.");
 extern char            *httpCopyPeerCredentials(http_t *http) _CUPS_PUBLIC;
 extern int             httpCredentialsAreValidForName(cups_array_t *credentials, const char *common_name) _CUPS_DEPRECATED_MSG("Use cupsAreCredentialsValidForName instead.");
index 7f751c96481e6e1b0a45097f0ec857b1129f21c2..dae2a86ce920b61685450c4be392a757fd9a5751 100644 (file)
@@ -194,7 +194,7 @@ cupsJSONExportFile(
     return (false);
 
   // Create the file...
-  if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
+  if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664)) < 0)
   {
     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
     free(s);
@@ -731,6 +731,13 @@ cupsJSONImportString(const char *s)        // I - JSON string
   DEBUG_printf("cupsJSONImportString(s=\"%s\")", s);
 
   // Range check input...
+  if (s)
+  {
+    // Skip leading whitespace...
+    while (*s && isspace(*s & 255))
+      s ++;
+  }
+
   if (!s || *s != '{')
   {
     DEBUG_puts("2cupsJSONImportString: Doesn't start with '{'.");
@@ -1148,14 +1155,8 @@ cupsJSONImportURL(
     const char *url,                   // I  - URL
     time_t     *last_modified)         // IO - Last modified date/time or `NULL`
 {
-  char         scheme[32],             // URL scheme
-               userpass[64],           // URL username:password info
-               host[256],              // URL hostname
-               resource[1024];         // URL resource path
-  int          port;                   // URL port number
-  http_uri_status_t uri_status;                // URL decode status
-  http_encryption_t encryption;                // Encryption to use
   http_t       *http;                  // HTTP connection
+  char         resource[1024];         // URL resource path
   http_status_t        status;                 // HTTP request status
   http_state_t initial_state;          // Initial HTTP state
   char         if_modified_since[HTTP_MAX_VALUE];
@@ -1174,26 +1175,8 @@ cupsJSONImportURL(
   if (!url)
     return (NULL);
 
-  // Get the URL components...
-  if ((uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, url, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource))) < HTTP_URI_STATUS_OK)
-  {
-    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, httpURIStatusString(uri_status), 0);
-    return (NULL);
-  }
-
-  if (strcmp(scheme, "http") && strcmp(scheme, "https"))
-  {
-    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unsupported URI scheme."), 1);
-    return (NULL);
-  }
-
-  // Connect to the server...
-  if (!strcmp(scheme, "https") || port == 443)
-    encryption = HTTP_ENCRYPTION_ALWAYS;
-  else
-    encryption = HTTP_ENCRYPTION_IF_REQUESTED;
-
-  if ((http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, true, 30000, NULL)) == NULL)
+  // Connect to the URI...
+  if ((http = httpConnectURI(url, /*host*/NULL, /*hsize*/0, /*port*/NULL, resource, sizeof(resource), /*blocking*/true, /*msec*/30000, /*cancel*/NULL, /*require_ca*/true)) == NULL)
     return (NULL);
 
   // Send a GET request for the resource path...
@@ -1208,7 +1191,7 @@ cupsJSONImportURL(
     if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close"))
     {
       httpClearFields(http);
-      if (httpReconnect2(http, 30000, NULL))
+      if (!httpConnectAgain(http, /*msec*/30000, /*cancel*/NULL))
       {
        status = HTTP_STATUS_ERROR;
        break;
@@ -1232,7 +1215,7 @@ cupsJSONImportURL(
     // Send the GET request...
     if (!httpWriteRequest(http, "GET", resource))
     {
-      if (!httpReconnect2(http, 30000, NULL))
+      if (httpConnectAgain(http, /*msec*/30000, /*cancel*/NULL))
       {
         status = HTTP_STATUS_UNAUTHORIZED;
         continue;
@@ -1263,7 +1246,7 @@ cupsJSONImportURL(
         break;
       }
 
-      if (httpReconnect2(http, 30000, NULL))
+      if (!httpConnectAgain(http, /*msec*/30000, /*cancel*/NULL))
       {
         status = HTTP_STATUS_ERROR;
         break;
@@ -1277,7 +1260,7 @@ cupsJSONImportURL(
       httpFlush(http);
 
       // Reconnect...
-      if (httpReconnect2(http, 30000, NULL))
+      if (!httpConnectAgain(http, /*msec*/30000, /*cancel*/NULL))
       {
         status = HTTP_STATUS_ERROR;
         break;