xref: /titanic_44/usr/src/lib/print/libhttp-core/common/http.c (revision 0a44ef6d9afbfe052a7e975f55ea0d2954b62a82)
1 /*
2  * "$Id: http.c 148 2006-04-25 16:54:17Z njacobs $"
3  *
4  *   HTTP routines for the Common UNIX Printing System (CUPS).
5  *
6  *   Copyright 1997-2005 by Easy Software Products, all rights reserved.
7  *
8  *   These coded instructions, statements, and computer programs are the
9  *   property of Easy Software Products and are protected by Federal
10  *   copyright law.  Distribution and use rights are outlined in the file
11  *   "LICENSE.txt" which should have been included with this file.  If this
12  *   file is missing or damaged please contact Easy Software Products
13  *   at:
14  *
15  *       Attn: CUPS Licensing Information
16  *       Easy Software Products
17  *       44141 Airport View Drive, Suite 204
18  *       Hollywood, Maryland 20636 USA
19  *
20  *       Voice: (301) 373-9600
21  *       EMail: cups-info@cups.org
22  *         WWW: http://www.cups.org
23  *
24  *   This file is subject to the Apple OS-Developed Software exception.
25  *
26  * Contents:
27  *
28  *   httpInitialize()     - Initialize the HTTP interface library and set the
29  *                          default HTTP proxy (if any).
30  *   httpCheck()          - Check to see if there is a pending response from
31  *                          the server.
32  *   httpClearCookie()    - Clear the cookie value(s).
33  *   httpClose()          - Close an HTTP connection...
34  *   httpConnect()        - Connect to a HTTP server.
35  *   httpConnectEncrypt() - Connect to a HTTP server using encryption.
36  *   httpEncryption()     - Set the required encryption on the link.
37  *   httpReconnect()      - Reconnect to a HTTP server...
38  *   httpGetSubField()    - Get a sub-field value.
39  *   httpSetField()       - Set the value of an HTTP header.
40  *   httpDelete()         - Send a DELETE request to the server.
41  *   httpGet()            - Send a GET request to the server.
42  *   httpHead()           - Send a HEAD request to the server.
43  *   httpOptions()        - Send an OPTIONS request to the server.
44  *   httpPost()           - Send a POST request to the server.
45  *   httpPut()            - Send a PUT request to the server.
46  *   httpTrace()          - Send an TRACE request to the server.
47  *   httpFlush()          - Flush data from a HTTP connection.
48  *   httpRead()           - Read data from a HTTP connection.
49  *   httpSetCookie()      - Set the cookie value(s)...
50  *   httpWait()           - Wait for data available on a connection.
51  *   httpWrite()          - Write data to a HTTP connection.
52  *   httpGets()           - Get a line of text from a HTTP connection.
53  *   httpPrintf()         - Print a formatted string to a HTTP connection.
54  *   httpGetDateString()  - Get a formatted date/time string from a time value.
55  *   httpGetDateTime()    - Get a time value from a formatted date/time string.
56  *   httpUpdate()         - Update the current HTTP state for incoming data.
57  *   httpDecode64()       - Base64-decode a string.
58  *   httpDecode64_2()     - Base64-decode a string.
59  *   httpEncode64()       - Base64-encode a string.
60  *   httpEncode64_2()     - Base64-encode a string.
61  *   httpGetLength()      - Get the amount of data remaining from the
62  *                          content-length or transfer-encoding fields.
63  *   http_field()         - Return the field index for a field name.
64  *   http_send()          - Send a request with all fields and the trailing
65  *                          blank line.
66  *   http_wait()          - Wait for data available on a connection.
67  *   http_upgrade()       - Force upgrade to TLS encryption.
68  *   http_setup_ssl()     - Set up SSL/TLS on a connection.
69  *   http_shutdown_ssl()  - Shut down SSL/TLS on a connection.
70  *   http_read_ssl()      - Read from a SSL/TLS connection.
71  *   http_write_ssl()     - Write to a SSL/TLS connection.
72  *   CDSAReadFunc()       - Read function for CDSA decryption code.
73  *   CDSAWriteFunc()      - Write function for CDSA encryption code.
74  */
75 
76 #pragma ident	"%Z%%M%	%I%	%E% SMI"
77 
78 /*
79  * Include necessary headers...
80  */
81 
82 #include "http-private.h"
83 
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <stdarg.h>
87 #include <ctype.h>
88 #include "string.h"
89 #include <fcntl.h>
90 #include <errno.h>
91 
92 #include "http.h"
93 #include "debug.h"
94 
95 #ifndef WIN32
96 #  include <signal.h>
97 #  include <sys/time.h>
98 #  include <sys/resource.h>
99 #endif /* !WIN32 */
100 
101 
102 /*
103  * Some operating systems have done away with the Fxxxx constants for
104  * the fcntl() call; this works around that "feature"...
105  */
106 
107 #ifndef FNONBLK
108 #  define FNONBLK O_NONBLOCK
109 #endif /* !FNONBLK */
110 
111 
112 /*
113  * Local functions...
114  */
115 
116 static http_field_t	http_field(const char *name);
117 static int		http_send(http_t *http, http_state_t request,
118 			          const char *uri);
119 static int		http_wait(http_t *http, int msec);
120 #ifdef HAVE_SSL
121 static int		http_upgrade(http_t *http);
122 static int		http_setup_ssl(http_t *http);
123 static void		http_shutdown_ssl(http_t *http);
124 static int		http_read_ssl(http_t *http, char *buf, int len);
125 static int		http_write_ssl(http_t *http, const char *buf, int len);
126 #  ifdef HAVE_CDSASSL
127 static OSStatus		CDSAReadFunc(SSLConnectionRef connection, void *data, size_t *dataLength);
128 static OSStatus		CDSAWriteFunc(SSLConnectionRef connection, const void *data, size_t *dataLength);
129 #  endif /* HAVE_CDSASSL */
130 #endif /* HAVE_SSL */
131 
132 
133 /*
134  * Local globals...
135  */
136 
137 static const char * const http_fields[] =
138 			{
139 			  "Accept-Language",
140 			  "Accept-Ranges",
141 			  "Authorization",
142 			  "Connection",
143 			  "Content-Encoding",
144 			  "Content-Language",
145 			  "Content-Length",
146 			  "Content-Location",
147 			  "Content-MD5",
148 			  "Content-Range",
149 			  "Content-Type",
150 			  "Content-Version",
151 			  "Date",
152 			  "Host",
153 			  "If-Modified-Since",
154 			  "If-Unmodified-since",
155 			  "Keep-Alive",
156 			  "Last-Modified",
157 			  "Link",
158 			  "Location",
159 			  "Range",
160 			  "Referer",
161 			  "Retry-After",
162 			  "Transfer-Encoding",
163 			  "Upgrade",
164 			  "User-Agent",
165 			  "WWW-Authenticate"
166 			};
167 static const char * const days[7] =
168 			{
169 			  "Sun",
170 			  "Mon",
171 			  "Tue",
172 			  "Wed",
173 			  "Thu",
174 			  "Fri",
175 			  "Sat"
176 			};
177 static const char * const months[12] =
178 			{
179 			  "Jan",
180 			  "Feb",
181 			  "Mar",
182 			  "Apr",
183 			  "May",
184 			  "Jun",
185 		          "Jul",
186 			  "Aug",
187 			  "Sep",
188 			  "Oct",
189 			  "Nov",
190 			  "Dec"
191 			};
192 
193 void
httpDumpData(FILE * fp,const char * tag,const char * buffer,int bytes)194 httpDumpData(FILE *fp, const char *tag, const char *buffer, int bytes)
195 {
196         int i, j, ch;
197 
198 	fprintf(fp, "%s %d(0x%x) bytes...\n", tag, bytes, bytes);
199         for (i = 0; i < bytes; i += 16) {
200                 fprintf(fp, "%s   ", (tag ? tag : ""));
201 
202                 for (j = 0; j < 16 && (i + j) < bytes; j ++)
203                         fprintf(fp, " %02X", buffer[i + j] & 255);
204 
205                 while (j < 16) {
206                         fprintf(fp, "   ");
207                         j++;
208                 }
209 
210                 fprintf(fp, "    ");
211                 for (j = 0; j < 16 && (i + j) < bytes; j ++) {
212                         ch = buffer[i + j] & 255;
213                         if (ch < ' ' || ch == 127)
214                                 ch = '.';
215                         putc(ch, fp);
216                 }
217                 putc('\n', fp);
218         }
219 }
220 
221 
222 /*
223  * 'httpInitialize()' - Initialize the HTTP interface library and set the
224  *                      default HTTP proxy (if any).
225  */
226 
227 void
httpInitialize(void)228 httpInitialize(void)
229 {
230 #ifdef HAVE_LIBSSL
231 #  ifndef WIN32
232   struct timeval	curtime;	/* Current time in microseconds */
233 #  endif /* !WIN32 */
234   int			i;		/* Looping var */
235   unsigned char		data[1024];	/* Seed data */
236 #endif /* HAVE_LIBSSL */
237 
238 #ifdef WIN32
239   WSADATA	winsockdata;		/* WinSock data */
240   static int	initialized = 0;	/* Has WinSock been initialized? */
241 
242 
243   if (!initialized)
244     WSAStartup(MAKEWORD(1,1), &winsockdata);
245 #elif defined(HAVE_SIGSET)
246   sigset(SIGPIPE, SIG_IGN);
247 #elif defined(HAVE_SIGACTION)
248   struct sigaction	action;		/* POSIX sigaction data */
249 
250 
251  /*
252   * Ignore SIGPIPE signals...
253   */
254 
255   memset(&action, 0, sizeof(action));
256   action.sa_handler = SIG_IGN;
257   sigaction(SIGPIPE, &action, NULL);
258 #else
259   signal(SIGPIPE, SIG_IGN);
260 #endif /* WIN32 */
261 
262 #ifdef HAVE_GNUTLS
263   gnutls_global_init();
264 #endif /* HAVE_GNUTLS */
265 
266 #ifdef HAVE_LIBSSL
267   SSL_load_error_strings();
268   SSL_library_init();
269 
270  /*
271   * Using the current time is a dubious random seed, but on some systems
272   * it is the best we can do (on others, this seed isn't even used...)
273   */
274 
275 #ifdef WIN32
276 #else
277   gettimeofday(&curtime, NULL);
278   srand(curtime.tv_sec + curtime.tv_usec);
279 #endif /* WIN32 */
280 
281   for (i = 0; i < sizeof(data); i ++)
282     data[i] = rand(); /* Yes, this is a poor source of random data... */
283 
284   RAND_seed(&data, sizeof(data));
285 #endif /* HAVE_LIBSSL */
286 }
287 
288 
289 /*
290  * 'httpCheck()' - Check to see if there is a pending response from the server.
291  */
292 
293 int				/* O - 0 = no data, 1 = data available */
httpCheck(http_t * http)294 httpCheck(http_t *http)		/* I - HTTP connection */
295 {
296   return (httpWait(http, 0));
297 }
298 
299 
300 /*
301  * 'httpClearCookie()' - Clear the cookie value(s).
302  */
303 
304 void
httpClearCookie(http_t * http)305 httpClearCookie(http_t *http)			/* I - Connection */
306 {
307   if (!http)
308     return;
309 
310   if (http->cookie)
311   {
312     free(http->cookie);
313     http->cookie = NULL;
314   }
315 }
316 
317 
318 /*
319  * 'httpClose()' - Close an HTTP connection...
320  */
321 
322 void
httpClose(http_t * http)323 httpClose(http_t *http)		/* I - Connection to close */
324 {
325   DEBUG_printf(("httpClose(http=%p)\n", http));
326 
327   if (!http)
328     return;
329 
330   if (http->input_set)
331     free(http->input_set);
332 
333   if (http->cookie)
334     free(http->cookie);
335 
336 #ifdef HAVE_SSL
337   if (http->tls)
338     http_shutdown_ssl(http);
339 #endif /* HAVE_SSL */
340 
341 #ifdef WIN32
342   closesocket(http->fd);
343 #else
344   close(http->fd);
345 #endif /* WIN32 */
346 
347   free(http);
348 }
349 
350 
351 /*
352  * 'httpConnect()' - Connect to a HTTP server.
353  */
354 
355 http_t *				/* O - New HTTP connection */
httpConnect(const char * host,int port)356 httpConnect(const char *host,		/* I - Host to connect to */
357             int        port)		/* I - Port number */
358 {
359   http_encryption_t	encrypt;	/* Type of encryption to use */
360 
361 
362  /*
363   * Set the default encryption status...
364   */
365 
366   if (port == 443)
367     encrypt = HTTP_ENCRYPT_ALWAYS;
368   else
369     encrypt = HTTP_ENCRYPT_IF_REQUESTED;
370 
371   return (httpConnectEncrypt(host, port, encrypt));
372 }
373 
374 
375 /*
376  * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption.
377  */
378 
379 http_t *				/* O - New HTTP connection */
httpConnectEncrypt(const char * host,int port,http_encryption_t encrypt)380 httpConnectEncrypt(const char *host,	/* I - Host to connect to */
381                    int        port,	/* I - Port number */
382 		   http_encryption_t encrypt)
383 					/* I - Type of encryption to use */
384 {
385   int			i;		/* Looping var */
386   http_t		*http;		/* New HTTP connection */
387   struct hostent	*hostaddr;	/* Host address data */
388 
389 
390   DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encrypt=%d)\n",
391                 host ? host : "(null)", port, encrypt));
392 
393   if (!host)
394     return (NULL);
395 
396   httpInitialize();
397 
398  /*
399   * Lookup the host...
400   */
401 
402   if ((hostaddr = httpGetHostByName(host)) == NULL)
403   {
404    /*
405     * This hack to make users that don't have a localhost entry in
406     * their hosts file or DNS happy...
407     */
408 
409     if (strcasecmp(host, "localhost") != 0)
410       return (NULL);
411     else if ((hostaddr = httpGetHostByName("127.0.0.1")) == NULL)
412       return (NULL);
413   }
414 
415  /*
416   * Verify that it is an IPv4, IPv6, or domain address...
417   */
418 
419   if ((hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4)
420 #ifdef AF_INET6
421       && (hostaddr->h_addrtype != AF_INET6 || hostaddr->h_length != 16)
422 #endif /* AF_INET6 */
423 #ifdef AF_LOCAL
424       && (hostaddr->h_addrtype != AF_LOCAL)
425 #endif /* AF_LOCAL */
426       )
427     return (NULL);
428 
429  /*
430   * Allocate memory for the structure...
431   */
432 
433   http = calloc(sizeof(http_t), 1);
434   if (http == NULL)
435     return (NULL);
436 
437   http->version  = HTTP_1_1;
438   http->blocking = 1;
439   http->activity = time(NULL);
440   http->fd       = -1;
441 
442  /*
443   * Set the encryption status...
444   */
445 
446   if (port == 443)			/* Always use encryption for https */
447     http->encryption = HTTP_ENCRYPT_ALWAYS;
448   else
449     http->encryption = encrypt;
450 
451  /*
452   * Loop through the addresses we have until one of them connects...
453   */
454 
455   strlcpy(http->hostname, host, sizeof(http->hostname));
456 
457   for (i = 0; hostaddr->h_addr_list[i]; i ++)
458   {
459    /*
460     * Load the address...
461     */
462 
463     httpAddrLoad(hostaddr, port, i, &(http->hostaddr));
464 
465    /*
466     * Connect to the remote system...
467     */
468 
469     if (!httpReconnect(http))
470       return (http);
471   }
472 
473  /*
474   * Could not connect to any known address - bail out!
475   */
476 
477   free(http);
478   return (NULL);
479 }
480 
481 
482 /*
483  * 'httpEncryption()' - Set the required encryption on the link.
484  */
485 
486 int					/* O - -1 on error, 0 on success */
httpEncryption(http_t * http,http_encryption_t e)487 httpEncryption(http_t            *http,	/* I - HTTP data */
488                http_encryption_t e)	/* I - New encryption preference */
489 {
490   DEBUG_printf(("httpEncryption(http=%p, e=%d)\n", http, e));
491 
492 #ifdef HAVE_SSL
493   if (!http)
494     return (0);
495 
496   http->encryption = e;
497 
498   if ((http->encryption == HTTP_ENCRYPT_ALWAYS && !http->tls) ||
499       (http->encryption == HTTP_ENCRYPT_NEVER && http->tls))
500     return (httpReconnect(http));
501   else if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
502     return (http_upgrade(http));
503   else
504     return (0);
505 #else
506   if (e == HTTP_ENCRYPT_ALWAYS || e == HTTP_ENCRYPT_REQUIRED)
507     return (-1);
508   else
509     return (0);
510 #endif /* HAVE_SSL */
511 }
512 
513 
514 /*
515  * 'httpReconnect()' - Reconnect to a HTTP server...
516  */
517 
518 int					/* O - 0 on success, non-zero on failure */
httpReconnect(http_t * http)519 httpReconnect(http_t *http)		/* I - HTTP data */
520 {
521   int		val;			/* Socket option value */
522   int		status;			/* Connect status */
523 
524 
525   DEBUG_printf(("httpReconnect(http=%p)\n", http));
526 
527   if (!http)
528     return (-1);
529 
530 #ifdef HAVE_SSL
531   if (http->tls)
532     http_shutdown_ssl(http);
533 #endif /* HAVE_SSL */
534 
535  /*
536   * Close any previously open socket...
537   */
538 
539   if (http->fd >= 0)
540 #ifdef WIN32
541     closesocket(http->fd);
542 #else
543     close(http->fd);
544 #endif /* WIN32 */
545 
546  /*
547   * Create the socket and set options to allow reuse.
548   */
549 
550   if ((http->fd = socket(http->hostaddr.addr.sa_family, SOCK_STREAM, 0)) < 0)
551   {
552 #ifdef WIN32
553     http->error  = WSAGetLastError();
554 #else
555     http->error  = errno;
556 #endif /* WIN32 */
557     http->status = HTTP_ERROR;
558     return (-1);
559   }
560 
561 #ifdef FD_CLOEXEC
562   fcntl(http->fd, F_SETFD, FD_CLOEXEC);	/* Close this socket when starting *
563 					 * other processes...              */
564 #endif /* FD_CLOEXEC */
565 
566   val = 1;
567   setsockopt(http->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
568 
569 #ifdef SO_REUSEPORT
570   val = 1;
571   setsockopt(http->fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
572 #endif /* SO_REUSEPORT */
573 
574  /*
575   * Using TCP_NODELAY improves responsiveness, especially on systems
576   * with a slow loopback interface...  Since we write large buffers
577   * when sending print files and requests, there shouldn't be any
578   * performance penalty for this...
579   */
580 
581   val = 1;
582 #ifdef WIN32
583   setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
584 #else
585   setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
586 #endif /* WIN32 */
587 
588  /*
589   * Connect to the server...
590   */
591 
592 #ifdef AF_INET6
593   if (http->hostaddr.addr.sa_family == AF_INET6)
594     status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
595                      sizeof(http->hostaddr.ipv6));
596   else
597 #endif /* AF_INET6 */
598 #ifdef AF_LOCAL
599   if (http->hostaddr.addr.sa_family == AF_LOCAL)
600     status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
601                      SUN_LEN(&(http->hostaddr.un)));
602   else
603 #endif /* AF_LOCAL */
604   status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
605                    sizeof(http->hostaddr.ipv4));
606 
607   if (status < 0)
608   {
609 #ifdef WIN32
610     http->error  = WSAGetLastError();
611 #else
612     http->error  = errno;
613 #endif /* WIN32 */
614     http->status = HTTP_ERROR;
615 
616 #ifdef WIN32
617     closesocket(http->fd);
618 #else
619     close(http->fd);
620 #endif
621 
622     http->fd = -1;
623 
624     return (-1);
625   }
626 
627   http->error  = 0;
628   http->status = HTTP_CONTINUE;
629 
630 #ifdef HAVE_SSL
631   if (http->encryption == HTTP_ENCRYPT_ALWAYS)
632   {
633    /*
634     * Always do encryption via SSL.
635     */
636 
637     if (http_setup_ssl(http) != 0)
638     {
639 #ifdef WIN32
640       closesocket(http->fd);
641 #else
642       close(http->fd);
643 #endif /* WIN32 */
644 
645       return (-1);
646     }
647   }
648   else if (http->encryption == HTTP_ENCRYPT_REQUIRED)
649     return (http_upgrade(http));
650 #endif /* HAVE_SSL */
651 
652   return (0);
653 }
654 
655 
656 /*
657  * 'httpGetSubField()' - Get a sub-field value.
658  */
659 
660 char *					/* O - Value or NULL */
httpGetSubField(http_t * http,http_field_t field,const char * name,char * value)661 httpGetSubField(http_t       *http,	/* I - HTTP data */
662                 http_field_t field,	/* I - Field index */
663                 const char   *name,	/* I - Name of sub-field */
664 		char         *value)	/* O - Value string */
665 {
666   const char	*fptr;			/* Pointer into field */
667   char		temp[HTTP_MAX_VALUE],	/* Temporary buffer for name */
668 		*ptr;			/* Pointer into string buffer */
669 
670 
671   DEBUG_printf(("httpGetSubField(http=%p, field=%d, name=\"%s\", value=%p)\n",
672                 http, field, name, value));
673 
674   if (http == NULL ||
675       field < HTTP_FIELD_ACCEPT_LANGUAGE ||
676       field > HTTP_FIELD_WWW_AUTHENTICATE ||
677       name == NULL || value == NULL)
678     return (NULL);
679 
680   for (fptr = http->fields[field]; *fptr;)
681   {
682    /*
683     * Skip leading whitespace...
684     */
685 
686     while (isspace(*fptr & 255))
687       fptr ++;
688 
689     if (*fptr == ',')
690     {
691       fptr ++;
692       continue;
693     }
694 
695    /*
696     * Get the sub-field name...
697     */
698 
699     for (ptr = temp;
700          *fptr && *fptr != '=' && !isspace(*fptr & 255) && ptr < (temp + sizeof(temp) - 1);
701          *ptr++ = *fptr++);
702 
703     *ptr = '\0';
704 
705     DEBUG_printf(("httpGetSubField: name=\"%s\"\n", temp));
706 
707    /*
708     * Skip trailing chars up to the '='...
709     */
710 
711     while (isspace(*fptr & 255))
712       fptr ++;
713 
714     if (!*fptr)
715       break;
716 
717     if (*fptr != '=')
718       continue;
719 
720    /*
721     * Skip = and leading whitespace...
722     */
723 
724     fptr ++;
725 
726     while (isspace(*fptr & 255))
727       fptr ++;
728 
729     if (*fptr == '\"')
730     {
731      /*
732       * Read quoted string...
733       */
734 
735       for (ptr = value, fptr ++;
736            *fptr && *fptr != '\"' && ptr < (value + HTTP_MAX_VALUE - 1);
737 	   *ptr++ = *fptr++);
738 
739       *ptr = '\0';
740 
741       while (*fptr && *fptr != '\"')
742         fptr ++;
743 
744       if (*fptr)
745         fptr ++;
746     }
747     else
748     {
749      /*
750       * Read unquoted string...
751       */
752 
753       for (ptr = value;
754            *fptr && !isspace(*fptr & 255) && *fptr != ',' && ptr < (value + HTTP_MAX_VALUE - 1);
755 	   *ptr++ = *fptr++);
756 
757       *ptr = '\0';
758 
759       while (*fptr && !isspace(*fptr & 255) && *fptr != ',')
760         fptr ++;
761     }
762 
763     DEBUG_printf(("httpGetSubField: value=\"%s\"\n", value));
764 
765    /*
766     * See if this is the one...
767     */
768 
769     if (strcmp(name, temp) == 0)
770       return (value);
771   }
772 
773   value[0] = '\0';
774 
775   return (NULL);
776 }
777 
778 
779 /*
780  * 'httpSetField()' - Set the value of an HTTP header.
781  */
782 
783 void
httpSetField(http_t * http,http_field_t field,const char * value)784 httpSetField(http_t       *http,	/* I - HTTP data */
785              http_field_t field,	/* I - Field index */
786 	     const char   *value)	/* I - Value */
787 {
788   if (http == NULL ||
789       field < HTTP_FIELD_ACCEPT_LANGUAGE ||
790       field > HTTP_FIELD_WWW_AUTHENTICATE ||
791       value == NULL)
792     return;
793 
794   strlcpy(http->fields[field], value, HTTP_MAX_VALUE);
795 }
796 
797 
798 /*
799  * 'httpDelete()' - Send a DELETE request to the server.
800  */
801 
802 int					/* O - Status of call (0 = success) */
httpDelete(http_t * http,const char * uri)803 httpDelete(http_t     *http,		/* I - HTTP data */
804            const char *uri)		/* I - URI to delete */
805 {
806   return (http_send(http, HTTP_DELETE, uri));
807 }
808 
809 
810 /*
811  * 'httpGet()' - Send a GET request to the server.
812  */
813 
814 int					/* O - Status of call (0 = success) */
httpGet(http_t * http,const char * uri)815 httpGet(http_t     *http,		/* I - HTTP data */
816         const char *uri)		/* I - URI to get */
817 {
818   return (http_send(http, HTTP_GET, uri));
819 }
820 
821 
822 /*
823  * 'httpHead()' - Send a HEAD request to the server.
824  */
825 
826 int					/* O - Status of call (0 = success) */
httpHead(http_t * http,const char * uri)827 httpHead(http_t     *http,		/* I - HTTP data */
828          const char *uri)		/* I - URI for head */
829 {
830   return (http_send(http, HTTP_HEAD, uri));
831 }
832 
833 
834 /*
835  * 'httpOptions()' - Send an OPTIONS request to the server.
836  */
837 
838 int					/* O - Status of call (0 = success) */
httpOptions(http_t * http,const char * uri)839 httpOptions(http_t     *http,		/* I - HTTP data */
840             const char *uri)		/* I - URI for options */
841 {
842   return (http_send(http, HTTP_OPTIONS, uri));
843 }
844 
845 
846 /*
847  * 'httpPost()' - Send a POST request to the server.
848  */
849 
850 int					/* O - Status of call (0 = success) */
httpPost(http_t * http,const char * uri)851 httpPost(http_t     *http,		/* I - HTTP data */
852          const char *uri)		/* I - URI for post */
853 {
854   httpGetLength(http);
855 
856   return (http_send(http, HTTP_POST, uri));
857 }
858 
859 
860 /*
861  * 'httpPut()' - Send a PUT request to the server.
862  */
863 
864 int					/* O - Status of call (0 = success) */
httpPut(http_t * http,const char * uri)865 httpPut(http_t     *http,		/* I - HTTP data */
866         const char *uri)		/* I - URI to put */
867 {
868   httpGetLength(http);
869 
870   return (http_send(http, HTTP_PUT, uri));
871 }
872 
873 
874 /*
875  * 'httpTrace()' - Send an TRACE request to the server.
876  */
877 
878 int					/* O - Status of call (0 = success) */
httpTrace(http_t * http,const char * uri)879 httpTrace(http_t     *http,		/* I - HTTP data */
880           const char *uri)		/* I - URI for trace */
881 {
882   return (http_send(http, HTTP_TRACE, uri));
883 }
884 
885 
886 /*
887  * 'httpFlush()' - Flush data from a HTTP connection.
888  */
889 
890 void
httpFlush(http_t * http)891 httpFlush(http_t *http)			/* I - HTTP data */
892 {
893   char	buffer[8192];			/* Junk buffer */
894 
895 
896   DEBUG_printf(("httpFlush(http=%p), state=%d\n", http, http->state));
897 
898   while (httpRead(http, buffer, sizeof(buffer)) > 0);
899 }
900 
901 
902 /*
903  * 'httpRead()' - Read data from a HTTP connection.
904  */
905 
906 int					/* O - Number of bytes read */
httpRead(http_t * http,char * buffer,int length)907 httpRead(http_t *http,			/* I - HTTP data */
908          char   *buffer,		/* I - Buffer for data */
909 	 int    length)			/* I - Maximum number of bytes */
910 {
911   int		bytes;			/* Bytes read */
912   char		len[32];		/* Length string */
913 
914 
915   DEBUG_printf(("httpRead(http=%p, buffer=%p, length=%d)\n",
916                 http, buffer, length));
917 
918   if (http == NULL || buffer == NULL)
919     return (-1);
920 
921   http->activity = time(NULL);
922 
923   if (length <= 0)
924     return (0);
925 
926   if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
927       http->data_remaining <= 0)
928   {
929     DEBUG_puts("httpRead: Getting chunk length...");
930 
931     if (httpGets(len, sizeof(len), http) == NULL)
932     {
933       DEBUG_puts("httpRead: Could not get length!");
934       return (0);
935     }
936 
937     http->data_remaining = strtol(len, NULL, 16);
938     if (http->data_remaining < 0)
939     {
940       DEBUG_puts("httpRead: Negative chunk length!");
941       return (0);
942     }
943   }
944 
945   DEBUG_printf(("httpRead: data_remaining=%d\n", http->data_remaining));
946 
947   if (http->data_remaining <= 0)
948   {
949    /*
950     * A zero-length chunk ends a transfer; unless we are reading POST
951     * data, go idle...
952     */
953 
954     if (http->data_encoding == HTTP_ENCODE_CHUNKED)
955       httpGets(len, sizeof(len), http);
956 
957     if (http->state == HTTP_POST_RECV)
958       http->state ++;
959     else
960       http->state = HTTP_WAITING;
961 
962    /*
963     * Prevent future reads for this request...
964     */
965 
966     http->data_encoding = HTTP_ENCODE_LENGTH;
967 
968     return (0);
969   }
970   else if (length > http->data_remaining)
971     length = http->data_remaining;
972 
973   if (http->used == 0 && length <= 256)
974   {
975    /*
976     * Buffer small reads for better performance...
977     */
978 
979     if (!http->blocking && !httpWait(http, 1000))
980       return (0);
981 
982     if (http->data_remaining > sizeof(http->buffer))
983       bytes = sizeof(http->buffer);
984     else
985       bytes = http->data_remaining;
986 
987 #ifdef HAVE_SSL
988     if (http->tls)
989       bytes = http_read_ssl(http, http->buffer, bytes);
990     else
991 #endif /* HAVE_SSL */
992     {
993       DEBUG_printf(("httpRead: reading %d bytes from socket into buffer...\n",
994                     bytes));
995 
996       bytes = recv(http->fd, http->buffer, bytes, 0);
997 
998       DEBUG_printf(("httpRead: read %d bytes from socket into buffer...\n",
999                     bytes));
1000 #ifdef DEBUG_HTTP
1001     httpDumpData(stdout, "httpRead:", http->buffer, bytes);
1002 #endif
1003     }
1004 
1005     if (bytes > 0)
1006       http->used = bytes;
1007     else if (bytes < 0)
1008     {
1009 #ifdef WIN32
1010       http->error = WSAGetLastError();
1011       return (-1);
1012 #else
1013       if (errno != EINTR)
1014       {
1015         http->error = errno;
1016         return (-1);
1017       }
1018 #endif /* WIN32 */
1019     }
1020     else
1021     {
1022       http->error = EPIPE;
1023       return (0);
1024     }
1025   }
1026 
1027   if (http->used > 0)
1028   {
1029     if (length > http->used)
1030       length = http->used;
1031 
1032     bytes = length;
1033 
1034     DEBUG_printf(("httpRead: grabbing %d bytes from input buffer...\n", bytes));
1035 
1036     memcpy(buffer, http->buffer, length);
1037     http->used -= length;
1038 
1039     if (http->used > 0)
1040       memmove(http->buffer, http->buffer + length, http->used);
1041   }
1042 #ifdef HAVE_SSL
1043   else if (http->tls)
1044   {
1045     if (!http->blocking && !httpWait(http, 1000))
1046       return (0);
1047 
1048     bytes = http_read_ssl(http, buffer, length);
1049   }
1050 #endif /* HAVE_SSL */
1051   else
1052   {
1053     if (!http->blocking && !httpWait(http, 1000))
1054       return (0);
1055 
1056     DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length));
1057 
1058     while ((bytes = recv(http->fd, buffer, length, 0)) < 0)
1059       if (errno != EINTR)
1060         break;
1061     DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes));
1062   }
1063 #ifdef DEBUG_HTTP
1064     httpDumpData(stdout, "httpRead:", buffer, bytes);
1065 #endif
1066 
1067   if (bytes > 0)
1068     http->data_remaining -= bytes;
1069   else if (bytes < 0)
1070   {
1071 #ifdef WIN32
1072     http->error = WSAGetLastError();
1073 #else
1074     if (errno == EINTR)
1075       bytes = 0;
1076     else
1077       http->error = errno;
1078 #endif /* WIN32 */
1079   }
1080   else
1081   {
1082     http->error = EPIPE;
1083     return (0);
1084   }
1085 
1086   if (http->data_remaining == 0)
1087   {
1088     if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1089       httpGets(len, sizeof(len), http);
1090 
1091     if (http->data_encoding != HTTP_ENCODE_CHUNKED)
1092     {
1093       if (http->state == HTTP_POST_RECV)
1094 	http->state ++;
1095       else
1096 	http->state = HTTP_WAITING;
1097     }
1098   }
1099 
1100   return (bytes);
1101 }
1102 
1103 
1104 /*
1105  * 'httpSetCookie()' - Set the cookie value(s)...
1106  */
1107 
1108 void
httpSetCookie(http_t * http,const char * cookie)1109 httpSetCookie(http_t     *http,		/* I - Connection */
1110               const char *cookie)	/* I - Cookie string */
1111 {
1112   if (!http)
1113     return;
1114 
1115   if (http->cookie)
1116     free(http->cookie);
1117 
1118   if (cookie)
1119     http->cookie = strdup(cookie);
1120   else
1121     http->cookie = NULL;
1122 }
1123 
1124 
1125 /*
1126  * 'httpWait()' - Wait for data available on a connection.
1127  */
1128 
1129 int					/* O - 1 if data is available, 0 otherwise */
httpWait(http_t * http,int msec)1130 httpWait(http_t *http,			/* I - HTTP data */
1131          int    msec)			/* I - Milliseconds to wait */
1132 {
1133  /*
1134   * First see if there is data in the buffer...
1135   */
1136 
1137   if (http == NULL)
1138     return (0);
1139 
1140   if (http->used)
1141     return (1);
1142 
1143  /*
1144   * If not, check the SSL/TLS buffers and do a select() on the connection...
1145   */
1146 
1147   return (http_wait(http, msec));
1148 }
1149 
1150 
1151 /*
1152  * 'httpWrite()' - Write data to a HTTP connection.
1153  */
1154 
1155 int					/* O - Number of bytes written */
httpWrite(http_t * http,const char * buffer,int length)1156 httpWrite(http_t     *http,		/* I - HTTP data */
1157           const char *buffer,		/* I - Buffer for data */
1158 	  int        length)		/* I - Number of bytes to write */
1159 {
1160   int	tbytes,				/* Total bytes sent */
1161 	bytes;				/* Bytes sent */
1162 
1163 
1164   if (http == NULL || buffer == NULL)
1165     return (-1);
1166 
1167   http->activity = time(NULL);
1168 
1169   if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1170   {
1171     if (httpPrintf(http, "%x\r\n", length) < 0)
1172       return (-1);
1173 
1174     if (length == 0)
1175     {
1176      /*
1177       * A zero-length chunk ends a transfer; unless we are sending POST
1178       * or PUT data, go idle...
1179       */
1180 
1181       DEBUG_printf(("httpWrite: changing states from %d", http->state));
1182 
1183       if (http->state == HTTP_POST_RECV)
1184 	http->state ++;
1185       else if (http->state == HTTP_PUT_RECV)
1186         http->state = HTTP_STATUS;
1187       else
1188 	http->state = HTTP_WAITING;
1189       DEBUG_printf((" to %d\n", http->state));
1190 
1191       if (httpPrintf(http, "\r\n") < 0)
1192 	return (-1);
1193 
1194       return (0);
1195     }
1196   }
1197 
1198   tbytes = 0;
1199 
1200   while (length > 0)
1201   {
1202 #ifdef HAVE_SSL
1203     if (http->tls)
1204       bytes = http_write_ssl(http, buffer, length);
1205     else
1206 #endif /* HAVE_SSL */
1207     bytes = send(http->fd, buffer, length, 0);
1208 
1209 #ifdef DEBUG_HTTP
1210   if (bytes >= 0)
1211   	httpDumpData(stdout, "httpWrite:", buffer, bytes);
1212 #endif /* DEBUG */
1213 
1214 
1215     if (bytes < 0)
1216     {
1217 #ifdef WIN32
1218       if (WSAGetLastError() != http->error)
1219       {
1220         http->error = WSAGetLastError();
1221 	continue;
1222       }
1223 #else
1224       if (errno == EINTR)
1225         continue;
1226       else if (errno != http->error && errno != ECONNRESET)
1227       {
1228         http->error = errno;
1229 	continue;
1230       }
1231 #endif /* WIN32 */
1232 
1233       DEBUG_puts("httpWrite: error writing data...\n");
1234 
1235       return (-1);
1236     }
1237 
1238     buffer += bytes;
1239     tbytes += bytes;
1240     length -= bytes;
1241     if (http->data_encoding == HTTP_ENCODE_LENGTH)
1242       http->data_remaining -= bytes;
1243   }
1244 
1245   if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1246     if (httpPrintf(http, "\r\n") < 0)
1247       return (-1);
1248 
1249   if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
1250   {
1251    /*
1252     * Finished with the transfer; unless we are sending POST or PUT
1253     * data, go idle...
1254     */
1255 
1256     DEBUG_printf(("httpWrite: changing states from %d", http->state));
1257 
1258     if (http->state == HTTP_POST_RECV)
1259       http->state ++;
1260     else if (http->state == HTTP_PUT_RECV)
1261       http->state = HTTP_STATUS;
1262     else
1263       http->state = HTTP_WAITING;
1264 
1265     DEBUG_printf((" to %d\n", http->state));
1266   }
1267 
1268   return (tbytes);
1269 }
1270 
1271 
1272 /*
1273  * 'httpGets()' - Get a line of text from a HTTP connection.
1274  */
1275 
1276 char *					/* O - Line or NULL */
httpGets(char * line,int length,http_t * http)1277 httpGets(char   *line,			/* I - Line to read into */
1278          int    length,			/* I - Max length of buffer */
1279 	 http_t *http)			/* I - HTTP data */
1280 {
1281   char	*lineptr,			/* Pointer into line */
1282 	*bufptr,			/* Pointer into input buffer */
1283 	*bufend;			/* Pointer to end of buffer */
1284   int	bytes;				/* Number of bytes read */
1285 
1286 
1287   DEBUG_printf(("httpGets(line=%p, length=%d, http=%p)\n", line, length, http));
1288 
1289   if (http == NULL || line == NULL)
1290     return (NULL);
1291 
1292  /*
1293   * Pre-scan the buffer and see if there is a newline in there...
1294   */
1295 
1296 #ifdef WIN32
1297   WSASetLastError(0);
1298 #else
1299   errno = 0;
1300 #endif /* WIN32 */
1301 
1302   do
1303   {
1304     bufptr  = http->buffer;
1305     bufend  = http->buffer + http->used;
1306 
1307     while (bufptr < bufend)
1308       if (*bufptr == 0x0a)
1309 	break;
1310       else
1311 	bufptr ++;
1312 
1313     if (bufptr >= bufend && http->used < HTTP_MAX_BUFFER)
1314     {
1315      /*
1316       * No newline; see if there is more data to be read...
1317       */
1318 
1319       if (!http->blocking && !http_wait(http, 1000))
1320         return (NULL);
1321 
1322 #ifdef HAVE_SSL
1323       if (http->tls)
1324 	bytes = http_read_ssl(http, bufend, HTTP_MAX_BUFFER - http->used);
1325       else
1326 #endif /* HAVE_SSL */
1327         bytes = recv(http->fd, bufend, HTTP_MAX_BUFFER - http->used, 0);
1328 
1329       DEBUG_printf(("httpGets: read %d bytes...\n", bytes));
1330 #ifdef DEBUG_HTTP
1331       httpDumpData(stdout, "httpGets:", bufend, bytes);
1332 #endif
1333 
1334       if (bytes < 0)
1335       {
1336        /*
1337 	* Nope, can't get a line this time...
1338 	*/
1339 
1340 #ifdef WIN32
1341         if (WSAGetLastError() != http->error)
1342 	{
1343 	  http->error = WSAGetLastError();
1344 	  continue;
1345 	}
1346 
1347         DEBUG_printf(("httpGets: recv() error %d!\n", WSAGetLastError()));
1348 #else
1349         DEBUG_printf(("httpGets: recv() error %d!\n", errno));
1350 
1351         if (errno == EINTR)
1352 	  continue;
1353 	else if (errno != http->error)
1354 	{
1355 	  http->error = errno;
1356 	  continue;
1357 	}
1358 #endif /* WIN32 */
1359 
1360         return (NULL);
1361       }
1362       else if (bytes == 0)
1363       {
1364 	http->error = EPIPE;
1365 
1366         return (NULL);
1367       }
1368 
1369      /*
1370       * Yup, update the amount used and the end pointer...
1371       */
1372 
1373       http->used += bytes;
1374       bufend     += bytes;
1375       bufptr     = bufend;
1376     }
1377   }
1378   while (bufptr >= bufend && http->used < HTTP_MAX_BUFFER);
1379 
1380   http->activity = time(NULL);
1381 
1382  /*
1383   * Read a line from the buffer...
1384   */
1385 
1386   lineptr = line;
1387   bufptr  = http->buffer;
1388   bytes   = 0;
1389   length --;
1390 
1391   while (bufptr < bufend && bytes < length)
1392   {
1393     bytes ++;
1394 
1395     if (*bufptr == 0x0a)
1396     {
1397       bufptr ++;
1398       break;
1399     }
1400     else if (*bufptr == 0x0d)
1401       bufptr ++;
1402     else
1403       *lineptr++ = *bufptr++;
1404   }
1405 
1406   if (bytes > 0)
1407   {
1408     *lineptr = '\0';
1409 
1410     http->used -= bytes;
1411     if (http->used > 0)
1412       memmove(http->buffer, bufptr, http->used);
1413 
1414     DEBUG_printf(("httpGets: Returning \"%s\"\n", line));
1415     return (line);
1416   }
1417 
1418   DEBUG_puts("httpGets: No new line available!");
1419 
1420   return (NULL);
1421 }
1422 
1423 
1424 /*
1425  * 'httpPrintf()' - Print a formatted string to a HTTP connection.
1426  */
1427 
1428 int					/* O - Number of bytes written */
httpPrintf(http_t * http,const char * format,...)1429 httpPrintf(http_t     *http,		/* I - HTTP data */
1430            const char *format,		/* I - printf-style format string */
1431 	   ...)				/* I - Additional args as needed */
1432 {
1433   int		bytes,			/* Number of bytes to write */
1434 		nbytes,			/* Number of bytes written */
1435 		tbytes;			/* Number of bytes all together */
1436   char		buf[HTTP_MAX_BUFFER],	/* Buffer for formatted string */
1437 		*bufptr;		/* Pointer into buffer */
1438   va_list	ap;			/* Variable argument pointer */
1439 
1440 
1441   DEBUG_printf(("httpPrintf: httpPrintf(http=%p, format=\"%s\", ...)\n", http, format));
1442 
1443   va_start(ap, format);
1444   bytes = vsnprintf(buf, sizeof(buf), format, ap);
1445   va_end(ap);
1446 
1447   DEBUG_printf(("httpPrintf: %s", buf));
1448 
1449   for (tbytes = 0, bufptr = buf; tbytes < bytes; tbytes += nbytes, bufptr += nbytes)
1450   {
1451 #ifdef HAVE_SSL
1452     if (http->tls)
1453       nbytes = http_write_ssl(http, bufptr, bytes - tbytes);
1454     else
1455 #endif /* HAVE_SSL */
1456     nbytes = send(http->fd, bufptr, bytes - tbytes, 0);
1457 
1458 #ifdef DEBUG_HTTP
1459     if (nbytes >= 0)
1460     	httpDumpData(stdout, "httpPrintf:", bufptr, nbytes);
1461 #endif
1462 
1463     if (nbytes < 0)
1464     {
1465       nbytes = 0;
1466 
1467 #ifdef WIN32
1468       if (WSAGetLastError() != http->error)
1469       {
1470         http->error = WSAGetLastError();
1471 	continue;
1472       }
1473 #else
1474       if (errno == EINTR)
1475 	continue;
1476       else if (errno != http->error)
1477       {
1478         http->error = errno;
1479 	continue;
1480       }
1481 #endif /* WIN32 */
1482 
1483       return (-1);
1484     }
1485   }
1486 
1487   return (bytes);
1488 }
1489 
1490 
1491 /*
1492  * 'httpGetDateString()' - Get a formatted date/time string from a time value.
1493  */
1494 
1495 const char *				/* O - Date/time string */
httpGetDateString(time_t t)1496 httpGetDateString(time_t t)		/* I - UNIX time */
1497 {
1498   struct tm	*tdate;
1499   static char	datetime[256];
1500 
1501 
1502   tdate = gmtime(&t);
1503   snprintf(datetime, sizeof(datetime), "%s, %02d %s %d %02d:%02d:%02d GMT",
1504            days[tdate->tm_wday], tdate->tm_mday, months[tdate->tm_mon],
1505 	   tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec);
1506 
1507   return (datetime);
1508 }
1509 
1510 
1511 /*
1512  * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
1513  */
1514 
1515 time_t					/* O - UNIX time */
httpGetDateTime(const char * s)1516 httpGetDateTime(const char *s)		/* I - Date/time string */
1517 {
1518   int		i;			/* Looping var */
1519   struct tm	tdate;			/* Time/date structure */
1520   char		mon[16];		/* Abbreviated month name */
1521   int		day, year;		/* Day of month and year */
1522   int		hour, min, sec;		/* Time */
1523 
1524 
1525   if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6)
1526     return (0);
1527 
1528   for (i = 0; i < 12; i ++)
1529     if (strcasecmp(mon, months[i]) == 0)
1530       break;
1531 
1532   if (i >= 12)
1533     return (0);
1534 
1535   tdate.tm_mon   = i;
1536   tdate.tm_mday  = day;
1537   tdate.tm_year  = year - 1900;
1538   tdate.tm_hour  = hour;
1539   tdate.tm_min   = min;
1540   tdate.tm_sec   = sec;
1541   tdate.tm_isdst = 0;
1542 
1543   return (mktime(&tdate));
1544 }
1545 
1546 
1547 /*
1548  * 'httpUpdate()' - Update the current HTTP state for incoming data.
1549  */
1550 
1551 http_status_t				/* O - HTTP status */
httpUpdate(http_t * http)1552 httpUpdate(http_t *http)		/* I - HTTP data */
1553 {
1554   char		line[1024],		/* Line from connection... */
1555 		*value;			/* Pointer to value on line */
1556   http_field_t	field;			/* Field index */
1557   int		major, minor,		/* HTTP version numbers */
1558 		status;			/* Request status */
1559 
1560 
1561   DEBUG_printf(("httpUpdate(http=%p), state=%d\n", http, http->state));
1562 
1563  /*
1564   * If we haven't issued any commands, then there is nothing to "update"...
1565   */
1566 
1567   if (http->state == HTTP_WAITING)
1568     return (HTTP_CONTINUE);
1569 
1570  /*
1571   * Grab all of the lines we can from the connection...
1572   */
1573 
1574   line[0] = '\0';
1575   while (httpGets(line, sizeof(line), http) != NULL)
1576   {
1577     DEBUG_printf(("httpUpdate: Got \"%s\"\n", line));
1578 
1579     if (line[0] == '\0')
1580     {
1581      /*
1582       * Blank line means the start of the data section (if any).  Return
1583       * the result code, too...
1584       *
1585       * If we get status 100 (HTTP_CONTINUE), then we *don't* change states.
1586       * Instead, we just return HTTP_CONTINUE to the caller and keep on
1587       * tryin'...
1588       */
1589 
1590       if (http->status == HTTP_CONTINUE)
1591         return (http->status);
1592 
1593       if (http->status < HTTP_BAD_REQUEST)
1594         http->digest_tries = 0;
1595 
1596 #ifdef HAVE_SSL
1597       if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls)
1598       {
1599 	if (http_setup_ssl(http) != 0)
1600 	{
1601 #  ifdef WIN32
1602 	  closesocket(http->fd);
1603 #  else
1604 	  close(http->fd);
1605 #  endif /* WIN32 */
1606 
1607 	  return (HTTP_ERROR);
1608 	}
1609 
1610         return (HTTP_CONTINUE);
1611       }
1612 #endif /* HAVE_SSL */
1613 
1614       httpGetLength(http);
1615 
1616       switch (http->state)
1617       {
1618         case HTTP_GET :
1619 	case HTTP_POST :
1620 	case HTTP_POST_RECV :
1621 	case HTTP_PUT :
1622 	    http->state ++;
1623 	case HTTP_POST_SEND :
1624 	    break;
1625 
1626 	default :
1627 	    http->state = HTTP_WAITING;
1628 	    break;
1629       }
1630 
1631       return (http->status);
1632     }
1633     else if (strncmp(line, "HTTP/", 5) == 0)
1634     {
1635      /*
1636       * Got the beginning of a response...
1637       */
1638 
1639       if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &status) != 3)
1640         return (HTTP_ERROR);
1641 
1642       http->version = (http_version_t)(major * 100 + minor);
1643       http->status  = (http_status_t)status;
1644     }
1645     else if ((value = strchr(line, ':')) != NULL)
1646     {
1647      /*
1648       * Got a value...
1649       */
1650 
1651       *value++ = '\0';
1652       while (isspace(*value & 255))
1653         value ++;
1654 
1655      /*
1656       * Be tolerants of servers that send unknown attribute fields...
1657       */
1658 
1659       if (!strcasecmp(line, "expect"))
1660       {
1661        /*
1662         * "Expect: 100-continue" or similar...
1663 	*/
1664 
1665         http->expect = (http_status_t)atoi(value);
1666       }
1667       else if (!strcasecmp(line, "cookie"))
1668       {
1669        /*
1670         * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
1671 	*/
1672 
1673         httpSetCookie(http, value);
1674       }
1675       else if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN)
1676       {
1677         DEBUG_printf(("httpUpdate: unknown field %s seen!\n", line));
1678         continue;
1679       }
1680       else
1681         httpSetField(http, field, value);
1682     }
1683     else
1684     {
1685       http->status = HTTP_ERROR;
1686       return (HTTP_ERROR);
1687     }
1688   }
1689 
1690  /*
1691   * See if there was an error...
1692   */
1693 
1694   if (http->error == EPIPE && http->status > HTTP_CONTINUE)
1695     return (http->status);
1696 
1697   if (http->error)
1698   {
1699     DEBUG_printf(("httpUpdate: socket error %d - %s\n", http->error,
1700                   strerror(http->error)));
1701     http->status = HTTP_ERROR;
1702     return (HTTP_ERROR);
1703   }
1704 
1705  /*
1706   * If we haven't already returned, then there is nothing new...
1707   */
1708 
1709   return (HTTP_CONTINUE);
1710 }
1711 
1712 
1713 /*
1714  * 'httpDecode64()' - Base64-decode a string.
1715  */
1716 
1717 char *					/* O - Decoded string */
httpDecode64(char * out,const char * in)1718 httpDecode64(char       *out,		/* I - String to write to */
1719              const char *in)		/* I - String to read from */
1720 {
1721   int	outlen;				/* Output buffer length */
1722 
1723 
1724  /*
1725   * Use the old maximum buffer size for binary compatibility...
1726   */
1727 
1728   outlen = 512;
1729 
1730   return (httpDecode64_2(out, &outlen, in));
1731 }
1732 
1733 
1734 /*
1735  * 'httpDecode64_2()' - Base64-decode a string.
1736  */
1737 
1738 char *					/* O  - Decoded string */
httpDecode64_2(char * out,int * outlen,const char * in)1739 httpDecode64_2(char       *out,		/* I  - String to write to */
1740 	       int        *outlen,	/* IO - Size of output string */
1741                const char *in)		/* I  - String to read from */
1742 {
1743   int	pos,				/* Bit position */
1744 	base64;				/* Value of this character */
1745   char	*outptr,			/* Output pointer */
1746 	*outend;			/* End of output buffer */
1747 
1748 
1749  /*
1750   * Range check input...
1751   */
1752 
1753   if (!out || !outlen || *outlen < 1 || !in || !*in)
1754     return (NULL);
1755 
1756  /*
1757   * Convert from base-64 to bytes...
1758   */
1759 
1760   for (outptr = out, outend = out + *outlen - 1, pos = 0; *in != '\0'; in ++)
1761   {
1762    /*
1763     * Decode this character into a number from 0 to 63...
1764     */
1765 
1766     if (*in >= 'A' && *in <= 'Z')
1767       base64 = *in - 'A';
1768     else if (*in >= 'a' && *in <= 'z')
1769       base64 = *in - 'a' + 26;
1770     else if (*in >= '0' && *in <= '9')
1771       base64 = *in - '0' + 52;
1772     else if (*in == '+')
1773       base64 = 62;
1774     else if (*in == '/')
1775       base64 = 63;
1776     else if (*in == '=')
1777       break;
1778     else
1779       continue;
1780 
1781    /*
1782     * Store the result in the appropriate chars...
1783     */
1784 
1785     switch (pos)
1786     {
1787       case 0 :
1788           if (outptr < outend)
1789             *outptr = base64 << 2;
1790 	  pos ++;
1791 	  break;
1792       case 1 :
1793           if (outptr < outend)
1794             *outptr++ |= (base64 >> 4) & 3;
1795           if (outptr < outend)
1796 	    *outptr = (base64 << 4) & 255;
1797 	  pos ++;
1798 	  break;
1799       case 2 :
1800           if (outptr < outend)
1801             *outptr++ |= (base64 >> 2) & 15;
1802           if (outptr < outend)
1803 	    *outptr = (base64 << 6) & 255;
1804 	  pos ++;
1805 	  break;
1806       case 3 :
1807           if (outptr < outend)
1808             *outptr++ |= base64;
1809 	  pos = 0;
1810 	  break;
1811     }
1812   }
1813 
1814   *outptr = '\0';
1815 
1816  /*
1817   * Return the decoded string and size...
1818   */
1819 
1820   *outlen = (int)(outptr - out);
1821 
1822   return (out);
1823 }
1824 
1825 
1826 /*
1827  * 'httpEncode64()' - Base64-encode a string.
1828  */
1829 
1830 char *					/* O - Encoded string */
httpEncode64(char * out,const char * in)1831 httpEncode64(char       *out,		/* I - String to write to */
1832              const char *in)		/* I - String to read from */
1833 {
1834   return (httpEncode64_2(out, 512, in, strlen(in)));
1835 }
1836 
1837 
1838 /*
1839  * 'httpEncode64_2()' - Base64-encode a string.
1840  */
1841 
1842 char *					/* O - Encoded string */
httpEncode64_2(char * out,int outlen,const char * in,int inlen)1843 httpEncode64_2(char       *out,		/* I - String to write to */
1844 	       int        outlen,	/* I - Size of output string */
1845                const char *in,		/* I - String to read from */
1846 	       int        inlen)	/* I - Size of input string */
1847 {
1848   char		*outptr,		/* Output pointer */
1849 		*outend;		/* End of output buffer */
1850   static const char base64[] =		/* Base64 characters... */
1851   		{
1852 		  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1853 		  "abcdefghijklmnopqrstuvwxyz"
1854 		  "0123456789"
1855 		  "+/"
1856   		};
1857 
1858 
1859  /*
1860   * Range check input...
1861   */
1862 
1863   if (!out || outlen < 1 || !in || inlen < 1)
1864     return (NULL);
1865 
1866  /*
1867   * Convert bytes to base-64...
1868   */
1869 
1870   for (outptr = out, outend = out + outlen - 1; inlen > 0; in ++, inlen --)
1871   {
1872    /*
1873     * Encode the up to 3 characters as 4 Base64 numbers...
1874     */
1875 
1876     if (outptr < outend)
1877       *outptr ++ = base64[(in[0] & 255) >> 2];
1878     if (outptr < outend)
1879       *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63];
1880 
1881     in ++;
1882     inlen --;
1883     if (inlen <= 0)
1884     {
1885       if (outptr < outend)
1886         *outptr ++ = '=';
1887       if (outptr < outend)
1888         *outptr ++ = '=';
1889       break;
1890     }
1891 
1892     if (outptr < outend)
1893       *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63];
1894 
1895     in ++;
1896     inlen --;
1897     if (inlen <= 0)
1898     {
1899       if (outptr < outend)
1900         *outptr ++ = '=';
1901       break;
1902     }
1903 
1904     if (outptr < outend)
1905       *outptr ++ = base64[in[0] & 63];
1906   }
1907 
1908   *outptr = '\0';
1909 
1910  /*
1911   * Return the encoded string...
1912   */
1913 
1914   return (out);
1915 }
1916 
1917 
1918 /*
1919  * 'httpGetLength()' - Get the amount of data remaining from the
1920  *                     content-length or transfer-encoding fields.
1921  */
1922 
1923 int				/* O - Content length */
httpGetLength(http_t * http)1924 httpGetLength(http_t *http)	/* I - HTTP data */
1925 {
1926   DEBUG_printf(("httpGetLength(http=%p), state=%d\n", http, http->state));
1927 
1928   if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0)
1929   {
1930     DEBUG_puts("httpGetLength: chunked request!");
1931 
1932     http->data_encoding  = HTTP_ENCODE_CHUNKED;
1933     http->data_remaining = 0;
1934   }
1935   else
1936   {
1937     http->data_encoding = HTTP_ENCODE_LENGTH;
1938 
1939    /*
1940     * The following is a hack for HTTP servers that don't send a
1941     * content-length or transfer-encoding field...
1942     *
1943     * If there is no content-length then the connection must close
1944     * after the transfer is complete...
1945     */
1946 
1947     if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0')
1948       http->data_remaining = 2147483647;
1949     else
1950       http->data_remaining = atoi(http->fields[HTTP_FIELD_CONTENT_LENGTH]);
1951 
1952     DEBUG_printf(("httpGetLength: content_length=%d\n", http->data_remaining));
1953   }
1954 
1955   return (http->data_remaining);
1956 }
1957 
1958 
1959 /*
1960  * 'http_field()' - Return the field index for a field name.
1961  */
1962 
1963 static http_field_t		/* O - Field index */
http_field(const char * name)1964 http_field(const char *name)	/* I - String name */
1965 {
1966   int	i;			/* Looping var */
1967 
1968 
1969   for (i = 0; i < HTTP_FIELD_MAX; i ++)
1970     if (strcasecmp(name, http_fields[i]) == 0)
1971       return ((http_field_t)i);
1972 
1973   return (HTTP_FIELD_UNKNOWN);
1974 }
1975 
1976 
1977 /*
1978  * 'http_send()' - Send a request with all fields and the trailing blank line.
1979  */
1980 
1981 static int			/* O - 0 on success, non-zero on error */
http_send(http_t * http,http_state_t request,const char * uri)1982 http_send(http_t       *http,	/* I - HTTP data */
1983           http_state_t request,	/* I - Request code */
1984 	  const char   *uri)	/* I - URI */
1985 {
1986   int		i;		/* Looping var */
1987   char		*ptr,		/* Pointer in buffer */
1988 		buf[1024];	/* Encoded URI buffer */
1989   static const char * const codes[] =
1990 		{		/* Request code strings */
1991 		  NULL,
1992 		  "OPTIONS",
1993 		  "GET",
1994 		  NULL,
1995 		  "HEAD",
1996 		  "POST",
1997 		  NULL,
1998 		  NULL,
1999 		  "PUT",
2000 		  NULL,
2001 		  "DELETE",
2002 		  "TRACE",
2003 		  "CLOSE"
2004 		};
2005   static const char hex[] = "0123456789ABCDEF";
2006 				/* Hex digits */
2007 
2008 
2009   DEBUG_printf(("http_send(http=%p, request=HTTP_%s, uri=\"%s\")\n",
2010                 http, codes[request], uri));
2011 
2012   if (http == NULL || uri == NULL)
2013     return (-1);
2014 
2015  /*
2016   * Encode the URI as needed...
2017   */
2018 
2019   for (ptr = buf; *uri != '\0' && ptr < (buf + sizeof(buf) - 1); uri ++)
2020     if (*uri <= ' ' || *uri >= 127)
2021     {
2022       if (ptr < (buf + sizeof(buf) - 1))
2023         *ptr ++ = '%';
2024       if (ptr < (buf + sizeof(buf) - 1))
2025         *ptr ++ = hex[(*uri >> 4) & 15];
2026       if (ptr < (buf + sizeof(buf) - 1))
2027         *ptr ++ = hex[*uri & 15];
2028     }
2029     else
2030       *ptr ++ = *uri;
2031 
2032   *ptr = '\0';
2033 
2034  /*
2035   * See if we had an error the last time around; if so, reconnect...
2036   */
2037 
2038   if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST)
2039     httpReconnect(http);
2040 
2041  /*
2042   * Send the request header...
2043   */
2044 
2045   http->state = request;
2046   if (request == HTTP_POST || request == HTTP_PUT)
2047     http->state ++;
2048 
2049   http->status = HTTP_CONTINUE;
2050 
2051 #ifdef HAVE_SSL
2052   if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
2053   {
2054     httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
2055     httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0,SSL/2.0,SSL/3.0");
2056   }
2057 #endif /* HAVE_SSL */
2058 
2059   if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
2060   {
2061     http->status = HTTP_ERROR;
2062     return (-1);
2063   }
2064 
2065   for (i = 0; i < HTTP_FIELD_MAX; i ++)
2066     if (http->fields[i][0] != '\0')
2067     {
2068       DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i]));
2069 
2070       if (httpPrintf(http, "%s: %s\r\n", http_fields[i], http->fields[i]) < 1)
2071       {
2072 	http->status = HTTP_ERROR;
2073 	return (-1);
2074       }
2075     }
2076 
2077   if (httpPrintf(http, "\r\n") < 1)
2078   {
2079     http->status = HTTP_ERROR;
2080     return (-1);
2081   }
2082 
2083   httpClearFields(http);
2084 
2085   return (0);
2086 }
2087 
2088 
2089 /*
2090  * 'http_wait()' - Wait for data available on a connection.
2091  */
2092 
2093 static int				/* O - 1 if data is available, 0 otherwise */
http_wait(http_t * http,int msec)2094 http_wait(http_t *http,			/* I - HTTP data */
2095           int    msec)			/* I - Milliseconds to wait */
2096 {
2097 #ifndef WIN32
2098   struct rlimit		limit;          /* Runtime limit */
2099 #endif /* !WIN32 */
2100   struct timeval	timeout;	/* Timeout */
2101   int			nfds;		/* Result from select() */
2102   int			set_size;	/* Size of select set */
2103 
2104 
2105   DEBUG_printf(("http_wait(http=%p, msec=%d)\n", http, msec));
2106 
2107  /*
2108   * Check the SSL/TLS buffers for data first...
2109   */
2110 
2111 #ifdef HAVE_SSL
2112   if (http->tls)
2113   {
2114 #  ifdef HAVE_LIBSSL
2115     if (SSL_pending((SSL *)(http->tls)))
2116       return (1);
2117 #  elif defined(HAVE_GNUTLS)
2118     if (gnutls_record_check_pending(((http_tls_t *)(http->tls))->session))
2119       return (1);
2120 #  elif defined(HAVE_CDSASSL)
2121     size_t bytes;			/* Bytes that are available */
2122 
2123     if (!SSLGetBufferedReadSize((SSLContextRef)http->tls, &bytes) && bytes > 0)
2124       return;
2125 #  endif /* HAVE_LIBSSL */
2126   }
2127 #endif /* HAVE_SSL */
2128 
2129  /*
2130   * Then try doing a select() to poll the socket...
2131   */
2132 
2133   if (!http->input_set)
2134   {
2135 #ifdef WIN32
2136    /*
2137     * Windows has a fixed-size select() structure, different (surprise,
2138     * surprise!) from all UNIX implementations.  Just allocate this
2139     * fixed structure...
2140     */
2141 
2142     http->input_set = calloc(1, sizeof(fd_set));
2143 #else
2144    /*
2145     * Allocate the select() input set based upon the max number of file
2146     * descriptors available for this process...
2147     */
2148 
2149     getrlimit(RLIMIT_NOFILE, &limit);
2150 
2151     set_size = (limit.rlim_cur + 31) / 8 + 4;
2152     if (set_size < sizeof(fd_set))
2153       set_size = sizeof(fd_set);
2154 
2155     http->input_set = calloc(1, set_size);
2156 #endif /* WIN32 */
2157 
2158     if (!http->input_set)
2159       return (0);
2160   }
2161 
2162   do
2163   {
2164     FD_SET(http->fd, http->input_set);
2165 
2166     if (msec >= 0)
2167     {
2168       timeout.tv_sec  = msec / 1000;
2169       timeout.tv_usec = (msec % 1000) * 1000;
2170 
2171       nfds = select(http->fd + 1, http->input_set, NULL, NULL, &timeout);
2172     }
2173     else
2174       nfds = select(http->fd + 1, http->input_set, NULL, NULL, NULL);
2175   }
2176 #ifdef WIN32
2177   while (nfds < 0 && WSAGetLastError() == WSAEINTR);
2178 #else
2179   while (nfds < 0 && errno == EINTR);
2180 #endif /* WIN32 */
2181 
2182   FD_CLR(http->fd, http->input_set);
2183 
2184   return (nfds > 0);
2185 }
2186 
2187 
2188 #ifdef HAVE_SSL
2189 /*
2190  * 'http_upgrade()' - Force upgrade to TLS encryption.
2191  */
2192 
2193 static int			/* O - Status of connection */
http_upgrade(http_t * http)2194 http_upgrade(http_t *http)	/* I - HTTP data */
2195 {
2196   int		ret;		/* Return value */
2197   http_t	myhttp;		/* Local copy of HTTP data */
2198 
2199 
2200   DEBUG_printf(("http_upgrade(%p)\n", http));
2201 
2202  /*
2203   * Copy the HTTP data to a local variable so we can do the OPTIONS
2204   * request without interfering with the existing request data...
2205   */
2206 
2207   memcpy(&myhttp, http, sizeof(myhttp));
2208 
2209  /*
2210   * Send an OPTIONS request to the server, requiring SSL or TLS
2211   * encryption on the link...
2212   */
2213 
2214   httpClearFields(&myhttp);
2215   httpSetField(&myhttp, HTTP_FIELD_CONNECTION, "upgrade");
2216   httpSetField(&myhttp, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0");
2217 
2218   if ((ret = httpOptions(&myhttp, "*")) == 0)
2219   {
2220    /*
2221     * Wait for the secure connection...
2222     */
2223 
2224     while (httpUpdate(&myhttp) == HTTP_CONTINUE);
2225   }
2226 
2227   httpFlush(&myhttp);
2228 
2229  /*
2230   * Copy the HTTP data back over, if any...
2231   */
2232 
2233   http->fd         = myhttp.fd;
2234   http->error      = myhttp.error;
2235   http->activity   = myhttp.activity;
2236   http->status     = myhttp.status;
2237   http->version    = myhttp.version;
2238   http->keep_alive = myhttp.keep_alive;
2239   http->used       = myhttp.used;
2240 
2241   if (http->used)
2242     memcpy(http->buffer, myhttp.buffer, http->used);
2243 
2244   http->auth_type   = myhttp.auth_type;
2245   http->nonce_count = myhttp.nonce_count;
2246 
2247   memcpy(http->nonce, myhttp.nonce, sizeof(http->nonce));
2248 
2249   http->tls        = myhttp.tls;
2250   http->encryption = myhttp.encryption;
2251 
2252  /*
2253   * See if we actually went secure...
2254   */
2255 
2256   if (!http->tls)
2257   {
2258    /*
2259     * Server does not support HTTP upgrade...
2260     */
2261 
2262     DEBUG_puts("Server does not support HTTP upgrade!");
2263 
2264 #  ifdef WIN32
2265     closesocket(http->fd);
2266 #  else
2267     close(http->fd);
2268 #  endif
2269 
2270     http->fd = -1;
2271 
2272     return (-1);
2273   }
2274   else
2275     return (ret);
2276 }
2277 
2278 
2279 /*
2280  * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
2281  */
2282 
2283 static int				/* O - Status of connection */
http_setup_ssl(http_t * http)2284 http_setup_ssl(http_t *http)		/* I - HTTP data */
2285 {
2286 #  ifdef HAVE_LIBSSL
2287   SSL_CTX	*context;	/* Context for encryption */
2288   SSL		*conn;		/* Connection for encryption */
2289 #  elif defined(HAVE_GNUTLS)
2290   http_tls_t	*conn;		/* TLS session object */
2291   gnutls_certificate_client_credentials *credentials;
2292 				/* TLS credentials */
2293 #  elif defined(HAVE_CDSASSL)
2294   SSLContextRef	conn;		/* Context for encryption */
2295   OSStatus	error;		/* Error info */
2296 #  endif /* HAVE_LIBSSL */
2297 
2298 
2299   DEBUG_printf(("http_setup_ssl(http=%p)\n", http));
2300 
2301 #  ifdef HAVE_LIBSSL
2302   context = SSL_CTX_new(SSLv23_client_method());
2303 
2304   SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
2305 
2306   conn = SSL_new(context);
2307 
2308   SSL_set_fd(conn, http->fd);
2309   if (SSL_connect(conn) != 1)
2310   {
2311 #    ifdef DEBUG
2312     unsigned long	error;	/* Error code */
2313 
2314     while ((error = ERR_get_error()) != 0)
2315       printf("http_setup_ssl: %s\n", ERR_error_string(error, NULL));
2316 #    endif /* DEBUG */
2317 
2318     SSL_CTX_free(context);
2319     SSL_free(conn);
2320 
2321 #    ifdef WIN32
2322     http->error  = WSAGetLastError();
2323 #    else
2324     http->error  = errno;
2325 #    endif /* WIN32 */
2326     http->status = HTTP_ERROR;
2327 
2328     return (HTTP_ERROR);
2329   }
2330 
2331 #  elif defined(HAVE_GNUTLS)
2332   conn = (http_tls_t *)malloc(sizeof(http_tls_t));
2333 
2334   if (conn == NULL)
2335   {
2336     http->error  = errno;
2337     http->status = HTTP_ERROR;
2338 
2339     return (-1);
2340   }
2341 
2342   credentials = (gnutls_certificate_client_credentials *)
2343                     malloc(sizeof(gnutls_certificate_client_credentials));
2344   if (credentials == NULL)
2345   {
2346     free(conn);
2347 
2348     http->error = errno;
2349     http->status = HTTP_ERROR;
2350 
2351     return (-1);
2352   }
2353 
2354   gnutls_certificate_allocate_credentials(credentials);
2355 
2356   gnutls_init(&(conn->session), GNUTLS_CLIENT);
2357   gnutls_set_default_priority(conn->session);
2358   gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials);
2359   gnutls_transport_set_ptr(conn->session, http->fd);
2360 
2361   if ((gnutls_handshake(conn->session)) != GNUTLS_E_SUCCESS)
2362   {
2363     http->error  = errno;
2364     http->status = HTTP_ERROR;
2365 
2366     return (-1);
2367   }
2368 
2369   conn->credentials = credentials;
2370 
2371 #  elif defined(HAVE_CDSASSL)
2372   error = SSLNewContext(false, &conn);
2373 
2374   if (!error)
2375     error = SSLSetIOFuncs(conn, CDSAReadFunc, CDSAWriteFunc);
2376 
2377   if (!error)
2378     error = SSLSetConnection(conn, (SSLConnectionRef)http->fd);
2379 
2380   if (!error)
2381     error = SSLSetAllowsExpiredCerts(conn, true);
2382 
2383   if (!error)
2384     error = SSLSetAllowsAnyRoot(conn, true);
2385 
2386   if (!error)
2387     error = SSLHandshake(conn);
2388 
2389   if (error != 0)
2390   {
2391     http->error  = error;
2392     http->status = HTTP_ERROR;
2393 
2394     SSLDisposeContext(conn);
2395 
2396     close(http->fd);
2397 
2398     return (-1);
2399   }
2400 #  endif /* HAVE_CDSASSL */
2401 
2402   http->tls = conn;
2403   return (0);
2404 }
2405 
2406 
2407 /*
2408  * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection.
2409  */
2410 
2411 static void
http_shutdown_ssl(http_t * http)2412 http_shutdown_ssl(http_t *http)	/* I - HTTP data */
2413 {
2414 #  ifdef HAVE_LIBSSL
2415   SSL_CTX	*context;	/* Context for encryption */
2416   SSL		*conn;		/* Connection for encryption */
2417 
2418 
2419   conn    = (SSL *)(http->tls);
2420   context = SSL_get_SSL_CTX(conn);
2421 
2422   SSL_shutdown(conn);
2423   SSL_CTX_free(context);
2424   SSL_free(conn);
2425 
2426 #  elif defined(HAVE_GNUTLS)
2427   http_tls_t      *conn;	/* Encryption session */
2428   gnutls_certificate_client_credentials *credentials;
2429 				/* TLS credentials */
2430 
2431 
2432   conn = (http_tls_t *)(http->tls);
2433   credentials = (gnutls_certificate_client_credentials *)(conn->credentials);
2434 
2435   gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
2436   gnutls_deinit(conn->session);
2437   gnutls_certificate_free_credentials(*credentials);
2438   free(credentials);
2439   free(conn);
2440 
2441 #  elif defined(HAVE_CDSASSL)
2442   SSLClose((SSLContextRef)http->tls);
2443   SSLDisposeContext((SSLContextRef)http->tls);
2444 #  endif /* HAVE_LIBSSL */
2445 
2446   http->tls = NULL;
2447 }
2448 
2449 
2450 /*
2451  * 'http_read_ssl()' - Read from a SSL/TLS connection.
2452  */
2453 
2454 static int				/* O - Bytes read */
http_read_ssl(http_t * http,char * buf,int len)2455 http_read_ssl(http_t *http,		/* I - HTTP data */
2456 	      char   *buf,		/* I - Buffer to store data */
2457 	      int    len)		/* I - Length of buffer */
2458 {
2459 #  if defined(HAVE_LIBSSL)
2460   return (SSL_read((SSL *)(http->tls), buf, len));
2461 
2462 #  elif defined(HAVE_GNUTLS)
2463   return (gnutls_record_recv(((http_tls_t *)(http->tls))->session, buf, len));
2464 
2465 #  elif defined(HAVE_CDSASSL)
2466   OSStatus	error;			/* Error info */
2467   size_t	processed;		/* Number of bytes processed */
2468 
2469 
2470   error = SSLRead((SSLContextRef)http->tls, buf, len, &processed);
2471 
2472   if (error == 0)
2473     return (processed);
2474   else
2475   {
2476     http->error = error;
2477 
2478     return (-1);
2479   }
2480 #  endif /* HAVE_LIBSSL */
2481 }
2482 
2483 
2484 /*
2485  * 'http_write_ssl()' - Write to a SSL/TLS connection.
2486  */
2487 
2488 static int				/* O - Bytes written */
http_write_ssl(http_t * http,const char * buf,int len)2489 http_write_ssl(http_t     *http,	/* I - HTTP data */
2490 	       const char *buf,		/* I - Buffer holding data */
2491 	       int        len)		/* I - Length of buffer */
2492 {
2493 #  if defined(HAVE_LIBSSL)
2494   return (SSL_write((SSL *)(http->tls), buf, len));
2495 
2496 #  elif defined(HAVE_GNUTLS)
2497   return (gnutls_record_send(((http_tls_t *)(http->tls))->session, buf, len));
2498 #  elif defined(HAVE_CDSASSL)
2499   OSStatus	error;			/* Error info */
2500   size_t	processed;		/* Number of bytes processed */
2501 
2502 
2503   error = SSLWrite((SSLContextRef)http->tls, buf, len, &processed);
2504 
2505   if (error == 0)
2506     return (processed);
2507   else
2508   {
2509     http->error = error;
2510     return (-1);
2511   }
2512 #  endif /* HAVE_LIBSSL */
2513 }
2514 
2515 
2516 #  if defined(HAVE_CDSASSL)
2517 /*
2518  * 'CDSAReadFunc()' - Read function for CDSA decryption code.
2519  */
2520 
2521 static OSStatus					/* O  - -1 on error, 0 on success */
CDSAReadFunc(SSLConnectionRef connection,void * data,size_t * dataLength)2522 CDSAReadFunc(SSLConnectionRef connection,	/* I  - SSL/TLS connection */
2523              void             *data,		/* I  - Data buffer */
2524 	     size_t           *dataLength)	/* IO - Number of bytes */
2525 {
2526   ssize_t	bytes;				/* Number of bytes read */
2527 
2528 #ifdef DEBUG_HTTP
2529   httpDumpData(stdout, "CDSAReadFunc:", data, *dataLength);
2530 #endif
2531   bytes = recv((int)connection, data, *dataLength, 0);
2532   if (bytes >= 0)
2533   {
2534     *dataLength = bytes;
2535     return (0);
2536   }
2537   else
2538     return (-1);
2539 }
2540 
2541 
2542 /*
2543  * 'CDSAWriteFunc()' - Write function for CDSA encryption code.
2544  */
2545 
2546 static OSStatus					/* O  - -1 on error, 0 on success */
CDSAWriteFunc(SSLConnectionRef connection,const void * data,size_t * dataLength)2547 CDSAWriteFunc(SSLConnectionRef connection,	/* I  - SSL/TLS connection */
2548               const void       *data,		/* I  - Data buffer */
2549 	      size_t           *dataLength)	/* IO - Number of bytes */
2550 {
2551   ssize_t bytes;
2552 
2553 
2554   bytes = write((int)connection, data, *dataLength);
2555   if (bytes >= 0)
2556   {
2557     *dataLength = bytes;
2558     return (0);
2559   }
2560   else
2561     return (-1);
2562 }
2563 #  endif /* HAVE_CDSASSL */
2564 #endif /* HAVE_SSL */
2565 
2566 
2567 /*
2568  * End of "$Id: http.c 148 2006-04-25 16:54:17Z njacobs $"
2569  */
2570