xref: /onnv-gate/usr/src/lib/print/libhttp-core/common/http.c (revision 3125:084bca4d4623)
12264Sjacobs /*
22264Sjacobs  * "$Id: http.c 148 2006-04-25 16:54:17Z njacobs $"
32264Sjacobs  *
42264Sjacobs  *   HTTP routines for the Common UNIX Printing System (CUPS).
52264Sjacobs  *
62264Sjacobs  *   Copyright 1997-2005 by Easy Software Products, all rights reserved.
72264Sjacobs  *
82264Sjacobs  *   These coded instructions, statements, and computer programs are the
92264Sjacobs  *   property of Easy Software Products and are protected by Federal
102264Sjacobs  *   copyright law.  Distribution and use rights are outlined in the file
112264Sjacobs  *   "LICENSE.txt" which should have been included with this file.  If this
122264Sjacobs  *   file is missing or damaged please contact Easy Software Products
132264Sjacobs  *   at:
142264Sjacobs  *
152264Sjacobs  *       Attn: CUPS Licensing Information
162264Sjacobs  *       Easy Software Products
172264Sjacobs  *       44141 Airport View Drive, Suite 204
182264Sjacobs  *       Hollywood, Maryland 20636 USA
192264Sjacobs  *
202264Sjacobs  *       Voice: (301) 373-9600
212264Sjacobs  *       EMail: cups-info@cups.org
222264Sjacobs  *         WWW: http://www.cups.org
232264Sjacobs  *
242264Sjacobs  *   This file is subject to the Apple OS-Developed Software exception.
252264Sjacobs  *
262264Sjacobs  * Contents:
272264Sjacobs  *
282264Sjacobs  *   httpInitialize()     - Initialize the HTTP interface library and set the
292264Sjacobs  *                          default HTTP proxy (if any).
302264Sjacobs  *   httpCheck()          - Check to see if there is a pending response from
312264Sjacobs  *                          the server.
322264Sjacobs  *   httpClearCookie()    - Clear the cookie value(s).
332264Sjacobs  *   httpClose()          - Close an HTTP connection...
342264Sjacobs  *   httpConnect()        - Connect to a HTTP server.
352264Sjacobs  *   httpConnectEncrypt() - Connect to a HTTP server using encryption.
362264Sjacobs  *   httpEncryption()     - Set the required encryption on the link.
372264Sjacobs  *   httpReconnect()      - Reconnect to a HTTP server...
382264Sjacobs  *   httpGetSubField()    - Get a sub-field value.
392264Sjacobs  *   httpSetField()       - Set the value of an HTTP header.
402264Sjacobs  *   httpDelete()         - Send a DELETE request to the server.
412264Sjacobs  *   httpGet()            - Send a GET request to the server.
422264Sjacobs  *   httpHead()           - Send a HEAD request to the server.
432264Sjacobs  *   httpOptions()        - Send an OPTIONS request to the server.
442264Sjacobs  *   httpPost()           - Send a POST request to the server.
452264Sjacobs  *   httpPut()            - Send a PUT request to the server.
462264Sjacobs  *   httpTrace()          - Send an TRACE request to the server.
472264Sjacobs  *   httpFlush()          - Flush data from a HTTP connection.
482264Sjacobs  *   httpRead()           - Read data from a HTTP connection.
492264Sjacobs  *   httpSetCookie()      - Set the cookie value(s)...
502264Sjacobs  *   httpWait()           - Wait for data available on a connection.
512264Sjacobs  *   httpWrite()          - Write data to a HTTP connection.
522264Sjacobs  *   httpGets()           - Get a line of text from a HTTP connection.
532264Sjacobs  *   httpPrintf()         - Print a formatted string to a HTTP connection.
542264Sjacobs  *   httpGetDateString()  - Get a formatted date/time string from a time value.
552264Sjacobs  *   httpGetDateTime()    - Get a time value from a formatted date/time string.
562264Sjacobs  *   httpUpdate()         - Update the current HTTP state for incoming data.
572264Sjacobs  *   httpDecode64()       - Base64-decode a string.
582264Sjacobs  *   httpDecode64_2()     - Base64-decode a string.
592264Sjacobs  *   httpEncode64()       - Base64-encode a string.
602264Sjacobs  *   httpEncode64_2()     - Base64-encode a string.
612264Sjacobs  *   httpGetLength()      - Get the amount of data remaining from the
622264Sjacobs  *                          content-length or transfer-encoding fields.
632264Sjacobs  *   http_field()         - Return the field index for a field name.
642264Sjacobs  *   http_send()          - Send a request with all fields and the trailing
652264Sjacobs  *                          blank line.
662264Sjacobs  *   http_wait()          - Wait for data available on a connection.
672264Sjacobs  *   http_upgrade()       - Force upgrade to TLS encryption.
682264Sjacobs  *   http_setup_ssl()     - Set up SSL/TLS on a connection.
692264Sjacobs  *   http_shutdown_ssl()  - Shut down SSL/TLS on a connection.
702264Sjacobs  *   http_read_ssl()      - Read from a SSL/TLS connection.
712264Sjacobs  *   http_write_ssl()     - Write to a SSL/TLS connection.
722264Sjacobs  *   CDSAReadFunc()       - Read function for CDSA decryption code.
732264Sjacobs  *   CDSAWriteFunc()      - Write function for CDSA encryption code.
742264Sjacobs  */
752264Sjacobs 
762264Sjacobs #pragma ident	"%Z%%M%	%I%	%E% SMI"
772264Sjacobs 
782264Sjacobs /*
792264Sjacobs  * Include necessary headers...
802264Sjacobs  */
812264Sjacobs 
822264Sjacobs #include "http-private.h"
832264Sjacobs 
842264Sjacobs #include <stdio.h>
852264Sjacobs #include <stdlib.h>
862264Sjacobs #include <stdarg.h>
872264Sjacobs #include <ctype.h>
882264Sjacobs #include "string.h"
892264Sjacobs #include <fcntl.h>
902264Sjacobs #include <errno.h>
912264Sjacobs 
922264Sjacobs #include "http.h"
932264Sjacobs #include "debug.h"
942264Sjacobs 
952264Sjacobs #ifndef WIN32
962264Sjacobs #  include <signal.h>
972264Sjacobs #  include <sys/time.h>
982264Sjacobs #  include <sys/resource.h>
992264Sjacobs #endif /* !WIN32 */
1002264Sjacobs 
1012264Sjacobs 
1022264Sjacobs /*
1032264Sjacobs  * Some operating systems have done away with the Fxxxx constants for
1042264Sjacobs  * the fcntl() call; this works around that "feature"...
1052264Sjacobs  */
1062264Sjacobs 
1072264Sjacobs #ifndef FNONBLK
1082264Sjacobs #  define FNONBLK O_NONBLOCK
1092264Sjacobs #endif /* !FNONBLK */
1102264Sjacobs 
1112264Sjacobs 
1122264Sjacobs /*
1132264Sjacobs  * Local functions...
1142264Sjacobs  */
1152264Sjacobs 
1162264Sjacobs static http_field_t	http_field(const char *name);
1172264Sjacobs static int		http_send(http_t *http, http_state_t request,
1182264Sjacobs 			          const char *uri);
1192264Sjacobs static int		http_wait(http_t *http, int msec);
1202264Sjacobs #ifdef HAVE_SSL
1212264Sjacobs static int		http_upgrade(http_t *http);
1222264Sjacobs static int		http_setup_ssl(http_t *http);
1232264Sjacobs static void		http_shutdown_ssl(http_t *http);
1242264Sjacobs static int		http_read_ssl(http_t *http, char *buf, int len);
1252264Sjacobs static int		http_write_ssl(http_t *http, const char *buf, int len);
1262264Sjacobs #  ifdef HAVE_CDSASSL
1272264Sjacobs static OSStatus		CDSAReadFunc(SSLConnectionRef connection, void *data, size_t *dataLength);
1282264Sjacobs static OSStatus		CDSAWriteFunc(SSLConnectionRef connection, const void *data, size_t *dataLength);
1292264Sjacobs #  endif /* HAVE_CDSASSL */
1302264Sjacobs #endif /* HAVE_SSL */
1312264Sjacobs 
1322264Sjacobs 
1332264Sjacobs /*
1342264Sjacobs  * Local globals...
1352264Sjacobs  */
1362264Sjacobs 
1372264Sjacobs static const char * const http_fields[] =
1382264Sjacobs 			{
1392264Sjacobs 			  "Accept-Language",
1402264Sjacobs 			  "Accept-Ranges",
1412264Sjacobs 			  "Authorization",
1422264Sjacobs 			  "Connection",
1432264Sjacobs 			  "Content-Encoding",
1442264Sjacobs 			  "Content-Language",
1452264Sjacobs 			  "Content-Length",
1462264Sjacobs 			  "Content-Location",
1472264Sjacobs 			  "Content-MD5",
1482264Sjacobs 			  "Content-Range",
1492264Sjacobs 			  "Content-Type",
1502264Sjacobs 			  "Content-Version",
1512264Sjacobs 			  "Date",
1522264Sjacobs 			  "Host",
1532264Sjacobs 			  "If-Modified-Since",
1542264Sjacobs 			  "If-Unmodified-since",
1552264Sjacobs 			  "Keep-Alive",
1562264Sjacobs 			  "Last-Modified",
1572264Sjacobs 			  "Link",
1582264Sjacobs 			  "Location",
1592264Sjacobs 			  "Range",
1602264Sjacobs 			  "Referer",
1612264Sjacobs 			  "Retry-After",
1622264Sjacobs 			  "Transfer-Encoding",
1632264Sjacobs 			  "Upgrade",
1642264Sjacobs 			  "User-Agent",
1652264Sjacobs 			  "WWW-Authenticate"
1662264Sjacobs 			};
1672264Sjacobs static const char * const days[7] =
1682264Sjacobs 			{
1692264Sjacobs 			  "Sun",
1702264Sjacobs 			  "Mon",
1712264Sjacobs 			  "Tue",
1722264Sjacobs 			  "Wed",
1732264Sjacobs 			  "Thu",
1742264Sjacobs 			  "Fri",
1752264Sjacobs 			  "Sat"
1762264Sjacobs 			};
1772264Sjacobs static const char * const months[12] =
1782264Sjacobs 			{
1792264Sjacobs 			  "Jan",
1802264Sjacobs 			  "Feb",
1812264Sjacobs 			  "Mar",
1822264Sjacobs 			  "Apr",
1832264Sjacobs 			  "May",
1842264Sjacobs 			  "Jun",
1852264Sjacobs 		          "Jul",
1862264Sjacobs 			  "Aug",
1872264Sjacobs 			  "Sep",
1882264Sjacobs 			  "Oct",
1892264Sjacobs 			  "Nov",
1902264Sjacobs 			  "Dec"
1912264Sjacobs 			};
1922264Sjacobs 
1932264Sjacobs void
httpDumpData(FILE * fp,const char * tag,const char * buffer,int bytes)194*3125Sjacobs httpDumpData(FILE *fp, const char *tag, const char *buffer, int bytes)
1952264Sjacobs {
1962264Sjacobs         int i, j, ch;
1972264Sjacobs 
1982264Sjacobs 	fprintf(fp, "%s %d(0x%x) bytes...\n", tag, bytes, bytes);
1992264Sjacobs         for (i = 0; i < bytes; i += 16) {
2002264Sjacobs                 fprintf(fp, "%s   ", (tag ? tag : ""));
2012264Sjacobs 
2022264Sjacobs                 for (j = 0; j < 16 && (i + j) < bytes; j ++)
2032264Sjacobs                         fprintf(fp, " %02X", buffer[i + j] & 255);
2042264Sjacobs 
2052264Sjacobs                 while (j < 16) {
2062264Sjacobs                         fprintf(fp, "   ");
2072264Sjacobs                         j++;
2082264Sjacobs                 }
2092264Sjacobs 
2102264Sjacobs                 fprintf(fp, "    ");
2112264Sjacobs                 for (j = 0; j < 16 && (i + j) < bytes; j ++) {
2122264Sjacobs                         ch = buffer[i + j] & 255;
2132264Sjacobs                         if (ch < ' ' || ch == 127)
2142264Sjacobs                                 ch = '.';
2152264Sjacobs                         putc(ch, fp);
2162264Sjacobs                 }
2172264Sjacobs                 putc('\n', fp);
2182264Sjacobs         }
2192264Sjacobs }
2202264Sjacobs 
2212264Sjacobs 
2222264Sjacobs /*
2232264Sjacobs  * 'httpInitialize()' - Initialize the HTTP interface library and set the
2242264Sjacobs  *                      default HTTP proxy (if any).
2252264Sjacobs  */
2262264Sjacobs 
2272264Sjacobs void
httpInitialize(void)2282264Sjacobs httpInitialize(void)
2292264Sjacobs {
2302264Sjacobs #ifdef HAVE_LIBSSL
2312264Sjacobs #  ifndef WIN32
2322264Sjacobs   struct timeval	curtime;	/* Current time in microseconds */
2332264Sjacobs #  endif /* !WIN32 */
2342264Sjacobs   int			i;		/* Looping var */
2352264Sjacobs   unsigned char		data[1024];	/* Seed data */
2362264Sjacobs #endif /* HAVE_LIBSSL */
2372264Sjacobs 
2382264Sjacobs #ifdef WIN32
2392264Sjacobs   WSADATA	winsockdata;		/* WinSock data */
2402264Sjacobs   static int	initialized = 0;	/* Has WinSock been initialized? */
2412264Sjacobs 
2422264Sjacobs 
2432264Sjacobs   if (!initialized)
2442264Sjacobs     WSAStartup(MAKEWORD(1,1), &winsockdata);
2452264Sjacobs #elif defined(HAVE_SIGSET)
2462264Sjacobs   sigset(SIGPIPE, SIG_IGN);
2472264Sjacobs #elif defined(HAVE_SIGACTION)
2482264Sjacobs   struct sigaction	action;		/* POSIX sigaction data */
2492264Sjacobs 
2502264Sjacobs 
2512264Sjacobs  /*
2522264Sjacobs   * Ignore SIGPIPE signals...
2532264Sjacobs   */
2542264Sjacobs 
2552264Sjacobs   memset(&action, 0, sizeof(action));
2562264Sjacobs   action.sa_handler = SIG_IGN;
2572264Sjacobs   sigaction(SIGPIPE, &action, NULL);
2582264Sjacobs #else
2592264Sjacobs   signal(SIGPIPE, SIG_IGN);
2602264Sjacobs #endif /* WIN32 */
2612264Sjacobs 
2622264Sjacobs #ifdef HAVE_GNUTLS
2632264Sjacobs   gnutls_global_init();
2642264Sjacobs #endif /* HAVE_GNUTLS */
2652264Sjacobs 
2662264Sjacobs #ifdef HAVE_LIBSSL
2672264Sjacobs   SSL_load_error_strings();
2682264Sjacobs   SSL_library_init();
2692264Sjacobs 
2702264Sjacobs  /*
2712264Sjacobs   * Using the current time is a dubious random seed, but on some systems
2722264Sjacobs   * it is the best we can do (on others, this seed isn't even used...)
2732264Sjacobs   */
2742264Sjacobs 
2752264Sjacobs #ifdef WIN32
2762264Sjacobs #else
2772264Sjacobs   gettimeofday(&curtime, NULL);
2782264Sjacobs   srand(curtime.tv_sec + curtime.tv_usec);
2792264Sjacobs #endif /* WIN32 */
2802264Sjacobs 
2812264Sjacobs   for (i = 0; i < sizeof(data); i ++)
2822264Sjacobs     data[i] = rand(); /* Yes, this is a poor source of random data... */
2832264Sjacobs 
2842264Sjacobs   RAND_seed(&data, sizeof(data));
2852264Sjacobs #endif /* HAVE_LIBSSL */
2862264Sjacobs }
2872264Sjacobs 
2882264Sjacobs 
2892264Sjacobs /*
2902264Sjacobs  * 'httpCheck()' - Check to see if there is a pending response from the server.
2912264Sjacobs  */
2922264Sjacobs 
2932264Sjacobs int				/* O - 0 = no data, 1 = data available */
httpCheck(http_t * http)2942264Sjacobs httpCheck(http_t *http)		/* I - HTTP connection */
2952264Sjacobs {
2962264Sjacobs   return (httpWait(http, 0));
2972264Sjacobs }
2982264Sjacobs 
2992264Sjacobs 
3002264Sjacobs /*
3012264Sjacobs  * 'httpClearCookie()' - Clear the cookie value(s).
3022264Sjacobs  */
3032264Sjacobs 
3042264Sjacobs void
httpClearCookie(http_t * http)3052264Sjacobs httpClearCookie(http_t *http)			/* I - Connection */
3062264Sjacobs {
3072264Sjacobs   if (!http)
3082264Sjacobs     return;
3092264Sjacobs 
3102264Sjacobs   if (http->cookie)
3112264Sjacobs   {
3122264Sjacobs     free(http->cookie);
3132264Sjacobs     http->cookie = NULL;
3142264Sjacobs   }
3152264Sjacobs }
3162264Sjacobs 
3172264Sjacobs 
3182264Sjacobs /*
3192264Sjacobs  * 'httpClose()' - Close an HTTP connection...
3202264Sjacobs  */
3212264Sjacobs 
3222264Sjacobs void
httpClose(http_t * http)3232264Sjacobs httpClose(http_t *http)		/* I - Connection to close */
3242264Sjacobs {
3252264Sjacobs   DEBUG_printf(("httpClose(http=%p)\n", http));
3262264Sjacobs 
3272264Sjacobs   if (!http)
3282264Sjacobs     return;
3292264Sjacobs 
3302264Sjacobs   if (http->input_set)
3312264Sjacobs     free(http->input_set);
3322264Sjacobs 
3332264Sjacobs   if (http->cookie)
3342264Sjacobs     free(http->cookie);
3352264Sjacobs 
3362264Sjacobs #ifdef HAVE_SSL
3372264Sjacobs   if (http->tls)
3382264Sjacobs     http_shutdown_ssl(http);
3392264Sjacobs #endif /* HAVE_SSL */
3402264Sjacobs 
3412264Sjacobs #ifdef WIN32
3422264Sjacobs   closesocket(http->fd);
3432264Sjacobs #else
3442264Sjacobs   close(http->fd);
3452264Sjacobs #endif /* WIN32 */
3462264Sjacobs 
3472264Sjacobs   free(http);
3482264Sjacobs }
3492264Sjacobs 
3502264Sjacobs 
3512264Sjacobs /*
3522264Sjacobs  * 'httpConnect()' - Connect to a HTTP server.
3532264Sjacobs  */
3542264Sjacobs 
3552264Sjacobs http_t *				/* O - New HTTP connection */
httpConnect(const char * host,int port)3562264Sjacobs httpConnect(const char *host,		/* I - Host to connect to */
3572264Sjacobs             int        port)		/* I - Port number */
3582264Sjacobs {
3592264Sjacobs   http_encryption_t	encrypt;	/* Type of encryption to use */
3602264Sjacobs 
3612264Sjacobs 
3622264Sjacobs  /*
3632264Sjacobs   * Set the default encryption status...
3642264Sjacobs   */
3652264Sjacobs 
3662264Sjacobs   if (port == 443)
3672264Sjacobs     encrypt = HTTP_ENCRYPT_ALWAYS;
3682264Sjacobs   else
3692264Sjacobs     encrypt = HTTP_ENCRYPT_IF_REQUESTED;
3702264Sjacobs 
3712264Sjacobs   return (httpConnectEncrypt(host, port, encrypt));
3722264Sjacobs }
3732264Sjacobs 
3742264Sjacobs 
3752264Sjacobs /*
3762264Sjacobs  * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption.
3772264Sjacobs  */
3782264Sjacobs 
3792264Sjacobs http_t *				/* O - New HTTP connection */
httpConnectEncrypt(const char * host,int port,http_encryption_t encrypt)3802264Sjacobs httpConnectEncrypt(const char *host,	/* I - Host to connect to */
3812264Sjacobs                    int        port,	/* I - Port number */
3822264Sjacobs 		   http_encryption_t encrypt)
3832264Sjacobs 					/* I - Type of encryption to use */
3842264Sjacobs {
3852264Sjacobs   int			i;		/* Looping var */
3862264Sjacobs   http_t		*http;		/* New HTTP connection */
3872264Sjacobs   struct hostent	*hostaddr;	/* Host address data */
3882264Sjacobs 
3892264Sjacobs 
3902264Sjacobs   DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encrypt=%d)\n",
3912264Sjacobs                 host ? host : "(null)", port, encrypt));
3922264Sjacobs 
3932264Sjacobs   if (!host)
3942264Sjacobs     return (NULL);
3952264Sjacobs 
3962264Sjacobs   httpInitialize();
3972264Sjacobs 
3982264Sjacobs  /*
3992264Sjacobs   * Lookup the host...
4002264Sjacobs   */
4012264Sjacobs 
4022264Sjacobs   if ((hostaddr = httpGetHostByName(host)) == NULL)
4032264Sjacobs   {
4042264Sjacobs    /*
4052264Sjacobs     * This hack to make users that don't have a localhost entry in
4062264Sjacobs     * their hosts file or DNS happy...
4072264Sjacobs     */
4082264Sjacobs 
4092264Sjacobs     if (strcasecmp(host, "localhost") != 0)
4102264Sjacobs       return (NULL);
4112264Sjacobs     else if ((hostaddr = httpGetHostByName("127.0.0.1")) == NULL)
4122264Sjacobs       return (NULL);
4132264Sjacobs   }
4142264Sjacobs 
4152264Sjacobs  /*
4162264Sjacobs   * Verify that it is an IPv4, IPv6, or domain address...
4172264Sjacobs   */
4182264Sjacobs 
4192264Sjacobs   if ((hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4)
4202264Sjacobs #ifdef AF_INET6
4212264Sjacobs       && (hostaddr->h_addrtype != AF_INET6 || hostaddr->h_length != 16)
4222264Sjacobs #endif /* AF_INET6 */
4232264Sjacobs #ifdef AF_LOCAL
4242264Sjacobs       && (hostaddr->h_addrtype != AF_LOCAL)
4252264Sjacobs #endif /* AF_LOCAL */
4262264Sjacobs       )
4272264Sjacobs     return (NULL);
4282264Sjacobs 
4292264Sjacobs  /*
4302264Sjacobs   * Allocate memory for the structure...
4312264Sjacobs   */
4322264Sjacobs 
4332264Sjacobs   http = calloc(sizeof(http_t), 1);
4342264Sjacobs   if (http == NULL)
4352264Sjacobs     return (NULL);
4362264Sjacobs 
4372264Sjacobs   http->version  = HTTP_1_1;
4382264Sjacobs   http->blocking = 1;
4392264Sjacobs   http->activity = time(NULL);
4402264Sjacobs   http->fd       = -1;
4412264Sjacobs 
4422264Sjacobs  /*
4432264Sjacobs   * Set the encryption status...
4442264Sjacobs   */
4452264Sjacobs 
4462264Sjacobs   if (port == 443)			/* Always use encryption for https */
4472264Sjacobs     http->encryption = HTTP_ENCRYPT_ALWAYS;
4482264Sjacobs   else
4492264Sjacobs     http->encryption = encrypt;
4502264Sjacobs 
4512264Sjacobs  /*
4522264Sjacobs   * Loop through the addresses we have until one of them connects...
4532264Sjacobs   */
4542264Sjacobs 
4552264Sjacobs   strlcpy(http->hostname, host, sizeof(http->hostname));
4562264Sjacobs 
4572264Sjacobs   for (i = 0; hostaddr->h_addr_list[i]; i ++)
4582264Sjacobs   {
4592264Sjacobs    /*
4602264Sjacobs     * Load the address...
4612264Sjacobs     */
4622264Sjacobs 
4632264Sjacobs     httpAddrLoad(hostaddr, port, i, &(http->hostaddr));
4642264Sjacobs 
4652264Sjacobs    /*
4662264Sjacobs     * Connect to the remote system...
4672264Sjacobs     */
4682264Sjacobs 
4692264Sjacobs     if (!httpReconnect(http))
4702264Sjacobs       return (http);
4712264Sjacobs   }
4722264Sjacobs 
4732264Sjacobs  /*
4742264Sjacobs   * Could not connect to any known address - bail out!
4752264Sjacobs   */
4762264Sjacobs 
4772264Sjacobs   free(http);
4782264Sjacobs   return (NULL);
4792264Sjacobs }
4802264Sjacobs 
4812264Sjacobs 
4822264Sjacobs /*
4832264Sjacobs  * 'httpEncryption()' - Set the required encryption on the link.
4842264Sjacobs  */
4852264Sjacobs 
4862264Sjacobs int					/* O - -1 on error, 0 on success */
httpEncryption(http_t * http,http_encryption_t e)4872264Sjacobs httpEncryption(http_t            *http,	/* I - HTTP data */
4882264Sjacobs                http_encryption_t e)	/* I - New encryption preference */
4892264Sjacobs {
4902264Sjacobs   DEBUG_printf(("httpEncryption(http=%p, e=%d)\n", http, e));
4912264Sjacobs 
4922264Sjacobs #ifdef HAVE_SSL
4932264Sjacobs   if (!http)
4942264Sjacobs     return (0);
4952264Sjacobs 
4962264Sjacobs   http->encryption = e;
4972264Sjacobs 
4982264Sjacobs   if ((http->encryption == HTTP_ENCRYPT_ALWAYS && !http->tls) ||
4992264Sjacobs       (http->encryption == HTTP_ENCRYPT_NEVER && http->tls))
5002264Sjacobs     return (httpReconnect(http));
5012264Sjacobs   else if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
5022264Sjacobs     return (http_upgrade(http));
5032264Sjacobs   else
5042264Sjacobs     return (0);
5052264Sjacobs #else
5062264Sjacobs   if (e == HTTP_ENCRYPT_ALWAYS || e == HTTP_ENCRYPT_REQUIRED)
5072264Sjacobs     return (-1);
5082264Sjacobs   else
5092264Sjacobs     return (0);
5102264Sjacobs #endif /* HAVE_SSL */
5112264Sjacobs }
5122264Sjacobs 
5132264Sjacobs 
5142264Sjacobs /*
5152264Sjacobs  * 'httpReconnect()' - Reconnect to a HTTP server...
5162264Sjacobs  */
5172264Sjacobs 
5182264Sjacobs int					/* O - 0 on success, non-zero on failure */
httpReconnect(http_t * http)5192264Sjacobs httpReconnect(http_t *http)		/* I - HTTP data */
5202264Sjacobs {
5212264Sjacobs   int		val;			/* Socket option value */
5222264Sjacobs   int		status;			/* Connect status */
5232264Sjacobs 
5242264Sjacobs 
5252264Sjacobs   DEBUG_printf(("httpReconnect(http=%p)\n", http));
5262264Sjacobs 
5272264Sjacobs   if (!http)
5282264Sjacobs     return (-1);
5292264Sjacobs 
5302264Sjacobs #ifdef HAVE_SSL
5312264Sjacobs   if (http->tls)
5322264Sjacobs     http_shutdown_ssl(http);
5332264Sjacobs #endif /* HAVE_SSL */
5342264Sjacobs 
5352264Sjacobs  /*
5362264Sjacobs   * Close any previously open socket...
5372264Sjacobs   */
5382264Sjacobs 
5392264Sjacobs   if (http->fd >= 0)
5402264Sjacobs #ifdef WIN32
5412264Sjacobs     closesocket(http->fd);
5422264Sjacobs #else
5432264Sjacobs     close(http->fd);
5442264Sjacobs #endif /* WIN32 */
5452264Sjacobs 
5462264Sjacobs  /*
5472264Sjacobs   * Create the socket and set options to allow reuse.
5482264Sjacobs   */
5492264Sjacobs 
5502264Sjacobs   if ((http->fd = socket(http->hostaddr.addr.sa_family, SOCK_STREAM, 0)) < 0)
5512264Sjacobs   {
5522264Sjacobs #ifdef WIN32
5532264Sjacobs     http->error  = WSAGetLastError();
5542264Sjacobs #else
5552264Sjacobs     http->error  = errno;
5562264Sjacobs #endif /* WIN32 */
5572264Sjacobs     http->status = HTTP_ERROR;
5582264Sjacobs     return (-1);
5592264Sjacobs   }
5602264Sjacobs 
5612264Sjacobs #ifdef FD_CLOEXEC
5622264Sjacobs   fcntl(http->fd, F_SETFD, FD_CLOEXEC);	/* Close this socket when starting *
5632264Sjacobs 					 * other processes...              */
5642264Sjacobs #endif /* FD_CLOEXEC */
5652264Sjacobs 
5662264Sjacobs   val = 1;
5672264Sjacobs   setsockopt(http->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
5682264Sjacobs 
5692264Sjacobs #ifdef SO_REUSEPORT
5702264Sjacobs   val = 1;
5712264Sjacobs   setsockopt(http->fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
5722264Sjacobs #endif /* SO_REUSEPORT */
5732264Sjacobs 
5742264Sjacobs  /*
5752264Sjacobs   * Using TCP_NODELAY improves responsiveness, especially on systems
5762264Sjacobs   * with a slow loopback interface...  Since we write large buffers
5772264Sjacobs   * when sending print files and requests, there shouldn't be any
5782264Sjacobs   * performance penalty for this...
5792264Sjacobs   */
5802264Sjacobs 
5812264Sjacobs   val = 1;
5822264Sjacobs #ifdef WIN32
5832264Sjacobs   setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
5842264Sjacobs #else
5852264Sjacobs   setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
5862264Sjacobs #endif /* WIN32 */
5872264Sjacobs 
5882264Sjacobs  /*
5892264Sjacobs   * Connect to the server...
5902264Sjacobs   */
5912264Sjacobs 
5922264Sjacobs #ifdef AF_INET6
5932264Sjacobs   if (http->hostaddr.addr.sa_family == AF_INET6)
5942264Sjacobs     status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
5952264Sjacobs                      sizeof(http->hostaddr.ipv6));
5962264Sjacobs   else
5972264Sjacobs #endif /* AF_INET6 */
5982264Sjacobs #ifdef AF_LOCAL
5992264Sjacobs   if (http->hostaddr.addr.sa_family == AF_LOCAL)
6002264Sjacobs     status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
6012264Sjacobs                      SUN_LEN(&(http->hostaddr.un)));
6022264Sjacobs   else
6032264Sjacobs #endif /* AF_LOCAL */
6042264Sjacobs   status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
6052264Sjacobs                    sizeof(http->hostaddr.ipv4));
6062264Sjacobs 
6072264Sjacobs   if (status < 0)
6082264Sjacobs   {
6092264Sjacobs #ifdef WIN32
6102264Sjacobs     http->error  = WSAGetLastError();
6112264Sjacobs #else
6122264Sjacobs     http->error  = errno;
6132264Sjacobs #endif /* WIN32 */
6142264Sjacobs     http->status = HTTP_ERROR;
6152264Sjacobs 
6162264Sjacobs #ifdef WIN32
6172264Sjacobs     closesocket(http->fd);
6182264Sjacobs #else
6192264Sjacobs     close(http->fd);
6202264Sjacobs #endif
6212264Sjacobs 
6222264Sjacobs     http->fd = -1;
6232264Sjacobs 
6242264Sjacobs     return (-1);
6252264Sjacobs   }
6262264Sjacobs 
6272264Sjacobs   http->error  = 0;
6282264Sjacobs   http->status = HTTP_CONTINUE;
6292264Sjacobs 
6302264Sjacobs #ifdef HAVE_SSL
6312264Sjacobs   if (http->encryption == HTTP_ENCRYPT_ALWAYS)
6322264Sjacobs   {
6332264Sjacobs    /*
6342264Sjacobs     * Always do encryption via SSL.
6352264Sjacobs     */
6362264Sjacobs 
6372264Sjacobs     if (http_setup_ssl(http) != 0)
6382264Sjacobs     {
6392264Sjacobs #ifdef WIN32
6402264Sjacobs       closesocket(http->fd);
6412264Sjacobs #else
6422264Sjacobs       close(http->fd);
6432264Sjacobs #endif /* WIN32 */
6442264Sjacobs 
6452264Sjacobs       return (-1);
6462264Sjacobs     }
6472264Sjacobs   }
6482264Sjacobs   else if (http->encryption == HTTP_ENCRYPT_REQUIRED)
6492264Sjacobs     return (http_upgrade(http));
6502264Sjacobs #endif /* HAVE_SSL */
6512264Sjacobs 
6522264Sjacobs   return (0);
6532264Sjacobs }
6542264Sjacobs 
6552264Sjacobs 
6562264Sjacobs /*
6572264Sjacobs  * 'httpGetSubField()' - Get a sub-field value.
6582264Sjacobs  */
6592264Sjacobs 
6602264Sjacobs char *					/* O - Value or NULL */
httpGetSubField(http_t * http,http_field_t field,const char * name,char * value)6612264Sjacobs httpGetSubField(http_t       *http,	/* I - HTTP data */
6622264Sjacobs                 http_field_t field,	/* I - Field index */
6632264Sjacobs                 const char   *name,	/* I - Name of sub-field */
6642264Sjacobs 		char         *value)	/* O - Value string */
6652264Sjacobs {
6662264Sjacobs   const char	*fptr;			/* Pointer into field */
6672264Sjacobs   char		temp[HTTP_MAX_VALUE],	/* Temporary buffer for name */
6682264Sjacobs 		*ptr;			/* Pointer into string buffer */
6692264Sjacobs 
6702264Sjacobs 
6712264Sjacobs   DEBUG_printf(("httpGetSubField(http=%p, field=%d, name=\"%s\", value=%p)\n",
6722264Sjacobs                 http, field, name, value));
6732264Sjacobs 
6742264Sjacobs   if (http == NULL ||
6752264Sjacobs       field < HTTP_FIELD_ACCEPT_LANGUAGE ||
6762264Sjacobs       field > HTTP_FIELD_WWW_AUTHENTICATE ||
6772264Sjacobs       name == NULL || value == NULL)
6782264Sjacobs     return (NULL);
6792264Sjacobs 
6802264Sjacobs   for (fptr = http->fields[field]; *fptr;)
6812264Sjacobs   {
6822264Sjacobs    /*
6832264Sjacobs     * Skip leading whitespace...
6842264Sjacobs     */
6852264Sjacobs 
6862264Sjacobs     while (isspace(*fptr & 255))
6872264Sjacobs       fptr ++;
6882264Sjacobs 
6892264Sjacobs     if (*fptr == ',')
6902264Sjacobs     {
6912264Sjacobs       fptr ++;
6922264Sjacobs       continue;
6932264Sjacobs     }
6942264Sjacobs 
6952264Sjacobs    /*
6962264Sjacobs     * Get the sub-field name...
6972264Sjacobs     */
6982264Sjacobs 
6992264Sjacobs     for (ptr = temp;
7002264Sjacobs          *fptr && *fptr != '=' && !isspace(*fptr & 255) && ptr < (temp + sizeof(temp) - 1);
7012264Sjacobs          *ptr++ = *fptr++);
7022264Sjacobs 
7032264Sjacobs     *ptr = '\0';
7042264Sjacobs 
7052264Sjacobs     DEBUG_printf(("httpGetSubField: name=\"%s\"\n", temp));
7062264Sjacobs 
7072264Sjacobs    /*
7082264Sjacobs     * Skip trailing chars up to the '='...
7092264Sjacobs     */
7102264Sjacobs 
7112264Sjacobs     while (isspace(*fptr & 255))
7122264Sjacobs       fptr ++;
7132264Sjacobs 
7142264Sjacobs     if (!*fptr)
7152264Sjacobs       break;
7162264Sjacobs 
7172264Sjacobs     if (*fptr != '=')
7182264Sjacobs       continue;
7192264Sjacobs 
7202264Sjacobs    /*
7212264Sjacobs     * Skip = and leading whitespace...
7222264Sjacobs     */
7232264Sjacobs 
7242264Sjacobs     fptr ++;
7252264Sjacobs 
7262264Sjacobs     while (isspace(*fptr & 255))
7272264Sjacobs       fptr ++;
7282264Sjacobs 
7292264Sjacobs     if (*fptr == '\"')
7302264Sjacobs     {
7312264Sjacobs      /*
7322264Sjacobs       * Read quoted string...
7332264Sjacobs       */
7342264Sjacobs 
7352264Sjacobs       for (ptr = value, fptr ++;
7362264Sjacobs            *fptr && *fptr != '\"' && ptr < (value + HTTP_MAX_VALUE - 1);
7372264Sjacobs 	   *ptr++ = *fptr++);
7382264Sjacobs 
7392264Sjacobs       *ptr = '\0';
7402264Sjacobs 
7412264Sjacobs       while (*fptr && *fptr != '\"')
7422264Sjacobs         fptr ++;
7432264Sjacobs 
7442264Sjacobs       if (*fptr)
7452264Sjacobs         fptr ++;
7462264Sjacobs     }
7472264Sjacobs     else
7482264Sjacobs     {
7492264Sjacobs      /*
7502264Sjacobs       * Read unquoted string...
7512264Sjacobs       */
7522264Sjacobs 
7532264Sjacobs       for (ptr = value;
7542264Sjacobs            *fptr && !isspace(*fptr & 255) && *fptr != ',' && ptr < (value + HTTP_MAX_VALUE - 1);
7552264Sjacobs 	   *ptr++ = *fptr++);
7562264Sjacobs 
7572264Sjacobs       *ptr = '\0';
7582264Sjacobs 
7592264Sjacobs       while (*fptr && !isspace(*fptr & 255) && *fptr != ',')
7602264Sjacobs         fptr ++;
7612264Sjacobs     }
7622264Sjacobs 
7632264Sjacobs     DEBUG_printf(("httpGetSubField: value=\"%s\"\n", value));
7642264Sjacobs 
7652264Sjacobs    /*
7662264Sjacobs     * See if this is the one...
7672264Sjacobs     */
7682264Sjacobs 
7692264Sjacobs     if (strcmp(name, temp) == 0)
7702264Sjacobs       return (value);
7712264Sjacobs   }
7722264Sjacobs 
7732264Sjacobs   value[0] = '\0';
7742264Sjacobs 
7752264Sjacobs   return (NULL);
7762264Sjacobs }
7772264Sjacobs 
7782264Sjacobs 
7792264Sjacobs /*
7802264Sjacobs  * 'httpSetField()' - Set the value of an HTTP header.
7812264Sjacobs  */
7822264Sjacobs 
7832264Sjacobs void
httpSetField(http_t * http,http_field_t field,const char * value)7842264Sjacobs httpSetField(http_t       *http,	/* I - HTTP data */
7852264Sjacobs              http_field_t field,	/* I - Field index */
7862264Sjacobs 	     const char   *value)	/* I - Value */
7872264Sjacobs {
7882264Sjacobs   if (http == NULL ||
7892264Sjacobs       field < HTTP_FIELD_ACCEPT_LANGUAGE ||
7902264Sjacobs       field > HTTP_FIELD_WWW_AUTHENTICATE ||
7912264Sjacobs       value == NULL)
7922264Sjacobs     return;
7932264Sjacobs 
7942264Sjacobs   strlcpy(http->fields[field], value, HTTP_MAX_VALUE);
7952264Sjacobs }
7962264Sjacobs 
7972264Sjacobs 
7982264Sjacobs /*
7992264Sjacobs  * 'httpDelete()' - Send a DELETE request to the server.
8002264Sjacobs  */
8012264Sjacobs 
8022264Sjacobs int					/* O - Status of call (0 = success) */
httpDelete(http_t * http,const char * uri)8032264Sjacobs httpDelete(http_t     *http,		/* I - HTTP data */
8042264Sjacobs            const char *uri)		/* I - URI to delete */
8052264Sjacobs {
8062264Sjacobs   return (http_send(http, HTTP_DELETE, uri));
8072264Sjacobs }
8082264Sjacobs 
8092264Sjacobs 
8102264Sjacobs /*
8112264Sjacobs  * 'httpGet()' - Send a GET request to the server.
8122264Sjacobs  */
8132264Sjacobs 
8142264Sjacobs int					/* O - Status of call (0 = success) */
httpGet(http_t * http,const char * uri)8152264Sjacobs httpGet(http_t     *http,		/* I - HTTP data */
8162264Sjacobs         const char *uri)		/* I - URI to get */
8172264Sjacobs {
8182264Sjacobs   return (http_send(http, HTTP_GET, uri));
8192264Sjacobs }
8202264Sjacobs 
8212264Sjacobs 
8222264Sjacobs /*
8232264Sjacobs  * 'httpHead()' - Send a HEAD request to the server.
8242264Sjacobs  */
8252264Sjacobs 
8262264Sjacobs int					/* O - Status of call (0 = success) */
httpHead(http_t * http,const char * uri)8272264Sjacobs httpHead(http_t     *http,		/* I - HTTP data */
8282264Sjacobs          const char *uri)		/* I - URI for head */
8292264Sjacobs {
8302264Sjacobs   return (http_send(http, HTTP_HEAD, uri));
8312264Sjacobs }
8322264Sjacobs 
8332264Sjacobs 
8342264Sjacobs /*
8352264Sjacobs  * 'httpOptions()' - Send an OPTIONS request to the server.
8362264Sjacobs  */
8372264Sjacobs 
8382264Sjacobs int					/* O - Status of call (0 = success) */
httpOptions(http_t * http,const char * uri)8392264Sjacobs httpOptions(http_t     *http,		/* I - HTTP data */
8402264Sjacobs             const char *uri)		/* I - URI for options */
8412264Sjacobs {
8422264Sjacobs   return (http_send(http, HTTP_OPTIONS, uri));
8432264Sjacobs }
8442264Sjacobs 
8452264Sjacobs 
8462264Sjacobs /*
8472264Sjacobs  * 'httpPost()' - Send a POST request to the server.
8482264Sjacobs  */
8492264Sjacobs 
8502264Sjacobs int					/* O - Status of call (0 = success) */
httpPost(http_t * http,const char * uri)8512264Sjacobs httpPost(http_t     *http,		/* I - HTTP data */
8522264Sjacobs          const char *uri)		/* I - URI for post */
8532264Sjacobs {
8542264Sjacobs   httpGetLength(http);
8552264Sjacobs 
8562264Sjacobs   return (http_send(http, HTTP_POST, uri));
8572264Sjacobs }
8582264Sjacobs 
8592264Sjacobs 
8602264Sjacobs /*
8612264Sjacobs  * 'httpPut()' - Send a PUT request to the server.
8622264Sjacobs  */
8632264Sjacobs 
8642264Sjacobs int					/* O - Status of call (0 = success) */
httpPut(http_t * http,const char * uri)8652264Sjacobs httpPut(http_t     *http,		/* I - HTTP data */
8662264Sjacobs         const char *uri)		/* I - URI to put */
8672264Sjacobs {
8682264Sjacobs   httpGetLength(http);
8692264Sjacobs 
8702264Sjacobs   return (http_send(http, HTTP_PUT, uri));
8712264Sjacobs }
8722264Sjacobs 
8732264Sjacobs 
8742264Sjacobs /*
8752264Sjacobs  * 'httpTrace()' - Send an TRACE request to the server.
8762264Sjacobs  */
8772264Sjacobs 
8782264Sjacobs int					/* O - Status of call (0 = success) */
httpTrace(http_t * http,const char * uri)8792264Sjacobs httpTrace(http_t     *http,		/* I - HTTP data */
8802264Sjacobs           const char *uri)		/* I - URI for trace */
8812264Sjacobs {
8822264Sjacobs   return (http_send(http, HTTP_TRACE, uri));
8832264Sjacobs }
8842264Sjacobs 
8852264Sjacobs 
8862264Sjacobs /*
8872264Sjacobs  * 'httpFlush()' - Flush data from a HTTP connection.
8882264Sjacobs  */
8892264Sjacobs 
8902264Sjacobs void
httpFlush(http_t * http)8912264Sjacobs httpFlush(http_t *http)			/* I - HTTP data */
8922264Sjacobs {
8932264Sjacobs   char	buffer[8192];			/* Junk buffer */
8942264Sjacobs 
8952264Sjacobs 
8962264Sjacobs   DEBUG_printf(("httpFlush(http=%p), state=%d\n", http, http->state));
8972264Sjacobs 
8982264Sjacobs   while (httpRead(http, buffer, sizeof(buffer)) > 0);
8992264Sjacobs }
9002264Sjacobs 
9012264Sjacobs 
9022264Sjacobs /*
9032264Sjacobs  * 'httpRead()' - Read data from a HTTP connection.
9042264Sjacobs  */
9052264Sjacobs 
9062264Sjacobs int					/* O - Number of bytes read */
httpRead(http_t * http,char * buffer,int length)9072264Sjacobs httpRead(http_t *http,			/* I - HTTP data */
9082264Sjacobs          char   *buffer,		/* I - Buffer for data */
9092264Sjacobs 	 int    length)			/* I - Maximum number of bytes */
9102264Sjacobs {
9112264Sjacobs   int		bytes;			/* Bytes read */
9122264Sjacobs   char		len[32];		/* Length string */
9132264Sjacobs 
9142264Sjacobs 
9152264Sjacobs   DEBUG_printf(("httpRead(http=%p, buffer=%p, length=%d)\n",
9162264Sjacobs                 http, buffer, length));
9172264Sjacobs 
9182264Sjacobs   if (http == NULL || buffer == NULL)
9192264Sjacobs     return (-1);
9202264Sjacobs 
9212264Sjacobs   http->activity = time(NULL);
9222264Sjacobs 
9232264Sjacobs   if (length <= 0)
9242264Sjacobs     return (0);
9252264Sjacobs 
9262264Sjacobs   if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
9272264Sjacobs       http->data_remaining <= 0)
9282264Sjacobs   {
9292264Sjacobs     DEBUG_puts("httpRead: Getting chunk length...");
9302264Sjacobs 
9312264Sjacobs     if (httpGets(len, sizeof(len), http) == NULL)
9322264Sjacobs     {
9332264Sjacobs       DEBUG_puts("httpRead: Could not get length!");
9342264Sjacobs       return (0);
9352264Sjacobs     }
9362264Sjacobs 
9372264Sjacobs     http->data_remaining = strtol(len, NULL, 16);
9382264Sjacobs     if (http->data_remaining < 0)
9392264Sjacobs     {
9402264Sjacobs       DEBUG_puts("httpRead: Negative chunk length!");
9412264Sjacobs       return (0);
9422264Sjacobs     }
9432264Sjacobs   }
9442264Sjacobs 
9452264Sjacobs   DEBUG_printf(("httpRead: data_remaining=%d\n", http->data_remaining));
9462264Sjacobs 
9472264Sjacobs   if (http->data_remaining <= 0)
9482264Sjacobs   {
9492264Sjacobs    /*
9502264Sjacobs     * A zero-length chunk ends a transfer; unless we are reading POST
9512264Sjacobs     * data, go idle...
9522264Sjacobs     */
9532264Sjacobs 
9542264Sjacobs     if (http->data_encoding == HTTP_ENCODE_CHUNKED)
9552264Sjacobs       httpGets(len, sizeof(len), http);
9562264Sjacobs 
9572264Sjacobs     if (http->state == HTTP_POST_RECV)
9582264Sjacobs       http->state ++;
9592264Sjacobs     else
9602264Sjacobs       http->state = HTTP_WAITING;
9612264Sjacobs 
9622264Sjacobs    /*
9632264Sjacobs     * Prevent future reads for this request...
9642264Sjacobs     */
9652264Sjacobs 
9662264Sjacobs     http->data_encoding = HTTP_ENCODE_LENGTH;
9672264Sjacobs 
9682264Sjacobs     return (0);
9692264Sjacobs   }
9702264Sjacobs   else if (length > http->data_remaining)
9712264Sjacobs     length = http->data_remaining;
9722264Sjacobs 
9732264Sjacobs   if (http->used == 0 && length <= 256)
9742264Sjacobs   {
9752264Sjacobs    /*
9762264Sjacobs     * Buffer small reads for better performance...
9772264Sjacobs     */
9782264Sjacobs 
9792264Sjacobs     if (!http->blocking && !httpWait(http, 1000))
9802264Sjacobs       return (0);
9812264Sjacobs 
9822264Sjacobs     if (http->data_remaining > sizeof(http->buffer))
9832264Sjacobs       bytes = sizeof(http->buffer);
9842264Sjacobs     else
9852264Sjacobs       bytes = http->data_remaining;
9862264Sjacobs 
9872264Sjacobs #ifdef HAVE_SSL
9882264Sjacobs     if (http->tls)
9892264Sjacobs       bytes = http_read_ssl(http, http->buffer, bytes);
9902264Sjacobs     else
9912264Sjacobs #endif /* HAVE_SSL */
9922264Sjacobs     {
9932264Sjacobs       DEBUG_printf(("httpRead: reading %d bytes from socket into buffer...\n",
9942264Sjacobs                     bytes));
9952264Sjacobs 
9962264Sjacobs       bytes = recv(http->fd, http->buffer, bytes, 0);
9972264Sjacobs 
9982264Sjacobs       DEBUG_printf(("httpRead: read %d bytes from socket into buffer...\n",
9992264Sjacobs                     bytes));
10002264Sjacobs #ifdef DEBUG_HTTP
10012264Sjacobs     httpDumpData(stdout, "httpRead:", http->buffer, bytes);
10022264Sjacobs #endif
10032264Sjacobs     }
10042264Sjacobs 
10052264Sjacobs     if (bytes > 0)
10062264Sjacobs       http->used = bytes;
10072264Sjacobs     else if (bytes < 0)
10082264Sjacobs     {
10092264Sjacobs #ifdef WIN32
10102264Sjacobs       http->error = WSAGetLastError();
10112264Sjacobs       return (-1);
10122264Sjacobs #else
10132264Sjacobs       if (errno != EINTR)
10142264Sjacobs       {
10152264Sjacobs         http->error = errno;
10162264Sjacobs         return (-1);
10172264Sjacobs       }
10182264Sjacobs #endif /* WIN32 */
10192264Sjacobs     }
10202264Sjacobs     else
10212264Sjacobs     {
10222264Sjacobs       http->error = EPIPE;
10232264Sjacobs       return (0);
10242264Sjacobs     }
10252264Sjacobs   }
10262264Sjacobs 
10272264Sjacobs   if (http->used > 0)
10282264Sjacobs   {
10292264Sjacobs     if (length > http->used)
10302264Sjacobs       length = http->used;
10312264Sjacobs 
10322264Sjacobs     bytes = length;
10332264Sjacobs 
10342264Sjacobs     DEBUG_printf(("httpRead: grabbing %d bytes from input buffer...\n", bytes));
10352264Sjacobs 
10362264Sjacobs     memcpy(buffer, http->buffer, length);
10372264Sjacobs     http->used -= length;
10382264Sjacobs 
10392264Sjacobs     if (http->used > 0)
10402264Sjacobs       memmove(http->buffer, http->buffer + length, http->used);
10412264Sjacobs   }
10422264Sjacobs #ifdef HAVE_SSL
10432264Sjacobs   else if (http->tls)
10442264Sjacobs   {
10452264Sjacobs     if (!http->blocking && !httpWait(http, 1000))
10462264Sjacobs       return (0);
10472264Sjacobs 
10482264Sjacobs     bytes = http_read_ssl(http, buffer, length);
10492264Sjacobs   }
10502264Sjacobs #endif /* HAVE_SSL */
10512264Sjacobs   else
10522264Sjacobs   {
10532264Sjacobs     if (!http->blocking && !httpWait(http, 1000))
10542264Sjacobs       return (0);
10552264Sjacobs 
10562264Sjacobs     DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length));
10572264Sjacobs 
10582264Sjacobs     while ((bytes = recv(http->fd, buffer, length, 0)) < 0)
10592264Sjacobs       if (errno != EINTR)
10602264Sjacobs         break;
10612264Sjacobs     DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes));
10622264Sjacobs   }
10632264Sjacobs #ifdef DEBUG_HTTP
10642264Sjacobs     httpDumpData(stdout, "httpRead:", buffer, bytes);
10652264Sjacobs #endif
10662264Sjacobs 
10672264Sjacobs   if (bytes > 0)
10682264Sjacobs     http->data_remaining -= bytes;
10692264Sjacobs   else if (bytes < 0)
10702264Sjacobs   {
10712264Sjacobs #ifdef WIN32
10722264Sjacobs     http->error = WSAGetLastError();
10732264Sjacobs #else
10742264Sjacobs     if (errno == EINTR)
10752264Sjacobs       bytes = 0;
10762264Sjacobs     else
10772264Sjacobs       http->error = errno;
10782264Sjacobs #endif /* WIN32 */
10792264Sjacobs   }
10802264Sjacobs   else
10812264Sjacobs   {
10822264Sjacobs     http->error = EPIPE;
10832264Sjacobs     return (0);
10842264Sjacobs   }
10852264Sjacobs 
10862264Sjacobs   if (http->data_remaining == 0)
10872264Sjacobs   {
10882264Sjacobs     if (http->data_encoding == HTTP_ENCODE_CHUNKED)
10892264Sjacobs       httpGets(len, sizeof(len), http);
10902264Sjacobs 
10912264Sjacobs     if (http->data_encoding != HTTP_ENCODE_CHUNKED)
10922264Sjacobs     {
10932264Sjacobs       if (http->state == HTTP_POST_RECV)
10942264Sjacobs 	http->state ++;
10952264Sjacobs       else
10962264Sjacobs 	http->state = HTTP_WAITING;
10972264Sjacobs     }
10982264Sjacobs   }
10992264Sjacobs 
11002264Sjacobs   return (bytes);
11012264Sjacobs }
11022264Sjacobs 
11032264Sjacobs 
11042264Sjacobs /*
11052264Sjacobs  * 'httpSetCookie()' - Set the cookie value(s)...
11062264Sjacobs  */
11072264Sjacobs 
11082264Sjacobs void
httpSetCookie(http_t * http,const char * cookie)11092264Sjacobs httpSetCookie(http_t     *http,		/* I - Connection */
11102264Sjacobs               const char *cookie)	/* I - Cookie string */
11112264Sjacobs {
11122264Sjacobs   if (!http)
11132264Sjacobs     return;
11142264Sjacobs 
11152264Sjacobs   if (http->cookie)
11162264Sjacobs     free(http->cookie);
11172264Sjacobs 
11182264Sjacobs   if (cookie)
11192264Sjacobs     http->cookie = strdup(cookie);
11202264Sjacobs   else
11212264Sjacobs     http->cookie = NULL;
11222264Sjacobs }
11232264Sjacobs 
11242264Sjacobs 
11252264Sjacobs /*
11262264Sjacobs  * 'httpWait()' - Wait for data available on a connection.
11272264Sjacobs  */
11282264Sjacobs 
11292264Sjacobs int					/* O - 1 if data is available, 0 otherwise */
httpWait(http_t * http,int msec)11302264Sjacobs httpWait(http_t *http,			/* I - HTTP data */
11312264Sjacobs          int    msec)			/* I - Milliseconds to wait */
11322264Sjacobs {
11332264Sjacobs  /*
11342264Sjacobs   * First see if there is data in the buffer...
11352264Sjacobs   */
11362264Sjacobs 
11372264Sjacobs   if (http == NULL)
11382264Sjacobs     return (0);
11392264Sjacobs 
11402264Sjacobs   if (http->used)
11412264Sjacobs     return (1);
11422264Sjacobs 
11432264Sjacobs  /*
11442264Sjacobs   * If not, check the SSL/TLS buffers and do a select() on the connection...
11452264Sjacobs   */
11462264Sjacobs 
11472264Sjacobs   return (http_wait(http, msec));
11482264Sjacobs }
11492264Sjacobs 
11502264Sjacobs 
11512264Sjacobs /*
11522264Sjacobs  * 'httpWrite()' - Write data to a HTTP connection.
11532264Sjacobs  */
11542264Sjacobs 
11552264Sjacobs int					/* O - Number of bytes written */
httpWrite(http_t * http,const char * buffer,int length)11562264Sjacobs httpWrite(http_t     *http,		/* I - HTTP data */
11572264Sjacobs           const char *buffer,		/* I - Buffer for data */
11582264Sjacobs 	  int        length)		/* I - Number of bytes to write */
11592264Sjacobs {
11602264Sjacobs   int	tbytes,				/* Total bytes sent */
11612264Sjacobs 	bytes;				/* Bytes sent */
11622264Sjacobs 
11632264Sjacobs 
11642264Sjacobs   if (http == NULL || buffer == NULL)
11652264Sjacobs     return (-1);
11662264Sjacobs 
11672264Sjacobs   http->activity = time(NULL);
11682264Sjacobs 
11692264Sjacobs   if (http->data_encoding == HTTP_ENCODE_CHUNKED)
11702264Sjacobs   {
11712264Sjacobs     if (httpPrintf(http, "%x\r\n", length) < 0)
11722264Sjacobs       return (-1);
11732264Sjacobs 
11742264Sjacobs     if (length == 0)
11752264Sjacobs     {
11762264Sjacobs      /*
11772264Sjacobs       * A zero-length chunk ends a transfer; unless we are sending POST
11782264Sjacobs       * or PUT data, go idle...
11792264Sjacobs       */
11802264Sjacobs 
11812264Sjacobs       DEBUG_printf(("httpWrite: changing states from %d", http->state));
11822264Sjacobs 
11832264Sjacobs       if (http->state == HTTP_POST_RECV)
11842264Sjacobs 	http->state ++;
11852264Sjacobs       else if (http->state == HTTP_PUT_RECV)
11862264Sjacobs         http->state = HTTP_STATUS;
11872264Sjacobs       else
11882264Sjacobs 	http->state = HTTP_WAITING;
11892264Sjacobs       DEBUG_printf((" to %d\n", http->state));
11902264Sjacobs 
11912264Sjacobs       if (httpPrintf(http, "\r\n") < 0)
11922264Sjacobs 	return (-1);
11932264Sjacobs 
11942264Sjacobs       return (0);
11952264Sjacobs     }
11962264Sjacobs   }
11972264Sjacobs 
11982264Sjacobs   tbytes = 0;
11992264Sjacobs 
12002264Sjacobs   while (length > 0)
12012264Sjacobs   {
12022264Sjacobs #ifdef HAVE_SSL
12032264Sjacobs     if (http->tls)
12042264Sjacobs       bytes = http_write_ssl(http, buffer, length);
12052264Sjacobs     else
12062264Sjacobs #endif /* HAVE_SSL */
12072264Sjacobs     bytes = send(http->fd, buffer, length, 0);
12082264Sjacobs 
12092264Sjacobs #ifdef DEBUG_HTTP
12102264Sjacobs   if (bytes >= 0)
12112264Sjacobs   	httpDumpData(stdout, "httpWrite:", buffer, bytes);
12122264Sjacobs #endif /* DEBUG */
12132264Sjacobs 
12142264Sjacobs 
12152264Sjacobs     if (bytes < 0)
12162264Sjacobs     {
12172264Sjacobs #ifdef WIN32
12182264Sjacobs       if (WSAGetLastError() != http->error)
12192264Sjacobs       {
12202264Sjacobs         http->error = WSAGetLastError();
12212264Sjacobs 	continue;
12222264Sjacobs       }
12232264Sjacobs #else
12242264Sjacobs       if (errno == EINTR)
12252264Sjacobs         continue;
12262264Sjacobs       else if (errno != http->error && errno != ECONNRESET)
12272264Sjacobs       {
12282264Sjacobs         http->error = errno;
12292264Sjacobs 	continue;
12302264Sjacobs       }
12312264Sjacobs #endif /* WIN32 */
12322264Sjacobs 
12332264Sjacobs       DEBUG_puts("httpWrite: error writing data...\n");
12342264Sjacobs 
12352264Sjacobs       return (-1);
12362264Sjacobs     }
12372264Sjacobs 
12382264Sjacobs     buffer += bytes;
12392264Sjacobs     tbytes += bytes;
12402264Sjacobs     length -= bytes;
12412264Sjacobs     if (http->data_encoding == HTTP_ENCODE_LENGTH)
12422264Sjacobs       http->data_remaining -= bytes;
12432264Sjacobs   }
12442264Sjacobs 
12452264Sjacobs   if (http->data_encoding == HTTP_ENCODE_CHUNKED)
12462264Sjacobs     if (httpPrintf(http, "\r\n") < 0)
12472264Sjacobs       return (-1);
12482264Sjacobs 
12492264Sjacobs   if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
12502264Sjacobs   {
12512264Sjacobs    /*
12522264Sjacobs     * Finished with the transfer; unless we are sending POST or PUT
12532264Sjacobs     * data, go idle...
12542264Sjacobs     */
12552264Sjacobs 
12562264Sjacobs     DEBUG_printf(("httpWrite: changing states from %d", http->state));
12572264Sjacobs 
12582264Sjacobs     if (http->state == HTTP_POST_RECV)
12592264Sjacobs       http->state ++;
12602264Sjacobs     else if (http->state == HTTP_PUT_RECV)
12612264Sjacobs       http->state = HTTP_STATUS;
12622264Sjacobs     else
12632264Sjacobs       http->state = HTTP_WAITING;
12642264Sjacobs 
12652264Sjacobs     DEBUG_printf((" to %d\n", http->state));
12662264Sjacobs   }
12672264Sjacobs 
12682264Sjacobs   return (tbytes);
12692264Sjacobs }
12702264Sjacobs 
12712264Sjacobs 
12722264Sjacobs /*
12732264Sjacobs  * 'httpGets()' - Get a line of text from a HTTP connection.
12742264Sjacobs  */
12752264Sjacobs 
12762264Sjacobs char *					/* O - Line or NULL */
httpGets(char * line,int length,http_t * http)12772264Sjacobs httpGets(char   *line,			/* I - Line to read into */
12782264Sjacobs          int    length,			/* I - Max length of buffer */
12792264Sjacobs 	 http_t *http)			/* I - HTTP data */
12802264Sjacobs {
12812264Sjacobs   char	*lineptr,			/* Pointer into line */
12822264Sjacobs 	*bufptr,			/* Pointer into input buffer */
12832264Sjacobs 	*bufend;			/* Pointer to end of buffer */
12842264Sjacobs   int	bytes;				/* Number of bytes read */
12852264Sjacobs 
12862264Sjacobs 
12872264Sjacobs   DEBUG_printf(("httpGets(line=%p, length=%d, http=%p)\n", line, length, http));
12882264Sjacobs 
12892264Sjacobs   if (http == NULL || line == NULL)
12902264Sjacobs     return (NULL);
12912264Sjacobs 
12922264Sjacobs  /*
12932264Sjacobs   * Pre-scan the buffer and see if there is a newline in there...
12942264Sjacobs   */
12952264Sjacobs 
12962264Sjacobs #ifdef WIN32
12972264Sjacobs   WSASetLastError(0);
12982264Sjacobs #else
12992264Sjacobs   errno = 0;
13002264Sjacobs #endif /* WIN32 */
13012264Sjacobs 
13022264Sjacobs   do
13032264Sjacobs   {
13042264Sjacobs     bufptr  = http->buffer;
13052264Sjacobs     bufend  = http->buffer + http->used;
13062264Sjacobs 
13072264Sjacobs     while (bufptr < bufend)
13082264Sjacobs       if (*bufptr == 0x0a)
13092264Sjacobs 	break;
13102264Sjacobs       else
13112264Sjacobs 	bufptr ++;
13122264Sjacobs 
13132264Sjacobs     if (bufptr >= bufend && http->used < HTTP_MAX_BUFFER)
13142264Sjacobs     {
13152264Sjacobs      /*
13162264Sjacobs       * No newline; see if there is more data to be read...
13172264Sjacobs       */
13182264Sjacobs 
13192264Sjacobs       if (!http->blocking && !http_wait(http, 1000))
13202264Sjacobs         return (NULL);
13212264Sjacobs 
13222264Sjacobs #ifdef HAVE_SSL
13232264Sjacobs       if (http->tls)
13242264Sjacobs 	bytes = http_read_ssl(http, bufend, HTTP_MAX_BUFFER - http->used);
13252264Sjacobs       else
13262264Sjacobs #endif /* HAVE_SSL */
13272264Sjacobs         bytes = recv(http->fd, bufend, HTTP_MAX_BUFFER - http->used, 0);
13282264Sjacobs 
13292264Sjacobs       DEBUG_printf(("httpGets: read %d bytes...\n", bytes));
13302264Sjacobs #ifdef DEBUG_HTTP
13312264Sjacobs       httpDumpData(stdout, "httpGets:", bufend, bytes);
13322264Sjacobs #endif
13332264Sjacobs 
13342264Sjacobs       if (bytes < 0)
13352264Sjacobs       {
13362264Sjacobs        /*
13372264Sjacobs 	* Nope, can't get a line this time...
13382264Sjacobs 	*/
13392264Sjacobs 
13402264Sjacobs #ifdef WIN32
13412264Sjacobs         if (WSAGetLastError() != http->error)
13422264Sjacobs 	{
13432264Sjacobs 	  http->error = WSAGetLastError();
13442264Sjacobs 	  continue;
13452264Sjacobs 	}
13462264Sjacobs 
13472264Sjacobs         DEBUG_printf(("httpGets: recv() error %d!\n", WSAGetLastError()));
13482264Sjacobs #else
13492264Sjacobs         DEBUG_printf(("httpGets: recv() error %d!\n", errno));
13502264Sjacobs 
13512264Sjacobs         if (errno == EINTR)
13522264Sjacobs 	  continue;
13532264Sjacobs 	else if (errno != http->error)
13542264Sjacobs 	{
13552264Sjacobs 	  http->error = errno;
13562264Sjacobs 	  continue;
13572264Sjacobs 	}
13582264Sjacobs #endif /* WIN32 */
13592264Sjacobs 
13602264Sjacobs         return (NULL);
13612264Sjacobs       }
13622264Sjacobs       else if (bytes == 0)
13632264Sjacobs       {
13642264Sjacobs 	http->error = EPIPE;
13652264Sjacobs 
13662264Sjacobs         return (NULL);
13672264Sjacobs       }
13682264Sjacobs 
13692264Sjacobs      /*
13702264Sjacobs       * Yup, update the amount used and the end pointer...
13712264Sjacobs       */
13722264Sjacobs 
13732264Sjacobs       http->used += bytes;
13742264Sjacobs       bufend     += bytes;
13752264Sjacobs       bufptr     = bufend;
13762264Sjacobs     }
13772264Sjacobs   }
13782264Sjacobs   while (bufptr >= bufend && http->used < HTTP_MAX_BUFFER);
13792264Sjacobs 
13802264Sjacobs   http->activity = time(NULL);
13812264Sjacobs 
13822264Sjacobs  /*
13832264Sjacobs   * Read a line from the buffer...
13842264Sjacobs   */
13852264Sjacobs 
13862264Sjacobs   lineptr = line;
13872264Sjacobs   bufptr  = http->buffer;
13882264Sjacobs   bytes   = 0;
13892264Sjacobs   length --;
13902264Sjacobs 
13912264Sjacobs   while (bufptr < bufend && bytes < length)
13922264Sjacobs   {
13932264Sjacobs     bytes ++;
13942264Sjacobs 
13952264Sjacobs     if (*bufptr == 0x0a)
13962264Sjacobs     {
13972264Sjacobs       bufptr ++;
13982264Sjacobs       break;
13992264Sjacobs     }
14002264Sjacobs     else if (*bufptr == 0x0d)
14012264Sjacobs       bufptr ++;
14022264Sjacobs     else
14032264Sjacobs       *lineptr++ = *bufptr++;
14042264Sjacobs   }
14052264Sjacobs 
14062264Sjacobs   if (bytes > 0)
14072264Sjacobs   {
14082264Sjacobs     *lineptr = '\0';
14092264Sjacobs 
14102264Sjacobs     http->used -= bytes;
14112264Sjacobs     if (http->used > 0)
14122264Sjacobs       memmove(http->buffer, bufptr, http->used);
14132264Sjacobs 
14142264Sjacobs     DEBUG_printf(("httpGets: Returning \"%s\"\n", line));
14152264Sjacobs     return (line);
14162264Sjacobs   }
14172264Sjacobs 
14182264Sjacobs   DEBUG_puts("httpGets: No new line available!");
14192264Sjacobs 
14202264Sjacobs   return (NULL);
14212264Sjacobs }
14222264Sjacobs 
14232264Sjacobs 
14242264Sjacobs /*
14252264Sjacobs  * 'httpPrintf()' - Print a formatted string to a HTTP connection.
14262264Sjacobs  */
14272264Sjacobs 
14282264Sjacobs int					/* O - Number of bytes written */
httpPrintf(http_t * http,const char * format,...)14292264Sjacobs httpPrintf(http_t     *http,		/* I - HTTP data */
14302264Sjacobs            const char *format,		/* I - printf-style format string */
14312264Sjacobs 	   ...)				/* I - Additional args as needed */
14322264Sjacobs {
14332264Sjacobs   int		bytes,			/* Number of bytes to write */
14342264Sjacobs 		nbytes,			/* Number of bytes written */
14352264Sjacobs 		tbytes;			/* Number of bytes all together */
14362264Sjacobs   char		buf[HTTP_MAX_BUFFER],	/* Buffer for formatted string */
14372264Sjacobs 		*bufptr;		/* Pointer into buffer */
14382264Sjacobs   va_list	ap;			/* Variable argument pointer */
14392264Sjacobs 
14402264Sjacobs 
14412264Sjacobs   DEBUG_printf(("httpPrintf: httpPrintf(http=%p, format=\"%s\", ...)\n", http, format));
14422264Sjacobs 
14432264Sjacobs   va_start(ap, format);
14442264Sjacobs   bytes = vsnprintf(buf, sizeof(buf), format, ap);
14452264Sjacobs   va_end(ap);
14462264Sjacobs 
14472264Sjacobs   DEBUG_printf(("httpPrintf: %s", buf));
14482264Sjacobs 
14492264Sjacobs   for (tbytes = 0, bufptr = buf; tbytes < bytes; tbytes += nbytes, bufptr += nbytes)
14502264Sjacobs   {
14512264Sjacobs #ifdef HAVE_SSL
14522264Sjacobs     if (http->tls)
14532264Sjacobs       nbytes = http_write_ssl(http, bufptr, bytes - tbytes);
14542264Sjacobs     else
14552264Sjacobs #endif /* HAVE_SSL */
14562264Sjacobs     nbytes = send(http->fd, bufptr, bytes - tbytes, 0);
14572264Sjacobs 
14582264Sjacobs #ifdef DEBUG_HTTP
14592264Sjacobs     if (nbytes >= 0)
14602264Sjacobs     	httpDumpData(stdout, "httpPrintf:", bufptr, nbytes);
14612264Sjacobs #endif
14622264Sjacobs 
14632264Sjacobs     if (nbytes < 0)
14642264Sjacobs     {
14652264Sjacobs       nbytes = 0;
14662264Sjacobs 
14672264Sjacobs #ifdef WIN32
14682264Sjacobs       if (WSAGetLastError() != http->error)
14692264Sjacobs       {
14702264Sjacobs         http->error = WSAGetLastError();
14712264Sjacobs 	continue;
14722264Sjacobs       }
14732264Sjacobs #else
14742264Sjacobs       if (errno == EINTR)
14752264Sjacobs 	continue;
14762264Sjacobs       else if (errno != http->error)
14772264Sjacobs       {
14782264Sjacobs         http->error = errno;
14792264Sjacobs 	continue;
14802264Sjacobs       }
14812264Sjacobs #endif /* WIN32 */
14822264Sjacobs 
14832264Sjacobs       return (-1);
14842264Sjacobs     }
14852264Sjacobs   }
14862264Sjacobs 
14872264Sjacobs   return (bytes);
14882264Sjacobs }
14892264Sjacobs 
14902264Sjacobs 
14912264Sjacobs /*
14922264Sjacobs  * 'httpGetDateString()' - Get a formatted date/time string from a time value.
14932264Sjacobs  */
14942264Sjacobs 
14952264Sjacobs const char *				/* O - Date/time string */
httpGetDateString(time_t t)14962264Sjacobs httpGetDateString(time_t t)		/* I - UNIX time */
14972264Sjacobs {
14982264Sjacobs   struct tm	*tdate;
14992264Sjacobs   static char	datetime[256];
15002264Sjacobs 
15012264Sjacobs 
15022264Sjacobs   tdate = gmtime(&t);
15032264Sjacobs   snprintf(datetime, sizeof(datetime), "%s, %02d %s %d %02d:%02d:%02d GMT",
15042264Sjacobs            days[tdate->tm_wday], tdate->tm_mday, months[tdate->tm_mon],
15052264Sjacobs 	   tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec);
15062264Sjacobs 
15072264Sjacobs   return (datetime);
15082264Sjacobs }
15092264Sjacobs 
15102264Sjacobs 
15112264Sjacobs /*
15122264Sjacobs  * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
15132264Sjacobs  */
15142264Sjacobs 
15152264Sjacobs time_t					/* O - UNIX time */
httpGetDateTime(const char * s)15162264Sjacobs httpGetDateTime(const char *s)		/* I - Date/time string */
15172264Sjacobs {
15182264Sjacobs   int		i;			/* Looping var */
15192264Sjacobs   struct tm	tdate;			/* Time/date structure */
15202264Sjacobs   char		mon[16];		/* Abbreviated month name */
15212264Sjacobs   int		day, year;		/* Day of month and year */
15222264Sjacobs   int		hour, min, sec;		/* Time */
15232264Sjacobs 
15242264Sjacobs 
15252264Sjacobs   if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6)
15262264Sjacobs     return (0);
15272264Sjacobs 
15282264Sjacobs   for (i = 0; i < 12; i ++)
15292264Sjacobs     if (strcasecmp(mon, months[i]) == 0)
15302264Sjacobs       break;
15312264Sjacobs 
15322264Sjacobs   if (i >= 12)
15332264Sjacobs     return (0);
15342264Sjacobs 
15352264Sjacobs   tdate.tm_mon   = i;
15362264Sjacobs   tdate.tm_mday  = day;
15372264Sjacobs   tdate.tm_year  = year - 1900;
15382264Sjacobs   tdate.tm_hour  = hour;
15392264Sjacobs   tdate.tm_min   = min;
15402264Sjacobs   tdate.tm_sec   = sec;
15412264Sjacobs   tdate.tm_isdst = 0;
15422264Sjacobs 
15432264Sjacobs   return (mktime(&tdate));
15442264Sjacobs }
15452264Sjacobs 
15462264Sjacobs 
15472264Sjacobs /*
15482264Sjacobs  * 'httpUpdate()' - Update the current HTTP state for incoming data.
15492264Sjacobs  */
15502264Sjacobs 
15512264Sjacobs http_status_t				/* O - HTTP status */
httpUpdate(http_t * http)15522264Sjacobs httpUpdate(http_t *http)		/* I - HTTP data */
15532264Sjacobs {
15542264Sjacobs   char		line[1024],		/* Line from connection... */
15552264Sjacobs 		*value;			/* Pointer to value on line */
15562264Sjacobs   http_field_t	field;			/* Field index */
15572264Sjacobs   int		major, minor,		/* HTTP version numbers */
15582264Sjacobs 		status;			/* Request status */
15592264Sjacobs 
15602264Sjacobs 
15612264Sjacobs   DEBUG_printf(("httpUpdate(http=%p), state=%d\n", http, http->state));
15622264Sjacobs 
15632264Sjacobs  /*
15642264Sjacobs   * If we haven't issued any commands, then there is nothing to "update"...
15652264Sjacobs   */
15662264Sjacobs 
15672264Sjacobs   if (http->state == HTTP_WAITING)
15682264Sjacobs     return (HTTP_CONTINUE);
15692264Sjacobs 
15702264Sjacobs  /*
15712264Sjacobs   * Grab all of the lines we can from the connection...
15722264Sjacobs   */
15732264Sjacobs 
15742264Sjacobs   line[0] = '\0';
15752264Sjacobs   while (httpGets(line, sizeof(line), http) != NULL)
15762264Sjacobs   {
15772264Sjacobs     DEBUG_printf(("httpUpdate: Got \"%s\"\n", line));
15782264Sjacobs 
15792264Sjacobs     if (line[0] == '\0')
15802264Sjacobs     {
15812264Sjacobs      /*
15822264Sjacobs       * Blank line means the start of the data section (if any).  Return
15832264Sjacobs       * the result code, too...
15842264Sjacobs       *
15852264Sjacobs       * If we get status 100 (HTTP_CONTINUE), then we *don't* change states.
15862264Sjacobs       * Instead, we just return HTTP_CONTINUE to the caller and keep on
15872264Sjacobs       * tryin'...
15882264Sjacobs       */
15892264Sjacobs 
15902264Sjacobs       if (http->status == HTTP_CONTINUE)
15912264Sjacobs         return (http->status);
15922264Sjacobs 
15932264Sjacobs       if (http->status < HTTP_BAD_REQUEST)
15942264Sjacobs         http->digest_tries = 0;
15952264Sjacobs 
15962264Sjacobs #ifdef HAVE_SSL
15972264Sjacobs       if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls)
15982264Sjacobs       {
15992264Sjacobs 	if (http_setup_ssl(http) != 0)
16002264Sjacobs 	{
16012264Sjacobs #  ifdef WIN32
16022264Sjacobs 	  closesocket(http->fd);
16032264Sjacobs #  else
16042264Sjacobs 	  close(http->fd);
16052264Sjacobs #  endif /* WIN32 */
16062264Sjacobs 
16072264Sjacobs 	  return (HTTP_ERROR);
16082264Sjacobs 	}
16092264Sjacobs 
16102264Sjacobs         return (HTTP_CONTINUE);
16112264Sjacobs       }
16122264Sjacobs #endif /* HAVE_SSL */
16132264Sjacobs 
16142264Sjacobs       httpGetLength(http);
16152264Sjacobs 
16162264Sjacobs       switch (http->state)
16172264Sjacobs       {
16182264Sjacobs         case HTTP_GET :
16192264Sjacobs 	case HTTP_POST :
16202264Sjacobs 	case HTTP_POST_RECV :
16212264Sjacobs 	case HTTP_PUT :
16222264Sjacobs 	    http->state ++;
16232264Sjacobs 	case HTTP_POST_SEND :
16242264Sjacobs 	    break;
16252264Sjacobs 
16262264Sjacobs 	default :
16272264Sjacobs 	    http->state = HTTP_WAITING;
16282264Sjacobs 	    break;
16292264Sjacobs       }
16302264Sjacobs 
16312264Sjacobs       return (http->status);
16322264Sjacobs     }
16332264Sjacobs     else if (strncmp(line, "HTTP/", 5) == 0)
16342264Sjacobs     {
16352264Sjacobs      /*
16362264Sjacobs       * Got the beginning of a response...
16372264Sjacobs       */
16382264Sjacobs 
16392264Sjacobs       if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &status) != 3)
16402264Sjacobs         return (HTTP_ERROR);
16412264Sjacobs 
16422264Sjacobs       http->version = (http_version_t)(major * 100 + minor);
16432264Sjacobs       http->status  = (http_status_t)status;
16442264Sjacobs     }
16452264Sjacobs     else if ((value = strchr(line, ':')) != NULL)
16462264Sjacobs     {
16472264Sjacobs      /*
16482264Sjacobs       * Got a value...
16492264Sjacobs       */
16502264Sjacobs 
16512264Sjacobs       *value++ = '\0';
16522264Sjacobs       while (isspace(*value & 255))
16532264Sjacobs         value ++;
16542264Sjacobs 
16552264Sjacobs      /*
16562264Sjacobs       * Be tolerants of servers that send unknown attribute fields...
16572264Sjacobs       */
16582264Sjacobs 
16592264Sjacobs       if (!strcasecmp(line, "expect"))
16602264Sjacobs       {
16612264Sjacobs        /*
16622264Sjacobs         * "Expect: 100-continue" or similar...
16632264Sjacobs 	*/
16642264Sjacobs 
16652264Sjacobs         http->expect = (http_status_t)atoi(value);
16662264Sjacobs       }
16672264Sjacobs       else if (!strcasecmp(line, "cookie"))
16682264Sjacobs       {
16692264Sjacobs        /*
16702264Sjacobs         * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
16712264Sjacobs 	*/
16722264Sjacobs 
16732264Sjacobs         httpSetCookie(http, value);
16742264Sjacobs       }
16752264Sjacobs       else if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN)
16762264Sjacobs       {
16772264Sjacobs         DEBUG_printf(("httpUpdate: unknown field %s seen!\n", line));
16782264Sjacobs         continue;
16792264Sjacobs       }
16802264Sjacobs       else
16812264Sjacobs         httpSetField(http, field, value);
16822264Sjacobs     }
16832264Sjacobs     else
16842264Sjacobs     {
16852264Sjacobs       http->status = HTTP_ERROR;
16862264Sjacobs       return (HTTP_ERROR);
16872264Sjacobs     }
16882264Sjacobs   }
16892264Sjacobs 
16902264Sjacobs  /*
16912264Sjacobs   * See if there was an error...
16922264Sjacobs   */
16932264Sjacobs 
16942264Sjacobs   if (http->error == EPIPE && http->status > HTTP_CONTINUE)
16952264Sjacobs     return (http->status);
16962264Sjacobs 
16972264Sjacobs   if (http->error)
16982264Sjacobs   {
16992264Sjacobs     DEBUG_printf(("httpUpdate: socket error %d - %s\n", http->error,
17002264Sjacobs                   strerror(http->error)));
17012264Sjacobs     http->status = HTTP_ERROR;
17022264Sjacobs     return (HTTP_ERROR);
17032264Sjacobs   }
17042264Sjacobs 
17052264Sjacobs  /*
17062264Sjacobs   * If we haven't already returned, then there is nothing new...
17072264Sjacobs   */
17082264Sjacobs 
17092264Sjacobs   return (HTTP_CONTINUE);
17102264Sjacobs }
17112264Sjacobs 
17122264Sjacobs 
17132264Sjacobs /*
17142264Sjacobs  * 'httpDecode64()' - Base64-decode a string.
17152264Sjacobs  */
17162264Sjacobs 
17172264Sjacobs char *					/* O - Decoded string */
httpDecode64(char * out,const char * in)17182264Sjacobs httpDecode64(char       *out,		/* I - String to write to */
17192264Sjacobs              const char *in)		/* I - String to read from */
17202264Sjacobs {
17212264Sjacobs   int	outlen;				/* Output buffer length */
17222264Sjacobs 
17232264Sjacobs 
17242264Sjacobs  /*
17252264Sjacobs   * Use the old maximum buffer size for binary compatibility...
17262264Sjacobs   */
17272264Sjacobs 
17282264Sjacobs   outlen = 512;
17292264Sjacobs 
17302264Sjacobs   return (httpDecode64_2(out, &outlen, in));
17312264Sjacobs }
17322264Sjacobs 
17332264Sjacobs 
17342264Sjacobs /*
17352264Sjacobs  * 'httpDecode64_2()' - Base64-decode a string.
17362264Sjacobs  */
17372264Sjacobs 
17382264Sjacobs char *					/* O  - Decoded string */
httpDecode64_2(char * out,int * outlen,const char * in)17392264Sjacobs httpDecode64_2(char       *out,		/* I  - String to write to */
17402264Sjacobs 	       int        *outlen,	/* IO - Size of output string */
17412264Sjacobs                const char *in)		/* I  - String to read from */
17422264Sjacobs {
17432264Sjacobs   int	pos,				/* Bit position */
17442264Sjacobs 	base64;				/* Value of this character */
17452264Sjacobs   char	*outptr,			/* Output pointer */
17462264Sjacobs 	*outend;			/* End of output buffer */
17472264Sjacobs 
17482264Sjacobs 
17492264Sjacobs  /*
17502264Sjacobs   * Range check input...
17512264Sjacobs   */
17522264Sjacobs 
17532264Sjacobs   if (!out || !outlen || *outlen < 1 || !in || !*in)
17542264Sjacobs     return (NULL);
17552264Sjacobs 
17562264Sjacobs  /*
17572264Sjacobs   * Convert from base-64 to bytes...
17582264Sjacobs   */
17592264Sjacobs 
17602264Sjacobs   for (outptr = out, outend = out + *outlen - 1, pos = 0; *in != '\0'; in ++)
17612264Sjacobs   {
17622264Sjacobs    /*
17632264Sjacobs     * Decode this character into a number from 0 to 63...
17642264Sjacobs     */
17652264Sjacobs 
17662264Sjacobs     if (*in >= 'A' && *in <= 'Z')
17672264Sjacobs       base64 = *in - 'A';
17682264Sjacobs     else if (*in >= 'a' && *in <= 'z')
17692264Sjacobs       base64 = *in - 'a' + 26;
17702264Sjacobs     else if (*in >= '0' && *in <= '9')
17712264Sjacobs       base64 = *in - '0' + 52;
17722264Sjacobs     else if (*in == '+')
17732264Sjacobs       base64 = 62;
17742264Sjacobs     else if (*in == '/')
17752264Sjacobs       base64 = 63;
17762264Sjacobs     else if (*in == '=')
17772264Sjacobs       break;
17782264Sjacobs     else
17792264Sjacobs       continue;
17802264Sjacobs 
17812264Sjacobs    /*
17822264Sjacobs     * Store the result in the appropriate chars...
17832264Sjacobs     */
17842264Sjacobs 
17852264Sjacobs     switch (pos)
17862264Sjacobs     {
17872264Sjacobs       case 0 :
17882264Sjacobs           if (outptr < outend)
17892264Sjacobs             *outptr = base64 << 2;
17902264Sjacobs 	  pos ++;
17912264Sjacobs 	  break;
17922264Sjacobs       case 1 :
17932264Sjacobs           if (outptr < outend)
17942264Sjacobs             *outptr++ |= (base64 >> 4) & 3;
17952264Sjacobs           if (outptr < outend)
17962264Sjacobs 	    *outptr = (base64 << 4) & 255;
17972264Sjacobs 	  pos ++;
17982264Sjacobs 	  break;
17992264Sjacobs       case 2 :
18002264Sjacobs           if (outptr < outend)
18012264Sjacobs             *outptr++ |= (base64 >> 2) & 15;
18022264Sjacobs           if (outptr < outend)
18032264Sjacobs 	    *outptr = (base64 << 6) & 255;
18042264Sjacobs 	  pos ++;
18052264Sjacobs 	  break;
18062264Sjacobs       case 3 :
18072264Sjacobs           if (outptr < outend)
18082264Sjacobs             *outptr++ |= base64;
18092264Sjacobs 	  pos = 0;
18102264Sjacobs 	  break;
18112264Sjacobs     }
18122264Sjacobs   }
18132264Sjacobs 
18142264Sjacobs   *outptr = '\0';
18152264Sjacobs 
18162264Sjacobs  /*
18172264Sjacobs   * Return the decoded string and size...
18182264Sjacobs   */
18192264Sjacobs 
18202264Sjacobs   *outlen = (int)(outptr - out);
18212264Sjacobs 
18222264Sjacobs   return (out);
18232264Sjacobs }
18242264Sjacobs 
18252264Sjacobs 
18262264Sjacobs /*
18272264Sjacobs  * 'httpEncode64()' - Base64-encode a string.
18282264Sjacobs  */
18292264Sjacobs 
18302264Sjacobs char *					/* O - Encoded string */
httpEncode64(char * out,const char * in)18312264Sjacobs httpEncode64(char       *out,		/* I - String to write to */
18322264Sjacobs              const char *in)		/* I - String to read from */
18332264Sjacobs {
18342264Sjacobs   return (httpEncode64_2(out, 512, in, strlen(in)));
18352264Sjacobs }
18362264Sjacobs 
18372264Sjacobs 
18382264Sjacobs /*
18392264Sjacobs  * 'httpEncode64_2()' - Base64-encode a string.
18402264Sjacobs  */
18412264Sjacobs 
18422264Sjacobs char *					/* O - Encoded string */
httpEncode64_2(char * out,int outlen,const char * in,int inlen)18432264Sjacobs httpEncode64_2(char       *out,		/* I - String to write to */
18442264Sjacobs 	       int        outlen,	/* I - Size of output string */
18452264Sjacobs                const char *in,		/* I - String to read from */
18462264Sjacobs 	       int        inlen)	/* I - Size of input string */
18472264Sjacobs {
18482264Sjacobs   char		*outptr,		/* Output pointer */
18492264Sjacobs 		*outend;		/* End of output buffer */
18502264Sjacobs   static const char base64[] =		/* Base64 characters... */
18512264Sjacobs   		{
18522264Sjacobs 		  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
18532264Sjacobs 		  "abcdefghijklmnopqrstuvwxyz"
18542264Sjacobs 		  "0123456789"
18552264Sjacobs 		  "+/"
18562264Sjacobs   		};
18572264Sjacobs 
18582264Sjacobs 
18592264Sjacobs  /*
18602264Sjacobs   * Range check input...
18612264Sjacobs   */
18622264Sjacobs 
18632264Sjacobs   if (!out || outlen < 1 || !in || inlen < 1)
18642264Sjacobs     return (NULL);
18652264Sjacobs 
18662264Sjacobs  /*
18672264Sjacobs   * Convert bytes to base-64...
18682264Sjacobs   */
18692264Sjacobs 
18702264Sjacobs   for (outptr = out, outend = out + outlen - 1; inlen > 0; in ++, inlen --)
18712264Sjacobs   {
18722264Sjacobs    /*
18732264Sjacobs     * Encode the up to 3 characters as 4 Base64 numbers...
18742264Sjacobs     */
18752264Sjacobs 
18762264Sjacobs     if (outptr < outend)
18772264Sjacobs       *outptr ++ = base64[(in[0] & 255) >> 2];
18782264Sjacobs     if (outptr < outend)
18792264Sjacobs       *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63];
18802264Sjacobs 
18812264Sjacobs     in ++;
18822264Sjacobs     inlen --;
18832264Sjacobs     if (inlen <= 0)
18842264Sjacobs     {
18852264Sjacobs       if (outptr < outend)
18862264Sjacobs         *outptr ++ = '=';
18872264Sjacobs       if (outptr < outend)
18882264Sjacobs         *outptr ++ = '=';
18892264Sjacobs       break;
18902264Sjacobs     }
18912264Sjacobs 
18922264Sjacobs     if (outptr < outend)
18932264Sjacobs       *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63];
18942264Sjacobs 
18952264Sjacobs     in ++;
18962264Sjacobs     inlen --;
18972264Sjacobs     if (inlen <= 0)
18982264Sjacobs     {
18992264Sjacobs       if (outptr < outend)
19002264Sjacobs         *outptr ++ = '=';
19012264Sjacobs       break;
19022264Sjacobs     }
19032264Sjacobs 
19042264Sjacobs     if (outptr < outend)
19052264Sjacobs       *outptr ++ = base64[in[0] & 63];
19062264Sjacobs   }
19072264Sjacobs 
19082264Sjacobs   *outptr = '\0';
19092264Sjacobs 
19102264Sjacobs  /*
19112264Sjacobs   * Return the encoded string...
19122264Sjacobs   */
19132264Sjacobs 
19142264Sjacobs   return (out);
19152264Sjacobs }
19162264Sjacobs 
19172264Sjacobs 
19182264Sjacobs /*
19192264Sjacobs  * 'httpGetLength()' - Get the amount of data remaining from the
19202264Sjacobs  *                     content-length or transfer-encoding fields.
19212264Sjacobs  */
19222264Sjacobs 
19232264Sjacobs int				/* O - Content length */
httpGetLength(http_t * http)19242264Sjacobs httpGetLength(http_t *http)	/* I - HTTP data */
19252264Sjacobs {
19262264Sjacobs   DEBUG_printf(("httpGetLength(http=%p), state=%d\n", http, http->state));
19272264Sjacobs 
19282264Sjacobs   if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0)
19292264Sjacobs   {
19302264Sjacobs     DEBUG_puts("httpGetLength: chunked request!");
19312264Sjacobs 
19322264Sjacobs     http->data_encoding  = HTTP_ENCODE_CHUNKED;
19332264Sjacobs     http->data_remaining = 0;
19342264Sjacobs   }
19352264Sjacobs   else
19362264Sjacobs   {
19372264Sjacobs     http->data_encoding = HTTP_ENCODE_LENGTH;
19382264Sjacobs 
19392264Sjacobs    /*
19402264Sjacobs     * The following is a hack for HTTP servers that don't send a
19412264Sjacobs     * content-length or transfer-encoding field...
19422264Sjacobs     *
19432264Sjacobs     * If there is no content-length then the connection must close
19442264Sjacobs     * after the transfer is complete...
19452264Sjacobs     */
19462264Sjacobs 
19472264Sjacobs     if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0')
19482264Sjacobs       http->data_remaining = 2147483647;
19492264Sjacobs     else
19502264Sjacobs       http->data_remaining = atoi(http->fields[HTTP_FIELD_CONTENT_LENGTH]);
19512264Sjacobs 
19522264Sjacobs     DEBUG_printf(("httpGetLength: content_length=%d\n", http->data_remaining));
19532264Sjacobs   }
19542264Sjacobs 
19552264Sjacobs   return (http->data_remaining);
19562264Sjacobs }
19572264Sjacobs 
19582264Sjacobs 
19592264Sjacobs /*
19602264Sjacobs  * 'http_field()' - Return the field index for a field name.
19612264Sjacobs  */
19622264Sjacobs 
19632264Sjacobs static http_field_t		/* O - Field index */
http_field(const char * name)19642264Sjacobs http_field(const char *name)	/* I - String name */
19652264Sjacobs {
19662264Sjacobs   int	i;			/* Looping var */
19672264Sjacobs 
19682264Sjacobs 
19692264Sjacobs   for (i = 0; i < HTTP_FIELD_MAX; i ++)
19702264Sjacobs     if (strcasecmp(name, http_fields[i]) == 0)
19712264Sjacobs       return ((http_field_t)i);
19722264Sjacobs 
19732264Sjacobs   return (HTTP_FIELD_UNKNOWN);
19742264Sjacobs }
19752264Sjacobs 
19762264Sjacobs 
19772264Sjacobs /*
19782264Sjacobs  * 'http_send()' - Send a request with all fields and the trailing blank line.
19792264Sjacobs  */
19802264Sjacobs 
19812264Sjacobs static int			/* O - 0 on success, non-zero on error */
http_send(http_t * http,http_state_t request,const char * uri)19822264Sjacobs http_send(http_t       *http,	/* I - HTTP data */
19832264Sjacobs           http_state_t request,	/* I - Request code */
19842264Sjacobs 	  const char   *uri)	/* I - URI */
19852264Sjacobs {
19862264Sjacobs   int		i;		/* Looping var */
19872264Sjacobs   char		*ptr,		/* Pointer in buffer */
19882264Sjacobs 		buf[1024];	/* Encoded URI buffer */
19892264Sjacobs   static const char * const codes[] =
19902264Sjacobs 		{		/* Request code strings */
19912264Sjacobs 		  NULL,
19922264Sjacobs 		  "OPTIONS",
19932264Sjacobs 		  "GET",
19942264Sjacobs 		  NULL,
19952264Sjacobs 		  "HEAD",
19962264Sjacobs 		  "POST",
19972264Sjacobs 		  NULL,
19982264Sjacobs 		  NULL,
19992264Sjacobs 		  "PUT",
20002264Sjacobs 		  NULL,
20012264Sjacobs 		  "DELETE",
20022264Sjacobs 		  "TRACE",
20032264Sjacobs 		  "CLOSE"
20042264Sjacobs 		};
20052264Sjacobs   static const char hex[] = "0123456789ABCDEF";
20062264Sjacobs 				/* Hex digits */
20072264Sjacobs 
20082264Sjacobs 
20092264Sjacobs   DEBUG_printf(("http_send(http=%p, request=HTTP_%s, uri=\"%s\")\n",
20102264Sjacobs                 http, codes[request], uri));
20112264Sjacobs 
20122264Sjacobs   if (http == NULL || uri == NULL)
20132264Sjacobs     return (-1);
20142264Sjacobs 
20152264Sjacobs  /*
20162264Sjacobs   * Encode the URI as needed...
20172264Sjacobs   */
20182264Sjacobs 
20192264Sjacobs   for (ptr = buf; *uri != '\0' && ptr < (buf + sizeof(buf) - 1); uri ++)
20202264Sjacobs     if (*uri <= ' ' || *uri >= 127)
20212264Sjacobs     {
20222264Sjacobs       if (ptr < (buf + sizeof(buf) - 1))
20232264Sjacobs         *ptr ++ = '%';
20242264Sjacobs       if (ptr < (buf + sizeof(buf) - 1))
20252264Sjacobs         *ptr ++ = hex[(*uri >> 4) & 15];
20262264Sjacobs       if (ptr < (buf + sizeof(buf) - 1))
20272264Sjacobs         *ptr ++ = hex[*uri & 15];
20282264Sjacobs     }
20292264Sjacobs     else
20302264Sjacobs       *ptr ++ = *uri;
20312264Sjacobs 
20322264Sjacobs   *ptr = '\0';
20332264Sjacobs 
20342264Sjacobs  /*
20352264Sjacobs   * See if we had an error the last time around; if so, reconnect...
20362264Sjacobs   */
20372264Sjacobs 
20382264Sjacobs   if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST)
20392264Sjacobs     httpReconnect(http);
20402264Sjacobs 
20412264Sjacobs  /*
20422264Sjacobs   * Send the request header...
20432264Sjacobs   */
20442264Sjacobs 
20452264Sjacobs   http->state = request;
20462264Sjacobs   if (request == HTTP_POST || request == HTTP_PUT)
20472264Sjacobs     http->state ++;
20482264Sjacobs 
20492264Sjacobs   http->status = HTTP_CONTINUE;
20502264Sjacobs 
20512264Sjacobs #ifdef HAVE_SSL
20522264Sjacobs   if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
20532264Sjacobs   {
20542264Sjacobs     httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
20552264Sjacobs     httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0,SSL/2.0,SSL/3.0");
20562264Sjacobs   }
20572264Sjacobs #endif /* HAVE_SSL */
20582264Sjacobs 
20592264Sjacobs   if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
20602264Sjacobs   {
20612264Sjacobs     http->status = HTTP_ERROR;
20622264Sjacobs     return (-1);
20632264Sjacobs   }
20642264Sjacobs 
20652264Sjacobs   for (i = 0; i < HTTP_FIELD_MAX; i ++)
20662264Sjacobs     if (http->fields[i][0] != '\0')
20672264Sjacobs     {
20682264Sjacobs       DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i]));
20692264Sjacobs 
20702264Sjacobs       if (httpPrintf(http, "%s: %s\r\n", http_fields[i], http->fields[i]) < 1)
20712264Sjacobs       {
20722264Sjacobs 	http->status = HTTP_ERROR;
20732264Sjacobs 	return (-1);
20742264Sjacobs       }
20752264Sjacobs     }
20762264Sjacobs 
20772264Sjacobs   if (httpPrintf(http, "\r\n") < 1)
20782264Sjacobs   {
20792264Sjacobs     http->status = HTTP_ERROR;
20802264Sjacobs     return (-1);
20812264Sjacobs   }
20822264Sjacobs 
20832264Sjacobs   httpClearFields(http);
20842264Sjacobs 
20852264Sjacobs   return (0);
20862264Sjacobs }
20872264Sjacobs 
20882264Sjacobs 
20892264Sjacobs /*
20902264Sjacobs  * 'http_wait()' - Wait for data available on a connection.
20912264Sjacobs  */
20922264Sjacobs 
20932264Sjacobs static int				/* O - 1 if data is available, 0 otherwise */
http_wait(http_t * http,int msec)20942264Sjacobs http_wait(http_t *http,			/* I - HTTP data */
20952264Sjacobs           int    msec)			/* I - Milliseconds to wait */
20962264Sjacobs {
20972264Sjacobs #ifndef WIN32
20982264Sjacobs   struct rlimit		limit;          /* Runtime limit */
20992264Sjacobs #endif /* !WIN32 */
21002264Sjacobs   struct timeval	timeout;	/* Timeout */
21012264Sjacobs   int			nfds;		/* Result from select() */
21022264Sjacobs   int			set_size;	/* Size of select set */
21032264Sjacobs 
21042264Sjacobs 
21052264Sjacobs   DEBUG_printf(("http_wait(http=%p, msec=%d)\n", http, msec));
21062264Sjacobs 
21072264Sjacobs  /*
21082264Sjacobs   * Check the SSL/TLS buffers for data first...
21092264Sjacobs   */
21102264Sjacobs 
21112264Sjacobs #ifdef HAVE_SSL
21122264Sjacobs   if (http->tls)
21132264Sjacobs   {
21142264Sjacobs #  ifdef HAVE_LIBSSL
21152264Sjacobs     if (SSL_pending((SSL *)(http->tls)))
21162264Sjacobs       return (1);
21172264Sjacobs #  elif defined(HAVE_GNUTLS)
21182264Sjacobs     if (gnutls_record_check_pending(((http_tls_t *)(http->tls))->session))
21192264Sjacobs       return (1);
21202264Sjacobs #  elif defined(HAVE_CDSASSL)
21212264Sjacobs     size_t bytes;			/* Bytes that are available */
21222264Sjacobs 
21232264Sjacobs     if (!SSLGetBufferedReadSize((SSLContextRef)http->tls, &bytes) && bytes > 0)
21242264Sjacobs       return;
21252264Sjacobs #  endif /* HAVE_LIBSSL */
21262264Sjacobs   }
21272264Sjacobs #endif /* HAVE_SSL */
21282264Sjacobs 
21292264Sjacobs  /*
21302264Sjacobs   * Then try doing a select() to poll the socket...
21312264Sjacobs   */
21322264Sjacobs 
21332264Sjacobs   if (!http->input_set)
21342264Sjacobs   {
21352264Sjacobs #ifdef WIN32
21362264Sjacobs    /*
21372264Sjacobs     * Windows has a fixed-size select() structure, different (surprise,
21382264Sjacobs     * surprise!) from all UNIX implementations.  Just allocate this
21392264Sjacobs     * fixed structure...
21402264Sjacobs     */
21412264Sjacobs 
21422264Sjacobs     http->input_set = calloc(1, sizeof(fd_set));
21432264Sjacobs #else
21442264Sjacobs    /*
21452264Sjacobs     * Allocate the select() input set based upon the max number of file
21462264Sjacobs     * descriptors available for this process...
21472264Sjacobs     */
21482264Sjacobs 
21492264Sjacobs     getrlimit(RLIMIT_NOFILE, &limit);
21502264Sjacobs 
21512264Sjacobs     set_size = (limit.rlim_cur + 31) / 8 + 4;
21522264Sjacobs     if (set_size < sizeof(fd_set))
21532264Sjacobs       set_size = sizeof(fd_set);
21542264Sjacobs 
21552264Sjacobs     http->input_set = calloc(1, set_size);
21562264Sjacobs #endif /* WIN32 */
21572264Sjacobs 
21582264Sjacobs     if (!http->input_set)
21592264Sjacobs       return (0);
21602264Sjacobs   }
21612264Sjacobs 
21622264Sjacobs   do
21632264Sjacobs   {
21642264Sjacobs     FD_SET(http->fd, http->input_set);
21652264Sjacobs 
21662264Sjacobs     if (msec >= 0)
21672264Sjacobs     {
21682264Sjacobs       timeout.tv_sec  = msec / 1000;
21692264Sjacobs       timeout.tv_usec = (msec % 1000) * 1000;
21702264Sjacobs 
21712264Sjacobs       nfds = select(http->fd + 1, http->input_set, NULL, NULL, &timeout);
21722264Sjacobs     }
21732264Sjacobs     else
21742264Sjacobs       nfds = select(http->fd + 1, http->input_set, NULL, NULL, NULL);
21752264Sjacobs   }
21762264Sjacobs #ifdef WIN32
21772264Sjacobs   while (nfds < 0 && WSAGetLastError() == WSAEINTR);
21782264Sjacobs #else
21792264Sjacobs   while (nfds < 0 && errno == EINTR);
21802264Sjacobs #endif /* WIN32 */
21812264Sjacobs 
21822264Sjacobs   FD_CLR(http->fd, http->input_set);
21832264Sjacobs 
21842264Sjacobs   return (nfds > 0);
21852264Sjacobs }
21862264Sjacobs 
21872264Sjacobs 
21882264Sjacobs #ifdef HAVE_SSL
21892264Sjacobs /*
21902264Sjacobs  * 'http_upgrade()' - Force upgrade to TLS encryption.
21912264Sjacobs  */
21922264Sjacobs 
21932264Sjacobs static int			/* O - Status of connection */
http_upgrade(http_t * http)21942264Sjacobs http_upgrade(http_t *http)	/* I - HTTP data */
21952264Sjacobs {
21962264Sjacobs   int		ret;		/* Return value */
21972264Sjacobs   http_t	myhttp;		/* Local copy of HTTP data */
21982264Sjacobs 
21992264Sjacobs 
22002264Sjacobs   DEBUG_printf(("http_upgrade(%p)\n", http));
22012264Sjacobs 
22022264Sjacobs  /*
22032264Sjacobs   * Copy the HTTP data to a local variable so we can do the OPTIONS
22042264Sjacobs   * request without interfering with the existing request data...
22052264Sjacobs   */
22062264Sjacobs 
22072264Sjacobs   memcpy(&myhttp, http, sizeof(myhttp));
22082264Sjacobs 
22092264Sjacobs  /*
22102264Sjacobs   * Send an OPTIONS request to the server, requiring SSL or TLS
22112264Sjacobs   * encryption on the link...
22122264Sjacobs   */
22132264Sjacobs 
22142264Sjacobs   httpClearFields(&myhttp);
22152264Sjacobs   httpSetField(&myhttp, HTTP_FIELD_CONNECTION, "upgrade");
22162264Sjacobs   httpSetField(&myhttp, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0");
22172264Sjacobs 
22182264Sjacobs   if ((ret = httpOptions(&myhttp, "*")) == 0)
22192264Sjacobs   {
22202264Sjacobs    /*
22212264Sjacobs     * Wait for the secure connection...
22222264Sjacobs     */
22232264Sjacobs 
22242264Sjacobs     while (httpUpdate(&myhttp) == HTTP_CONTINUE);
22252264Sjacobs   }
22262264Sjacobs 
22272264Sjacobs   httpFlush(&myhttp);
22282264Sjacobs 
22292264Sjacobs  /*
22302264Sjacobs   * Copy the HTTP data back over, if any...
22312264Sjacobs   */
22322264Sjacobs 
22332264Sjacobs   http->fd         = myhttp.fd;
22342264Sjacobs   http->error      = myhttp.error;
22352264Sjacobs   http->activity   = myhttp.activity;
22362264Sjacobs   http->status     = myhttp.status;
22372264Sjacobs   http->version    = myhttp.version;
22382264Sjacobs   http->keep_alive = myhttp.keep_alive;
22392264Sjacobs   http->used       = myhttp.used;
22402264Sjacobs 
22412264Sjacobs   if (http->used)
22422264Sjacobs     memcpy(http->buffer, myhttp.buffer, http->used);
22432264Sjacobs 
22442264Sjacobs   http->auth_type   = myhttp.auth_type;
22452264Sjacobs   http->nonce_count = myhttp.nonce_count;
22462264Sjacobs 
22472264Sjacobs   memcpy(http->nonce, myhttp.nonce, sizeof(http->nonce));
22482264Sjacobs 
22492264Sjacobs   http->tls        = myhttp.tls;
22502264Sjacobs   http->encryption = myhttp.encryption;
22512264Sjacobs 
22522264Sjacobs  /*
22532264Sjacobs   * See if we actually went secure...
22542264Sjacobs   */
22552264Sjacobs 
22562264Sjacobs   if (!http->tls)
22572264Sjacobs   {
22582264Sjacobs    /*
22592264Sjacobs     * Server does not support HTTP upgrade...
22602264Sjacobs     */
22612264Sjacobs 
22622264Sjacobs     DEBUG_puts("Server does not support HTTP upgrade!");
22632264Sjacobs 
22642264Sjacobs #  ifdef WIN32
22652264Sjacobs     closesocket(http->fd);
22662264Sjacobs #  else
22672264Sjacobs     close(http->fd);
22682264Sjacobs #  endif
22692264Sjacobs 
22702264Sjacobs     http->fd = -1;
22712264Sjacobs 
22722264Sjacobs     return (-1);
22732264Sjacobs   }
22742264Sjacobs   else
22752264Sjacobs     return (ret);
22762264Sjacobs }
22772264Sjacobs 
22782264Sjacobs 
22792264Sjacobs /*
22802264Sjacobs  * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
22812264Sjacobs  */
22822264Sjacobs 
22832264Sjacobs static int				/* O - Status of connection */
http_setup_ssl(http_t * http)22842264Sjacobs http_setup_ssl(http_t *http)		/* I - HTTP data */
22852264Sjacobs {
22862264Sjacobs #  ifdef HAVE_LIBSSL
22872264Sjacobs   SSL_CTX	*context;	/* Context for encryption */
22882264Sjacobs   SSL		*conn;		/* Connection for encryption */
22892264Sjacobs #  elif defined(HAVE_GNUTLS)
22902264Sjacobs   http_tls_t	*conn;		/* TLS session object */
22912264Sjacobs   gnutls_certificate_client_credentials *credentials;
22922264Sjacobs 				/* TLS credentials */
22932264Sjacobs #  elif defined(HAVE_CDSASSL)
22942264Sjacobs   SSLContextRef	conn;		/* Context for encryption */
22952264Sjacobs   OSStatus	error;		/* Error info */
22962264Sjacobs #  endif /* HAVE_LIBSSL */
22972264Sjacobs 
22982264Sjacobs 
22992264Sjacobs   DEBUG_printf(("http_setup_ssl(http=%p)\n", http));
23002264Sjacobs 
23012264Sjacobs #  ifdef HAVE_LIBSSL
23022264Sjacobs   context = SSL_CTX_new(SSLv23_client_method());
23032264Sjacobs 
23042264Sjacobs   SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
23052264Sjacobs 
23062264Sjacobs   conn = SSL_new(context);
23072264Sjacobs 
23082264Sjacobs   SSL_set_fd(conn, http->fd);
23092264Sjacobs   if (SSL_connect(conn) != 1)
23102264Sjacobs   {
23112264Sjacobs #    ifdef DEBUG
23122264Sjacobs     unsigned long	error;	/* Error code */
23132264Sjacobs 
23142264Sjacobs     while ((error = ERR_get_error()) != 0)
23152264Sjacobs       printf("http_setup_ssl: %s\n", ERR_error_string(error, NULL));
23162264Sjacobs #    endif /* DEBUG */
23172264Sjacobs 
23182264Sjacobs     SSL_CTX_free(context);
23192264Sjacobs     SSL_free(conn);
23202264Sjacobs 
23212264Sjacobs #    ifdef WIN32
23222264Sjacobs     http->error  = WSAGetLastError();
23232264Sjacobs #    else
23242264Sjacobs     http->error  = errno;
23252264Sjacobs #    endif /* WIN32 */
23262264Sjacobs     http->status = HTTP_ERROR;
23272264Sjacobs 
23282264Sjacobs     return (HTTP_ERROR);
23292264Sjacobs   }
23302264Sjacobs 
23312264Sjacobs #  elif defined(HAVE_GNUTLS)
23322264Sjacobs   conn = (http_tls_t *)malloc(sizeof(http_tls_t));
23332264Sjacobs 
23342264Sjacobs   if (conn == NULL)
23352264Sjacobs   {
23362264Sjacobs     http->error  = errno;
23372264Sjacobs     http->status = HTTP_ERROR;
23382264Sjacobs 
23392264Sjacobs     return (-1);
23402264Sjacobs   }
23412264Sjacobs 
23422264Sjacobs   credentials = (gnutls_certificate_client_credentials *)
23432264Sjacobs                     malloc(sizeof(gnutls_certificate_client_credentials));
23442264Sjacobs   if (credentials == NULL)
23452264Sjacobs   {
23462264Sjacobs     free(conn);
23472264Sjacobs 
23482264Sjacobs     http->error = errno;
23492264Sjacobs     http->status = HTTP_ERROR;
23502264Sjacobs 
23512264Sjacobs     return (-1);
23522264Sjacobs   }
23532264Sjacobs 
23542264Sjacobs   gnutls_certificate_allocate_credentials(credentials);
23552264Sjacobs 
23562264Sjacobs   gnutls_init(&(conn->session), GNUTLS_CLIENT);
23572264Sjacobs   gnutls_set_default_priority(conn->session);
23582264Sjacobs   gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials);
23592264Sjacobs   gnutls_transport_set_ptr(conn->session, http->fd);
23602264Sjacobs 
23612264Sjacobs   if ((gnutls_handshake(conn->session)) != GNUTLS_E_SUCCESS)
23622264Sjacobs   {
23632264Sjacobs     http->error  = errno;
23642264Sjacobs     http->status = HTTP_ERROR;
23652264Sjacobs 
23662264Sjacobs     return (-1);
23672264Sjacobs   }
23682264Sjacobs 
23692264Sjacobs   conn->credentials = credentials;
23702264Sjacobs 
23712264Sjacobs #  elif defined(HAVE_CDSASSL)
23722264Sjacobs   error = SSLNewContext(false, &conn);
23732264Sjacobs 
23742264Sjacobs   if (!error)
23752264Sjacobs     error = SSLSetIOFuncs(conn, CDSAReadFunc, CDSAWriteFunc);
23762264Sjacobs 
23772264Sjacobs   if (!error)
23782264Sjacobs     error = SSLSetConnection(conn, (SSLConnectionRef)http->fd);
23792264Sjacobs 
23802264Sjacobs   if (!error)
23812264Sjacobs     error = SSLSetAllowsExpiredCerts(conn, true);
23822264Sjacobs 
23832264Sjacobs   if (!error)
23842264Sjacobs     error = SSLSetAllowsAnyRoot(conn, true);
23852264Sjacobs 
23862264Sjacobs   if (!error)
23872264Sjacobs     error = SSLHandshake(conn);
23882264Sjacobs 
23892264Sjacobs   if (error != 0)
23902264Sjacobs   {
23912264Sjacobs     http->error  = error;
23922264Sjacobs     http->status = HTTP_ERROR;
23932264Sjacobs 
23942264Sjacobs     SSLDisposeContext(conn);
23952264Sjacobs 
23962264Sjacobs     close(http->fd);
23972264Sjacobs 
23982264Sjacobs     return (-1);
23992264Sjacobs   }
24002264Sjacobs #  endif /* HAVE_CDSASSL */
24012264Sjacobs 
24022264Sjacobs   http->tls = conn;
24032264Sjacobs   return (0);
24042264Sjacobs }
24052264Sjacobs 
24062264Sjacobs 
24072264Sjacobs /*
24082264Sjacobs  * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection.
24092264Sjacobs  */
24102264Sjacobs 
24112264Sjacobs static void
http_shutdown_ssl(http_t * http)24122264Sjacobs http_shutdown_ssl(http_t *http)	/* I - HTTP data */
24132264Sjacobs {
24142264Sjacobs #  ifdef HAVE_LIBSSL
24152264Sjacobs   SSL_CTX	*context;	/* Context for encryption */
24162264Sjacobs   SSL		*conn;		/* Connection for encryption */
24172264Sjacobs 
24182264Sjacobs 
24192264Sjacobs   conn    = (SSL *)(http->tls);
24202264Sjacobs   context = SSL_get_SSL_CTX(conn);
24212264Sjacobs 
24222264Sjacobs   SSL_shutdown(conn);
24232264Sjacobs   SSL_CTX_free(context);
24242264Sjacobs   SSL_free(conn);
24252264Sjacobs 
24262264Sjacobs #  elif defined(HAVE_GNUTLS)
24272264Sjacobs   http_tls_t      *conn;	/* Encryption session */
24282264Sjacobs   gnutls_certificate_client_credentials *credentials;
24292264Sjacobs 				/* TLS credentials */
24302264Sjacobs 
24312264Sjacobs 
24322264Sjacobs   conn = (http_tls_t *)(http->tls);
24332264Sjacobs   credentials = (gnutls_certificate_client_credentials *)(conn->credentials);
24342264Sjacobs 
24352264Sjacobs   gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
24362264Sjacobs   gnutls_deinit(conn->session);
24372264Sjacobs   gnutls_certificate_free_credentials(*credentials);
24382264Sjacobs   free(credentials);
24392264Sjacobs   free(conn);
24402264Sjacobs 
24412264Sjacobs #  elif defined(HAVE_CDSASSL)
24422264Sjacobs   SSLClose((SSLContextRef)http->tls);
24432264Sjacobs   SSLDisposeContext((SSLContextRef)http->tls);
24442264Sjacobs #  endif /* HAVE_LIBSSL */
24452264Sjacobs 
24462264Sjacobs   http->tls = NULL;
24472264Sjacobs }
24482264Sjacobs 
24492264Sjacobs 
24502264Sjacobs /*
24512264Sjacobs  * 'http_read_ssl()' - Read from a SSL/TLS connection.
24522264Sjacobs  */
24532264Sjacobs 
24542264Sjacobs static int				/* O - Bytes read */
http_read_ssl(http_t * http,char * buf,int len)24552264Sjacobs http_read_ssl(http_t *http,		/* I - HTTP data */
24562264Sjacobs 	      char   *buf,		/* I - Buffer to store data */
24572264Sjacobs 	      int    len)		/* I - Length of buffer */
24582264Sjacobs {
24592264Sjacobs #  if defined(HAVE_LIBSSL)
24602264Sjacobs   return (SSL_read((SSL *)(http->tls), buf, len));
24612264Sjacobs 
24622264Sjacobs #  elif defined(HAVE_GNUTLS)
24632264Sjacobs   return (gnutls_record_recv(((http_tls_t *)(http->tls))->session, buf, len));
24642264Sjacobs 
24652264Sjacobs #  elif defined(HAVE_CDSASSL)
24662264Sjacobs   OSStatus	error;			/* Error info */
24672264Sjacobs   size_t	processed;		/* Number of bytes processed */
24682264Sjacobs 
24692264Sjacobs 
24702264Sjacobs   error = SSLRead((SSLContextRef)http->tls, buf, len, &processed);
24712264Sjacobs 
24722264Sjacobs   if (error == 0)
24732264Sjacobs     return (processed);
24742264Sjacobs   else
24752264Sjacobs   {
24762264Sjacobs     http->error = error;
24772264Sjacobs 
24782264Sjacobs     return (-1);
24792264Sjacobs   }
24802264Sjacobs #  endif /* HAVE_LIBSSL */
24812264Sjacobs }
24822264Sjacobs 
24832264Sjacobs 
24842264Sjacobs /*
24852264Sjacobs  * 'http_write_ssl()' - Write to a SSL/TLS connection.
24862264Sjacobs  */
24872264Sjacobs 
24882264Sjacobs static int				/* O - Bytes written */
http_write_ssl(http_t * http,const char * buf,int len)24892264Sjacobs http_write_ssl(http_t     *http,	/* I - HTTP data */
24902264Sjacobs 	       const char *buf,		/* I - Buffer holding data */
24912264Sjacobs 	       int        len)		/* I - Length of buffer */
24922264Sjacobs {
24932264Sjacobs #  if defined(HAVE_LIBSSL)
24942264Sjacobs   return (SSL_write((SSL *)(http->tls), buf, len));
24952264Sjacobs 
24962264Sjacobs #  elif defined(HAVE_GNUTLS)
24972264Sjacobs   return (gnutls_record_send(((http_tls_t *)(http->tls))->session, buf, len));
24982264Sjacobs #  elif defined(HAVE_CDSASSL)
24992264Sjacobs   OSStatus	error;			/* Error info */
25002264Sjacobs   size_t	processed;		/* Number of bytes processed */
25012264Sjacobs 
25022264Sjacobs 
25032264Sjacobs   error = SSLWrite((SSLContextRef)http->tls, buf, len, &processed);
25042264Sjacobs 
25052264Sjacobs   if (error == 0)
25062264Sjacobs     return (processed);
25072264Sjacobs   else
25082264Sjacobs   {
25092264Sjacobs     http->error = error;
25102264Sjacobs     return (-1);
25112264Sjacobs   }
25122264Sjacobs #  endif /* HAVE_LIBSSL */
25132264Sjacobs }
25142264Sjacobs 
25152264Sjacobs 
25162264Sjacobs #  if defined(HAVE_CDSASSL)
25172264Sjacobs /*
25182264Sjacobs  * 'CDSAReadFunc()' - Read function for CDSA decryption code.
25192264Sjacobs  */
25202264Sjacobs 
25212264Sjacobs static OSStatus					/* O  - -1 on error, 0 on success */
CDSAReadFunc(SSLConnectionRef connection,void * data,size_t * dataLength)25222264Sjacobs CDSAReadFunc(SSLConnectionRef connection,	/* I  - SSL/TLS connection */
25232264Sjacobs              void             *data,		/* I  - Data buffer */
25242264Sjacobs 	     size_t           *dataLength)	/* IO - Number of bytes */
25252264Sjacobs {
25262264Sjacobs   ssize_t	bytes;				/* Number of bytes read */
25272264Sjacobs 
25282264Sjacobs #ifdef DEBUG_HTTP
25292264Sjacobs   httpDumpData(stdout, "CDSAReadFunc:", data, *dataLength);
25302264Sjacobs #endif
25312264Sjacobs   bytes = recv((int)connection, data, *dataLength, 0);
25322264Sjacobs   if (bytes >= 0)
25332264Sjacobs   {
25342264Sjacobs     *dataLength = bytes;
25352264Sjacobs     return (0);
25362264Sjacobs   }
25372264Sjacobs   else
25382264Sjacobs     return (-1);
25392264Sjacobs }
25402264Sjacobs 
25412264Sjacobs 
25422264Sjacobs /*
25432264Sjacobs  * 'CDSAWriteFunc()' - Write function for CDSA encryption code.
25442264Sjacobs  */
25452264Sjacobs 
25462264Sjacobs static OSStatus					/* O  - -1 on error, 0 on success */
CDSAWriteFunc(SSLConnectionRef connection,const void * data,size_t * dataLength)25472264Sjacobs CDSAWriteFunc(SSLConnectionRef connection,	/* I  - SSL/TLS connection */
25482264Sjacobs               const void       *data,		/* I  - Data buffer */
25492264Sjacobs 	      size_t           *dataLength)	/* IO - Number of bytes */
25502264Sjacobs {
25512264Sjacobs   ssize_t bytes;
25522264Sjacobs 
25532264Sjacobs 
25542264Sjacobs   bytes = write((int)connection, data, *dataLength);
25552264Sjacobs   if (bytes >= 0)
25562264Sjacobs   {
25572264Sjacobs     *dataLength = bytes;
25582264Sjacobs     return (0);
25592264Sjacobs   }
25602264Sjacobs   else
25612264Sjacobs     return (-1);
25622264Sjacobs }
25632264Sjacobs #  endif /* HAVE_CDSASSL */
25642264Sjacobs #endif /* HAVE_SSL */
25652264Sjacobs 
25662264Sjacobs 
25672264Sjacobs /*
25682264Sjacobs  * End of "$Id: http.c 148 2006-04-25 16:54:17Z njacobs $"
25692264Sjacobs  */
2570