From: Michael R Sweet Date: Mon, 9 Sep 2024 20:49:18 +0000 (-0400) Subject: Merge HTTP and JSON changes from libcups v3, including httpConnectURI API. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0fa45ad068a5146762a425f9636de5a356012a1d;p=thirdparty%2Fcups.git Merge HTTP and JSON changes from libcups v3, including httpConnectURI API. --- diff --git a/cups/http.c b/cups/http.c index 124530a9df..c0716f1dbf 100644 --- a/cups/http.c +++ b/cups/http.c @@ -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. // diff --git a/cups/http.h b/cups/http.h index 71a01fdb9d..6cc06ce0ff 100644 --- a/cups/http.h +++ b/cups/http.h @@ -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."); diff --git a/cups/json.c b/cups/json.c index 7f751c9648..dae2a86ce9 100644 --- a/cups/json.c +++ b/cups/json.c @@ -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;