📄 http.c
字号:
/* * "$Id: http.c,v 1.144 2005/01/03 19:29:45 mike Exp $" * * HTTP routines for the Common UNIX Printing System (CUPS). * * Copyright 1997-2005 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products 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 missing or damaged please contact Easy Software Products * at: * * Attn: CUPS Licensing Information * Easy Software Products * 44141 Airport View Drive, Suite 204 * Hollywood, Maryland 20636 USA * * Voice: (301) 373-9600 * EMail: cups-info@cups.org * WWW: http://www.cups.org * * This file is subject to the Apple OS-Developed Software exception. * * Contents: * * httpInitialize() - Initialize the HTTP interface library and set the * default HTTP proxy (if any). * httpCheck() - Check to see if there is a pending response from * the server. * httpClearCookie() - Clear the cookie value(s). * httpClose() - Close an HTTP connection... * httpConnect() - Connect to a HTTP server. * httpConnectEncrypt() - Connect to a HTTP server using encryption. * httpEncryption() - Set the required encryption on the link. * httpReconnect() - Reconnect to a HTTP server... * httpGetSubField() - Get a sub-field value. * httpSetField() - Set the value of an HTTP header. * httpDelete() - Send a DELETE request to the server. * httpGet() - Send a GET request to the server. * httpHead() - Send a HEAD request to the server. * httpOptions() - Send an OPTIONS request to the server. * httpPost() - Send a POST request to the server. * httpPut() - Send a PUT request to the server. * httpTrace() - Send an TRACE request to the server. * httpFlush() - Flush data from a HTTP connection. * httpRead() - Read data from a HTTP connection. * httpSetCookie() - Set the cookie value(s)... * httpWait() - Wait for data available on a connection. * httpWrite() - Write data to a HTTP connection. * httpGets() - Get a line of text from a HTTP connection. * httpPrintf() - Print a formatted string to a HTTP connection. * httpGetDateString() - Get a formatted date/time string from a time value. * httpGetDateTime() - Get a time value from a formatted date/time string. * httpUpdate() - Update the current HTTP state for incoming data. * httpDecode64() - Base64-decode a string. * httpDecode64_2() - Base64-decode a string. * httpEncode64() - Base64-encode a string. * httpEncode64_2() - Base64-encode a string. * httpGetLength() - Get the amount of data remaining from the * content-length or transfer-encoding fields. * http_field() - Return the field index for a field name. * http_send() - Send a request with all fields and the trailing * blank line. * http_wait() - Wait for data available on a connection. * http_upgrade() - Force upgrade to TLS encryption. * http_setup_ssl() - Set up SSL/TLS on a connection. * http_shutdown_ssl() - Shut down SSL/TLS on a connection. * http_read_ssl() - Read from a SSL/TLS connection. * http_write_ssl() - Write to a SSL/TLS connection. * CDSAReadFunc() - Read function for CDSA decryption code. * CDSAWriteFunc() - Write function for CDSA encryption code. *//* * Include necessary headers... */#include "http-private.h"#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <ctype.h>#include "string.h"#include <fcntl.h>#include <errno.h>#include "http.h"#include "debug.h"#ifndef WIN32# include <signal.h># include <sys/time.h># include <sys/resource.h>#endif /* !WIN32 *//* * Some operating systems have done away with the Fxxxx constants for * the fcntl() call; this works around that "feature"... */#ifndef FNONBLK# define FNONBLK O_NONBLOCK#endif /* !FNONBLK *//* * Local functions... */static http_field_t http_field(const char *name);static int http_send(http_t *http, http_state_t request, const char *uri);static int http_wait(http_t *http, int msec);#ifdef HAVE_SSLstatic int http_upgrade(http_t *http);static int http_setup_ssl(http_t *http);static void http_shutdown_ssl(http_t *http);static int http_read_ssl(http_t *http, char *buf, int len);static int http_write_ssl(http_t *http, const char *buf, int len);# ifdef HAVE_CDSASSLstatic OSStatus CDSAReadFunc(SSLConnectionRef connection, void *data, size_t *dataLength);static OSStatus CDSAWriteFunc(SSLConnectionRef connection, const void *data, size_t *dataLength);# endif /* HAVE_CDSASSL */#endif /* HAVE_SSL *//* * Local globals... */static const char * const http_fields[] = { "Accept-Language", "Accept-Ranges", "Authorization", "Connection", "Content-Encoding", "Content-Language", "Content-Length", "Content-Location", "Content-MD5", "Content-Range", "Content-Type", "Content-Version", "Date", "Host", "If-Modified-Since", "If-Unmodified-since", "Keep-Alive", "Last-Modified", "Link", "Location", "Range", "Referer", "Retry-After", "Transfer-Encoding", "Upgrade", "User-Agent", "WWW-Authenticate" };static const char * const days[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };static const char * const months[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };/* * 'httpInitialize()' - Initialize the HTTP interface library and set the * default HTTP proxy (if any). */voidhttpInitialize(void){#ifdef HAVE_LIBSSL# ifndef WIN32 struct timeval curtime; /* Current time in microseconds */# endif /* !WIN32 */ int i; /* Looping var */ unsigned char data[1024]; /* Seed data */#endif /* HAVE_LIBSSL */#ifdef WIN32 WSADATA winsockdata; /* WinSock data */ static int initialized = 0; /* Has WinSock been initialized? */ if (!initialized) WSAStartup(MAKEWORD(1,1), &winsockdata);#elif defined(HAVE_SIGSET) sigset(SIGPIPE, SIG_IGN);#elif defined(HAVE_SIGACTION) struct sigaction action; /* POSIX sigaction data */ /* * Ignore SIGPIPE signals... */ memset(&action, 0, sizeof(action)); action.sa_handler = SIG_IGN; sigaction(SIGPIPE, &action, NULL);#else signal(SIGPIPE, SIG_IGN);#endif /* WIN32 */#ifdef HAVE_GNUTLS gnutls_global_init();#endif /* HAVE_GNUTLS */#ifdef HAVE_LIBSSL SSL_load_error_strings(); SSL_library_init(); /* * Using the current time is a dubious random seed, but on some systems * it is the best we can do (on others, this seed isn't even used...) */#ifdef WIN32#else gettimeofday(&curtime, NULL); srand(curtime.tv_sec + curtime.tv_usec);#endif /* WIN32 */ for (i = 0; i < sizeof(data); i ++) data[i] = rand(); /* Yes, this is a poor source of random data... */ RAND_seed(&data, sizeof(data));#endif /* HAVE_LIBSSL */}/* * 'httpCheck()' - Check to see if there is a pending response from the server. */int /* O - 0 = no data, 1 = data available */httpCheck(http_t *http) /* I - HTTP connection */{ return (httpWait(http, 0));}/* * 'httpClearCookie()' - Clear the cookie value(s). */voidhttpClearCookie(http_t *http) /* I - Connection */{ if (!http) return; if (http->cookie) { free(http->cookie); http->cookie = NULL; }}/* * 'httpClose()' - Close an HTTP connection... */voidhttpClose(http_t *http) /* I - Connection to close */{ DEBUG_printf(("httpClose(http=%p)\n", http)); if (!http) return; if (http->input_set) free(http->input_set); if (http->cookie) free(http->cookie);#ifdef HAVE_SSL if (http->tls) http_shutdown_ssl(http);#endif /* HAVE_SSL */#ifdef WIN32 closesocket(http->fd);#else close(http->fd);#endif /* WIN32 */ free(http);}/* * 'httpConnect()' - Connect to a HTTP server. */http_t * /* O - New HTTP connection */httpConnect(const char *host, /* I - Host to connect to */ int port) /* I - Port number */{ http_encryption_t encrypt;/* Type of encryption to use */ /* * Set the default encryption status... */ if (port == 443) encrypt = HTTP_ENCRYPT_ALWAYS; else encrypt = HTTP_ENCRYPT_IF_REQUESTED; return (httpConnectEncrypt(host, port, encrypt));}/* * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption. */http_t * /* O - New HTTP connection */httpConnectEncrypt(const char *host, /* I - Host to connect to */ int port, /* I - Port number */ http_encryption_t encrypt) /* I - Type of encryption to use */{ int i; /* Looping var */ http_t *http; /* New HTTP connection */ struct hostent *hostaddr; /* Host address data */ DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encrypt=%d)\n", host ? host : "(null)", port, encrypt)); if (!host) return (NULL); httpInitialize(); /* * Lookup the host... */ if ((hostaddr = httpGetHostByName(host)) == NULL) { /* * This hack to make users that don't have a localhost entry in * their hosts file or DNS happy... */ if (strcasecmp(host, "localhost") != 0) return (NULL); else if ((hostaddr = httpGetHostByName("127.0.0.1")) == NULL) return (NULL); } /* * Verify that it is an IPv4 address (IPv6 support will come in CUPS 1.2...) */ if (hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4) return (NULL); /* * Allocate memory for the structure... */ http = calloc(sizeof(http_t), 1); if (http == NULL) return (NULL); http->version = HTTP_1_1; http->blocking = 1; http->activity = time(NULL); http->fd = -1; /* * Copy the hostname and port and then "reconnect"... */ strlcpy(http->hostname, host, sizeof(http->hostname)); http->hostaddr.sin_family = hostaddr->h_addrtype;#ifdef WIN32 http->hostaddr.sin_port = htons((u_short)port);#else http->hostaddr.sin_port = htons(port);#endif /* WIN32 */ /* * Set the encryption status... */ if (port == 443) /* Always use encryption for https */ http->encryption = HTTP_ENCRYPT_ALWAYS; else http->encryption = encrypt; /* * Loop through the addresses we have until one of them connects... */ strlcpy(http->hostname, host, sizeof(http->hostname)); for (i = 0; hostaddr->h_addr_list[i]; i ++) { /* * Load the address... */ memcpy((char *)&(http->hostaddr.sin_addr), hostaddr->h_addr_list[i], hostaddr->h_length); /* * Connect to the remote system... */ if (!httpReconnect(http)) return (http); } /* * Could not connect to any known address - bail out! */ free(http); return (NULL);}/* * 'httpEncryption()' - Set the required encryption on the link. */int /* O - -1 on error, 0 on success */httpEncryption(http_t *http, /* I - HTTP data */ http_encryption_t e) /* I - New encryption preference */{ DEBUG_printf(("httpEncryption(http=%p, e=%d)\n", http, e));#ifdef HAVE_SSL if (!http) return (0); http->encryption = e; if ((http->encryption == HTTP_ENCRYPT_ALWAYS && !http->tls) || (http->encryption == HTTP_ENCRYPT_NEVER && http->tls)) return (httpReconnect(http)); else if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls) return (http_upgrade(http)); else return (0);#else if (e == HTTP_ENCRYPT_ALWAYS || e == HTTP_ENCRYPT_REQUIRED) return (-1); else return (0);#endif /* HAVE_SSL */}/* * 'httpReconnect()' - Reconnect to a HTTP server... */int /* O - 0 on success, non-zero on failure */httpReconnect(http_t *http) /* I - HTTP data */{ int val; /* Socket option value */ DEBUG_printf(("httpReconnect(http=%p)\n", http)); if (!http) return (-1);#ifdef HAVE_SSL if (http->tls) http_shutdown_ssl(http);#endif /* HAVE_SSL */ /* * Close any previously open socket... */ if (http->fd >= 0)#ifdef WIN32 closesocket(http->fd);#else close(http->fd);#endif /* WIN32 */ /* * Create the socket and set options to allow reuse. */ if ((http->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {#ifdef WIN32 http->error = WSAGetLastError();#else http->error = errno;#endif /* WIN32 */ http->status = HTTP_ERROR; return (-1); }#ifdef FD_CLOEXEC fcntl(http->fd, F_SETFD, FD_CLOEXEC); /* Close this socket when starting * * other processes... */#endif /* FD_CLOEXEC */ val = 1; setsockopt(http->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));#ifdef SO_REUSEPORT val = 1; setsockopt(http->fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));#endif /* SO_REUSEPORT */ /* * 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;#ifdef WIN32 setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); #else setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); #endif // WIN32 /* * Connect to the server... */ if (connect(http->fd, (struct sockaddr *)&(http->hostaddr), sizeof(http->hostaddr)) < 0) {#ifdef WIN32 http->error = WSAGetLastError();#else http->error = errno;#endif /* WIN32 */ http->status = HTTP_ERROR;#ifdef WIN32 closesocket(http->fd);#else close(http->fd);#endif http->fd = -1; return (-1); } http->error = 0; http->status = HTTP_CONTINUE;#ifdef HAVE_SSL if (http->encryption == HTTP_ENCRYPT_ALWAYS) { /* * Always do encryption via SSL. */ if (http_setup_ssl(http) != 0) {#ifdef WIN32 closesocket(http->fd);#else close(http->fd);#endif /* WIN32 */ return (-1); } } else if (http->encryption == HTTP_ENCRYPT_REQUIRED) return (http_upgrade(http));#endif /* HAVE_SSL */ return (0);}/* * 'httpGetSubField()' - Get a sub-field value. */char * /* O - Value or NULL */httpGetSubField(http_t *http, /* I - HTTP data */ http_field_t field, /* I - Field index */ const char *name, /* I - Name of sub-field */ char *value) /* O - Value string */{ const char *fptr; /* Pointer into field */ char temp[HTTP_MAX_VALUE], /* Temporary buffer for name */ *ptr; /* Pointer into string buffer */ DEBUG_printf(("httpGetSubField(http=%p, field=%d, name=\"%s\", value=%p)\n", http, field, name, value)); if (http == NULL || field < HTTP_FIELD_ACCEPT_LANGUAGE || field > HTTP_FIELD_WWW_AUTHENTICATE || name == NULL || value == NULL) return (NULL); for (fptr = http->fields[field]; *fptr;)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -