X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=scheduler%2Fclient.c;h=02e5fafb8c9e2afffff519f2ffa9ff67d7f0be0f;hb=503b54c9302c8de6207e079a80a89a787eb612ea;hp=55bff423696be7a77975456133ba8c7127617f8d;hpb=21f36711d9982978da9d7c64a1aaec7f81d16010;p=thirdparty%2Fcups.git diff --git a/scheduler/client.c b/scheduler/client.c index 55bff4236..02e5fafb8 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -1,52 +1,25 @@ /* - * "$Id$" + * Client routines for the CUPS scheduler. * - * Client routines for the CUPS scheduler. + * Copyright 2007-2015 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * - * Copyright 2007-2013 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * This file contains Kerberos support code, copyright 2006 by + * Jelmer Vernooij. * - * This file contains Kerberos support code, copyright 2006 by - * Jelmer Vernooij. - * - * These coded instructions, statements, and computer programs are the - * property of Apple Inc. and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "LICENSE.txt" - * which should have been included with this file. If this file is - * file is missing or damaged, see the license at "http://www.cups.org/". - * - * Contents: - * - * cupsdAcceptClient() - Accept a new client. - * cupsdCloseAllClients() - Close all remote clients immediately. - * cupsdCloseClient() - Close a remote client. - * cupsdFlushHeader() - Flush the header fields to the client. - * cupsdReadClient() - Read data from a client. - * cupsdSendCommand() - Send output from a command via HTTP. - * cupsdSendError() - Send an error message via HTTP. - * cupsdSendHeader() - Send an HTTP request. - * cupsdUpdateCGI() - Read status messages from CGI scripts and - * programs. - * cupsdWriteClient() - Write data to a client as needed. - * check_if_modified() - Decode an "If-Modified-Since" line. - * compare_clients() - Compare two client connections. - * data_ready() - Check whether data is available from a client. - * get_file() - Get a filename and state info. - * install_cupsd_conf() - Install a configuration file. - * is_cgi() - Is the resource a CGI script/program? - * is_path_absolute() - Is a path absolute and free of relative elements - * (i.e. ".."). - * pipe_command() - Pipe the output of a command to the remote - * client. - * valid_host() - Is the Host: field valid? - * write_file() - Send a file via HTTP. - * write_pipe() - Flag that data is available on the CGI pipe. + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". */ /* * Include necessary headers... */ +#define _CUPS_NO_DEPRECATED +#define _HTTP_NO_PRIVATE #include "cupsd.h" #ifdef __APPLE__ @@ -57,39 +30,6 @@ #endif /* HAVE_TCPD_H */ -/* - * Local globals... - */ - -static const char * const http_states[] = - { /* HTTP state strings */ - "HTTP_STATE_ERROR", - "HTTP_STATE_WAITING", - "HTTP_STATE_OPTIONS", - "HTTP_STATE_GET", - "HTTP_STATE_GET_SEND", - "HTTP_STATE_HEAD", - "HTTP_STATE_POST", - "HTTP_STATE_POST_RECV", - "HTTP_STATE_POST_SEND", - "HTTP_STATE_PUT", - "HTTP_STATE_PUT_RECV", - "HTTP_STATE_DELETE", - "HTTP_STATE_TRACE", - "HTTP_STATE_CONNECT", - "HTTP_STATE_STATUS", - "HTTP_STATE_UNKNOWN_METHOD", - "HTTP_STATE_UNKNOWN_VERSION" - }; -static const char * const ipp_states[] = - { /* IPP state strings */ - "IPP_IDLE", - "IPP_HEADER", - "IPP_ATTRIBUTE", - "IPP_DATA" - }; - - /* * Local functions... */ @@ -98,9 +38,11 @@ static int check_if_modified(cupsd_client_t *con, struct stat *filestats); static int compare_clients(cupsd_client_t *a, cupsd_client_t *b, void *data); -static int data_ready(cupsd_client_t *con); +#ifdef HAVE_SSL +static int cupsd_start_tls(cupsd_client_t *con, http_encryption_t e); +#endif /* HAVE_SSL */ static char *get_file(cupsd_client_t *con, struct stat *filestats, - char *filename, int len); + char *filename, size_t len); static http_status_t install_cupsd_conf(cupsd_client_t *con); static int is_cgi(cupsd_client_t *con, const char *filename, struct stat *filestats, mime_type_t *type); @@ -121,14 +63,12 @@ static void write_pipe(cupsd_client_t *con); void cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ { + const char *hostname; /* Hostname of client */ + char name[256]; /* Hostname of client */ int count; /* Count of connections on a host */ - int val; /* Parameter value */ cupsd_client_t *con, /* New client pointer */ *tempcon; /* Temporary client pointer */ - http_addrlist_t *addrlist, /* List of adddresses for host */ - *addr; /* Current address */ socklen_t addrlen; /* Length of address */ - char *hostname; /* Hostname for address */ http_addr_t temp; /* Temporary address variable */ static time_t last_dos = 0; /* Time of last DoS attack */ #ifdef HAVE_TCPD_H @@ -136,9 +76,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ #endif /* HAVE_TCPD_H */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdAcceptClient(lis=%p(%d)) Clients=%d", - lis, lis->fd, cupsArrayCount(Clients)); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAcceptClient(lis=%p(%d)) Clients=%d", lis, lis->fd, cupsArrayCount(Clients)); /* * Make sure we don't have a full set of clients already... @@ -180,20 +118,14 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ return; } - con->file = -1; - con->http.activity = time(NULL); - con->http.hostaddr = &(con->clientaddr); - con->http.wait_value = 10000; - con->http.mode = _HTTP_MODE_SERVER; - /* * Accept the client and get the remote address... */ - addrlen = sizeof(http_addr_t); + con->number = ++ LastClientNumber; + con->file = -1; - if ((con->http.fd = accept(lis->fd, (struct sockaddr *)con->http.hostaddr, - &addrlen)) < 0) + if ((con->http = httpAcceptConnection(lis->fd, 0)) == NULL) { if (errno == ENFILE || errno == EMFILE) cupsdPauseListening(); @@ -206,23 +138,15 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ } /* - * Save the connected port number... + * Save the connected address and port number... */ - _httpAddrSetPort(con->http.hostaddr, httpAddrPort(&(lis->address))); + addrlen = sizeof(con->clientaddr); -#ifdef AF_INET6 - /* - * Convert IPv4 over IPv6 addresses (::ffff:n.n.n.n) to IPv4 forms we - * can more easily use... - */ + if (getsockname(httpGetFd(con->http), (struct sockaddr *)&con->clientaddr, &addrlen) || addrlen == 0) + con->clientaddr = lis->address; - if (lis->address.addr.sa_family == AF_INET6 && - con->http.hostaddr->ipv6.sin6_addr.s6_addr32[0] == 0 && - con->http.hostaddr->ipv6.sin6_addr.s6_addr32[1] == 0 && - ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2]) == 0xffff) - con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2] = 0; -#endif /* AF_INET6 */ + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Server address is \"%s\".", httpAddrString(&con->clientaddr, name, sizeof(name))); /* * Check the number of clients on the same address... @@ -231,7 +155,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ for (count = 0, tempcon = (cupsd_client_t *)cupsArrayFirst(Clients); tempcon; tempcon = (cupsd_client_t *)cupsArrayNext(Clients)) - if (httpAddrEqual(tempcon->http.hostaddr, con->http.hostaddr)) + if (httpAddrEqual(httpGetAddress(tempcon->http), httpGetAddress(con->http))) { count ++; if (count >= MaxClientsPerHost) @@ -245,18 +169,12 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ last_dos = time(NULL); cupsdLogMessage(CUPSD_LOG_WARN, "Possible DoS attack - more than %d clients connecting " - "from %s!", + "from %s.", MaxClientsPerHost, - httpAddrString(con->http.hostaddr, con->http.hostname, - sizeof(con->http.hostname))); + httpGetHostname(con->http, name, sizeof(name))); } -#ifdef WIN32 - closesocket(con->http.fd); -#else - close(con->http.fd); -#endif /* WIN32 */ - + httpClose(con->http); free(con); return; } @@ -265,31 +183,10 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ * Get the hostname or format the IP address as needed... */ - if (httpAddrLocalhost(con->http.hostaddr)) - { - /* - * Map accesses from the loopback interface to "localhost"... - */ - - strlcpy(con->http.hostname, "localhost", sizeof(con->http.hostname)); - hostname = con->http.hostname; - } + if (HostNameLookups) + hostname = httpResolveHostname(con->http, NULL, 0); else - { - /* - * Map accesses from the same host to the server name. - */ - - if (HostNameLookups) - hostname = httpAddrLookup(con->http.hostaddr, con->http.hostname, - sizeof(con->http.hostname)); - else - { - hostname = NULL; - httpAddrString(con->http.hostaddr, con->http.hostname, - sizeof(con->http.hostname)); - } - } + hostname = httpGetHostname(con->http, NULL, 0); if (hostname == NULL && HostNameLookups == 2) { @@ -297,15 +194,11 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ * Can't have an unresolved IP address with double-lookups enabled... */ -#ifdef WIN32 - closesocket(con->http.fd); -#else - close(con->http.fd); -#endif /* WIN32 */ + httpClose(con->http); - cupsdLogMessage(CUPSD_LOG_WARN, + cupsdLogClient(con, CUPSD_LOG_WARN, "Name lookup failed - connection from %s closed!", - con->http.hostname); + httpGetHostname(con->http, NULL, 0)); free(con); return; @@ -317,15 +210,17 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ * Do double lookups as needed... */ - if ((addrlist = httpAddrGetList(con->http.hostname, AF_UNSPEC, NULL)) - != NULL) + http_addrlist_t *addrlist, /* List of addresses */ + *addr; /* Current address */ + + if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, NULL)) != NULL) { /* * See if the hostname maps to the same IP address... */ for (addr = addrlist; addr; addr = addr->next) - if (httpAddrEqual(con->http.hostaddr, &(addr->addr))) + if (httpAddrEqual(httpGetAddress(con->http), &(addr->addr))) break; } else @@ -340,15 +235,11 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ * with double-lookups enabled... */ -#ifdef WIN32 - closesocket(con->http.fd); -#else - close(con->http.fd); -#endif /* WIN32 */ + httpClose(con->http); - cupsdLogMessage(CUPSD_LOG_WARN, + cupsdLogClient(con, CUPSD_LOG_WARN, "IP lookup failed - connection from %s closed!", - con->http.hostname); + httpGetHostname(con->http, NULL, 0)); free(con); return; } @@ -359,74 +250,71 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ * See if the connection is denied by TCP wrappers... */ - request_init(&wrap_req, RQ_DAEMON, "cupsd", RQ_FILE, con->http.fd, NULL); + request_init(&wrap_req, RQ_DAEMON, "cupsd", RQ_FILE, httpGetFd(con->http), + NULL); fromhost(&wrap_req); if (!hosts_access(&wrap_req)) { -#ifdef WIN32 - closesocket(con->http.fd); -#else - close(con->http.fd); -#endif /* WIN32 */ + httpClose(con->http); - cupsdLogMessage(CUPSD_LOG_WARN, + cupsdLogClient(con, CUPSD_LOG_WARN, "Connection from %s refused by /etc/hosts.allow and " - "/etc/hosts.deny rules.", con->http.hostname); + "/etc/hosts.deny rules.", httpGetHostname(con->http, NULL, 0)); free(con); return; } #endif /* HAVE_TCPD_H */ #ifdef AF_LOCAL - if (con->http.hostaddr->addr.sa_family == AF_LOCAL) + if (httpAddrFamily(httpGetAddress(con->http)) == AF_LOCAL) { # ifdef __APPLE__ socklen_t peersize; /* Size of peer credentials */ pid_t peerpid; /* Peer process ID */ - char name[256]; /* Name of process */ + char peername[256]; /* Name of process */ peersize = sizeof(peerpid); - if (!getsockopt(con->http.fd, SOL_LOCAL, LOCAL_PEERPID, &peerpid, - &peersize)) + if (!getsockopt(httpGetFd(con->http), SOL_LOCAL, LOCAL_PEERPID, &peerpid, + &peersize)) { - if (!proc_name(peerpid, name, sizeof(name))) - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] Accepted from %s (Domain ???[%d])", - con->http.fd, con->http.hostname, (int)peerpid); + if (!proc_name((int)peerpid, peername, sizeof(peername))) + cupsdLogClient(con, CUPSD_LOG_DEBUG, + "Accepted from %s (Domain ???[%d])", + httpGetHostname(con->http, NULL, 0), (int)peerpid); else - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] Accepted from %s (Domain %s[%d])", - con->http.fd, con->http.hostname, name, (int)peerpid); + cupsdLogClient(con, CUPSD_LOG_DEBUG, + "Accepted from %s (Domain %s[%d])", + httpGetHostname(con->http, NULL, 0), peername, (int)peerpid); } else # endif /* __APPLE__ */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Accepted from %s (Domain)", - con->http.fd, con->http.hostname); + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Accepted from %s (Domain)", + httpGetHostname(con->http, NULL, 0)); } else #endif /* AF_LOCAL */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Accepted from %s:%d (IPv%d)", - con->http.fd, con->http.hostname, - httpAddrPort(con->http.hostaddr), - _httpAddrFamily(con->http.hostaddr) == AF_INET ? 4 : 6); + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Accepted from %s:%d (IPv%d)", + httpGetHostname(con->http, NULL, 0), + httpAddrPort(httpGetAddress(con->http)), + httpAddrFamily(httpGetAddress(con->http)) == AF_INET ? 4 : 6); /* * Get the local address the client connected to... */ addrlen = sizeof(temp); - if (getsockname(con->http.fd, (struct sockaddr *)&temp, &addrlen)) + if (getsockname(httpGetFd(con->http), (struct sockaddr *)&temp, &addrlen)) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get local address - %s", - strerror(errno)); + cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to get local address - %s", + strerror(errno)); strlcpy(con->servername, "localhost", sizeof(con->servername)); con->serverport = LocalPort; } #ifdef AF_LOCAL - else if (_httpAddrFamily(&temp) == AF_LOCAL) + else if (httpAddrFamily(&temp) == AF_LOCAL) { strlcpy(con->servername, "localhost", sizeof(con->servername)); con->serverport = LocalPort; @@ -450,26 +338,14 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ cupsArrayAdd(Clients, con); - /* - * Using TCP_NODELAY improves responsiveness, especially on systems with a slow - * loopback interface. Since we write large buffers when sending print files - * and requests there shouldn't be any performance penalty for this... - */ - - val = 1; - setsockopt(con->http.fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); - - /* - * Close this file on all execs... - */ - - fcntl(con->http.fd, F_SETFD, fcntl(con->http.fd, F_GETFD) | FD_CLOEXEC); - /* * Add the socket to the server select. */ - cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con); + cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, NULL, + con); + + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Waiting for request."); /* * Temporarily suspend accept()'s until we lose a client... @@ -483,15 +359,13 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ * See if we are connecting on a secure port... */ - if (lis->encryption == HTTP_ENCRYPT_ALWAYS) + if (lis->encryption == HTTP_ENCRYPTION_ALWAYS) { /* * https connection; go secure... */ - con->http.encryption = HTTP_ENCRYPT_ALWAYS; - - if (!cupsdStartTLS(con)) + if (cupsd_start_tls(con, HTTP_ENCRYPTION_ALWAYS)) cupsdCloseClient(con); } else @@ -510,8 +384,7 @@ cupsdCloseAllClients(void) cupsd_client_t *con; /* Current client */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCloseAllClients() Clients=%d", - cupsArrayCount(Clients)); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCloseAllClients() Clients=%d", cupsArrayCount(Clients)); for (con = (cupsd_client_t *)cupsArrayFirst(Clients); con; @@ -529,36 +402,18 @@ int /* O - 1 if partial close, 0 if fully closed */ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ { int partial; /* Do partial close for SSL? */ -#ifdef HAVE_LIBSSL -#elif defined(HAVE_GNUTLS) -# elif defined(HAVE_CDSASSL) -#endif /* HAVE_LIBSSL */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Closing connection.", - con->http.fd); + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Closing connection."); /* * Flush pending writes before closing... */ - httpFlushWrite(HTTP(con)); + httpFlushWrite(con->http); partial = 0; -#ifdef HAVE_SSL - /* - * Shutdown encryption as needed... - */ - - if (con->http.tls) - { - partial = 1; - - cupsdEndTLS(con); - } -#endif /* HAVE_SSL */ - if (con->pipe_pid != 0) { /* @@ -581,19 +436,31 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ * Close the socket and clear the file from the input set for select()... */ - if (con->http.fd >= 0) + if (httpGetFd(con->http) >= 0) { cupsArrayRemove(ActiveClients, con); cupsdSetBusyState(); +#ifdef HAVE_SSL + /* + * Shutdown encryption as needed... + */ + + if (httpIsEncrypted(con->http)) + partial = 1; +#endif /* HAVE_SSL */ + if (partial) { /* * Only do a partial close so that the encrypted client gets everything. */ - shutdown(con->http.fd, 0); - cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con); + httpShutdown(con->http); + cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, + NULL, con); + + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Waiting for socket close."); } else { @@ -601,9 +468,9 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ * Shut the socket down fully... */ - cupsdRemoveSelect(con->http.fd); - close(con->http.fd); - con->http.fd = -1; + cupsdRemoveSelect(httpGetFd(con->http)); + httpClose(con->http); + con->http = NULL; } } @@ -613,13 +480,16 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ * Free memory... */ - if (con->http.input_set) - free(con->http.input_set); + cupsdRemoveSelect(httpGetFd(con->http)); - httpClearCookie(HTTP(con)); - httpClearFields(HTTP(con)); + httpClose(con->http); + + if (con->filename) + { + unlink(con->filename); + cupsdClearString(&con->filename); + } - cupsdClearString(&con->filename); cupsdClearString(&con->command); cupsdClearString(&con->options); cupsdClearString(&con->query_string); @@ -671,21 +541,6 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ } -/* - * 'cupsdFlushHeader()' - Flush the header fields to the client. - */ - -int /* I - Bytes written or -1 on error */ -cupsdFlushHeader(cupsd_client_t *con) /* I - Client to flush to */ -{ - int bytes = httpFlushWrite(HTTP(con)); - - con->http.data_encoding = HTTP_ENCODING_LENGTH; - - return (bytes); -} - - /* * 'cupsdReadClient()' - Read data from a client. */ @@ -694,11 +549,8 @@ void cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ { char line[32768], /* Line from client... */ - operation[64], /* Operation code from socket */ - version[64], /* HTTP version number string */ locale[64], /* Locale */ *ptr; /* Pointer into strings */ - int major, minor; /* HTTP version numbers */ http_status_t status; /* Transfer status */ ipp_state_t ipp_state; /* State of IPP transfer */ int bytes; /* Number of bytes to POST */ @@ -710,25 +562,34 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ static unsigned request_id = 0; /* Request ID for temp files */ - status = HTTP_CONTINUE; - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "[Client %d] cupsdReadClient " - "error=%d, " - "used=%d, " - "state=%s, " - "data_encoding=HTTP_ENCODING_%s, " - "data_remaining=" CUPS_LLFMT ", " - "request=%p(%s), " - "file=%d", - con->http.fd, con->http.error, con->http.used, - http_states[con->http.state + 1], - con->http.data_encoding == HTTP_ENCODING_CHUNKED ? - "CHUNKED" : "LENGTH", - CUPS_LLCAST con->http.data_remaining, - con->request, - con->request ? ipp_states[con->request->state] : "", - con->file); + status = HTTP_STATUS_CONTINUE; + + cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cupsdReadClient: error=%d, used=%d, state=%s, data_encoding=HTTP_ENCODING_%s, data_remaining=" CUPS_LLFMT ", request=%p(%s), file=%d", httpError(con->http), (int)httpGetReady(con->http), httpStateString(httpGetState(con->http)), httpIsChunked(con->http) ? "CHUNKED" : "LENGTH", CUPS_LLCAST httpGetRemaining(con->http), con->request, con->request ? ippStateString(ippGetState(con->request)) : "", con->file); + + if (httpGetState(con->http) == HTTP_STATE_GET_SEND || + httpGetState(con->http) == HTTP_STATE_POST_SEND || + httpGetState(con->http) == HTTP_STATE_STATUS) + { + /* + * If we get called in the wrong state, then something went wrong with the + * connection and we need to shut it down... + */ + + if (!httpGetReady(con->http) && recv(httpGetFd(con->http), buf, 1, MSG_PEEK) < 1) + { + /* + * Connection closed... + */ + + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Closing on EOF."); + cupsdCloseClient(con); + return; + } + + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Closing on unexpected HTTP read state %s.", httpStateString(httpGetState(con->http))); + cupsdCloseClient(con); + return; + } #ifdef HAVE_SSL if (con->auto_ssl) @@ -739,18 +600,16 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ con->auto_ssl = 0; - if (recv(con->http.fd, buf, 1, MSG_PEEK) == 1 && + if (recv(httpGetFd(con->http), buf, 1, MSG_PEEK) == 1 && (!buf[0] || !strchr("DGHOPT", buf[0]))) { /* * Encrypt this connection... */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "[Client %d] Saw first byte %02X, auto-negotiating " - "SSL/TLS session.", con->http.fd, buf[0] & 255); + cupsdLogClient(con, CUPSD_LOG_DEBUG2, "Saw first byte %02X, auto-negotiating SSL/TLS session.", buf[0] & 255); - if (!cupsdStartTLS(con)) + if (cupsd_start_tls(con, HTTP_ENCRYPTION_ALWAYS)) cupsdCloseClient(con); return; @@ -758,24 +617,26 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ } #endif /* HAVE_SSL */ - switch (con->http.state) + switch (httpGetState(con->http)) { case HTTP_STATE_WAITING : /* * See if we've received a request line... */ - if (httpGets(line, sizeof(line) - 1, HTTP(con)) == NULL) + con->operation = httpReadRequest(con->http, con->uri, sizeof(con->uri)); + if (con->operation == HTTP_STATE_ERROR || + con->operation == HTTP_STATE_UNKNOWN_METHOD || + con->operation == HTTP_STATE_UNKNOWN_VERSION) { - if (con->http.error && con->http.error != EPIPE) - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] HTTP_STATE_WAITING Closing for error %d " - "(%s)", con->http.fd, con->http.error, - strerror(con->http.error)); + if (httpError(con->http)) + cupsdLogClient(con, CUPSD_LOG_DEBUG, + "HTTP_STATE_WAITING Closing for error %d (%s)", + httpError(con->http), strerror(httpError(con->http))); else - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] HTTP_STATE_WAITING Closing on EOF", - con->http.fd); + cupsdLogClient(con, CUPSD_LOG_DEBUG, + "HTTP_STATE_WAITING Closing on error: %s", + cupsLastErrorString()); cupsdCloseClient(con); return; @@ -785,29 +646,19 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Ignore blank request lines... */ - if (line[0] == '\0') + if (con->operation == HTTP_STATE_WAITING) break; /* * Clear other state variables... */ - httpClearFields(HTTP(con)); - - con->http.activity = time(NULL); - con->http.version = HTTP_1_0; - con->http.keep_alive = HTTP_KEEPALIVE_OFF; - con->http.data_encoding = HTTP_ENCODING_LENGTH; - con->http.data_remaining = 0; - con->http._data_remaining = 0; - con->operation = HTTP_STATE_WAITING; - con->bytes = 0; - con->file = -1; - con->file_ready = 0; - con->pipe_pid = 0; - con->username[0] = '\0'; - con->password[0] = '\0'; - con->uri[0] = '\0'; + con->bytes = 0; + con->file = -1; + con->file_ready = 0; + con->pipe_pid = 0; + con->username[0] = '\0'; + con->password[0] = '\0'; cupsdClearString(&con->command); cupsdClearString(&con->options); @@ -836,62 +687,6 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ con->gss_uid = 0; #endif /* HAVE_GSSAPI */ - /* - * Grab the request line... - */ - - switch (sscanf(line, "%63s%1023s%63s", operation, con->uri, version)) - { - case 1 : - if (line[0]) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Bad request line \"%s\" from %s.", - con->http.fd, - _httpEncodeURI(buf, line, sizeof(buf)), - con->http.hostname); - cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE); - cupsdCloseClient(con); - } - return; - case 2 : - con->http.version = HTTP_0_9; - break; - case 3 : - if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Bad request line \"%s\" from %s.", - con->http.fd, - _httpEncodeURI(buf, line, sizeof(buf)), - con->http.hostname); - cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE); - cupsdCloseClient(con); - return; - } - - if (major < 2) - { - con->http.version = (http_version_t)(major * 100 + minor); - if (con->http.version == HTTP_1_1 && KeepAlive) - con->http.keep_alive = HTTP_KEEPALIVE_ON; - else - con->http.keep_alive = HTTP_KEEPALIVE_OFF; - } - else - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Unsupported request line \"%s\" " - "from %s.", con->http.fd, - _httpEncodeURI(buf, line, sizeof(buf)), - con->http.hostname); - cupsdSendError(con, HTTP_NOT_SUPPORTED, CUPSD_AUTH_NONE); - cupsdCloseClient(con); - return; - } - break; - } - /* * Handle full URLs in the request line... */ @@ -904,18 +699,24 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ resource[HTTP_MAX_URI]; /* Resource path */ int port; /* Port number */ - /* * Separate the URI into its components... */ - httpSeparateURI(HTTP_URI_CODING_MOST, con->uri, - scheme, sizeof(scheme), - userpass, sizeof(userpass), - hostname, sizeof(hostname), &port, - resource, sizeof(resource)); + if (httpSeparateURI(HTTP_URI_CODING_MOST, con->uri, + scheme, sizeof(scheme), + userpass, sizeof(userpass), + hostname, sizeof(hostname), &port, + resource, sizeof(resource)) < HTTP_URI_STATUS_OK) + { + cupsdLogClient(con, CUPSD_LOG_ERROR, "Bad URI \"%s\" in request.", + con->uri); + cupsdSendError(con, HTTP_STATUS_METHOD_NOT_ALLOWED, CUPSD_AUTH_NONE); + cupsdCloseClient(con); + return; + } - /* + /* * Only allow URIs with the servername, localhost, or an IP * address... */ @@ -923,16 +724,16 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (strcmp(scheme, "file") && _cups_strcasecmp(hostname, ServerName) && _cups_strcasecmp(hostname, "localhost") && + !cupsArrayFind(ServerAlias, hostname) && !isdigit(hostname[0]) && hostname[0] != '[') { /* * Nope, we don't do proxies... */ - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Bad URI \"%s\" in request.", - con->http.fd, con->uri); - cupsdSendError(con, HTTP_METHOD_NOT_ALLOWED, CUPSD_AUTH_NONE); + cupsdLogClient(con, CUPSD_LOG_ERROR, "Bad URI \"%s\" in request.", + con->uri); + cupsdSendError(con, HTTP_STATUS_METHOD_NOT_ALLOWED, CUPSD_AUTH_NONE); cupsdCloseClient(con); return; } @@ -949,38 +750,12 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Process the request... */ - if (!strcmp(operation, "GET")) - con->http.state = HTTP_STATE_GET; - else if (!strcmp(operation, "PUT")) - con->http.state = HTTP_STATE_PUT; - else if (!strcmp(operation, "POST")) - con->http.state = HTTP_STATE_POST; - else if (!strcmp(operation, "DELETE")) - con->http.state = HTTP_STATE_DELETE; - else if (!strcmp(operation, "TRACE")) - con->http.state = HTTP_STATE_TRACE; - else if (!strcmp(operation, "OPTIONS")) - con->http.state = HTTP_STATE_OPTIONS; - else if (!strcmp(operation, "HEAD")) - con->http.state = HTTP_STATE_HEAD; - else - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Bad operation \"%s\".", con->http.fd, - operation); - cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE); - cupsdCloseClient(con); - return; - } - gettimeofday(&(con->start), NULL); - con->operation = con->http.state; - - cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] %s %s HTTP/%d.%d", - con->http.fd, operation, con->uri, - con->http.version / 100, con->http.version % 100); - con->http.status = HTTP_OK; + cupsdLogClient(con, CUPSD_LOG_DEBUG, "%s %s HTTP/%d.%d", + httpStateString(con->operation) + 11, con->uri, + httpGetVersion(con->http) / 100, + httpGetVersion(con->http) % 100); if (!cupsArrayFind(ActiveClients, con)) { @@ -999,38 +774,34 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Parse incoming parameters until the status changes... */ - while ((status = httpUpdate(HTTP(con))) == HTTP_CONTINUE) - if (!data_ready(con)) + while ((status = httpUpdate(con->http)) == HTTP_STATUS_CONTINUE) + if (!httpGetReady(con->http)) break; - if (status != HTTP_OK && status != HTTP_CONTINUE) + if (status != HTTP_STATUS_OK && status != HTTP_STATUS_CONTINUE) { - if (con->http.error && con->http.error != EPIPE) - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] Closing for error %d (%s) while " - "reading headers.", - con->http.fd, con->http.error, - strerror(con->http.error)); + if (httpError(con->http) && httpError(con->http) != EPIPE) + cupsdLogClient(con, CUPSD_LOG_DEBUG, + "Closing for error %d (%s) while reading headers.", + httpError(con->http), strerror(httpError(con->http))); else - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] Closing on EOF while reading headers.", - con->http.fd); + cupsdLogClient(con, CUPSD_LOG_DEBUG, + "Closing on EOF while reading headers."); - cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE); + cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE); cupsdCloseClient(con); return; } break; default : - if (!data_ready(con) && recv(con->http.fd, buf, 1, MSG_PEEK) < 1) + if (!httpGetReady(con->http) && recv(httpGetFd(con->http), buf, 1, MSG_PEEK) < 1) { /* * Connection closed... */ - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] Closing on EOF", con->http.fd); + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Closing on EOF."); cupsdCloseClient(con); return; } @@ -1041,24 +812,26 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Handle new transfers... */ - if (status == HTTP_OK) + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Read: status=%d", status); + + if (status == HTTP_STATUS_OK) { - if (con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE][0]) + if (httpGetField(con->http, HTTP_FIELD_ACCEPT_LANGUAGE)[0]) { /* * Figure out the locale from the Accept-Language and Content-Type * fields... */ - if ((ptr = strchr(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], + if ((ptr = strchr(httpGetField(con->http, HTTP_FIELD_ACCEPT_LANGUAGE), ',')) != NULL) *ptr = '\0'; - if ((ptr = strchr(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], + if ((ptr = strchr(httpGetField(con->http, HTTP_FIELD_ACCEPT_LANGUAGE), ';')) != NULL) *ptr = '\0'; - if ((ptr = strstr(con->http.fields[HTTP_FIELD_CONTENT_TYPE], + if ((ptr = strstr(httpGetField(con->http, HTTP_FIELD_CONTENT_TYPE), "charset=")) != NULL) { /* @@ -1067,14 +840,14 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ */ snprintf(locale, sizeof(locale), "%s.%s", - con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], ptr + 8); + httpGetField(con->http, HTTP_FIELD_ACCEPT_LANGUAGE), ptr + 8); if ((ptr = strchr(locale, ',')) != NULL) *ptr = '\0'; } else snprintf(locale, sizeof(locale), "%s.UTF-8", - con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE]); + httpGetField(con->http, HTTP_FIELD_ACCEPT_LANGUAGE)); con->language = cupsLangGet(locale); } @@ -1083,25 +856,23 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ cupsdAuthorize(con); - if (!_cups_strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], + if (!_cups_strncasecmp(httpGetField(con->http, HTTP_FIELD_CONNECTION), "Keep-Alive", 10) && KeepAlive) - con->http.keep_alive = HTTP_KEEPALIVE_ON; - else if (!_cups_strncasecmp(con->http.fields[HTTP_FIELD_CONNECTION], + httpSetKeepAlive(con->http, HTTP_KEEPALIVE_ON); + else if (!_cups_strncasecmp(httpGetField(con->http, HTTP_FIELD_CONNECTION), "close", 5)) - con->http.keep_alive = HTTP_KEEPALIVE_OFF; + httpSetKeepAlive(con->http, HTTP_KEEPALIVE_OFF); - if (!con->http.fields[HTTP_FIELD_HOST][0] && - con->http.version >= HTTP_1_1) + if (!httpGetField(con->http, HTTP_FIELD_HOST)[0] && + httpGetVersion(con->http) >= HTTP_VERSION_1_1) { /* * HTTP/1.1 and higher require the "Host:" field... */ - if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE)) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Missing Host: field in request.", - con->http.fd); + cupsdLogClient(con, CUPSD_LOG_ERROR, "Missing Host: field in request."); cupsdCloseClient(con); return; } @@ -1113,12 +884,11 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * or IPv6 values in the Host: field. */ - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Request from \"%s\" using invalid Host: " - "field \"%s\"", con->http.fd, con->http.hostname, - con->http.fields[HTTP_FIELD_HOST]); + cupsdLogClient(con, CUPSD_LOG_ERROR, + "Request from \"%s\" using invalid Host: field \"%s\".", + httpGetHostname(con->http, NULL, 0), httpGetField(con->http, HTTP_FIELD_HOST)); - if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1132,45 +902,37 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (con->best && con->best->type != CUPSD_AUTH_NONE) { - if (!cupsdSendHeader(con, HTTP_UNAUTHORIZED, NULL, CUPSD_AUTH_NONE)) + httpClearFields(con->http); + + if (!cupsdSendHeader(con, HTTP_STATUS_UNAUTHORIZED, NULL, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } } - if (!_cups_strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") && - con->http.tls == NULL) + if (!_cups_strcasecmp(httpGetField(con->http, HTTP_FIELD_CONNECTION), "Upgrade") && strstr(httpGetField(con->http, HTTP_FIELD_UPGRADE), "TLS/") != NULL && !httpIsEncrypted(con->http)) { #ifdef HAVE_SSL /* * Do encryption stuff... */ - if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL, CUPSD_AUTH_NONE)) - { - cupsdCloseClient(con); - return; - } + httpClearFields(con->http); - httpPrintf(HTTP(con), "Connection: Upgrade\r\n"); - httpPrintf(HTTP(con), "Upgrade: TLS/1.2,TLS/1.1,TLS/1.0\r\n"); - httpPrintf(HTTP(con), "Content-Length: 0\r\n"); - httpPrintf(HTTP(con), "\r\n"); - - if (cupsdFlushHeader(con) < 0) - { + if (!cupsdSendHeader(con, HTTP_STATUS_SWITCHING_PROTOCOLS, NULL, CUPSD_AUTH_NONE)) + { cupsdCloseClient(con); return; } - if (!cupsdStartTLS(con)) + if (cupsd_start_tls(con, HTTP_ENCRYPTION_REQUIRED)) { cupsdCloseClient(con); return; } #else - if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_IMPLEMENTED, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1178,17 +940,12 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ #endif /* HAVE_SSL */ } - if (!cupsdSendHeader(con, HTTP_OK, NULL, CUPSD_AUTH_NONE)) - { - cupsdCloseClient(con); - return; - } + httpClearFields(con->http); + httpSetField(con->http, HTTP_FIELD_ALLOW, + "GET, HEAD, OPTIONS, POST, PUT"); + httpSetField(con->http, HTTP_FIELD_CONTENT_LENGTH, "0"); - httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST, PUT\r\n"); - httpPrintf(HTTP(con), "Content-Length: 0\r\n"); - httpPrintf(HTTP(con), "\r\n"); - - if (cupsdFlushHeader(con) < 0) + if (!cupsdSendHeader(con, HTTP_STATUS_OK, NULL, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1200,11 +957,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Protect against malicious users! */ - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Request for non-absolute resource \"%s\".", - con->http.fd, con->uri); + cupsdLogClient(con, CUPSD_LOG_ERROR, + "Request for non-absolute resource \"%s\".", con->uri); - if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_FORBIDDEN, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1212,39 +968,30 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ } else { - if (!_cups_strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], - "Upgrade") && con->http.tls == NULL) + if (!_cups_strcasecmp(httpGetField(con->http, HTTP_FIELD_CONNECTION), + "Upgrade") && !httpIsEncrypted(con->http)) { #ifdef HAVE_SSL /* * Do encryption stuff... */ - if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL, + httpClearFields(con->http); + + if (!cupsdSendHeader(con, HTTP_STATUS_SWITCHING_PROTOCOLS, NULL, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } - httpPrintf(HTTP(con), "Connection: Upgrade\r\n"); - httpPrintf(HTTP(con), "Upgrade: TLS/1.2,TLS/1.1,TLS/1.0\r\n"); - httpPrintf(HTTP(con), "Content-Length: 0\r\n"); - httpPrintf(HTTP(con), "\r\n"); - - if (cupsdFlushHeader(con) < 0) - { - cupsdCloseClient(con); - return; - } - - if (!cupsdStartTLS(con)) + if (cupsd_start_tls(con, HTTP_ENCRYPTION_REQUIRED)) { cupsdCloseClient(con); return; } #else - if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_IMPLEMENTED, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1252,23 +999,23 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ #endif /* HAVE_SSL */ } - if ((status = cupsdIsAuthorized(con, NULL)) != HTTP_OK) + if ((status = cupsdIsAuthorized(con, NULL)) != HTTP_STATUS_OK) { cupsdSendError(con, status, CUPSD_AUTH_NONE); cupsdCloseClient(con); return; } - if (con->http.expect && + if (httpGetExpect(con->http) && (con->operation == HTTP_STATE_POST || con->operation == HTTP_STATE_PUT)) { - if (con->http.expect == HTTP_CONTINUE) + if (httpGetExpect(con->http) == HTTP_STATUS_CONTINUE) { /* * Send 100-continue header... */ - if (!cupsdSendHeader(con, HTTP_CONTINUE, NULL, CUPSD_AUTH_NONE)) + if (httpWriteResponse(con->http, HTTP_STATUS_CONTINUE)) { cupsdCloseClient(con); return; @@ -1280,27 +1027,20 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Send 417-expectation-failed header... */ - if (!cupsdSendHeader(con, HTTP_EXPECTATION_FAILED, NULL, - CUPSD_AUTH_NONE)) - { - cupsdCloseClient(con); - return; - } + httpClearFields(con->http); + httpSetField(con->http, HTTP_FIELD_CONTENT_LENGTH, "0"); - httpPrintf(HTTP(con), "Content-Length: 0\r\n"); - httpPrintf(HTTP(con), "\r\n"); - - if (cupsdFlushHeader(con) < 0) - { - cupsdCloseClient(con); - return; - } + cupsdSendError(con, HTTP_STATUS_EXPECTATION_FAILED, CUPSD_AUTH_NONE); + cupsdCloseClient(con); + return; } } - switch (con->http.state) + switch (httpGetState(con->http)) { case HTTP_STATE_GET_SEND : + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Processing GET %s", con->uri); + if ((!strncmp(con->uri, "/ppd/", 5) || !strncmp(con->uri, "/printers/", 10) || !strncmp(con->uri, "/classes/", 9)) && @@ -1352,7 +1092,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ } else { - if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1410,7 +1150,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ snprintf(con->uri, sizeof(con->uri), "/icons/%s.png", p->name); else { - if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1419,29 +1159,28 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ break; } } - else if (!WebInterface) - { - /* - * Web interface is disabled. Show an appropriate message... - */ - - if (!cupsdSendError(con, HTTP_WEBIF_DISABLED, CUPSD_AUTH_NONE)) - { - cupsdCloseClient(con); - return; - } - - break; - } - if ((!strncmp(con->uri, "/admin", 6) && - strncmp(con->uri, "/admin/conf/", 12) && - strncmp(con->uri, "/admin/log/", 11)) || + if ((!strncmp(con->uri, "/admin", 6) && strcmp(con->uri, "/admin/conf/cupsd.conf") && strncmp(con->uri, "/admin/log/", 11)) || !strncmp(con->uri, "/printers", 9) || !strncmp(con->uri, "/classes", 8) || !strncmp(con->uri, "/help", 5) || !strncmp(con->uri, "/jobs", 5)) { + if (!WebInterface) + { + /* + * Web interface is disabled. Show an appropriate message... + */ + + if (!cupsdSendError(con, HTTP_STATUS_CUPS_WEBIF_DISABLED, CUPSD_AUTH_NONE)) + { + cupsdCloseClient(con); + return; + } + + break; + } + /* * Send CGI output... */ @@ -1496,34 +1235,28 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (!cupsdSendCommand(con, con->command, con->options, 0)) { - if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } } else - cupsdLogRequest(con, HTTP_OK); + cupsdLogRequest(con, HTTP_STATUS_OK); - if (con->http.version <= HTTP_1_0) - con->http.keep_alive = HTTP_KEEPALIVE_OFF; + if (httpGetVersion(con->http) <= HTTP_VERSION_1_0) + httpSetKeepAlive(con->http, HTTP_KEEPALIVE_OFF); } - else if ((!strncmp(con->uri, "/admin/conf/", 12) && - (strchr(con->uri + 12, '/') || - strlen(con->uri) == 12)) || - (!strncmp(con->uri, "/admin/log/", 11) && - (strchr(con->uri + 11, '/') || - strlen(con->uri) == 11))) + else if (!strncmp(con->uri, "/admin/log/", 11) && (strchr(con->uri + 11, '/') || strlen(con->uri) == 11)) { /* * GET can only be done to configuration files directly under * /admin/conf... */ - cupsdLogMessage(CUPSD_LOG_ERROR, - "Request for subdirectory \"%s\"!", con->uri); + cupsdLogClient(con, CUPSD_LOG_ERROR, "Request for subdirectory \"%s\".", con->uri); - if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_FORBIDDEN, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1540,7 +1273,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if ((filename = get_file(con, &filestats, buf, sizeof(buf))) == NULL) { - if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1551,6 +1284,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ type = mimeFileType(MimeDatabase, filename, NULL, NULL); + cupsdLogClient(con, CUPSD_LOG_DEBUG, "filename=\"%s\", type=%s/%s", filename, type ? type->super : "", type ? type->type : ""); + if (is_cgi(con, filename, &filestats, type)) { /* @@ -1560,23 +1295,23 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (!cupsdSendCommand(con, con->command, con->options, 0)) { - if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } } else - cupsdLogRequest(con, HTTP_OK); + cupsdLogRequest(con, HTTP_STATUS_OK); - if (con->http.version <= HTTP_1_0) - con->http.keep_alive = HTTP_KEEPALIVE_OFF; + if (httpGetVersion(con->http) <= HTTP_VERSION_1_0) + httpSetKeepAlive(con->http, HTTP_KEEPALIVE_OFF); break; } if (!check_if_modified(con, &filestats)) { - if (!cupsdSendError(con, HTTP_NOT_MODIFIED, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_MODIFIED, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1589,7 +1324,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ else snprintf(line, sizeof(line), "%s/%s", type->super, type->type); - if (!write_file(con, HTTP_OK, filename, line, &filestats)) + if (!write_file(con, HTTP_STATUS_OK, filename, line, &filestats)) { cupsdCloseClient(con); return; @@ -1604,15 +1339,15 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * so check the length against any limits that are set... */ - if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] && + if (httpGetField(con->http, HTTP_FIELD_CONTENT_LENGTH)[0] && MaxRequestSize > 0 && - con->http.data_remaining > MaxRequestSize) + httpGetLength2(con->http) > MaxRequestSize) { /* * Request too large... */ - if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1620,15 +1355,13 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ break; } - else if (con->http.data_remaining < 0 || - (!con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] && - con->http.data_encoding == HTTP_ENCODING_LENGTH)) + else if (httpGetLength2(con->http) < 0) { /* * Negative content lengths are invalid! */ - if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1642,7 +1375,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * content-type field will be "application/ipp"... */ - if (!strcmp(con->http.fields[HTTP_FIELD_CONTENT_TYPE], + if (!strcmp(httpGetField(con->http, HTTP_FIELD_CONTENT_TYPE), "application/ipp")) con->request = ippNew(); else if (!WebInterface) @@ -1651,7 +1384,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Web interface is disabled. Show an appropriate message... */ - if (!cupsdSendError(con, HTTP_WEBIF_DISABLED, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_CUPS_WEBIF_DISABLED, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1659,9 +1392,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ break; } - else if ((!strncmp(con->uri, "/admin", 6) && - strncmp(con->uri, "/admin/conf/", 12) && - strncmp(con->uri, "/admin/log/", 11)) || + else if ((!strncmp(con->uri, "/admin", 6) && strncmp(con->uri, "/admin/log/", 11)) || !strncmp(con->uri, "/printers", 9) || !strncmp(con->uri, "/classes", 8) || !strncmp(con->uri, "/help", 5) || @@ -1719,8 +1450,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ cupsdSetString(&con->options, NULL); } - if (con->http.version <= HTTP_1_0) - con->http.keep_alive = HTTP_KEEPALIVE_OFF; + if (httpGetVersion(con->http) <= HTTP_VERSION_1_0) + httpSetKeepAlive(con->http, HTTP_KEEPALIVE_OFF); } else { @@ -1731,7 +1462,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if ((filename = get_file(con, &filestats, buf, sizeof(buf))) == NULL) { - if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1748,7 +1479,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Only POST to CGI's... */ - if (!cupsdSendError(con, HTTP_UNAUTHORIZED, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_UNAUTHORIZED, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1768,11 +1499,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * PUT can only be done to the cupsd.conf file... */ - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Disallowed PUT request for \"%s\".", - con->http.fd, con->uri); + cupsdLogClient(con, CUPSD_LOG_ERROR, + "Disallowed PUT request for \"%s\".", con->uri); - if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_FORBIDDEN, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1786,15 +1516,15 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * so check the length against any limits that are set... */ - if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] && + if (httpGetField(con->http, HTTP_FIELD_CONTENT_LENGTH)[0] && MaxRequestSize > 0 && - con->http.data_remaining > MaxRequestSize) + httpGetLength2(con->http) > MaxRequestSize) { /* * Request too large... */ - if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1802,13 +1532,13 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ break; } - else if (con->http.data_remaining < 0) + else if (httpGetLength2(con->http) < 0) { /* * Negative content lengths are invalid! */ - if (!cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1827,12 +1557,11 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (con->file < 0) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Unable to create request file " - "\"%s\": %s", con->http.fd, con->filename, - strerror(errno)); + cupsdLogClient(con, CUPSD_LOG_ERROR, + "Unable to create request file \"%s\": %s", + con->filename, strerror(errno)); - if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -1846,7 +1575,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ case HTTP_STATE_DELETE : case HTTP_STATE_TRACE : - cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE); + cupsdSendError(con, HTTP_STATUS_NOT_IMPLEMENTED, CUPSD_AUTH_NONE); cupsdCloseClient(con); return; @@ -1865,12 +1594,13 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name); else { - if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } + cupsdLogRequest(con, HTTP_STATUS_NOT_FOUND); break; } } @@ -1888,44 +1618,31 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ snprintf(con->uri, sizeof(con->uri), "/icons/%s.png", p->name); else { - if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } + cupsdLogRequest(con, HTTP_STATUS_NOT_FOUND); break; } } else if (!WebInterface) { - if (!cupsdSendHeader(con, HTTP_OK, line, CUPSD_AUTH_NONE)) - { - cupsdCloseClient(con); - return; - } + httpClearFields(con->http); - if (httpPrintf(HTTP(con), "\r\n") < 0) + if (!cupsdSendHeader(con, HTTP_STATUS_OK, NULL, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } - if (cupsdFlushHeader(con) < 0) - { - cupsdCloseClient(con); - return; - } - - con->http.state = HTTP_STATE_WAITING; - DEBUG_puts("cupsdReadClient: Set state to HTTP_STATE_WAITING " - "after HEAD."); + cupsdLogRequest(con, HTTP_STATUS_OK); break; } - if ((!strncmp(con->uri, "/admin", 6) && - strncmp(con->uri, "/admin/conf/", 12) && - strncmp(con->uri, "/admin/log/", 11)) || + if ((!strncmp(con->uri, "/admin", 6) && strcmp(con->uri, "/admin/conf/cupsd.conf") && strncmp(con->uri, "/admin/log/", 11)) || !strncmp(con->uri, "/printers", 9) || !strncmp(con->uri, "/classes", 8) || !strncmp(con->uri, "/help", 5) || @@ -1935,71 +1652,58 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * CGI output... */ - if (!cupsdSendHeader(con, HTTP_OK, "text/html", CUPSD_AUTH_NONE)) - { - cupsdCloseClient(con); - return; - } + httpClearFields(con->http); - if (httpPrintf(HTTP(con), "\r\n") < 0) + if (!cupsdSendHeader(con, HTTP_STATUS_OK, "text/html", CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } - if (cupsdFlushHeader(con) < 0) - { - cupsdCloseClient(con); - return; - } - - cupsdLogRequest(con, HTTP_OK); + cupsdLogRequest(con, HTTP_STATUS_OK); } - else if ((!strncmp(con->uri, "/admin/conf/", 12) && - (strchr(con->uri + 12, '/') || - strlen(con->uri) == 12)) || - (!strncmp(con->uri, "/admin/log/", 11) && - (strchr(con->uri + 11, '/') || - strlen(con->uri) == 11))) + else if (!strncmp(con->uri, "/admin/log/", 11) && (strchr(con->uri + 11, '/') || strlen(con->uri) == 11)) { /* * HEAD can only be done to configuration files under * /admin/conf... */ - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Request for subdirectory \"%s\".", - con->http.fd, con->uri); + cupsdLogClient(con, CUPSD_LOG_ERROR, + "Request for subdirectory \"%s\".", con->uri); - if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_FORBIDDEN, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } + cupsdLogRequest(con, HTTP_STATUS_FORBIDDEN); break; } else if ((filename = get_file(con, &filestats, buf, sizeof(buf))) == NULL) { - if (!cupsdSendHeader(con, HTTP_NOT_FOUND, "text/html", + httpClearFields(con->http); + + if (!cupsdSendHeader(con, HTTP_STATUS_NOT_FOUND, "text/html", CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } - cupsdLogRequest(con, HTTP_NOT_FOUND); + cupsdLogRequest(con, HTTP_STATUS_NOT_FOUND); } else if (!check_if_modified(con, &filestats)) { - if (!cupsdSendError(con, HTTP_NOT_MODIFIED, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_MODIFIED, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } - cupsdLogRequest(con, HTTP_NOT_MODIFIED); + cupsdLogRequest(con, HTTP_STATUS_NOT_MODIFIED); } else { @@ -2013,44 +1717,20 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ else snprintf(line, sizeof(line), "%s/%s", type->super, type->type); - if (!cupsdSendHeader(con, HTTP_OK, line, CUPSD_AUTH_NONE)) - { - cupsdCloseClient(con); - return; - } + httpClearFields(con->http); - if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n", - httpGetDateString(filestats.st_mtime)) < 0) - { - cupsdCloseClient(con); - return; - } + httpSetField(con->http, HTTP_FIELD_LAST_MODIFIED, + httpGetDateString(filestats.st_mtime)); + httpSetLength(con->http, (size_t)filestats.st_size); - if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n", - (unsigned long)filestats.st_size) < 0) + if (!cupsdSendHeader(con, HTTP_STATUS_OK, line, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } - cupsdLogRequest(con, HTTP_OK); + cupsdLogRequest(con, HTTP_STATUS_OK); } - - if (httpPrintf(HTTP(con), "\r\n") < 0) - { - cupsdCloseClient(con); - return; - } - - if (cupsdFlushHeader(con) < 0) - { - cupsdCloseClient(con); - return; - } - - con->http.state = HTTP_STATE_WAITING; - DEBUG_puts("cupsdReadClient: Set state to HTTP_STATE_WAITING " - "after HEAD."); break; default : @@ -2063,22 +1743,20 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Handle any incoming data... */ - switch (con->http.state) + switch (httpGetState(con->http)) { case HTTP_STATE_PUT_RECV : do { - if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0) + if ((bytes = httpRead2(con->http, line, sizeof(line))) < 0) { - if (con->http.error && con->http.error != EPIPE) - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] HTTP_STATE_PUT_RECV Closing for error " - "%d (%s)", con->http.fd, con->http.error, - strerror(con->http.error)); + if (httpError(con->http) && httpError(con->http) != EPIPE) + cupsdLogClient(con, CUPSD_LOG_DEBUG, + "HTTP_STATE_PUT_RECV Closing for error %d (%s)", + httpError(con->http), strerror(httpError(con->http))); else - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] HTTP_STATE_PUT_RECV Closing on EOF", - con->http.fd); + cupsdLogClient(con, CUPSD_LOG_DEBUG, + "HTTP_STATE_PUT_RECV Closing on EOF."); cupsdCloseClient(con); return; @@ -2087,29 +1765,47 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ { con->bytes += bytes; - if (write(con->file, line, bytes) < bytes) + if (MaxRequestSize > 0 && con->bytes > MaxRequestSize) + { + close(con->file); + con->file = -1; + unlink(con->filename); + cupsdClearString(&con->filename); + + if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) + { + cupsdCloseClient(con); + return; + } + } + + if (write(con->file, line, (size_t)bytes) < bytes) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Unable to write %d bytes to " - "\"%s\": %s", con->http.fd, bytes, con->filename, - strerror(errno)); + cupsdLogClient(con, CUPSD_LOG_ERROR, + "Unable to write %d bytes to \"%s\": %s", bytes, + con->filename, strerror(errno)); close(con->file); con->file = -1; unlink(con->filename); cupsdClearString(&con->filename); - if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } } } + else if (httpGetState(con->http) == HTTP_STATE_PUT_RECV) + { + cupsdCloseClient(con); + return; + } } - while (con->http.state == HTTP_STATE_PUT_RECV && data_ready(con)); + while (httpGetState(con->http) == HTTP_STATE_PUT_RECV && httpGetReady(con->http)); - if (con->http.state == HTTP_STATE_STATUS) + if (httpGetState(con->http) == HTTP_STATE_STATUS) { /* * End of file, see how big it is... @@ -2130,7 +1826,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ unlink(con->filename); cupsdClearString(&con->filename); - if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -2164,41 +1860,43 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ * Grab any request data from the connection... */ - if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR) + if (!httpWait(con->http, 0)) + return; + + if ((ipp_state = ippRead(con->http, con->request)) == IPP_STATE_ERROR) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] IPP read error: %s", con->http.fd, - cupsLastErrorString()); + cupsdLogClient(con, CUPSD_LOG_ERROR, "IPP read error: %s", + cupsLastErrorString()); - cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE); + cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE); cupsdCloseClient(con); return; } - else if (ipp_state != IPP_DATA) + else if (ipp_state != IPP_STATE_DATA) { - if (con->http.state == HTTP_STATE_POST_SEND) + if (httpGetState(con->http) == HTTP_STATE_POST_SEND) { - cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE); + cupsdSendError(con, HTTP_STATUS_BAD_REQUEST, CUPSD_AUTH_NONE); cupsdCloseClient(con); return; } - if (data_ready(con)) + if (httpGetReady(con->http)) continue; break; } else { - cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] %d.%d %s %d", - con->http.fd, con->request->request.op.version[0], + cupsdLogClient(con, CUPSD_LOG_DEBUG, "%d.%d %s %d", + con->request->request.op.version[0], con->request->request.op.version[1], ippOpString(con->request->request.op.operation_id), con->request->request.op.request_id); - con->bytes += ippLength(con->request); + con->bytes += (off_t)ippLength(con->request); } } - if (con->file < 0 && con->http.state != HTTP_STATE_POST_SEND) + if (con->file < 0 && httpGetState(con->http) != HTTP_STATE_POST_SEND) { /* * Create a file as needed for the request data... @@ -2210,12 +1908,11 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ if (con->file < 0) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Unable to create request file " - "\"%s\": %s", con->http.fd, con->filename, - strerror(errno)); + cupsdLogClient(con, CUPSD_LOG_ERROR, + "Unable to create request file \"%s\": %s", + con->filename, strerror(errno)); - if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -2227,21 +1924,19 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC); } - if (con->http.state != HTTP_STATE_POST_SEND) + if (httpGetState(con->http) != HTTP_STATE_POST_SEND) { - if (!httpWait(HTTP(con), 0)) + if (!httpWait(con->http, 0)) return; - else if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0) + else if ((bytes = httpRead2(con->http, line, sizeof(line))) < 0) { - if (con->http.error && con->http.error != EPIPE) - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] HTTP_STATE_POST_SEND Closing for " - "error %d (%s)", con->http.fd, con->http.error, - strerror(con->http.error)); + if (httpError(con->http) && httpError(con->http) != EPIPE) + cupsdLogClient(con, CUPSD_LOG_DEBUG, + "HTTP_STATE_POST_SEND Closing for error %d (%s)", + httpError(con->http), strerror(httpError(con->http))); else - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] HTTP_STATE_POST_SEND Closing on EOF", - con->http.fd); + cupsdLogClient(con, CUPSD_LOG_DEBUG, + "HTTP_STATE_POST_SEND Closing on EOF."); cupsdCloseClient(con); return; @@ -2250,19 +1945,32 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ { con->bytes += bytes; - if (write(con->file, line, bytes) < bytes) + if (MaxRequestSize > 0 && con->bytes > MaxRequestSize) + { + close(con->file); + con->file = -1; + unlink(con->filename); + cupsdClearString(&con->filename); + + if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) + { + cupsdCloseClient(con); + return; + } + } + + if (write(con->file, line, (size_t)bytes) < bytes) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Unable to write %d bytes to " - "\"%s\": %s", con->http.fd, bytes, - con->filename, strerror(errno)); + cupsdLogClient(con, CUPSD_LOG_ERROR, + "Unable to write %d bytes to \"%s\": %s", + bytes, con->filename, strerror(errno)); close(con->file); con->file = -1; unlink(con->filename); cupsdClearString(&con->filename); - if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, + if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); @@ -2270,21 +1978,21 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ } } } - else if (con->http.state == HTTP_STATE_POST_RECV) + else if (httpGetState(con->http) == HTTP_STATE_POST_RECV) return; - else if (con->http.state != HTTP_STATE_POST_SEND) + else if (httpGetState(con->http) != HTTP_STATE_POST_SEND) { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] Closing on unexpected state %s.", - con->http.fd, http_states[con->http.state + 1]); + cupsdLogClient(con, CUPSD_LOG_DEBUG, + "Closing on unexpected state %s.", + httpStateString(httpGetState(con->http))); cupsdCloseClient(con); return; } } } - while (con->http.state == HTTP_STATE_POST_RECV && data_ready(con)); + while (httpGetState(con->http) == HTTP_STATE_POST_RECV && httpGetReady(con->http)); - if (con->http.state == HTTP_STATE_POST_SEND) + if (httpGetState(con->http) == HTTP_STATE_POST_SEND) { if (con->file >= 0) { @@ -2313,7 +2021,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ con->request = NULL; } - if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_REQUEST_TOO_LARGE, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; @@ -2333,14 +2041,14 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ { if (!cupsdSendCommand(con, con->command, con->options, 0)) { - if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE)) + if (!cupsdSendError(con, HTTP_STATUS_NOT_FOUND, CUPSD_AUTH_NONE)) { cupsdCloseClient(con); return; } } else - cupsdLogRequest(con, HTTP_OK); + cupsdLogRequest(con, HTTP_STATUS_OK); } } @@ -2363,13 +2071,12 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ break; /* Anti-compiler-warning-code */ } - if (con->http.state == HTTP_STATE_WAITING) + if (httpGetState(con->http) == HTTP_STATE_WAITING) { - if (!con->http.keep_alive) + if (!httpGetKeepAlive(con->http)) { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "[Client %d] Closing because Keep-Alive disabled", - con->http.fd); + cupsdLogClient(con, CUPSD_LOG_DEBUG, + "Closing because Keep-Alive is disabled."); cupsdCloseClient(con); } else @@ -2401,10 +2108,10 @@ cupsdSendCommand( if (fd < 0) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "[Client %d] Unable to open \"%s\" for reading: %s", - con->http.fd, con->filename ? con->filename : "/dev/null", - strerror(errno)); + cupsdLogClient(con, CUPSD_LOG_ERROR, + "Unable to open \"%s\" for reading: %s", + con->filename ? con->filename : "/dev/null", + strerror(errno)); return (0); } @@ -2413,16 +2120,16 @@ cupsdSendCommand( else fd = -1; - con->pipe_pid = pipe_command(con, fd, &(con->file), command, options, root); + con->pipe_pid = pipe_command(con, fd, &(con->file), command, options, root); + con->pipe_status = HTTP_STATUS_OK; + + httpClearFields(con->http); if (fd >= 0) close(fd); - cupsdLogMessage(CUPSD_LOG_INFO, "[Client %d] Started \"%s\" (pid=%d)", - con->http.fd, command, con->pipe_pid); - - cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] file=%d", con->http.fd, - con->file); + cupsdLogClient(con, CUPSD_LOG_INFO, "Started \"%s\" (pid=%d, file=%d)", + command, con->pipe_pid, con->file); if (con->pipe_pid == 0) return (0); @@ -2431,6 +2138,8 @@ cupsdSendCommand( cupsdAddSelect(con->file, (cupsd_selfunc_t)write_pipe, NULL, con); + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Waiting for CGI data."); + con->sent_header = 0; con->file_ready = 0; con->got_fields = 0; @@ -2449,9 +2158,10 @@ cupsdSendError(cupsd_client_t *con, /* I - Connection */ http_status_t code, /* I - Error code */ int auth_type)/* I - Authentication type */ { - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "[Client %d] cupsdSendError code=%d, auth_type=%d", - con->http.fd, code, auth_type); + char location[HTTP_MAX_VALUE]; /* Location field */ + + + cupsdLogClient(con, CUPSD_LOG_DEBUG2, "cupsdSendError code=%d, auth_type=%d", code, auth_type); #ifdef HAVE_SSL /* @@ -2459,12 +2169,12 @@ cupsdSendError(cupsd_client_t *con, /* I - Connection */ * server is configured... */ - if (code == HTTP_UNAUTHORIZED && - DefaultEncryption == HTTP_ENCRYPT_REQUIRED && - _cups_strcasecmp(con->http.hostname, "localhost") && - !con->http.tls) + if (code == HTTP_STATUS_UNAUTHORIZED && + DefaultEncryption == HTTP_ENCRYPTION_REQUIRED && + _cups_strcasecmp(httpGetHostname(con->http, NULL, 0), "localhost") && + !httpIsEncrypted(con->http)) { - code = HTTP_UPGRADE_REQUIRED; + code = HTTP_STATUS_UPGRADE_REQUIRED; } #endif /* HAVE_SSL */ @@ -2482,34 +2192,20 @@ cupsdSendError(cupsd_client_t *con, /* I - Connection */ * never disable it in that case. */ - if (code >= HTTP_BAD_REQUEST && con->http.auth_type != CUPSD_AUTH_NEGOTIATE) - con->http.keep_alive = HTTP_KEEPALIVE_OFF; + strlcpy(location, httpGetField(con->http, HTTP_FIELD_LOCATION), sizeof(location)); - /* - * Send an error message back to the client. If the error code is a - * 400 or 500 series, make sure the message contains some text, too! - */ + httpClearFields(con->http); - if (!cupsdSendHeader(con, code, NULL, auth_type)) - return (0); + httpSetField(con->http, HTTP_FIELD_LOCATION, location); -#ifdef HAVE_SSL - if (code == HTTP_UPGRADE_REQUIRED) - if (httpPrintf(HTTP(con), "Connection: Upgrade\r\n") < 0) - return (0); + if (code >= HTTP_STATUS_BAD_REQUEST && con->type != CUPSD_AUTH_NEGOTIATE) + httpSetKeepAlive(con->http, HTTP_KEEPALIVE_OFF); - if (httpPrintf(HTTP(con), "Upgrade: TLS/1.2,TLS/1.1,TLS/1.0\r\n") < 0) - return (0); -#endif /* HAVE_SSL */ + if (httpGetVersion(con->http) >= HTTP_VERSION_1_1 && + httpGetKeepAlive(con->http) == HTTP_KEEPALIVE_OFF) + httpSetField(con->http, HTTP_FIELD_CONNECTION, "close"); - if (con->http.version >= HTTP_1_1 && - con->http.keep_alive == HTTP_KEEPALIVE_OFF) - { - if (httpPrintf(HTTP(con), "Connection: close\r\n") < 0) - return (0); - } - - if (code >= HTTP_BAD_REQUEST) + if (code >= HTTP_STATUS_BAD_REQUEST) { /* * Send a human-readable error message. @@ -2523,13 +2219,13 @@ cupsdSendError(cupsd_client_t *con, /* I - Connection */ redirect[0] = '\0'; - if (code == HTTP_UNAUTHORIZED) + if (code == HTTP_STATUS_UNAUTHORIZED) text = _cupsLangString(con->language, _("Enter your username and password or the " "root username and password to access this " "page. If you are using Kerberos authentication, " "make sure you have a valid Kerberos ticket.")); - else if (code == HTTP_UPGRADE_REQUIRED) + else if (code == HTTP_STATUS_UPGRADE_REQUIRED) { text = urltext; @@ -2546,7 +2242,7 @@ cupsdSendError(cupsd_client_t *con, /* I - Connection */ "CONTENT=\"3;URL=https://%s:%d%s\">\n", con->servername, con->serverport, con->uri); } - else if (code == HTTP_WEBIF_DISABLED) + else if (code == HTTP_STATUS_CUPS_WEBIF_DISABLED) text = _cupsLangString(con->language, _("The web interface is currently disabled. Run " "\"cupsctl WebInterface=yes\" to enable it.")); @@ -2570,27 +2266,34 @@ cupsdSendError(cupsd_client_t *con, /* I - Connection */ "
%s
\n" "