1 /*
2  * HTTP routines for CUPS.
3  *
4  * Copyright 2007-2017 by Apple Inc.
5  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
6  *
7  * This file contains Kerberos support code, copyright 2006 by
8  * Jelmer Vernooij.
9  *
10  * These coded instructions, statements, and computer programs are the
11  * property of Apple Inc. and are protected by Federal copyright
12  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
13  * which should have been included with this file.  If this file is
14  * missing or damaged, see the license at "http://www.cups.org/".
15  *
16  * This file is subject to the Apple OS-Developed Software exception.
17  */
18 
19 /*
20  * Include necessary headers...
21  */
22 
23 #include "cups-private.h"
24 #include <fcntl.h>
25 #include <math.h>
26 #ifdef WIN32
27 #  include <tchar.h>
28 #else
29 #  include <signal.h>
30 #  include <sys/time.h>
31 #  include <sys/resource.h>
32 #endif /* WIN32 */
33 #ifdef HAVE_POLL
34 #  include <poll.h>
35 #endif /* HAVE_POLL */
36 
37 
38 /*
39  * Local functions...
40  */
41 
42 #ifdef HAVE_LIBZ
43 static void		http_content_coding_finish(http_t *http);
44 static void		http_content_coding_start(http_t *http,
45 						  const char *value);
46 #endif /* HAVE_LIBZ */
47 static http_t		*http_create(const char *host, int port,
48 			             http_addrlist_t *addrlist, int family,
49 				     http_encryption_t encryption,
50 				     int blocking, _http_mode_t mode);
51 #ifdef DEBUG
52 static void		http_debug_hex(const char *prefix, const char *buffer,
53 			               int bytes);
54 #endif /* DEBUG */
55 static ssize_t		http_read(http_t *http, char *buffer, size_t length);
56 static ssize_t		http_read_buffered(http_t *http, char *buffer, size_t length);
57 static ssize_t		http_read_chunk(http_t *http, char *buffer, size_t length);
58 static int		http_send(http_t *http, http_state_t request,
59 			          const char *uri);
60 static ssize_t		http_write(http_t *http, const char *buffer,
61 			           size_t length);
62 static ssize_t		http_write_chunk(http_t *http, const char *buffer,
63 			                 size_t length);
64 static off_t		http_set_length(http_t *http);
65 static void		http_set_timeout(int fd, double timeout);
66 static void		http_set_wait(http_t *http);
67 
68 #ifdef HAVE_SSL
69 static int		http_tls_upgrade(http_t *http);
70 #endif /* HAVE_SSL */
71 
72 
73 /*
74  * Local globals...
75  */
76 
77 static const char * const http_fields[] =
78 			{
79 			  "Accept-Language",
80 			  "Accept-Ranges",
81 			  "Authorization",
82 			  "Connection",
83 			  "Content-Encoding",
84 			  "Content-Language",
85 			  "Content-Length",
86 			  "Content-Location",
87 			  "Content-MD5",
88 			  "Content-Range",
89 			  "Content-Type",
90 			  "Content-Version",
91 			  "Date",
92 			  "Host",
93 			  "If-Modified-Since",
94 			  "If-Unmodified-since",
95 			  "Keep-Alive",
96 			  "Last-Modified",
97 			  "Link",
98 			  "Location",
99 			  "Range",
100 			  "Referer",
101 			  "Retry-After",
102 			  "Transfer-Encoding",
103 			  "Upgrade",
104 			  "User-Agent",
105 			  "WWW-Authenticate",
106 			  "Accept-Encoding",
107 			  "Allow",
108 			  "Server"
109 			};
110 
111 
112 /*
113  * 'httpAcceptConnection()' - Accept a new HTTP client connection from the
114  *                            specified listening socket.
115  *
116  * @since CUPS 1.7/macOS 10.9@
117  */
118 
119 http_t *				/* O - HTTP connection or @code NULL@ */
httpAcceptConnection(int fd,int blocking)120 httpAcceptConnection(int fd,		/* I - Listen socket file descriptor */
121                      int blocking)	/* I - 1 if the connection should be
122         				       blocking, 0 otherwise */
123 {
124   http_t		*http;		/* HTTP connection */
125   http_addrlist_t	addrlist;	/* Dummy address list */
126   socklen_t		addrlen;	/* Length of address */
127   int			val;		/* Socket option value */
128 
129 
130  /*
131   * Range check input...
132   */
133 
134   if (fd < 0)
135     return (NULL);
136 
137  /*
138   * Create the client connection...
139   */
140 
141   memset(&addrlist, 0, sizeof(addrlist));
142 
143   if ((http = http_create(NULL, 0, &addrlist, AF_UNSPEC,
144                           HTTP_ENCRYPTION_IF_REQUESTED, blocking,
145                           _HTTP_MODE_SERVER)) == NULL)
146     return (NULL);
147 
148  /*
149   * Accept the client and get the remote address...
150   */
151 
152   addrlen = sizeof(http_addr_t);
153 
154   if ((http->fd = accept(fd, (struct sockaddr *)&(http->addrlist->addr),
155 			 &addrlen)) < 0)
156   {
157     _cupsSetHTTPError(HTTP_STATUS_ERROR);
158     httpClose(http);
159 
160     return (NULL);
161   }
162 
163   http->hostaddr = &(http->addrlist->addr);
164 
165   if (httpAddrLocalhost(http->hostaddr))
166     strlcpy(http->hostname, "localhost", sizeof(http->hostname));
167   else
168     httpAddrString(http->hostaddr, http->hostname, sizeof(http->hostname));
169 
170 #ifdef SO_NOSIGPIPE
171  /*
172   * Disable SIGPIPE for this socket.
173   */
174 
175   val = 1;
176   setsockopt(http->fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
177 #endif /* SO_NOSIGPIPE */
178 
179  /*
180   * Using TCP_NODELAY improves responsiveness, especially on systems
181   * with a slow loopback interface.  Since we write large buffers
182   * when sending print files and requests, there shouldn't be any
183   * performance penalty for this...
184   */
185 
186   val = 1;
187   setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val));
188 
189 #ifdef FD_CLOEXEC
190  /*
191   * Close this socket when starting another process...
192   */
193 
194   fcntl(http->fd, F_SETFD, FD_CLOEXEC);
195 #endif /* FD_CLOEXEC */
196 
197   return (http);
198 }
199 
200 
201 /*
202  * 'httpAddCredential()' - Allocates and adds a single credential to an array.
203  *
204  * Use @code cupsArrayNew(NULL, NULL)@ to create a credentials array.
205  *
206  * @since CUPS 1.5/macOS 10.7@
207  */
208 
209 int					/* O - 0 on success, -1 on error */
httpAddCredential(cups_array_t * credentials,const void * data,size_t datalen)210 httpAddCredential(
211     cups_array_t *credentials,		/* I - Credentials array */
212     const void   *data,			/* I - PEM-encoded X.509 data */
213     size_t       datalen)		/* I - Length of data */
214 {
215   http_credential_t	*credential;	/* Credential data */
216 
217 
218   if ((credential = malloc(sizeof(http_credential_t))) != NULL)
219   {
220     credential->datalen = datalen;
221 
222     if ((credential->data = malloc(datalen)) != NULL)
223     {
224       memcpy(credential->data, data, datalen);
225       cupsArrayAdd(credentials, credential);
226       return (0);
227     }
228 
229     free(credential);
230   }
231 
232   return (-1);
233 }
234 
235 
236 /*
237  * 'httpBlocking()' - Set blocking/non-blocking behavior on a connection.
238  */
239 
240 void
httpBlocking(http_t * http,int b)241 httpBlocking(http_t *http,		/* I - HTTP connection */
242              int    b)			/* I - 1 = blocking, 0 = non-blocking */
243 {
244   if (http)
245   {
246     http->blocking = b;
247     http_set_wait(http);
248   }
249 }
250 
251 
252 /*
253  * 'httpCheck()' - Check to see if there is a pending response from the server.
254  */
255 
256 int					/* O - 0 = no data, 1 = data available */
httpCheck(http_t * http)257 httpCheck(http_t *http)			/* I - HTTP connection */
258 {
259   return (httpWait(http, 0));
260 }
261 
262 
263 /*
264  * 'httpClearCookie()' - Clear the cookie value(s).
265  *
266  * @since CUPS 1.1.19/macOS 10.3@
267  */
268 
269 void
httpClearCookie(http_t * http)270 httpClearCookie(http_t *http)		/* I - HTTP connection */
271 {
272   if (!http)
273     return;
274 
275   if (http->cookie)
276   {
277     free(http->cookie);
278     http->cookie = NULL;
279   }
280 }
281 
282 
283 /*
284  * 'httpClearFields()' - Clear HTTP request fields.
285  */
286 
287 void
httpClearFields(http_t * http)288 httpClearFields(http_t *http)		/* I - HTTP connection */
289 {
290   DEBUG_printf(("httpClearFields(http=%p)", (void *)http));
291 
292   if (http)
293   {
294     memset(http->fields, 0, sizeof(http->fields));
295 
296     if (http->mode == _HTTP_MODE_CLIENT)
297     {
298       if (http->hostname[0] == '/')
299 	httpSetField(http, HTTP_FIELD_HOST, "localhost");
300       else
301 	httpSetField(http, HTTP_FIELD_HOST, http->hostname);
302     }
303 
304     if (http->field_authorization)
305     {
306       free(http->field_authorization);
307       http->field_authorization = NULL;
308     }
309 
310     if (http->accept_encoding)
311     {
312       _cupsStrFree(http->accept_encoding);
313       http->accept_encoding = NULL;
314     }
315 
316     if (http->allow)
317     {
318       _cupsStrFree(http->allow);
319       http->allow = NULL;
320     }
321 
322     if (http->server)
323     {
324       _cupsStrFree(http->server);
325       http->server = NULL;
326     }
327 
328     http->expect = (http_status_t)0;
329   }
330 }
331 
332 
333 /*
334  * 'httpClose()' - Close an HTTP connection.
335  */
336 
337 void
httpClose(http_t * http)338 httpClose(http_t *http)			/* I - HTTP connection */
339 {
340 #ifdef HAVE_GSSAPI
341   OM_uint32	minor_status;		/* Minor status code */
342 #endif /* HAVE_GSSAPI */
343 
344 
345   DEBUG_printf(("httpClose(http=%p)", (void *)http));
346 
347  /*
348   * Range check input...
349   */
350 
351   if (!http)
352     return;
353 
354  /*
355   * Close any open connection...
356   */
357 
358   _httpDisconnect(http);
359 
360  /*
361   * Free memory used...
362   */
363 
364   httpAddrFreeList(http->addrlist);
365 
366   if (http->cookie)
367     free(http->cookie);
368 
369 #ifdef HAVE_GSSAPI
370   if (http->gssctx != GSS_C_NO_CONTEXT)
371     gss_delete_sec_context(&minor_status, &http->gssctx, GSS_C_NO_BUFFER);
372 
373   if (http->gssname != GSS_C_NO_NAME)
374     gss_release_name(&minor_status, &http->gssname);
375 #endif /* HAVE_GSSAPI */
376 
377 #ifdef HAVE_AUTHORIZATION_H
378   if (http->auth_ref)
379     AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults);
380 #endif /* HAVE_AUTHORIZATION_H */
381 
382   httpClearFields(http);
383 
384   if (http->authstring && http->authstring != http->_authstring)
385     free(http->authstring);
386 
387   free(http);
388 }
389 
390 
391 /*
392  * 'httpCompareCredentials()' - Compare two sets of X.509 credentials.
393  *
394  * @since CUPS 2.0/OS 10.10@
395  */
396 
397 int					/* O - 1 if they match, 0 if they do not */
httpCompareCredentials(cups_array_t * cred1,cups_array_t * cred2)398 httpCompareCredentials(
399     cups_array_t *cred1,		/* I - First set of X.509 credentials */
400     cups_array_t *cred2)		/* I - Second set of X.509 credentials */
401 {
402   http_credential_t	*temp1, *temp2;	/* Temporary credentials */
403 
404 
405   for (temp1 = (http_credential_t *)cupsArrayFirst(cred1), temp2 = (http_credential_t *)cupsArrayFirst(cred2); temp1 && temp2; temp1 = (http_credential_t *)cupsArrayNext(cred1), temp2 = (http_credential_t *)cupsArrayNext(cred2))
406     if (temp1->datalen != temp2->datalen)
407       return (0);
408     else if (memcmp(temp1->data, temp2->data, temp1->datalen))
409       return (0);
410 
411   return (temp1 == temp2);
412 }
413 
414 
415 /*
416  * 'httpConnect()' - Connect to a HTTP server.
417  *
418  * This function is deprecated - use @link httpConnect2@ instead.
419  *
420  * @deprecated@ @exclude all@
421  */
422 
423 http_t *				/* O - New HTTP connection */
httpConnect(const char * host,int port)424 httpConnect(const char *host,		/* I - Host to connect to */
425             int        port)		/* I - Port number */
426 {
427   return (httpConnect2(host, port, NULL, AF_UNSPEC,
428                        HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL));
429 }
430 
431 
432 /*
433  * 'httpConnect2()' - Connect to a HTTP server.
434  *
435  * @since CUPS 1.7/macOS 10.9@
436  */
437 
438 http_t *				/* O - New HTTP connection */
httpConnect2(const char * host,int port,http_addrlist_t * addrlist,int family,http_encryption_t encryption,int blocking,int msec,int * cancel)439 httpConnect2(
440     const char        *host,		/* I - Host to connect to */
441     int               port,		/* I - Port number */
442     http_addrlist_t   *addrlist,	/* I - List of addresses or @code NULL@ to lookup */
443     int               family,		/* I - Address family to use or @code AF_UNSPEC@ for any */
444     http_encryption_t encryption,	/* I - Type of encryption to use */
445     int               blocking,		/* I - 1 for blocking connection, 0 for non-blocking */
446     int               msec,		/* I - Connection timeout in milliseconds, 0 means don't connect */
447     int               *cancel)		/* I - Pointer to "cancel" variable */
448 {
449   http_t	*http;			/* New HTTP connection */
450 
451 
452   DEBUG_printf(("httpConnect2(host=\"%s\", port=%d, addrlist=%p, family=%d, encryption=%d, blocking=%d, msec=%d, cancel=%p)", host, port, (void *)addrlist, family, encryption, blocking, msec, (void *)cancel));
453 
454  /*
455   * Create the HTTP structure...
456   */
457 
458   if ((http = http_create(host, port, addrlist, family, encryption, blocking,
459                           _HTTP_MODE_CLIENT)) == NULL)
460     return (NULL);
461 
462  /*
463   * Optionally connect to the remote system...
464   */
465 
466   if (msec == 0 || !httpReconnect2(http, msec, cancel))
467     return (http);
468 
469  /*
470   * Could not connect to any known address - bail out!
471   */
472 
473   httpClose(http);
474 
475   return (NULL);
476 }
477 
478 
479 /*
480  * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption.
481  *
482  * This function is now deprecated. Please use the @link httpConnect2@ function
483  * instead.
484  *
485  * @deprecated@ @exclude all@
486  */
487 
488 http_t *				/* O - New HTTP connection */
httpConnectEncrypt(const char * host,int port,http_encryption_t encryption)489 httpConnectEncrypt(
490     const char        *host,		/* I - Host to connect to */
491     int               port,		/* I - Port number */
492     http_encryption_t encryption)	/* I - Type of encryption to use */
493 {
494   DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encryption=%d)",
495                 host, port, encryption));
496 
497   return (httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000,
498                        NULL));
499 }
500 
501 
502 /*
503  * 'httpDelete()' - Send a DELETE request to the server.
504  */
505 
506 int					/* O - Status of call (0 = success) */
httpDelete(http_t * http,const char * uri)507 httpDelete(http_t     *http,		/* I - HTTP connection */
508            const char *uri)		/* I - URI to delete */
509 {
510   return (http_send(http, HTTP_STATE_DELETE, uri));
511 }
512 
513 
514 /*
515  * '_httpDisconnect()' - Disconnect a HTTP connection.
516  */
517 
518 void
_httpDisconnect(http_t * http)519 _httpDisconnect(http_t *http)		/* I - HTTP connection */
520 {
521 #ifdef HAVE_SSL
522   if (http->tls)
523     _httpTLSStop(http);
524 #endif /* HAVE_SSL */
525 
526   httpAddrClose(NULL, http->fd);
527 
528   http->fd = -1;
529 }
530 
531 
532 /*
533  * 'httpEncryption()' - Set the required encryption on the link.
534  */
535 
536 int					/* O - -1 on error, 0 on success */
httpEncryption(http_t * http,http_encryption_t e)537 httpEncryption(http_t            *http,	/* I - HTTP connection */
538                http_encryption_t e)	/* I - New encryption preference */
539 {
540   DEBUG_printf(("httpEncryption(http=%p, e=%d)", (void *)http, e));
541 
542 #ifdef HAVE_SSL
543   if (!http)
544     return (0);
545 
546   if (http->mode == _HTTP_MODE_CLIENT)
547   {
548     http->encryption = e;
549 
550     if ((http->encryption == HTTP_ENCRYPTION_ALWAYS && !http->tls) ||
551         (http->encryption == HTTP_ENCRYPTION_NEVER && http->tls))
552       return (httpReconnect2(http, 30000, NULL));
553     else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls)
554       return (http_tls_upgrade(http));
555     else
556       return (0);
557   }
558   else
559   {
560     if (e == HTTP_ENCRYPTION_NEVER && http->tls)
561       return (-1);
562 
563     http->encryption = e;
564     if (e != HTTP_ENCRYPTION_IF_REQUESTED && !http->tls)
565       return (_httpTLSStart(http));
566     else
567       return (0);
568   }
569 #else
570   if (e == HTTP_ENCRYPTION_ALWAYS || e == HTTP_ENCRYPTION_REQUIRED)
571     return (-1);
572   else
573     return (0);
574 #endif /* HAVE_SSL */
575 }
576 
577 
578 /*
579  * 'httpError()' - Get the last error on a connection.
580  */
581 
582 int					/* O - Error code (errno) value */
httpError(http_t * http)583 httpError(http_t *http)			/* I - HTTP connection */
584 {
585   if (http)
586     return (http->error);
587   else
588     return (EINVAL);
589 }
590 
591 
592 /*
593  * 'httpFieldValue()' - Return the HTTP field enumeration value for a field
594  *                      name.
595  */
596 
597 http_field_t				/* O - Field index */
httpFieldValue(const char * name)598 httpFieldValue(const char *name)	/* I - String name */
599 {
600   int	i;				/* Looping var */
601 
602 
603   for (i = 0; i < HTTP_FIELD_MAX; i ++)
604     if (!_cups_strcasecmp(name, http_fields[i]))
605       return ((http_field_t)i);
606 
607   return (HTTP_FIELD_UNKNOWN);
608 }
609 
610 
611 /*
612  * 'httpFlush()' - Flush data read from a HTTP connection.
613  */
614 
615 void
httpFlush(http_t * http)616 httpFlush(http_t *http)			/* I - HTTP connection */
617 {
618   char		buffer[8192];		/* Junk buffer */
619   int		blocking;		/* To block or not to block */
620   http_state_t	oldstate;		/* Old state */
621 
622 
623   DEBUG_printf(("httpFlush(http=%p), state=%s", (void *)http, httpStateString(http->state)));
624 
625  /*
626   * Nothing to do if we are in the "waiting" state...
627   */
628 
629   if (http->state == HTTP_STATE_WAITING)
630     return;
631 
632  /*
633   * Temporarily set non-blocking mode so we don't get stuck in httpRead()...
634   */
635 
636   blocking = http->blocking;
637   http->blocking = 0;
638 
639  /*
640   * Read any data we can...
641   */
642 
643   oldstate = http->state;
644   while (httpRead2(http, buffer, sizeof(buffer)) > 0);
645 
646  /*
647   * Restore blocking and reset the connection if we didn't get all of
648   * the remaining data...
649   */
650 
651   http->blocking = blocking;
652 
653   if (http->state == oldstate && http->state != HTTP_STATE_WAITING &&
654       http->fd >= 0)
655   {
656    /*
657     * Didn't get the data back, so close the current connection.
658     */
659 
660 #ifdef HAVE_LIBZ
661     if (http->coding)
662       http_content_coding_finish(http);
663 #endif /* HAVE_LIBZ */
664 
665     DEBUG_puts("1httpFlush: Setting state to HTTP_STATE_WAITING and closing.");
666 
667     http->state = HTTP_STATE_WAITING;
668 
669 #ifdef HAVE_SSL
670     if (http->tls)
671       _httpTLSStop(http);
672 #endif /* HAVE_SSL */
673 
674     httpAddrClose(NULL, http->fd);
675 
676     http->fd = -1;
677   }
678 }
679 
680 
681 /*
682  * 'httpFlushWrite()' - Flush data written to a HTTP connection.
683  *
684  * @since CUPS 1.2/macOS 10.5@
685  */
686 
687 int					/* O - Bytes written or -1 on error */
httpFlushWrite(http_t * http)688 httpFlushWrite(http_t *http)		/* I - HTTP connection */
689 {
690   ssize_t	bytes;			/* Bytes written */
691 
692 
693   DEBUG_printf(("httpFlushWrite(http=%p) data_encoding=%d", (void *)http, http ? http->data_encoding : 100));
694 
695   if (!http || !http->wused)
696   {
697     DEBUG_puts(http ? "1httpFlushWrite: Write buffer is empty." :
698                       "1httpFlushWrite: No connection.");
699     return (0);
700   }
701 
702   if (http->data_encoding == HTTP_ENCODING_CHUNKED)
703     bytes = http_write_chunk(http, http->wbuffer, (size_t)http->wused);
704   else
705     bytes = http_write(http, http->wbuffer, (size_t)http->wused);
706 
707   http->wused = 0;
708 
709   DEBUG_printf(("1httpFlushWrite: Returning %d, errno=%d.", (int)bytes, errno));
710 
711   return ((int)bytes);
712 }
713 
714 
715 /*
716  * 'httpFreeCredentials()' - Free an array of credentials.
717  */
718 
719 void
httpFreeCredentials(cups_array_t * credentials)720 httpFreeCredentials(
721     cups_array_t *credentials)		/* I - Array of credentials */
722 {
723   http_credential_t	*credential;	/* Credential */
724 
725 
726   for (credential = (http_credential_t *)cupsArrayFirst(credentials);
727        credential;
728        credential = (http_credential_t *)cupsArrayNext(credentials))
729   {
730     cupsArrayRemove(credentials, credential);
731     free((void *)credential->data);
732     free(credential);
733   }
734 
735   cupsArrayDelete(credentials);
736 }
737 
738 
739 /*
740  * 'httpGet()' - Send a GET request to the server.
741  */
742 
743 int					/* O - Status of call (0 = success) */
httpGet(http_t * http,const char * uri)744 httpGet(http_t     *http,		/* I - HTTP connection */
745         const char *uri)		/* I - URI to get */
746 {
747   return (http_send(http, HTTP_STATE_GET, uri));
748 }
749 
750 
751 /*
752  * 'httpGetActivity()' - Get the most recent activity for a connection.
753  *
754  * The return value is the time in seconds of the last read or write.
755  *
756  * @since CUPS 2.0/OS 10.10@
757  */
758 
759 time_t					/* O - Time of last read or write */
httpGetActivity(http_t * http)760 httpGetActivity(http_t *http)		/* I - HTTP connection */
761 {
762   return (http ? http->activity : 0);
763 }
764 
765 
766 /*
767  * 'httpGetAuthString()' - Get the current authorization string.
768  *
769  * The authorization string is set by @link cupsDoAuthentication@ and
770  * @link httpSetAuthString@.  Use @link httpGetAuthString@ to retrieve the
771  * string to use with @link httpSetField@ for the
772  * @code HTTP_FIELD_AUTHORIZATION@ value.
773  *
774  * @since CUPS 1.3/macOS 10.5@
775  */
776 
777 char *					/* O - Authorization string */
httpGetAuthString(http_t * http)778 httpGetAuthString(http_t *http)		/* I - HTTP connection */
779 {
780   if (http)
781     return (http->authstring);
782   else
783     return (NULL);
784 }
785 
786 
787 /*
788  * 'httpGetBlocking()' - Get the blocking/non-block state of a connection.
789  *
790  * @since CUPS 1.2/macOS 10.5@
791  */
792 
793 int					/* O - 1 if blocking, 0 if non-blocking */
httpGetBlocking(http_t * http)794 httpGetBlocking(http_t *http)		/* I - HTTP connection */
795 {
796   return (http ? http->blocking : 0);
797 }
798 
799 
800 /*
801  * 'httpGetContentEncoding()' - Get a common content encoding, if any, between
802  *                              the client and server.
803  *
804  * This function uses the value of the Accepts-Encoding HTTP header and must be
805  * called after receiving a response from the server or a request from the
806  * client.  The value returned can be use in subsequent requests (for clients)
807  * or in the response (for servers) in order to compress the content stream.
808  *
809  * @since CUPS 1.7/macOS 10.9@
810  */
811 
812 const char *				/* O - Content-Coding value or
813 					       @code NULL@ for the identity
814 					       coding. */
httpGetContentEncoding(http_t * http)815 httpGetContentEncoding(http_t *http)	/* I - HTTP connection */
816 {
817 #ifdef HAVE_LIBZ
818   if (http && http->accept_encoding)
819   {
820     int		i;			/* Looping var */
821     char	temp[HTTP_MAX_VALUE],	/* Copy of Accepts-Encoding value */
822 		*start,			/* Start of coding value */
823 		*end;			/* End of coding value */
824     double	qvalue;			/* "qvalue" for coding */
825     struct lconv *loc = localeconv();	/* Locale data */
826     static const char * const codings[] =
827     {					/* Supported content codings */
828       "deflate",
829       "gzip",
830       "x-deflate",
831       "x-gzip"
832     };
833 
834     strlcpy(temp, http->accept_encoding, sizeof(temp));
835 
836     for (start = temp; *start; start = end)
837     {
838      /*
839       * Find the end of the coding name...
840       */
841 
842       qvalue = 1.0;
843       end    = start;
844       while (*end && *end != ';' && *end != ',' && !isspace(*end & 255))
845         end ++;
846 
847       if (*end == ';')
848       {
849        /*
850         * Grab the qvalue as needed...
851         */
852 
853         if (!strncmp(end, ";q=", 3))
854           qvalue = _cupsStrScand(end + 3, NULL, loc);
855 
856        /*
857         * Skip past all attributes...
858         */
859 
860         *end++ = '\0';
861         while (*end && *end != ',' && !isspace(*end & 255))
862           end ++;
863       }
864       else if (*end)
865         *end++ = '\0';
866 
867       while (*end && isspace(*end & 255))
868 	end ++;
869 
870      /*
871       * Check value if it matches something we support...
872       */
873 
874       if (qvalue <= 0.0)
875         continue;
876 
877       for (i = 0; i < (int)(sizeof(codings) / sizeof(codings[0])); i ++)
878         if (!strcmp(start, codings[i]))
879           return (codings[i]);
880     }
881   }
882 #endif /* HAVE_LIBZ */
883 
884   return (NULL);
885 }
886 
887 
888 /*
889  * 'httpGetCookie()' - Get any cookie data from the response.
890  *
891  * @since CUPS 1.1.19/macOS 10.3@
892  */
893 
894 const char *				/* O - Cookie data or @code NULL@ */
httpGetCookie(http_t * http)895 httpGetCookie(http_t *http)		/* I - HTTP connection */
896 {
897   return (http ? http->cookie : NULL);
898 }
899 
900 
901 /*
902  * 'httpGetEncryption()' - Get the current encryption mode of a connection.
903  *
904  * This function returns the encryption mode for the connection. Use the
905  * @link httpIsEncrypted@ function to determine whether a TLS session has
906  * been established.
907  *
908  * @since CUPS 2.0/OS 10.10@
909  */
910 
911 http_encryption_t			/* O - Current encryption mode */
httpGetEncryption(http_t * http)912 httpGetEncryption(http_t *http)		/* I - HTTP connection */
913 {
914   return (http ? http->encryption : HTTP_ENCRYPTION_IF_REQUESTED);
915 }
916 
917 
918 /*
919  * 'httpGetExpect()' - Get the value of the Expect header, if any.
920  *
921  * Returns @code HTTP_STATUS_NONE@ if there is no Expect header, otherwise
922  * returns the expected HTTP status code, typically @code HTTP_STATUS_CONTINUE@.
923  *
924  * @since CUPS 1.7/macOS 10.9@
925  */
926 
927 http_status_t				/* O - Expect: status, if any */
httpGetExpect(http_t * http)928 httpGetExpect(http_t *http)		/* I - HTTP connection */
929 {
930   if (!http)
931     return (HTTP_STATUS_ERROR);
932   else
933     return (http->expect);
934 }
935 
936 
937 /*
938  * 'httpGetFd()' - Get the file descriptor associated with a connection.
939  *
940  * @since CUPS 1.2/macOS 10.5@
941  */
942 
943 int					/* O - File descriptor or -1 if none */
httpGetFd(http_t * http)944 httpGetFd(http_t *http)			/* I - HTTP connection */
945 {
946   return (http ? http->fd : -1);
947 }
948 
949 
950 /*
951  * 'httpGetField()' - Get a field value from a request/response.
952  */
953 
954 const char *				/* O - Field value */
httpGetField(http_t * http,http_field_t field)955 httpGetField(http_t       *http,	/* I - HTTP connection */
956              http_field_t field)	/* I - Field to get */
957 {
958   if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
959     return (NULL);
960 
961   switch (field)
962   {
963     case HTTP_FIELD_ACCEPT_ENCODING :
964         return (http->accept_encoding);
965 
966     case HTTP_FIELD_ALLOW :
967         return (http->allow);
968 
969     case HTTP_FIELD_SERVER :
970         return (http->server);
971 
972     case HTTP_FIELD_AUTHORIZATION :
973         if (http->field_authorization)
974 	{
975 	 /*
976 	  * Special case for WWW-Authenticate: as its contents can be
977 	  * longer than HTTP_MAX_VALUE...
978 	  */
979 
980 	  return (http->field_authorization);
981 	}
982 
983     default :
984         return (http->fields[field]);
985   }
986 }
987 
988 
989 /*
990  * 'httpGetKeepAlive()' - Get the current Keep-Alive state of the connection.
991  *
992  * @since CUPS 2.0/OS 10.10@
993  */
994 
995 http_keepalive_t			/* O - Keep-Alive state */
httpGetKeepAlive(http_t * http)996 httpGetKeepAlive(http_t *http)		/* I - HTTP connection */
997 {
998   return (http ? http->keep_alive : HTTP_KEEPALIVE_OFF);
999 }
1000 
1001 
1002 /*
1003  * 'httpGetLength()' - Get the amount of data remaining from the
1004  *                     content-length or transfer-encoding fields.
1005  *
1006  * This function is deprecated and will not return lengths larger than
1007  * 2^31 - 1; use httpGetLength2() instead.
1008  *
1009  * @deprecated@ @exclude all@
1010  */
1011 
1012 int					/* O - Content length */
httpGetLength(http_t * http)1013 httpGetLength(http_t *http)		/* I - HTTP connection */
1014 {
1015  /*
1016   * Get the read content length and return the 32-bit value.
1017   */
1018 
1019   if (http)
1020   {
1021     httpGetLength2(http);
1022 
1023     return (http->_data_remaining);
1024   }
1025   else
1026     return (-1);
1027 }
1028 
1029 
1030 /*
1031  * 'httpGetLength2()' - Get the amount of data remaining from the
1032  *                      content-length or transfer-encoding fields.
1033  *
1034  * This function returns the complete content length, even for
1035  * content larger than 2^31 - 1.
1036  *
1037  * @since CUPS 1.2/macOS 10.5@
1038  */
1039 
1040 off_t					/* O - Content length */
httpGetLength2(http_t * http)1041 httpGetLength2(http_t *http)		/* I - HTTP connection */
1042 {
1043   off_t			remaining;	/* Remaining length */
1044 
1045 
1046   DEBUG_printf(("2httpGetLength2(http=%p), state=%s", (void *)http, httpStateString(http->state)));
1047 
1048   if (!http)
1049     return (-1);
1050 
1051   if (!_cups_strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked"))
1052   {
1053     DEBUG_puts("4httpGetLength2: chunked request!");
1054     remaining = 0;
1055   }
1056   else
1057   {
1058    /*
1059     * The following is a hack for HTTP servers that don't send a
1060     * Content-Length or Transfer-Encoding field...
1061     *
1062     * If there is no Content-Length then the connection must close
1063     * after the transfer is complete...
1064     */
1065 
1066     if (!http->fields[HTTP_FIELD_CONTENT_LENGTH][0])
1067     {
1068      /*
1069       * Default content length is 0 for errors and certain types of operations,
1070       * and 2^31-1 for other successful requests...
1071       */
1072 
1073       if (http->status >= HTTP_STATUS_MULTIPLE_CHOICES ||
1074           http->state == HTTP_STATE_OPTIONS ||
1075           (http->state == HTTP_STATE_GET && http->mode == _HTTP_MODE_SERVER) ||
1076           http->state == HTTP_STATE_HEAD ||
1077           (http->state == HTTP_STATE_PUT && http->mode == _HTTP_MODE_CLIENT) ||
1078           http->state == HTTP_STATE_DELETE ||
1079           http->state == HTTP_STATE_TRACE ||
1080           http->state == HTTP_STATE_CONNECT)
1081         remaining = 0;
1082       else
1083         remaining = 2147483647;
1084     }
1085     else if ((remaining = strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH],
1086 			          NULL, 10)) < 0)
1087       remaining = -1;
1088 
1089     DEBUG_printf(("4httpGetLength2: content_length=" CUPS_LLFMT,
1090                   CUPS_LLCAST remaining));
1091   }
1092 
1093   return (remaining);
1094 }
1095 
1096 
1097 /*
1098  * 'httpGetPending()' - Get the number of bytes that are buffered for writing.
1099  *
1100  * @since CUPS 2.0/OS 10.10@
1101  */
1102 
1103 size_t					/* O - Number of bytes buffered */
httpGetPending(http_t * http)1104 httpGetPending(http_t *http)		/* I - HTTP connection */
1105 {
1106   return (http ? (size_t)http->wused : 0);
1107 }
1108 
1109 
1110 /*
1111  * 'httpGetReady()' - Get the number of bytes that can be read without blocking.
1112  *
1113  * @since CUPS 2.0/OS 10.10@
1114  */
1115 
1116 size_t					/* O - Number of bytes available */
httpGetReady(http_t * http)1117 httpGetReady(http_t *http)		/* I - HTTP connection */
1118 {
1119   if (!http)
1120     return (0);
1121   else if (http->used > 0)
1122     return ((size_t)http->used);
1123 #ifdef HAVE_SSL
1124   else if (http->tls)
1125     return (_httpTLSPending(http));
1126 #endif /* HAVE_SSL */
1127 
1128   return (0);
1129 }
1130 
1131 
1132 /*
1133  * 'httpGetRemaining()' - Get the number of remaining bytes in the message
1134  *                        body or current chunk.
1135  *
1136  * The @link httpIsChunked@ function can be used to determine whether the
1137  * message body is chunked or fixed-length.
1138  *
1139  * @since CUPS 2.0/OS 10.10@
1140  */
1141 
1142 size_t					/* O - Remaining bytes */
httpGetRemaining(http_t * http)1143 httpGetRemaining(http_t *http)		/* I - HTTP connection */
1144 {
1145   return (http ? (size_t)http->data_remaining : 0);
1146 }
1147 
1148 
1149 /*
1150  * 'httpGets()' - Get a line of text from a HTTP connection.
1151  */
1152 
1153 char *					/* O - Line or @code NULL@ */
httpGets(char * line,int length,http_t * http)1154 httpGets(char   *line,			/* I - Line to read into */
1155          int    length,			/* I - Max length of buffer */
1156 	 http_t *http)			/* I - HTTP connection */
1157 {
1158   char		*lineptr,		/* Pointer into line */
1159 		*lineend,		/* End of line */
1160 		*bufptr,		/* Pointer into input buffer */
1161 	        *bufend;		/* Pointer to end of buffer */
1162   ssize_t	bytes;			/* Number of bytes read */
1163   int		eol;			/* End-of-line? */
1164 
1165 
1166   DEBUG_printf(("2httpGets(line=%p, length=%d, http=%p)", (void *)line, length, (void *)http));
1167 
1168   if (!http || !line || length <= 1)
1169     return (NULL);
1170 
1171  /*
1172   * Read a line from the buffer...
1173   */
1174 
1175   http->error = 0;
1176   lineptr     = line;
1177   lineend     = line + length - 1;
1178   eol         = 0;
1179 
1180   while (lineptr < lineend)
1181   {
1182    /*
1183     * Pre-load the buffer as needed...
1184     */
1185 
1186 #ifdef WIN32
1187     WSASetLastError(0);
1188 #else
1189     errno = 0;
1190 #endif /* WIN32 */
1191 
1192     while (http->used == 0)
1193     {
1194      /*
1195       * No newline; see if there is more data to be read...
1196       */
1197 
1198       while (!_httpWait(http, http->wait_value, 1))
1199       {
1200 	if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
1201 	  continue;
1202 
1203         DEBUG_puts("3httpGets: Timed out!");
1204 #ifdef WIN32
1205         http->error = WSAETIMEDOUT;
1206 #else
1207         http->error = ETIMEDOUT;
1208 #endif /* WIN32 */
1209         return (NULL);
1210       }
1211 
1212       bytes = http_read(http, http->buffer + http->used, (size_t)(HTTP_MAX_BUFFER - http->used));
1213 
1214       DEBUG_printf(("4httpGets: read " CUPS_LLFMT " bytes.", CUPS_LLCAST bytes));
1215 
1216       if (bytes < 0)
1217       {
1218        /*
1219 	* Nope, can't get a line this time...
1220 	*/
1221 
1222 #ifdef WIN32
1223         DEBUG_printf(("3httpGets: recv() error %d!", WSAGetLastError()));
1224 
1225         if (WSAGetLastError() == WSAEINTR)
1226 	  continue;
1227 	else if (WSAGetLastError() == WSAEWOULDBLOCK)
1228 	{
1229 	  if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
1230 	    continue;
1231 
1232 	  http->error = WSAGetLastError();
1233 	}
1234 	else if (WSAGetLastError() != http->error)
1235 	{
1236 	  http->error = WSAGetLastError();
1237 	  continue;
1238 	}
1239 
1240 #else
1241         DEBUG_printf(("3httpGets: recv() error %d!", errno));
1242 
1243         if (errno == EINTR)
1244 	  continue;
1245 	else if (errno == EWOULDBLOCK || errno == EAGAIN)
1246 	{
1247 	  if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
1248 	    continue;
1249 	  else if (!http->timeout_cb && errno == EAGAIN)
1250 	    continue;
1251 
1252 	  http->error = errno;
1253 	}
1254 	else if (errno != http->error)
1255 	{
1256 	  http->error = errno;
1257 	  continue;
1258 	}
1259 #endif /* WIN32 */
1260 
1261         return (NULL);
1262       }
1263       else if (bytes == 0)
1264       {
1265 	http->error = EPIPE;
1266 
1267         return (NULL);
1268       }
1269 
1270      /*
1271       * Yup, update the amount used...
1272       */
1273 
1274       http->used += (int)bytes;
1275     }
1276 
1277    /*
1278     * Now copy as much of the current line as possible...
1279     */
1280 
1281     for (bufptr = http->buffer, bufend = http->buffer + http->used;
1282          lineptr < lineend && bufptr < bufend;)
1283     {
1284       if (*bufptr == 0x0a)
1285       {
1286         eol = 1;
1287 	bufptr ++;
1288 	break;
1289       }
1290       else if (*bufptr == 0x0d)
1291 	bufptr ++;
1292       else
1293 	*lineptr++ = *bufptr++;
1294     }
1295 
1296     http->used -= (int)(bufptr - http->buffer);
1297     if (http->used > 0)
1298       memmove(http->buffer, bufptr, (size_t)http->used);
1299 
1300     if (eol)
1301     {
1302      /*
1303       * End of line...
1304       */
1305 
1306       http->activity = time(NULL);
1307 
1308       *lineptr = '\0';
1309 
1310       DEBUG_printf(("3httpGets: Returning \"%s\"", line));
1311 
1312       return (line);
1313     }
1314   }
1315 
1316   DEBUG_puts("3httpGets: No new line available!");
1317 
1318   return (NULL);
1319 }
1320 
1321 
1322 /*
1323  * 'httpGetState()' - Get the current state of the HTTP request.
1324  */
1325 
1326 http_state_t				/* O - HTTP state */
httpGetState(http_t * http)1327 httpGetState(http_t *http)		/* I - HTTP connection */
1328 {
1329   return (http ? http->state : HTTP_STATE_ERROR);
1330 }
1331 
1332 
1333 /*
1334  * 'httpGetStatus()' - Get the status of the last HTTP request.
1335  *
1336  * @since CUPS 1.2/macOS 10.5@
1337  */
1338 
1339 http_status_t				/* O - HTTP status */
httpGetStatus(http_t * http)1340 httpGetStatus(http_t *http)		/* I - HTTP connection */
1341 {
1342   return (http ? http->status : HTTP_STATUS_ERROR);
1343 }
1344 
1345 
1346 /*
1347  * 'httpGetSubField()' - Get a sub-field value.
1348  *
1349  * @deprecated@ @exclude all@
1350  */
1351 
1352 char *					/* O - Value or @code NULL@ */
httpGetSubField(http_t * http,http_field_t field,const char * name,char * value)1353 httpGetSubField(http_t       *http,	/* I - HTTP connection */
1354                 http_field_t field,	/* I - Field index */
1355                 const char   *name,	/* I - Name of sub-field */
1356 		char         *value)	/* O - Value string */
1357 {
1358   return (httpGetSubField2(http, field, name, value, HTTP_MAX_VALUE));
1359 }
1360 
1361 
1362 /*
1363  * 'httpGetSubField2()' - Get a sub-field value.
1364  *
1365  * @since CUPS 1.2/macOS 10.5@
1366  */
1367 
1368 char *					/* O - Value or @code NULL@ */
httpGetSubField2(http_t * http,http_field_t field,const char * name,char * value,int valuelen)1369 httpGetSubField2(http_t       *http,	/* I - HTTP connection */
1370                  http_field_t field,	/* I - Field index */
1371                  const char   *name,	/* I - Name of sub-field */
1372 		 char         *value,	/* O - Value string */
1373 		 int          valuelen)	/* I - Size of value buffer */
1374 {
1375   const char	*fptr;			/* Pointer into field */
1376   char		temp[HTTP_MAX_VALUE],	/* Temporary buffer for name */
1377 		*ptr,			/* Pointer into string buffer */
1378 		*end;			/* End of value buffer */
1379 
1380   DEBUG_printf(("2httpGetSubField2(http=%p, field=%d, name=\"%s\", value=%p, valuelen=%d)", (void *)http, field, name, (void *)value, valuelen));
1381 
1382   if (!http || !name || !value || valuelen < 2 ||
1383       field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
1384     return (NULL);
1385 
1386   end = value + valuelen - 1;
1387 
1388   for (fptr = http->fields[field]; *fptr;)
1389   {
1390    /*
1391     * Skip leading whitespace...
1392     */
1393 
1394     while (_cups_isspace(*fptr))
1395       fptr ++;
1396 
1397     if (*fptr == ',')
1398     {
1399       fptr ++;
1400       continue;
1401     }
1402 
1403    /*
1404     * Get the sub-field name...
1405     */
1406 
1407     for (ptr = temp;
1408          *fptr && *fptr != '=' && !_cups_isspace(*fptr) &&
1409 	     ptr < (temp + sizeof(temp) - 1);
1410          *ptr++ = *fptr++);
1411 
1412     *ptr = '\0';
1413 
1414     DEBUG_printf(("4httpGetSubField2: name=\"%s\"", temp));
1415 
1416    /*
1417     * Skip trailing chars up to the '='...
1418     */
1419 
1420     while (_cups_isspace(*fptr))
1421       fptr ++;
1422 
1423     if (!*fptr)
1424       break;
1425 
1426     if (*fptr != '=')
1427       continue;
1428 
1429    /*
1430     * Skip = and leading whitespace...
1431     */
1432 
1433     fptr ++;
1434 
1435     while (_cups_isspace(*fptr))
1436       fptr ++;
1437 
1438     if (*fptr == '\"')
1439     {
1440      /*
1441       * Read quoted string...
1442       */
1443 
1444       for (ptr = value, fptr ++;
1445            *fptr && *fptr != '\"' && ptr < end;
1446 	   *ptr++ = *fptr++);
1447 
1448       *ptr = '\0';
1449 
1450       while (*fptr && *fptr != '\"')
1451         fptr ++;
1452 
1453       if (*fptr)
1454         fptr ++;
1455     }
1456     else
1457     {
1458      /*
1459       * Read unquoted string...
1460       */
1461 
1462       for (ptr = value;
1463            *fptr && !_cups_isspace(*fptr) && *fptr != ',' && ptr < end;
1464 	   *ptr++ = *fptr++);
1465 
1466       *ptr = '\0';
1467 
1468       while (*fptr && !_cups_isspace(*fptr) && *fptr != ',')
1469         fptr ++;
1470     }
1471 
1472     DEBUG_printf(("4httpGetSubField2: value=\"%s\"", value));
1473 
1474    /*
1475     * See if this is the one...
1476     */
1477 
1478     if (!strcmp(name, temp))
1479     {
1480       DEBUG_printf(("3httpGetSubField2: Returning \"%s\"", value));
1481       return (value);
1482     }
1483   }
1484 
1485   value[0] = '\0';
1486 
1487   DEBUG_puts("3httpGetSubField2: Returning NULL");
1488 
1489   return (NULL);
1490 }
1491 
1492 
1493 /*
1494  * 'httpGetVersion()' - Get the HTTP version at the other end.
1495  */
1496 
1497 http_version_t				/* O - Version number */
httpGetVersion(http_t * http)1498 httpGetVersion(http_t *http)		/* I - HTTP connection */
1499 {
1500   return (http ? http->version : HTTP_VERSION_1_0);
1501 }
1502 
1503 
1504 /*
1505  * 'httpHead()' - Send a HEAD request to the server.
1506  */
1507 
1508 int					/* O - Status of call (0 = success) */
httpHead(http_t * http,const char * uri)1509 httpHead(http_t     *http,		/* I - HTTP connection */
1510          const char *uri)		/* I - URI for head */
1511 {
1512   DEBUG_printf(("httpHead(http=%p, uri=\"%s\")", (void *)http, uri));
1513   return (http_send(http, HTTP_STATE_HEAD, uri));
1514 }
1515 
1516 
1517 /*
1518  * 'httpInitialize()' - Initialize the HTTP interface library and set the
1519  *                      default HTTP proxy (if any).
1520  */
1521 
1522 void
httpInitialize(void)1523 httpInitialize(void)
1524 {
1525   static int	initialized = 0;	/* Have we been called before? */
1526 #ifdef WIN32
1527   WSADATA	winsockdata;		/* WinSock data */
1528 #endif /* WIN32 */
1529 
1530 
1531   _cupsGlobalLock();
1532   if (initialized)
1533   {
1534     _cupsGlobalUnlock();
1535     return;
1536   }
1537 
1538 #ifdef WIN32
1539   WSAStartup(MAKEWORD(2,2), &winsockdata);
1540 
1541 #elif !defined(SO_NOSIGPIPE)
1542  /*
1543   * Ignore SIGPIPE signals...
1544   */
1545 
1546 #  ifdef HAVE_SIGSET
1547   sigset(SIGPIPE, SIG_IGN);
1548 
1549 #  elif defined(HAVE_SIGACTION)
1550   struct sigaction	action;		/* POSIX sigaction data */
1551 
1552 
1553   memset(&action, 0, sizeof(action));
1554   action.sa_handler = SIG_IGN;
1555   sigaction(SIGPIPE, &action, NULL);
1556 
1557 #  else
1558   signal(SIGPIPE, SIG_IGN);
1559 #  endif /* !SO_NOSIGPIPE */
1560 #endif /* WIN32 */
1561 
1562 #  ifdef HAVE_SSL
1563   _httpTLSInitialize();
1564 #  endif /* HAVE_SSL */
1565 
1566   initialized = 1;
1567   _cupsGlobalUnlock();
1568 }
1569 
1570 
1571 /*
1572  * 'httpIsChunked()' - Report whether a message body is chunked.
1573  *
1574  * This function returns non-zero if the message body is composed of
1575  * variable-length chunks.
1576  *
1577  * @since CUPS 2.0/OS 10.10@
1578  */
1579 
1580 int					/* O - 1 if chunked, 0 if not */
httpIsChunked(http_t * http)1581 httpIsChunked(http_t *http)		/* I - HTTP connection */
1582 {
1583   return (http ? http->data_encoding == HTTP_ENCODING_CHUNKED : 0);
1584 }
1585 
1586 
1587 /*
1588  * 'httpIsEncrypted()' - Report whether a connection is encrypted.
1589  *
1590  * This function returns non-zero if the connection is currently encrypted.
1591  *
1592  * @since CUPS 2.0/OS 10.10@
1593  */
1594 
1595 int					/* O - 1 if encrypted, 0 if not */
httpIsEncrypted(http_t * http)1596 httpIsEncrypted(http_t *http)		/* I - HTTP connection */
1597 {
1598   return (http ? http->tls != NULL : 0);
1599 }
1600 
1601 
1602 /*
1603  * 'httpOptions()' - Send an OPTIONS request to the server.
1604  */
1605 
1606 int					/* O - Status of call (0 = success) */
httpOptions(http_t * http,const char * uri)1607 httpOptions(http_t     *http,		/* I - HTTP connection */
1608             const char *uri)		/* I - URI for options */
1609 {
1610   return (http_send(http, HTTP_STATE_OPTIONS, uri));
1611 }
1612 
1613 
1614 /*
1615  * 'httpPeek()' - Peek at data from a HTTP connection.
1616  *
1617  * This function copies available data from the given HTTP connection, reading
1618  * a buffer as needed.  The data is still available for reading using
1619  * @link httpRead2@.
1620  *
1621  * For non-blocking connections the usual timeouts apply.
1622  *
1623  * @since CUPS 1.7/macOS 10.9@
1624  */
1625 
1626 ssize_t					/* O - Number of bytes copied */
httpPeek(http_t * http,char * buffer,size_t length)1627 httpPeek(http_t *http,			/* I - HTTP connection */
1628          char   *buffer,		/* I - Buffer for data */
1629 	 size_t length)			/* I - Maximum number of bytes */
1630 {
1631   ssize_t	bytes;			/* Bytes read */
1632   char		len[32];		/* Length string */
1633 
1634 
1635   DEBUG_printf(("httpPeek(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
1636 
1637   if (http == NULL || buffer == NULL)
1638     return (-1);
1639 
1640   http->activity = time(NULL);
1641   http->error    = 0;
1642 
1643   if (length <= 0)
1644     return (0);
1645 
1646   if (http->data_encoding == HTTP_ENCODING_CHUNKED &&
1647       http->data_remaining <= 0)
1648   {
1649     DEBUG_puts("2httpPeek: Getting chunk length...");
1650 
1651     if (httpGets(len, sizeof(len), http) == NULL)
1652     {
1653       DEBUG_puts("1httpPeek: Could not get length!");
1654       return (0);
1655     }
1656 
1657     if (!len[0])
1658     {
1659       DEBUG_puts("1httpPeek: Blank chunk length, trying again...");
1660       if (!httpGets(len, sizeof(len), http))
1661       {
1662 	DEBUG_puts("1httpPeek: Could not get chunk length.");
1663 	return (0);
1664       }
1665     }
1666 
1667     http->data_remaining = strtoll(len, NULL, 16);
1668 
1669     if (http->data_remaining < 0)
1670     {
1671       DEBUG_puts("1httpPeek: Negative chunk length!");
1672       return (0);
1673     }
1674   }
1675 
1676   DEBUG_printf(("2httpPeek: data_remaining=" CUPS_LLFMT,
1677                 CUPS_LLCAST http->data_remaining));
1678 
1679   if (http->data_remaining <= 0 && http->data_encoding != HTTP_ENCODING_FIELDS)
1680   {
1681    /*
1682     * A zero-length chunk ends a transfer; unless we are reading POST
1683     * data, go idle...
1684     */
1685 
1686 #ifdef HAVE_LIBZ
1687     if (http->coding >= _HTTP_CODING_GUNZIP)
1688       http_content_coding_finish(http);
1689 #endif /* HAVE_LIBZ */
1690 
1691     if (http->data_encoding == HTTP_ENCODING_CHUNKED)
1692       httpGets(len, sizeof(len), http);
1693 
1694     if (http->state == HTTP_STATE_POST_RECV)
1695       http->state ++;
1696     else
1697       http->state = HTTP_STATE_STATUS;
1698 
1699     DEBUG_printf(("1httpPeek: 0-length chunk, set state to %s.",
1700                   httpStateString(http->state)));
1701 
1702    /*
1703     * Prevent future reads for this request...
1704     */
1705 
1706     http->data_encoding = HTTP_ENCODING_FIELDS;
1707 
1708     return (0);
1709   }
1710   else if (length > (size_t)http->data_remaining)
1711     length = (size_t)http->data_remaining;
1712 
1713 #ifdef HAVE_LIBZ
1714   if (http->used == 0 &&
1715       (http->coding == _HTTP_CODING_IDENTITY ||
1716        (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in == 0)))
1717 #else
1718   if (http->used == 0)
1719 #endif /* HAVE_LIBZ */
1720   {
1721    /*
1722     * Buffer small reads for better performance...
1723     */
1724 
1725     ssize_t	buflen;			/* Length of read for buffer */
1726 
1727     if (!http->blocking)
1728     {
1729       while (!httpWait(http, http->wait_value))
1730       {
1731 	if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
1732 	  continue;
1733 
1734 	return (0);
1735       }
1736     }
1737 
1738     if ((size_t)http->data_remaining > sizeof(http->buffer))
1739       buflen = sizeof(http->buffer);
1740     else
1741       buflen = (ssize_t)http->data_remaining;
1742 
1743     DEBUG_printf(("2httpPeek: Reading %d bytes into buffer.", (int)buflen));
1744     bytes = http_read(http, http->buffer, (size_t)buflen);
1745 
1746     DEBUG_printf(("2httpPeek: Read " CUPS_LLFMT " bytes into buffer.",
1747                   CUPS_LLCAST bytes));
1748     if (bytes > 0)
1749     {
1750 #ifdef DEBUG
1751       http_debug_hex("httpPeek", http->buffer, (int)bytes);
1752 #endif /* DEBUG */
1753 
1754       http->used = (int)bytes;
1755     }
1756   }
1757 
1758 #ifdef HAVE_LIBZ
1759   if (http->coding >= _HTTP_CODING_GUNZIP)
1760   {
1761 #  ifdef HAVE_INFLATECOPY
1762     int		zerr;			/* Decompressor error */
1763     z_stream	stream;			/* Copy of decompressor stream */
1764 
1765     if (http->used > 0 && http->stream.avail_in < HTTP_MAX_BUFFER)
1766     {
1767       size_t buflen = buflen = HTTP_MAX_BUFFER - http->stream.avail_in;
1768 					/* Number of bytes to copy */
1769 
1770       if (http->stream.avail_in > 0 &&
1771 	  http->stream.next_in > http->sbuffer)
1772         memmove(http->sbuffer, http->stream.next_in, http->stream.avail_in);
1773 
1774       http->stream.next_in = http->sbuffer;
1775 
1776       if (buflen > (size_t)http->data_remaining)
1777         buflen = (size_t)http->data_remaining;
1778 
1779       if (buflen > (size_t)http->used)
1780         buflen = (size_t)http->used;
1781 
1782       DEBUG_printf(("1httpPeek: Copying %d more bytes of data into "
1783 		    "decompression buffer.", (int)buflen));
1784 
1785       memcpy(http->sbuffer + http->stream.avail_in, http->buffer, buflen);
1786       http->stream.avail_in += buflen;
1787       http->used            -= (int)buflen;
1788       http->data_remaining  -= (off_t)buflen;
1789 
1790       if (http->used > 0)
1791         memmove(http->buffer, http->buffer + buflen, (size_t)http->used);
1792     }
1793 
1794     DEBUG_printf(("2httpPeek: length=%d, avail_in=%d", (int)length,
1795                   (int)http->stream.avail_in));
1796 
1797     if (inflateCopy(&stream, &(http->stream)) != Z_OK)
1798     {
1799       DEBUG_puts("2httpPeek: Unable to copy decompressor stream.");
1800       http->error = ENOMEM;
1801       return (-1);
1802     }
1803 
1804     stream.next_out  = (Bytef *)buffer;
1805     stream.avail_out = (uInt)length;
1806 
1807     zerr = inflate(&stream, Z_SYNC_FLUSH);
1808     inflateEnd(&stream);
1809 
1810     if (zerr < Z_OK)
1811     {
1812       DEBUG_printf(("2httpPeek: zerr=%d", zerr));
1813 #ifdef DEBUG
1814       http_debug_hex("2httpPeek", (char *)http->sbuffer, (int)http->stream.avail_in);
1815 #endif /* DEBUG */
1816 
1817       http->error = EIO;
1818       return (-1);
1819     }
1820 
1821     bytes = (ssize_t)(length - http->stream.avail_out);
1822 
1823 #  else
1824     DEBUG_puts("2httpPeek: No inflateCopy on this platform, httpPeek does not "
1825                "work with compressed streams.");
1826     return (-1);
1827 #  endif /* HAVE_INFLATECOPY */
1828   }
1829   else
1830 #endif /* HAVE_LIBZ */
1831   if (http->used > 0)
1832   {
1833     if (length > (size_t)http->used)
1834       length = (size_t)http->used;
1835 
1836     bytes = (ssize_t)length;
1837 
1838     DEBUG_printf(("2httpPeek: grabbing %d bytes from input buffer...",
1839                   (int)bytes));
1840 
1841     memcpy(buffer, http->buffer, length);
1842   }
1843   else
1844     bytes = 0;
1845 
1846   if (bytes < 0)
1847   {
1848 #ifdef WIN32
1849     if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
1850       bytes = 0;
1851     else
1852       http->error = WSAGetLastError();
1853 #else
1854     if (errno == EINTR || errno == EAGAIN)
1855       bytes = 0;
1856     else
1857       http->error = errno;
1858 #endif /* WIN32 */
1859   }
1860   else if (bytes == 0)
1861   {
1862     http->error = EPIPE;
1863     return (0);
1864   }
1865 
1866   return (bytes);
1867 }
1868 
1869 
1870 /*
1871  * 'httpPost()' - Send a POST request to the server.
1872  */
1873 
1874 int					/* O - Status of call (0 = success) */
httpPost(http_t * http,const char * uri)1875 httpPost(http_t     *http,		/* I - HTTP connection */
1876          const char *uri)		/* I - URI for post */
1877 {
1878   return (http_send(http, HTTP_STATE_POST, uri));
1879 }
1880 
1881 
1882 /*
1883  * 'httpPrintf()' - Print a formatted string to a HTTP connection.
1884  *
1885  * @private@
1886  */
1887 
1888 int					/* O - Number of bytes written */
httpPrintf(http_t * http,const char * format,...)1889 httpPrintf(http_t     *http,		/* I - HTTP connection */
1890            const char *format,		/* I - printf-style format string */
1891 	   ...)				/* I - Additional args as needed */
1892 {
1893   ssize_t	bytes;			/* Number of bytes to write */
1894   char		buf[16384];		/* Buffer for formatted string */
1895   va_list	ap;			/* Variable argument pointer */
1896 
1897 
1898   DEBUG_printf(("2httpPrintf(http=%p, format=\"%s\", ...)", (void *)http, format));
1899 
1900   va_start(ap, format);
1901   bytes = vsnprintf(buf, sizeof(buf), format, ap);
1902   va_end(ap);
1903 
1904   DEBUG_printf(("3httpPrintf: (" CUPS_LLFMT " bytes) %s", CUPS_LLCAST bytes, buf));
1905 
1906   if (http->data_encoding == HTTP_ENCODING_FIELDS)
1907     return ((int)httpWrite2(http, buf, (size_t)bytes));
1908   else
1909   {
1910     if (http->wused)
1911     {
1912       DEBUG_puts("4httpPrintf: flushing existing data...");
1913 
1914       if (httpFlushWrite(http) < 0)
1915 	return (-1);
1916     }
1917 
1918     return ((int)http_write(http, buf, (size_t)bytes));
1919   }
1920 }
1921 
1922 
1923 /*
1924  * 'httpPut()' - Send a PUT request to the server.
1925  */
1926 
1927 int					/* O - Status of call (0 = success) */
httpPut(http_t * http,const char * uri)1928 httpPut(http_t     *http,		/* I - HTTP connection */
1929         const char *uri)		/* I - URI to put */
1930 {
1931   DEBUG_printf(("httpPut(http=%p, uri=\"%s\")", (void *)http, uri));
1932   return (http_send(http, HTTP_STATE_PUT, uri));
1933 }
1934 
1935 
1936 /*
1937  * 'httpRead()' - Read data from a HTTP connection.
1938  *
1939  * This function is deprecated. Use the httpRead2() function which can
1940  * read more than 2GB of data.
1941  *
1942  * @deprecated@ @exclude all@
1943  */
1944 
1945 int					/* O - Number of bytes read */
httpRead(http_t * http,char * buffer,int length)1946 httpRead(http_t *http,			/* I - HTTP connection */
1947          char   *buffer,		/* I - Buffer for data */
1948 	 int    length)			/* I - Maximum number of bytes */
1949 {
1950   return ((int)httpRead2(http, buffer, (size_t)length));
1951 }
1952 
1953 
1954 /*
1955  * 'httpRead2()' - Read data from a HTTP connection.
1956  *
1957  * @since CUPS 1.2/macOS 10.5@
1958  */
1959 
1960 ssize_t					/* O - Number of bytes read */
httpRead2(http_t * http,char * buffer,size_t length)1961 httpRead2(http_t *http,			/* I - HTTP connection */
1962           char   *buffer,		/* I - Buffer for data */
1963 	  size_t length)		/* I - Maximum number of bytes */
1964 {
1965   ssize_t	bytes;			/* Bytes read */
1966 
1967 
1968 #ifdef HAVE_LIBZ
1969   DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" CUPS_LLFMT ") coding=%d data_encoding=%d data_remaining=" CUPS_LLFMT, (void *)http, (void *)buffer, CUPS_LLCAST length, http->coding, http->data_encoding, CUPS_LLCAST http->data_remaining));
1970 #else
1971   DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" CUPS_LLFMT ") data_encoding=%d data_remaining=" CUPS_LLFMT, (void *)http, (void *)buffer, CUPS_LLCAST length, http->data_encoding, CUPS_LLCAST http->data_remaining));
1972 #endif /* HAVE_LIBZ */
1973 
1974   if (http == NULL || buffer == NULL)
1975     return (-1);
1976 
1977   http->activity = time(NULL);
1978   http->error    = 0;
1979 
1980   if (length <= 0)
1981     return (0);
1982 
1983 #ifdef HAVE_LIBZ
1984   if (http->coding >= _HTTP_CODING_GUNZIP)
1985   {
1986     do
1987     {
1988       if (http->stream.avail_in > 0)
1989       {
1990 	int	zerr;			/* Decompressor error */
1991 
1992 	DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d",
1993 	              (int)http->stream.avail_in, (int)length));
1994 
1995 	http->stream.next_out  = (Bytef *)buffer;
1996 	http->stream.avail_out = (uInt)length;
1997 
1998 	if ((zerr = inflate(&(http->stream), Z_SYNC_FLUSH)) < Z_OK)
1999 	{
2000 	  DEBUG_printf(("2httpRead2: zerr=%d", zerr));
2001 #ifdef DEBUG
2002           http_debug_hex("2httpRead2", (char *)http->sbuffer, (int)http->stream.avail_in);
2003 #endif /* DEBUG */
2004 
2005 	  http->error = EIO;
2006 	  return (-1);
2007 	}
2008 
2009 	bytes = (ssize_t)(length - http->stream.avail_out);
2010 
2011 	DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d, bytes=%d",
2012 		      http->stream.avail_in, http->stream.avail_out,
2013 		      (int)bytes));
2014       }
2015       else
2016         bytes = 0;
2017 
2018       if (bytes == 0)
2019       {
2020         ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)http->stream.avail_in;
2021 					/* Additional bytes for buffer */
2022 
2023         if (buflen > 0)
2024         {
2025           if (http->stream.avail_in > 0 &&
2026               http->stream.next_in > http->sbuffer)
2027             memmove(http->sbuffer, http->stream.next_in, http->stream.avail_in);
2028 
2029 	  http->stream.next_in = http->sbuffer;
2030 
2031           DEBUG_printf(("1httpRead2: Reading up to %d more bytes of data into "
2032                         "decompression buffer.", (int)buflen));
2033 
2034           if (http->data_remaining > 0)
2035           {
2036 	    if (buflen > http->data_remaining)
2037 	      buflen = (ssize_t)http->data_remaining;
2038 
2039 	    bytes = http_read_buffered(http, (char *)http->sbuffer + http->stream.avail_in, (size_t)buflen);
2040           }
2041           else if (http->data_encoding == HTTP_ENCODING_CHUNKED)
2042             bytes = http_read_chunk(http, (char *)http->sbuffer + http->stream.avail_in, (size_t)buflen);
2043           else
2044             bytes = 0;
2045 
2046           if (bytes < 0)
2047             return (bytes);
2048           else if (bytes == 0)
2049             break;
2050 
2051           DEBUG_printf(("1httpRead2: Adding " CUPS_LLFMT " bytes to "
2052                         "decompression buffer.", CUPS_LLCAST bytes));
2053 
2054           http->data_remaining  -= bytes;
2055           http->stream.avail_in += (uInt)bytes;
2056 
2057 	  if (http->data_remaining <= 0 &&
2058 	      http->data_encoding == HTTP_ENCODING_CHUNKED)
2059 	  {
2060 	   /*
2061 	    * Read the trailing blank line now...
2062 	    */
2063 
2064 	    char	len[32];		/* Length string */
2065 
2066 	    httpGets(len, sizeof(len), http);
2067 	  }
2068 
2069           bytes = 0;
2070         }
2071         else
2072           return (0);
2073       }
2074     }
2075     while (bytes == 0);
2076   }
2077   else
2078 #endif /* HAVE_LIBZ */
2079   if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
2080   {
2081     if ((bytes = http_read_chunk(http, buffer, length)) > 0)
2082     {
2083       http->data_remaining -= bytes;
2084 
2085       if (http->data_remaining <= 0)
2086       {
2087        /*
2088         * Read the trailing blank line now...
2089         */
2090 
2091         char	len[32];		/* Length string */
2092 
2093         httpGets(len, sizeof(len), http);
2094       }
2095     }
2096   }
2097   else if (http->data_remaining <= 0)
2098   {
2099    /*
2100     * No more data to read...
2101     */
2102 
2103     return (0);
2104   }
2105   else
2106   {
2107     DEBUG_printf(("1httpRead2: Reading up to %d bytes into buffer.",
2108                   (int)length));
2109 
2110     if (length > (size_t)http->data_remaining)
2111       length = (size_t)http->data_remaining;
2112 
2113     if ((bytes = http_read_buffered(http, buffer, length)) > 0)
2114     {
2115       http->data_remaining -= bytes;
2116 
2117       if (http->data_remaining <= 0 &&
2118           http->data_encoding == HTTP_ENCODING_CHUNKED)
2119       {
2120        /*
2121         * Read the trailing blank line now...
2122         */
2123 
2124         char	len[32];		/* Length string */
2125 
2126         httpGets(len, sizeof(len), http);
2127       }
2128     }
2129   }
2130 
2131   if (
2132 #ifdef HAVE_LIBZ
2133       (http->coding == _HTTP_CODING_IDENTITY ||
2134        (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in == 0)) &&
2135 #endif /* HAVE_LIBZ */
2136       ((http->data_remaining <= 0 &&
2137         http->data_encoding == HTTP_ENCODING_LENGTH) ||
2138        (http->data_encoding == HTTP_ENCODING_CHUNKED && bytes == 0)))
2139   {
2140 #ifdef HAVE_LIBZ
2141     if (http->coding >= _HTTP_CODING_GUNZIP)
2142       http_content_coding_finish(http);
2143 #endif /* HAVE_LIBZ */
2144 
2145     if (http->state == HTTP_STATE_POST_RECV)
2146       http->state ++;
2147     else if (http->state == HTTP_STATE_GET_SEND ||
2148              http->state == HTTP_STATE_POST_SEND)
2149       http->state = HTTP_STATE_WAITING;
2150     else
2151       http->state = HTTP_STATE_STATUS;
2152 
2153     DEBUG_printf(("1httpRead2: End of content, set state to %s.",
2154 		  httpStateString(http->state)));
2155   }
2156 
2157   return (bytes);
2158 }
2159 
2160 
2161 /*
2162  * 'httpReadRequest()' - Read a HTTP request from a connection.
2163  *
2164  * @since CUPS 1.7/macOS 10.9@
2165  */
2166 
2167 http_state_t				/* O - New state of connection */
httpReadRequest(http_t * http,char * uri,size_t urilen)2168 httpReadRequest(http_t *http,		/* I - HTTP connection */
2169                 char   *uri,		/* I - URI buffer */
2170 		size_t urilen)		/* I - Size of URI buffer */
2171 {
2172   char	line[4096],			/* HTTP request line */
2173 	*req_method,			/* HTTP request method */
2174 	*req_uri,			/* HTTP request URI */
2175 	*req_version;			/* HTTP request version number string */
2176 
2177 
2178  /*
2179   * Range check input...
2180   */
2181 
2182   DEBUG_printf(("httpReadRequest(http=%p, uri=%p, urilen=" CUPS_LLFMT ")", (void *)http, (void *)uri, CUPS_LLCAST urilen));
2183 
2184   if (uri)
2185     *uri = '\0';
2186 
2187   if (!http || !uri || urilen < 1)
2188   {
2189     DEBUG_puts("1httpReadRequest: Bad arguments, returning HTTP_STATE_ERROR.");
2190     return (HTTP_STATE_ERROR);
2191   }
2192   else if (http->state != HTTP_STATE_WAITING)
2193   {
2194     DEBUG_printf(("1httpReadRequest: Bad state %s, returning HTTP_STATE_ERROR.",
2195                   httpStateString(http->state)));
2196     return (HTTP_STATE_ERROR);
2197   }
2198 
2199  /*
2200   * Reset state...
2201   */
2202 
2203   httpClearFields(http);
2204 
2205   http->activity       = time(NULL);
2206   http->data_encoding  = HTTP_ENCODING_FIELDS;
2207   http->data_remaining = 0;
2208   http->keep_alive     = HTTP_KEEPALIVE_OFF;
2209   http->status         = HTTP_STATUS_OK;
2210   http->version        = HTTP_VERSION_1_1;
2211 
2212  /*
2213   * Read a line from the socket...
2214   */
2215 
2216   if (!httpGets(line, sizeof(line), http))
2217   {
2218     DEBUG_puts("1httpReadRequest: Unable to read, returning HTTP_STATE_ERROR");
2219     return (HTTP_STATE_ERROR);
2220   }
2221 
2222   if (!line[0])
2223   {
2224     DEBUG_puts("1httpReadRequest: Blank line, returning HTTP_STATE_WAITING");
2225     return (HTTP_STATE_WAITING);
2226   }
2227 
2228   DEBUG_printf(("1httpReadRequest: %s", line));
2229 
2230  /*
2231   * Parse it...
2232   */
2233 
2234   req_method = line;
2235   req_uri    = line;
2236 
2237   while (*req_uri && !isspace(*req_uri & 255))
2238     req_uri ++;
2239 
2240   if (!*req_uri)
2241   {
2242     DEBUG_puts("1httpReadRequest: No request URI.");
2243     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request URI."), 1);
2244     return (HTTP_STATE_ERROR);
2245   }
2246 
2247   *req_uri++ = '\0';
2248 
2249   while (*req_uri && isspace(*req_uri & 255))
2250     req_uri ++;
2251 
2252   req_version = req_uri;
2253 
2254   while (*req_version && !isspace(*req_version & 255))
2255     req_version ++;
2256 
2257   if (!*req_version)
2258   {
2259     DEBUG_puts("1httpReadRequest: No request protocol version.");
2260     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request protocol version."), 1);
2261     return (HTTP_STATE_ERROR);
2262   }
2263 
2264   *req_version++ = '\0';
2265 
2266   while (*req_version && isspace(*req_version & 255))
2267     req_version ++;
2268 
2269  /*
2270   * Validate...
2271   */
2272 
2273   if (!strcmp(req_method, "OPTIONS"))
2274     http->state = HTTP_STATE_OPTIONS;
2275   else if (!strcmp(req_method, "GET"))
2276     http->state = HTTP_STATE_GET;
2277   else if (!strcmp(req_method, "HEAD"))
2278     http->state = HTTP_STATE_HEAD;
2279   else if (!strcmp(req_method, "POST"))
2280     http->state = HTTP_STATE_POST;
2281   else if (!strcmp(req_method, "PUT"))
2282     http->state = HTTP_STATE_PUT;
2283   else if (!strcmp(req_method, "DELETE"))
2284     http->state = HTTP_STATE_DELETE;
2285   else if (!strcmp(req_method, "TRACE"))
2286     http->state = HTTP_STATE_TRACE;
2287   else if (!strcmp(req_method, "CONNECT"))
2288     http->state = HTTP_STATE_CONNECT;
2289   else
2290   {
2291     DEBUG_printf(("1httpReadRequest: Unknown method \"%s\".", req_method));
2292     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request method."), 1);
2293     return (HTTP_STATE_UNKNOWN_METHOD);
2294   }
2295 
2296   DEBUG_printf(("1httpReadRequest: Set state to %s.",
2297                 httpStateString(http->state)));
2298 
2299   if (!strcmp(req_version, "HTTP/1.0"))
2300   {
2301     http->version    = HTTP_VERSION_1_0;
2302     http->keep_alive = HTTP_KEEPALIVE_OFF;
2303   }
2304   else if (!strcmp(req_version, "HTTP/1.1"))
2305   {
2306     http->version    = HTTP_VERSION_1_1;
2307     http->keep_alive = HTTP_KEEPALIVE_ON;
2308   }
2309   else
2310   {
2311     DEBUG_printf(("1httpReadRequest: Unknown version \"%s\".", req_version));
2312     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request version."), 1);
2313     return (HTTP_STATE_UNKNOWN_VERSION);
2314   }
2315 
2316   DEBUG_printf(("1httpReadRequest: URI is \"%s\".", req_uri));
2317   strlcpy(uri, req_uri, urilen);
2318 
2319   return (http->state);
2320 }
2321 
2322 
2323 /*
2324  * 'httpReconnect()' - Reconnect to a HTTP server.
2325  *
2326  * This function is deprecated. Please use the @link httpReconnect2@ function
2327  * instead.
2328  *
2329  * @deprecated@ @exclude all@
2330  */
2331 
2332 int					/* O - 0 on success, non-zero on failure */
httpReconnect(http_t * http)2333 httpReconnect(http_t *http)		/* I - HTTP connection */
2334 {
2335   DEBUG_printf(("httpReconnect(http=%p)", (void *)http));
2336 
2337   return (httpReconnect2(http, 30000, NULL));
2338 }
2339 
2340 
2341 /*
2342  * 'httpReconnect2()' - Reconnect to a HTTP server with timeout and optional
2343  *                      cancel.
2344  */
2345 
2346 int					/* O - 0 on success, non-zero on failure */
httpReconnect2(http_t * http,int msec,int * cancel)2347 httpReconnect2(http_t *http,		/* I - HTTP connection */
2348 	       int    msec,		/* I - Timeout in milliseconds */
2349 	       int    *cancel)		/* I - Pointer to "cancel" variable */
2350 {
2351   http_addrlist_t	*addr;		/* Connected address */
2352 #ifdef DEBUG
2353   http_addrlist_t	*current;	/* Current address */
2354   char			temp[256];	/* Temporary address string */
2355 #endif /* DEBUG */
2356 
2357 
2358   DEBUG_printf(("httpReconnect2(http=%p, msec=%d, cancel=%p)", (void *)http, msec, (void *)cancel));
2359 
2360   if (!http)
2361   {
2362     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
2363     return (-1);
2364   }
2365 
2366 #ifdef HAVE_SSL
2367   if (http->tls)
2368   {
2369     DEBUG_puts("2httpReconnect2: Shutting down SSL/TLS...");
2370     _httpTLSStop(http);
2371   }
2372 #endif /* HAVE_SSL */
2373 
2374  /*
2375   * Close any previously open socket...
2376   */
2377 
2378   if (http->fd >= 0)
2379   {
2380     DEBUG_printf(("2httpReconnect2: Closing socket %d...", http->fd));
2381 
2382     httpAddrClose(NULL, http->fd);
2383 
2384     http->fd = -1;
2385   }
2386 
2387  /*
2388   * Reset all state (except fields, which may be reused)...
2389   */
2390 
2391   http->state           = HTTP_STATE_WAITING;
2392   http->version         = HTTP_VERSION_1_1;
2393   http->keep_alive      = HTTP_KEEPALIVE_OFF;
2394   memset(&http->_hostaddr, 0, sizeof(http->_hostaddr));
2395   http->data_encoding   = HTTP_ENCODING_FIELDS;
2396   http->_data_remaining = 0;
2397   http->used            = 0;
2398   http->data_remaining  = 0;
2399   http->hostaddr        = NULL;
2400   http->wused           = 0;
2401 
2402  /*
2403   * Connect to the server...
2404   */
2405 
2406 #ifdef DEBUG
2407   for (current = http->addrlist; current; current = current->next)
2408     DEBUG_printf(("2httpReconnect2: Address %s:%d",
2409                   httpAddrString(&(current->addr), temp, sizeof(temp)),
2410                   httpAddrPort(&(current->addr))));
2411 #endif /* DEBUG */
2412 
2413   if ((addr = httpAddrConnect2(http->addrlist, &(http->fd), msec, cancel)) == NULL)
2414   {
2415    /*
2416     * Unable to connect...
2417     */
2418 
2419 #ifdef WIN32
2420     http->error  = WSAGetLastError();
2421 #else
2422     http->error  = errno;
2423 #endif /* WIN32 */
2424     http->status = HTTP_STATUS_ERROR;
2425 
2426     DEBUG_printf(("1httpReconnect2: httpAddrConnect failed: %s",
2427                   strerror(http->error)));
2428 
2429     return (-1);
2430   }
2431 
2432   DEBUG_printf(("2httpReconnect2: New socket=%d", http->fd));
2433 
2434   if (http->timeout_value > 0)
2435     http_set_timeout(http->fd, http->timeout_value);
2436 
2437   http->hostaddr = &(addr->addr);
2438   http->error    = 0;
2439 
2440 #ifdef HAVE_SSL
2441   if (http->encryption == HTTP_ENCRYPTION_ALWAYS)
2442   {
2443    /*
2444     * Always do encryption via SSL.
2445     */
2446 
2447     if (_httpTLSStart(http) != 0)
2448     {
2449       httpAddrClose(NULL, http->fd);
2450 
2451       return (-1);
2452     }
2453   }
2454   else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls_upgrade)
2455     return (http_tls_upgrade(http));
2456 #endif /* HAVE_SSL */
2457 
2458   DEBUG_printf(("1httpReconnect2: Connected to %s:%d...",
2459 		httpAddrString(http->hostaddr, temp, sizeof(temp)),
2460 		httpAddrPort(http->hostaddr)));
2461 
2462   return (0);
2463 }
2464 
2465 
2466 /*
2467  * 'httpSetAuthString()' - Set the current authorization string.
2468  *
2469  * This function just stores a copy of the current authorization string in
2470  * the HTTP connection object.  You must still call @link httpSetField@ to set
2471  * @code HTTP_FIELD_AUTHORIZATION@ prior to issuing a HTTP request using
2472  * @link httpGet@, @link httpHead@, @link httpOptions@, @link httpPost@, or
2473  * @link httpPut@.
2474  *
2475  * @since CUPS 1.3/macOS 10.5@
2476  */
2477 
2478 void
httpSetAuthString(http_t * http,const char * scheme,const char * data)2479 httpSetAuthString(http_t     *http,	/* I - HTTP connection */
2480                   const char *scheme,	/* I - Auth scheme (NULL to clear it) */
2481 		  const char *data)	/* I - Auth data (NULL for none) */
2482 {
2483  /*
2484   * Range check input...
2485   */
2486 
2487   if (!http)
2488     return;
2489 
2490   if (http->authstring && http->authstring != http->_authstring)
2491     free(http->authstring);
2492 
2493   http->authstring = http->_authstring;
2494 
2495   if (scheme)
2496   {
2497    /*
2498     * Set the current authorization string...
2499     */
2500 
2501     size_t len = strlen(scheme) + (data ? strlen(data) + 1 : 0) + 1;
2502     char *temp;
2503 
2504     if (len > sizeof(http->_authstring))
2505     {
2506       if ((temp = malloc(len)) == NULL)
2507         len = sizeof(http->_authstring);
2508       else
2509         http->authstring = temp;
2510     }
2511 
2512     if (data)
2513       snprintf(http->authstring, len, "%s %s", scheme, data);
2514     else
2515       strlcpy(http->authstring, scheme, len);
2516   }
2517   else
2518   {
2519    /*
2520     * Clear the current authorization string...
2521     */
2522 
2523     http->_authstring[0] = '\0';
2524   }
2525 }
2526 
2527 
2528 /*
2529  * 'httpSetCredentials()' - Set the credentials associated with an encrypted
2530  *			    connection.
2531  *
2532  * @since CUPS 1.5/macOS 10.7@
2533  */
2534 
2535 int						/* O - Status of call (0 = success) */
httpSetCredentials(http_t * http,cups_array_t * credentials)2536 httpSetCredentials(http_t	*http,		/* I - HTTP connection */
2537 		   cups_array_t *credentials)	/* I - Array of credentials */
2538 {
2539   if (!http || cupsArrayCount(credentials) < 1)
2540     return (-1);
2541 
2542 #ifdef HAVE_SSL
2543   _httpFreeCredentials(http->tls_credentials);
2544 
2545   http->tls_credentials = _httpCreateCredentials(credentials);
2546 #endif /* HAVE_SSL */
2547 
2548   return (http->tls_credentials ? 0 : -1);
2549 }
2550 
2551 
2552 /*
2553  * 'httpSetCookie()' - Set the cookie value(s).
2554  *
2555  * @since CUPS 1.1.19/macOS 10.3@
2556  */
2557 
2558 void
httpSetCookie(http_t * http,const char * cookie)2559 httpSetCookie(http_t     *http,		/* I - Connection */
2560               const char *cookie)	/* I - Cookie string */
2561 {
2562   if (!http)
2563     return;
2564 
2565   if (http->cookie)
2566     free(http->cookie);
2567 
2568   if (cookie)
2569     http->cookie = strdup(cookie);
2570   else
2571     http->cookie = NULL;
2572 }
2573 
2574 
2575 /*
2576  * 'httpSetDefaultField()' - Set the default value of an HTTP header.
2577  *
2578  * Currently only @code HTTP_FIELD_ACCEPT_ENCODING@, @code HTTP_FIELD_SERVER@,
2579  * and @code HTTP_FIELD_USER_AGENT@ can be set.
2580  *
2581  * @since CUPS 1.7/macOS 10.9@
2582  */
2583 
2584 void
httpSetDefaultField(http_t * http,http_field_t field,const char * value)2585 httpSetDefaultField(http_t       *http,	/* I - HTTP connection */
2586                     http_field_t field,	/* I - Field index */
2587 	            const char   *value)/* I - Value */
2588 {
2589   DEBUG_printf(("httpSetDefaultField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));
2590 
2591   if (!http)
2592     return;
2593 
2594   switch (field)
2595   {
2596     case HTTP_FIELD_ACCEPT_ENCODING :
2597         if (http->default_accept_encoding)
2598           _cupsStrFree(http->default_accept_encoding);
2599 
2600         http->default_accept_encoding = value ? _cupsStrAlloc(value) : NULL;
2601         break;
2602 
2603     case HTTP_FIELD_SERVER :
2604         if (http->default_server)
2605           _cupsStrFree(http->default_server);
2606 
2607         http->default_server = value ? _cupsStrAlloc(value) : NULL;
2608         break;
2609 
2610     case HTTP_FIELD_USER_AGENT :
2611         if (http->default_user_agent)
2612           _cupsStrFree(http->default_user_agent);
2613 
2614         http->default_user_agent = value ? _cupsStrAlloc(value) : NULL;
2615         break;
2616 
2617     default :
2618         DEBUG_puts("1httpSetDefaultField: Ignored.");
2619 	break;
2620   }
2621 }
2622 
2623 
2624 /*
2625  * 'httpSetExpect()' - Set the Expect: header in a request.
2626  *
2627  * Currently only @code HTTP_STATUS_CONTINUE@ is supported for the "expect"
2628  * argument.
2629  *
2630  * @since CUPS 1.2/macOS 10.5@
2631  */
2632 
2633 void
httpSetExpect(http_t * http,http_status_t expect)2634 httpSetExpect(http_t        *http,	/* I - HTTP connection */
2635               http_status_t expect)	/* I - HTTP status to expect
2636               				       (@code HTTP_STATUS_CONTINUE@) */
2637 {
2638   DEBUG_printf(("httpSetExpect(http=%p, expect=%d)", (void *)http, expect));
2639 
2640   if (http)
2641     http->expect = expect;
2642 }
2643 
2644 
2645 /*
2646  * 'httpSetField()' - Set the value of an HTTP header.
2647  */
2648 
2649 void
httpSetField(http_t * http,http_field_t field,const char * value)2650 httpSetField(http_t       *http,	/* I - HTTP connection */
2651              http_field_t field,	/* I - Field index */
2652 	     const char   *value)	/* I - Value */
2653 {
2654   DEBUG_printf(("httpSetField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));
2655 
2656   if (http == NULL ||
2657       field < HTTP_FIELD_ACCEPT_LANGUAGE ||
2658       field >= HTTP_FIELD_MAX ||
2659       value == NULL)
2660     return;
2661 
2662   switch (field)
2663   {
2664     case HTTP_FIELD_ACCEPT_ENCODING :
2665         if (http->accept_encoding)
2666           _cupsStrFree(http->accept_encoding);
2667 
2668         http->accept_encoding = _cupsStrAlloc(value);
2669         break;
2670 
2671     case HTTP_FIELD_ALLOW :
2672         if (http->allow)
2673           _cupsStrFree(http->allow);
2674 
2675         http->allow = _cupsStrAlloc(value);
2676         break;
2677 
2678     case HTTP_FIELD_SERVER :
2679         if (http->server)
2680           _cupsStrFree(http->server);
2681 
2682         http->server = _cupsStrAlloc(value);
2683         break;
2684 
2685     case HTTP_FIELD_WWW_AUTHENTICATE :
2686        /* CUPS STR #4503 - don't override WWW-Authenticate for unknown auth schemes */
2687         if (http->fields[HTTP_FIELD_WWW_AUTHENTICATE][0] &&
2688 	    _cups_strncasecmp(value, "Basic ", 6) &&
2689 	    _cups_strncasecmp(value, "Digest ", 7) &&
2690 	    _cups_strncasecmp(value, "Negotiate ", 10))
2691 	{
2692 	  DEBUG_printf(("1httpSetField: Ignoring unknown auth scheme in \"%s\".", value));
2693           return;
2694 	}
2695 
2696 	/* Fall through to copy */
2697 
2698     default :
2699 	strlcpy(http->fields[field], value, HTTP_MAX_VALUE);
2700 	break;
2701   }
2702 
2703   if (field == HTTP_FIELD_AUTHORIZATION)
2704   {
2705    /*
2706     * Special case for Authorization: as its contents can be
2707     * longer than HTTP_MAX_VALUE
2708     */
2709 
2710     if (http->field_authorization)
2711       free(http->field_authorization);
2712 
2713     http->field_authorization = strdup(value);
2714   }
2715   else if (field == HTTP_FIELD_HOST)
2716   {
2717    /*
2718     * Special-case for Host: as we don't want a trailing "." on the hostname and
2719     * need to bracket IPv6 numeric addresses.
2720     */
2721 
2722     char *ptr = strchr(value, ':');
2723 
2724     if (value[0] != '[' && ptr && strchr(ptr + 1, ':'))
2725     {
2726      /*
2727       * Bracket IPv6 numeric addresses...
2728       *
2729       * This is slightly inefficient (basically copying twice), but is an edge
2730       * case and not worth optimizing...
2731       */
2732 
2733       snprintf(http->fields[HTTP_FIELD_HOST],
2734                sizeof(http->fields[HTTP_FIELD_HOST]), "[%s]", value);
2735     }
2736     else
2737     {
2738      /*
2739       * Check for a trailing dot on the hostname...
2740       */
2741 
2742       ptr = http->fields[HTTP_FIELD_HOST];
2743 
2744       if (*ptr)
2745       {
2746 	ptr += strlen(ptr) - 1;
2747 
2748 	if (*ptr == '.')
2749 	  *ptr = '\0';
2750       }
2751     }
2752   }
2753 #ifdef HAVE_LIBZ
2754   else if (field == HTTP_FIELD_CONTENT_ENCODING &&
2755            http->data_encoding != HTTP_ENCODING_FIELDS)
2756   {
2757     DEBUG_puts("1httpSetField: Calling http_content_coding_start.");
2758     http_content_coding_start(http, value);
2759   }
2760 #endif /* HAVE_LIBZ */
2761 }
2762 
2763 
2764 /*
2765  * 'httpSetKeepAlive()' - Set the current Keep-Alive state of a connection.
2766  *
2767  * @since CUPS 2.0/OS 10.10@
2768  */
2769 
2770 void
httpSetKeepAlive(http_t * http,http_keepalive_t keep_alive)2771 httpSetKeepAlive(
2772     http_t           *http,		/* I - HTTP connection */
2773     http_keepalive_t keep_alive)	/* I - New Keep-Alive value */
2774 {
2775   if (http)
2776     http->keep_alive = keep_alive;
2777 }
2778 
2779 
2780 /*
2781  * 'httpSetLength()' - Set the content-length and content-encoding.
2782  *
2783  * @since CUPS 1.2/macOS 10.5@
2784  */
2785 
2786 void
httpSetLength(http_t * http,size_t length)2787 httpSetLength(http_t *http,		/* I - HTTP connection */
2788               size_t length)		/* I - Length (0 for chunked) */
2789 {
2790   DEBUG_printf(("httpSetLength(http=%p, length=" CUPS_LLFMT ")", (void *)http, CUPS_LLCAST length));
2791 
2792   if (!http)
2793     return;
2794 
2795   if (!length)
2796   {
2797     strlcpy(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked",
2798             HTTP_MAX_VALUE);
2799     http->fields[HTTP_FIELD_CONTENT_LENGTH][0] = '\0';
2800   }
2801   else
2802   {
2803     http->fields[HTTP_FIELD_TRANSFER_ENCODING][0] = '\0';
2804     snprintf(http->fields[HTTP_FIELD_CONTENT_LENGTH], HTTP_MAX_VALUE,
2805              CUPS_LLFMT, CUPS_LLCAST length);
2806   }
2807 }
2808 
2809 
2810 /*
2811  * 'httpSetTimeout()' - Set read/write timeouts and an optional callback.
2812  *
2813  * The optional timeout callback receives both the HTTP connection and a user
2814  * data pointer and must return 1 to continue or 0 to error (time) out.
2815  *
2816  * @since CUPS 1.5/macOS 10.7@
2817  */
2818 
2819 void
httpSetTimeout(http_t * http,double timeout,http_timeout_cb_t cb,void * user_data)2820 httpSetTimeout(
2821     http_t            *http,		/* I - HTTP connection */
2822     double            timeout,		/* I - Number of seconds for timeout,
2823                                                must be greater than 0 */
2824     http_timeout_cb_t cb,		/* I - Callback function or @code NULL@ */
2825     void              *user_data)	/* I - User data pointer */
2826 {
2827   if (!http || timeout <= 0.0)
2828     return;
2829 
2830   http->timeout_cb    = cb;
2831   http->timeout_data  = user_data;
2832   http->timeout_value = timeout;
2833 
2834   if (http->fd >= 0)
2835     http_set_timeout(http->fd, timeout);
2836 
2837   http_set_wait(http);
2838 }
2839 
2840 
2841 /*
2842  * 'httpShutdown()' - Shutdown one side of an HTTP connection.
2843  *
2844  * @since CUPS 2.0/OS 10.10@
2845  */
2846 
2847 void
httpShutdown(http_t * http)2848 httpShutdown(http_t *http)		/* I - HTTP connection */
2849 {
2850   if (!http || http->fd < 0)
2851     return;
2852 
2853 #ifdef HAVE_SSL
2854   if (http->tls)
2855     _httpTLSStop(http);
2856 #endif /* HAVE_SSL */
2857 
2858 #ifdef WIN32
2859   shutdown(http->fd, SD_RECEIVE);	/* Microsoft-ism... */
2860 #else
2861   shutdown(http->fd, SHUT_RD);
2862 #endif /* WIN32 */
2863 }
2864 
2865 
2866 /*
2867  * 'httpTrace()' - Send an TRACE request to the server.
2868  *
2869  * @exclude all@
2870  */
2871 
2872 int					/* O - Status of call (0 = success) */
httpTrace(http_t * http,const char * uri)2873 httpTrace(http_t     *http,		/* I - HTTP connection */
2874           const char *uri)		/* I - URI for trace */
2875 {
2876   return (http_send(http, HTTP_STATE_TRACE, uri));
2877 }
2878 
2879 
2880 /*
2881  * '_httpUpdate()' - Update the current HTTP status for incoming data.
2882  *
2883  * Note: Unlike httpUpdate(), this function does not flush pending write data
2884  * and only retrieves a single status line from the HTTP connection.
2885  */
2886 
2887 int					/* O - 1 to continue, 0 to stop */
_httpUpdate(http_t * http,http_status_t * status)2888 _httpUpdate(http_t        *http,	/* I - HTTP connection */
2889             http_status_t *status)	/* O - Current HTTP status */
2890 {
2891   char		line[32768],		/* Line from connection... */
2892 		*value;			/* Pointer to value on line */
2893   http_field_t	field;			/* Field index */
2894   int		major, minor;		/* HTTP version numbers */
2895 
2896 
2897   DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", (void *)http, (void *)status, httpStateString(http->state)));
2898 
2899  /*
2900   * Grab a single line from the connection...
2901   */
2902 
2903   if (!httpGets(line, sizeof(line), http))
2904   {
2905     *status = HTTP_STATUS_ERROR;
2906     return (0);
2907   }
2908 
2909   DEBUG_printf(("2_httpUpdate: Got \"%s\"", line));
2910 
2911   if (line[0] == '\0')
2912   {
2913    /*
2914     * Blank line means the start of the data section (if any).  Return
2915     * the result code, too...
2916     *
2917     * If we get status 100 (HTTP_STATUS_CONTINUE), then we *don't* change
2918     * states.  Instead, we just return HTTP_STATUS_CONTINUE to the caller and
2919     * keep on tryin'...
2920     */
2921 
2922     if (http->status == HTTP_STATUS_CONTINUE)
2923     {
2924       *status = http->status;
2925       return (0);
2926     }
2927 
2928     if (http->status < HTTP_STATUS_BAD_REQUEST)
2929       http->digest_tries = 0;
2930 
2931 #ifdef HAVE_SSL
2932     if (http->status == HTTP_STATUS_SWITCHING_PROTOCOLS && !http->tls)
2933     {
2934       if (_httpTLSStart(http) != 0)
2935       {
2936         httpAddrClose(NULL, http->fd);
2937 
2938 	*status = http->status = HTTP_STATUS_ERROR;
2939 	return (0);
2940       }
2941 
2942       *status = HTTP_STATUS_CONTINUE;
2943       return (0);
2944     }
2945 #endif /* HAVE_SSL */
2946 
2947     if (http_set_length(http) < 0)
2948     {
2949       DEBUG_puts("1_httpUpdate: Bad Content-Length.");
2950       http->error  = EINVAL;
2951       http->status = *status = HTTP_STATUS_ERROR;
2952       return (0);
2953     }
2954 
2955     switch (http->state)
2956     {
2957       case HTTP_STATE_GET :
2958       case HTTP_STATE_POST :
2959       case HTTP_STATE_POST_RECV :
2960       case HTTP_STATE_PUT :
2961 	  http->state ++;
2962 
2963 	  DEBUG_printf(("1_httpUpdate: Set state to %s.",
2964 	                httpStateString(http->state)));
2965 
2966       case HTTP_STATE_POST_SEND :
2967       case HTTP_STATE_HEAD :
2968 	  break;
2969 
2970       default :
2971 	  http->state = HTTP_STATE_WAITING;
2972 
2973 	  DEBUG_puts("1_httpUpdate: Reset state to HTTP_STATE_WAITING.");
2974 	  break;
2975     }
2976 
2977 #ifdef HAVE_LIBZ
2978     DEBUG_puts("1_httpUpdate: Calling http_content_coding_start.");
2979     http_content_coding_start(http,
2980                               httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
2981 #endif /* HAVE_LIBZ */
2982 
2983     *status = http->status;
2984     return (0);
2985   }
2986   else if (!strncmp(line, "HTTP/", 5) && http->mode == _HTTP_MODE_CLIENT)
2987   {
2988    /*
2989     * Got the beginning of a response...
2990     */
2991 
2992     int	intstatus;			/* Status value as an integer */
2993 
2994     if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &intstatus) != 3)
2995     {
2996       *status = http->status = HTTP_STATUS_ERROR;
2997       return (0);
2998     }
2999 
3000     httpClearFields(http);
3001 
3002     http->version = (http_version_t)(major * 100 + minor);
3003     *status       = http->status = (http_status_t)intstatus;
3004   }
3005   else if ((value = strchr(line, ':')) != NULL)
3006   {
3007    /*
3008     * Got a value...
3009     */
3010 
3011     *value++ = '\0';
3012     while (_cups_isspace(*value))
3013       value ++;
3014 
3015     DEBUG_printf(("1_httpUpdate: Header %s: %s", line, value));
3016 
3017    /*
3018     * Be tolerants of servers that send unknown attribute fields...
3019     */
3020 
3021     if (!_cups_strcasecmp(line, "expect"))
3022     {
3023      /*
3024       * "Expect: 100-continue" or similar...
3025       */
3026 
3027       http->expect = (http_status_t)atoi(value);
3028     }
3029     else if (!_cups_strcasecmp(line, "cookie"))
3030     {
3031      /*
3032       * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
3033       */
3034 
3035       httpSetCookie(http, value);
3036     }
3037     else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN)
3038       httpSetField(http, field, value);
3039 #ifdef DEBUG
3040     else
3041       DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line));
3042 #endif /* DEBUG */
3043   }
3044   else
3045   {
3046     DEBUG_printf(("1_httpUpdate: Bad response line \"%s\"!", line));
3047     http->error  = EINVAL;
3048     http->status = *status = HTTP_STATUS_ERROR;
3049     return (0);
3050   }
3051 
3052   return (1);
3053 }
3054 
3055 
3056 /*
3057  * 'httpUpdate()' - Update the current HTTP state for incoming data.
3058  */
3059 
3060 http_status_t				/* O - HTTP status */
httpUpdate(http_t * http)3061 httpUpdate(http_t *http)		/* I - HTTP connection */
3062 {
3063   http_status_t	status;			/* Request status */
3064 
3065 
3066   DEBUG_printf(("httpUpdate(http=%p), state=%s", (void *)http, httpStateString(http->state)));
3067 
3068  /*
3069   * Flush pending data, if any...
3070   */
3071 
3072   if (http->wused)
3073   {
3074     DEBUG_puts("2httpUpdate: flushing buffer...");
3075 
3076     if (httpFlushWrite(http) < 0)
3077       return (HTTP_STATUS_ERROR);
3078   }
3079 
3080  /*
3081   * If we haven't issued any commands, then there is nothing to "update"...
3082   */
3083 
3084   if (http->state == HTTP_STATE_WAITING)
3085     return (HTTP_STATUS_CONTINUE);
3086 
3087  /*
3088   * Grab all of the lines we can from the connection...
3089   */
3090 
3091   while (_httpUpdate(http, &status));
3092 
3093  /*
3094   * See if there was an error...
3095   */
3096 
3097   if (http->error == EPIPE && http->status > HTTP_STATUS_CONTINUE)
3098   {
3099     DEBUG_printf(("1httpUpdate: Returning status %d...", http->status));
3100     return (http->status);
3101   }
3102 
3103   if (http->error)
3104   {
3105     DEBUG_printf(("1httpUpdate: socket error %d - %s", http->error,
3106                   strerror(http->error)));
3107     http->status = HTTP_STATUS_ERROR;
3108     return (HTTP_STATUS_ERROR);
3109   }
3110 
3111  /*
3112   * Return the current status...
3113   */
3114 
3115   return (status);
3116 }
3117 
3118 
3119 /*
3120  * '_httpWait()' - Wait for data available on a connection (no flush).
3121  */
3122 
3123 int					/* O - 1 if data is available, 0 otherwise */
_httpWait(http_t * http,int msec,int usessl)3124 _httpWait(http_t *http,			/* I - HTTP connection */
3125           int    msec,			/* I - Milliseconds to wait */
3126 	  int    usessl)		/* I - Use SSL context? */
3127 {
3128 #ifdef HAVE_POLL
3129   struct pollfd		pfd;		/* Polled file descriptor */
3130 #else
3131   fd_set		input_set;	/* select() input set */
3132   struct timeval	timeout;	/* Timeout */
3133 #endif /* HAVE_POLL */
3134   int			nfds;		/* Result from select()/poll() */
3135 
3136 
3137   DEBUG_printf(("4_httpWait(http=%p, msec=%d, usessl=%d)", (void *)http, msec, usessl));
3138 
3139   if (http->fd < 0)
3140   {
3141     DEBUG_printf(("5_httpWait: Returning 0 since fd=%d", http->fd));
3142     return (0);
3143   }
3144 
3145  /*
3146   * Check the SSL/TLS buffers for data first...
3147   */
3148 
3149 #ifdef HAVE_SSL
3150   if (http->tls && _httpTLSPending(http))
3151   {
3152     DEBUG_puts("5_httpWait: Return 1 since there is pending TLS data.");
3153     return (1);
3154   }
3155 #endif /* HAVE_SSL */
3156 
3157  /*
3158   * Then try doing a select() or poll() to poll the socket...
3159   */
3160 
3161 #ifdef HAVE_POLL
3162   pfd.fd     = http->fd;
3163   pfd.events = POLLIN;
3164 
3165   do
3166   {
3167     nfds = poll(&pfd, 1, msec);
3168   }
3169   while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
3170 
3171 #else
3172   do
3173   {
3174     FD_ZERO(&input_set);
3175     FD_SET(http->fd, &input_set);
3176 
3177     DEBUG_printf(("6_httpWait: msec=%d, http->fd=%d", msec, http->fd));
3178 
3179     if (msec >= 0)
3180     {
3181       timeout.tv_sec  = msec / 1000;
3182       timeout.tv_usec = (msec % 1000) * 1000;
3183 
3184       nfds = select(http->fd + 1, &input_set, NULL, NULL, &timeout);
3185     }
3186     else
3187       nfds = select(http->fd + 1, &input_set, NULL, NULL, NULL);
3188 
3189     DEBUG_printf(("6_httpWait: select() returned %d...", nfds));
3190   }
3191 #  ifdef WIN32
3192   while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
3193                       WSAGetLastError() == WSAEWOULDBLOCK));
3194 #  else
3195   while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
3196 #  endif /* WIN32 */
3197 #endif /* HAVE_POLL */
3198 
3199   DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds,
3200                 errno));
3201 
3202   return (nfds > 0);
3203 }
3204 
3205 
3206 /*
3207  * 'httpWait()' - Wait for data available on a connection.
3208  *
3209  * @since CUPS 1.1.19/macOS 10.3@
3210  */
3211 
3212 int					/* O - 1 if data is available, 0 otherwise */
httpWait(http_t * http,int msec)3213 httpWait(http_t *http,			/* I - HTTP connection */
3214          int    msec)			/* I - Milliseconds to wait */
3215 {
3216  /*
3217   * First see if there is data in the buffer...
3218   */
3219 
3220   DEBUG_printf(("2httpWait(http=%p, msec=%d)", (void *)http, msec));
3221 
3222   if (http == NULL)
3223     return (0);
3224 
3225   if (http->used)
3226   {
3227     DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
3228     return (1);
3229   }
3230 
3231 #ifdef HAVE_LIBZ
3232   if (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in > 0)
3233   {
3234     DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
3235     return (1);
3236   }
3237 #endif /* HAVE_LIBZ */
3238 
3239  /*
3240   * Flush pending data, if any...
3241   */
3242 
3243   if (http->wused)
3244   {
3245     DEBUG_puts("3httpWait: Flushing write buffer.");
3246 
3247     if (httpFlushWrite(http) < 0)
3248       return (0);
3249   }
3250 
3251  /*
3252   * If not, check the SSL/TLS buffers and do a select() on the connection...
3253   */
3254 
3255   return (_httpWait(http, msec, 1));
3256 }
3257 
3258 
3259 /*
3260  * 'httpWrite()' - Write data to a HTTP connection.
3261  *
3262  * This function is deprecated. Use the httpWrite2() function which can
3263  * write more than 2GB of data.
3264  *
3265  * @deprecated@ @exclude all@
3266  */
3267 
3268 int					/* O - Number of bytes written */
httpWrite(http_t * http,const char * buffer,int length)3269 httpWrite(http_t     *http,		/* I - HTTP connection */
3270           const char *buffer,		/* I - Buffer for data */
3271 	  int        length)		/* I - Number of bytes to write */
3272 {
3273   return ((int)httpWrite2(http, buffer, (size_t)length));
3274 }
3275 
3276 
3277 /*
3278  * 'httpWrite2()' - Write data to a HTTP connection.
3279  *
3280  * @since CUPS 1.2/macOS 10.5@
3281  */
3282 
3283 ssize_t					/* O - Number of bytes written */
httpWrite2(http_t * http,const char * buffer,size_t length)3284 httpWrite2(http_t     *http,		/* I - HTTP connection */
3285            const char *buffer,		/* I - Buffer for data */
3286 	   size_t     length)		/* I - Number of bytes to write */
3287 {
3288   ssize_t	bytes;			/* Bytes written */
3289 
3290 
3291   DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
3292 
3293  /*
3294   * Range check input...
3295   */
3296 
3297   if (!http || !buffer)
3298   {
3299     DEBUG_puts("1httpWrite2: Returning -1 due to bad input.");
3300     return (-1);
3301   }
3302 
3303  /*
3304   * Mark activity on the connection...
3305   */
3306 
3307   http->activity = time(NULL);
3308 
3309  /*
3310   * Buffer small writes for better performance...
3311   */
3312 
3313 #ifdef HAVE_LIBZ
3314   if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
3315   {
3316     DEBUG_printf(("1httpWrite2: http->coding=%d", http->coding));
3317 
3318     if (length == 0)
3319     {
3320       http_content_coding_finish(http);
3321       bytes = 0;
3322     }
3323     else
3324     {
3325       size_t	slen;			/* Bytes to write */
3326       ssize_t	sret;			/* Bytes written */
3327 
3328       http->stream.next_in   = (Bytef *)buffer;
3329       http->stream.avail_in  = (uInt)length;
3330 
3331       while (deflate(&(http->stream), Z_NO_FLUSH) == Z_OK)
3332       {
3333         DEBUG_printf(("1httpWrite2: avail_out=%d", http->stream.avail_out));
3334 
3335         if (http->stream.avail_out > 0)
3336 	  continue;
3337 
3338 	slen = _HTTP_MAX_SBUFFER - http->stream.avail_out;
3339 
3340         DEBUG_printf(("1httpWrite2: Writing intermediate chunk, len=%d", (int)slen));
3341 
3342 	if (slen > 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
3343 	  sret = http_write_chunk(http, (char *)http->sbuffer, slen);
3344 	else if (slen > 0)
3345 	  sret = http_write(http, (char *)http->sbuffer, slen);
3346 	else
3347 	  sret = 0;
3348 
3349         if (sret < 0)
3350 	{
3351 	  DEBUG_puts("1httpWrite2: Unable to write, returning -1.");
3352 	  return (-1);
3353 	}
3354 
3355 	http->stream.next_out  = (Bytef *)http->sbuffer;
3356 	http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER;
3357       }
3358 
3359       bytes = (ssize_t)length;
3360     }
3361   }
3362   else
3363 #endif /* HAVE_LIBZ */
3364   if (length > 0)
3365   {
3366     if (http->wused && (length + (size_t)http->wused) > sizeof(http->wbuffer))
3367     {
3368       DEBUG_printf(("2httpWrite2: Flushing buffer (wused=%d, length="
3369                     CUPS_LLFMT ")", http->wused, CUPS_LLCAST length));
3370 
3371       httpFlushWrite(http);
3372     }
3373 
3374     if ((length + (size_t)http->wused) <= sizeof(http->wbuffer) && length < sizeof(http->wbuffer))
3375     {
3376      /*
3377       * Write to buffer...
3378       */
3379 
3380       DEBUG_printf(("2httpWrite2: Copying " CUPS_LLFMT " bytes to wbuffer...",
3381                     CUPS_LLCAST length));
3382 
3383       memcpy(http->wbuffer + http->wused, buffer, length);
3384       http->wused += (int)length;
3385       bytes = (ssize_t)length;
3386     }
3387     else
3388     {
3389      /*
3390       * Otherwise write the data directly...
3391       */
3392 
3393       DEBUG_printf(("2httpWrite2: Writing " CUPS_LLFMT " bytes to socket...",
3394                     CUPS_LLCAST length));
3395 
3396       if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3397 	bytes = (ssize_t)http_write_chunk(http, buffer, length);
3398       else
3399 	bytes = (ssize_t)http_write(http, buffer, length);
3400 
3401       DEBUG_printf(("2httpWrite2: Wrote " CUPS_LLFMT " bytes...",
3402                     CUPS_LLCAST bytes));
3403     }
3404 
3405     if (http->data_encoding == HTTP_ENCODING_LENGTH)
3406       http->data_remaining -= bytes;
3407   }
3408   else
3409     bytes = 0;
3410 
3411  /*
3412   * Handle end-of-request processing...
3413   */
3414 
3415   if ((http->data_encoding == HTTP_ENCODING_CHUNKED && length == 0) ||
3416       (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0))
3417   {
3418    /*
3419     * Finished with the transfer; unless we are sending POST or PUT
3420     * data, go idle...
3421     */
3422 
3423 #ifdef HAVE_LIBZ
3424     if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
3425       http_content_coding_finish(http);
3426 #endif /* HAVE_LIBZ */
3427 
3428     if (http->wused)
3429     {
3430       if (httpFlushWrite(http) < 0)
3431         return (-1);
3432     }
3433 
3434     if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3435     {
3436      /*
3437       * Send a 0-length chunk at the end of the request...
3438       */
3439 
3440       http_write(http, "0\r\n\r\n", 5);
3441 
3442      /*
3443       * Reset the data state...
3444       */
3445 
3446       http->data_encoding  = HTTP_ENCODING_FIELDS;
3447       http->data_remaining = 0;
3448     }
3449 
3450     if (http->state == HTTP_STATE_POST_RECV)
3451       http->state ++;
3452     else if (http->state == HTTP_STATE_POST_SEND ||
3453              http->state == HTTP_STATE_GET_SEND)
3454       http->state = HTTP_STATE_WAITING;
3455     else
3456       http->state = HTTP_STATE_STATUS;
3457 
3458     DEBUG_printf(("2httpWrite2: Changed state to %s.",
3459 		  httpStateString(http->state)));
3460   }
3461 
3462   DEBUG_printf(("1httpWrite2: Returning " CUPS_LLFMT ".", CUPS_LLCAST bytes));
3463 
3464   return (bytes);
3465 }
3466 
3467 
3468 /*
3469  * 'httpWriteResponse()' - Write a HTTP response to a client connection.
3470  *
3471  * @since CUPS 1.7/macOS 10.9@
3472  */
3473 
3474 int					/* O - 0 on success, -1 on error */
httpWriteResponse(http_t * http,http_status_t status)3475 httpWriteResponse(http_t        *http,	/* I - HTTP connection */
3476 		  http_status_t status)	/* I - Status code */
3477 {
3478   http_encoding_t	old_encoding;	/* Old data_encoding value */
3479   off_t			old_remaining;	/* Old data_remaining value */
3480 
3481 
3482  /*
3483   * Range check input...
3484   */
3485 
3486   DEBUG_printf(("httpWriteResponse(http=%p, status=%d)", (void *)http, status));
3487 
3488   if (!http || status < HTTP_STATUS_CONTINUE)
3489   {
3490     DEBUG_puts("1httpWriteResponse: Bad input.");
3491     return (-1);
3492   }
3493 
3494  /*
3495   * Set the various standard fields if they aren't already...
3496   */
3497 
3498   if (!http->fields[HTTP_FIELD_DATE][0])
3499     httpSetField(http, HTTP_FIELD_DATE, httpGetDateString(time(NULL)));
3500 
3501   if (status >= HTTP_STATUS_BAD_REQUEST && http->keep_alive)
3502   {
3503     http->keep_alive = HTTP_KEEPALIVE_OFF;
3504     httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "");
3505   }
3506 
3507   if (http->version == HTTP_VERSION_1_1)
3508   {
3509     if (!http->fields[HTTP_FIELD_CONNECTION][0])
3510     {
3511       if (http->keep_alive)
3512 	httpSetField(http, HTTP_FIELD_CONNECTION, "Keep-Alive");
3513       else
3514 	httpSetField(http, HTTP_FIELD_CONNECTION, "close");
3515     }
3516 
3517     if (http->keep_alive && !http->fields[HTTP_FIELD_KEEP_ALIVE][0])
3518       httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "timeout=10");
3519   }
3520 
3521 #ifdef HAVE_SSL
3522   if (status == HTTP_STATUS_UPGRADE_REQUIRED ||
3523       status == HTTP_STATUS_SWITCHING_PROTOCOLS)
3524   {
3525     if (!http->fields[HTTP_FIELD_CONNECTION][0])
3526       httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
3527 
3528     if (!http->fields[HTTP_FIELD_UPGRADE][0])
3529       httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
3530 
3531     if (!http->fields[HTTP_FIELD_CONTENT_LENGTH][0])
3532       httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "0");
3533   }
3534 #endif /* HAVE_SSL */
3535 
3536   if (!http->server)
3537     httpSetField(http, HTTP_FIELD_SERVER,
3538                  http->default_server ? http->default_server : CUPS_MINIMAL);
3539 
3540  /*
3541   * Set the Accept-Encoding field if it isn't already...
3542   */
3543 
3544   if (!http->accept_encoding)
3545     httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING,
3546                  http->default_accept_encoding ? http->default_accept_encoding :
3547 #ifdef HAVE_LIBZ
3548                                                  "gzip, deflate, identity");
3549 #else
3550                                                  "identity");
3551 #endif /* HAVE_LIBZ */
3552 
3553  /*
3554   * Send the response header...
3555   */
3556 
3557   old_encoding        = http->data_encoding;
3558   old_remaining       = http->data_remaining;
3559   http->data_encoding = HTTP_ENCODING_FIELDS;
3560 
3561   if (httpPrintf(http, "HTTP/%d.%d %d %s\r\n", http->version / 100,
3562                  http->version % 100, (int)status, httpStatus(status)) < 0)
3563   {
3564     http->status = HTTP_STATUS_ERROR;
3565     return (-1);
3566   }
3567 
3568   if (status != HTTP_STATUS_CONTINUE)
3569   {
3570    /*
3571     * 100 Continue doesn't have the rest of the response headers...
3572     */
3573 
3574     int		i;			/* Looping var */
3575     const char	*value;			/* Field value */
3576 
3577     for (i = 0; i < HTTP_FIELD_MAX; i ++)
3578     {
3579       if ((value = httpGetField(http, i)) != NULL && *value)
3580       {
3581 	if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
3582 	{
3583 	  http->status = HTTP_STATUS_ERROR;
3584 	  return (-1);
3585 	}
3586       }
3587     }
3588 
3589     if (http->cookie)
3590     {
3591       if (strchr(http->cookie, ';'))
3592       {
3593         if (httpPrintf(http, "Set-Cookie: %s\r\n", http->cookie) < 1)
3594 	{
3595 	  http->status = HTTP_STATUS_ERROR;
3596 	  return (-1);
3597 	}
3598       }
3599       else if (httpPrintf(http, "Set-Cookie: %s; path=/; httponly;%s\r\n", http->cookie, http->tls ? " secure;" : "") < 1)
3600       {
3601 	http->status = HTTP_STATUS_ERROR;
3602 	return (-1);
3603       }
3604     }
3605 
3606    /*
3607     * "Click-jacking" defense (STR #4492)...
3608     */
3609 
3610     if (httpPrintf(http, "X-Frame-Options: DENY\r\n"
3611                          "Content-Security-Policy: frame-ancestors 'none'\r\n") < 1)
3612     {
3613       http->status = HTTP_STATUS_ERROR;
3614       return (-1);
3615     }
3616   }
3617 
3618   if (httpWrite2(http, "\r\n", 2) < 2)
3619   {
3620     http->status = HTTP_STATUS_ERROR;
3621     return (-1);
3622   }
3623 
3624   if (httpFlushWrite(http) < 0)
3625   {
3626     http->status = HTTP_STATUS_ERROR;
3627     return (-1);
3628   }
3629 
3630   if (status == HTTP_STATUS_CONTINUE ||
3631       status == HTTP_STATUS_SWITCHING_PROTOCOLS)
3632   {
3633    /*
3634     * Restore the old data_encoding and data_length values...
3635     */
3636 
3637     http->data_encoding  = old_encoding;
3638     http->data_remaining = old_remaining;
3639 
3640     if (old_remaining <= INT_MAX)
3641       http->_data_remaining = (int)old_remaining;
3642     else
3643       http->_data_remaining = INT_MAX;
3644   }
3645   else if (http->state == HTTP_STATE_OPTIONS ||
3646            http->state == HTTP_STATE_HEAD ||
3647            http->state == HTTP_STATE_PUT ||
3648            http->state == HTTP_STATE_TRACE ||
3649            http->state == HTTP_STATE_CONNECT ||
3650            http->state == HTTP_STATE_STATUS)
3651   {
3652     DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, "
3653                   "was %s.", httpStateString(http->state)));
3654     http->state = HTTP_STATE_WAITING;
3655   }
3656   else
3657   {
3658    /*
3659     * Force data_encoding and data_length to be set according to the response
3660     * headers...
3661     */
3662 
3663     http_set_length(http);
3664 
3665     if (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0)
3666     {
3667       DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, "
3668                     "was %s.", httpStateString(http->state)));
3669       http->state = HTTP_STATE_WAITING;
3670       return (0);
3671     }
3672 
3673     if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_GET)
3674       http->state ++;
3675 
3676 #ifdef HAVE_LIBZ
3677    /*
3678     * Then start any content encoding...
3679     */
3680 
3681     DEBUG_puts("1httpWriteResponse: Calling http_content_coding_start.");
3682     http_content_coding_start(http,
3683 			      httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
3684 #endif /* HAVE_LIBZ */
3685 
3686   }
3687 
3688   return (0);
3689 }
3690 
3691 
3692 #ifdef HAVE_LIBZ
3693 /*
3694  * 'http_content_coding_finish()' - Finish doing any content encoding.
3695  */
3696 
3697 static void
http_content_coding_finish(http_t * http)3698 http_content_coding_finish(
3699     http_t *http)			/* I - HTTP connection */
3700 {
3701   int		zerr;			/* Compression status */
3702   Byte		dummy[1];		/* Dummy read buffer */
3703   size_t	bytes;			/* Number of bytes to write */
3704 
3705 
3706   DEBUG_printf(("http_content_coding_finish(http=%p)", (void *)http));
3707   DEBUG_printf(("1http_content_coding_finishing: http->coding=%d", http->coding));
3708 
3709   switch (http->coding)
3710   {
3711     case _HTTP_CODING_DEFLATE :
3712     case _HTTP_CODING_GZIP :
3713         http->stream.next_in  = dummy;
3714         http->stream.avail_in = 0;
3715 
3716         do
3717         {
3718           zerr  = deflate(&(http->stream), Z_FINISH);
3719 	  bytes = _HTTP_MAX_SBUFFER - http->stream.avail_out;
3720 
3721           if (bytes > 0)
3722 	  {
3723 	    DEBUG_printf(("1http_content_coding_finish: Writing trailing chunk, len=%d", (int)bytes));
3724 
3725 	    if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3726 	      http_write_chunk(http, (char *)http->sbuffer, bytes);
3727 	    else
3728 	      http_write(http, (char *)http->sbuffer, bytes);
3729           }
3730 
3731           http->stream.next_out  = (Bytef *)http->sbuffer;
3732           http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER;
3733 	}
3734         while (zerr == Z_OK);
3735 
3736         deflateEnd(&(http->stream));
3737 
3738         free(http->sbuffer);
3739         http->sbuffer = NULL;
3740 
3741         if (http->wused)
3742           httpFlushWrite(http);
3743         break;
3744 
3745     case _HTTP_CODING_INFLATE :
3746     case _HTTP_CODING_GUNZIP :
3747         inflateEnd(&(http->stream));
3748         free(http->sbuffer);
3749         http->sbuffer = NULL;
3750         break;
3751 
3752     default :
3753         break;
3754   }
3755 
3756   http->coding = _HTTP_CODING_IDENTITY;
3757 }
3758 
3759 
3760 /*
3761  * 'http_content_coding_start()' - Start doing content encoding.
3762  */
3763 
3764 static void
http_content_coding_start(http_t * http,const char * value)3765 http_content_coding_start(
3766     http_t     *http,			/* I - HTTP connection */
3767     const char *value)			/* I - Value of Content-Encoding */
3768 {
3769   int			zerr;		/* Error/status */
3770   _http_coding_t	coding;		/* Content coding value */
3771 
3772 
3773   DEBUG_printf(("http_content_coding_start(http=%p, value=\"%s\")", (void *)http, value));
3774 
3775   if (http->coding != _HTTP_CODING_IDENTITY)
3776   {
3777     DEBUG_printf(("1http_content_coding_start: http->coding already %d.",
3778                   http->coding));
3779     return;
3780   }
3781   else if (!strcmp(value, "x-gzip") || !strcmp(value, "gzip"))
3782   {
3783     if (http->state == HTTP_STATE_GET_SEND ||
3784         http->state == HTTP_STATE_POST_SEND)
3785       coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_GZIP :
3786                                                  _HTTP_CODING_GUNZIP;
3787     else if (http->state == HTTP_STATE_POST_RECV ||
3788              http->state == HTTP_STATE_PUT_RECV)
3789       coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_GZIP :
3790                                                  _HTTP_CODING_GUNZIP;
3791     else
3792     {
3793       DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3794       return;
3795     }
3796   }
3797   else if (!strcmp(value, "x-deflate") || !strcmp(value, "deflate"))
3798   {
3799     if (http->state == HTTP_STATE_GET_SEND ||
3800         http->state == HTTP_STATE_POST_SEND)
3801       coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_DEFLATE :
3802                                                  _HTTP_CODING_INFLATE;
3803     else if (http->state == HTTP_STATE_POST_RECV ||
3804              http->state == HTTP_STATE_PUT_RECV)
3805       coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_DEFLATE :
3806                                                  _HTTP_CODING_INFLATE;
3807     else
3808     {
3809       DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3810       return;
3811     }
3812   }
3813   else
3814   {
3815     DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3816     return;
3817   }
3818 
3819   memset(&(http->stream), 0, sizeof(http->stream));
3820 
3821   switch (coding)
3822   {
3823     case _HTTP_CODING_DEFLATE :
3824     case _HTTP_CODING_GZIP :
3825         if (http->wused)
3826           httpFlushWrite(http);
3827 
3828         if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL)
3829         {
3830           http->status = HTTP_STATUS_ERROR;
3831           http->error  = errno;
3832           return;
3833         }
3834 
3835        /*
3836         * Window size for compression is 11 bits - optimal based on PWG Raster
3837         * sample files on pwg.org.  -11 is raw deflate, 27 is gzip, per ZLIB
3838         * documentation.
3839         */
3840 
3841         if ((zerr = deflateInit2(&(http->stream), Z_DEFAULT_COMPRESSION,
3842                                  Z_DEFLATED,
3843 				 coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7,
3844 				 Z_DEFAULT_STRATEGY)) < Z_OK)
3845         {
3846           http->status = HTTP_STATUS_ERROR;
3847           http->error  = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
3848           return;
3849         }
3850 
3851 	http->stream.next_out  = (Bytef *)http->sbuffer;
3852 	http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER;
3853         break;
3854 
3855     case _HTTP_CODING_INFLATE :
3856     case _HTTP_CODING_GUNZIP :
3857         if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL)
3858         {
3859           http->status = HTTP_STATUS_ERROR;
3860           http->error  = errno;
3861           return;
3862         }
3863 
3864        /*
3865         * Window size for decompression is up to 15 bits (maximum supported).
3866         * -15 is raw inflate, 31 is gunzip, per ZLIB documentation.
3867         */
3868 
3869         if ((zerr = inflateInit2(&(http->stream),
3870                                  coding == _HTTP_CODING_INFLATE ? -15 : 31))
3871 		< Z_OK)
3872         {
3873           free(http->sbuffer);
3874           http->sbuffer = NULL;
3875           http->status  = HTTP_STATUS_ERROR;
3876           http->error   = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
3877           return;
3878         }
3879 
3880         http->stream.avail_in = 0;
3881         http->stream.next_in  = http->sbuffer;
3882         break;
3883 
3884     default :
3885         break;
3886   }
3887 
3888   http->coding = coding;
3889 
3890   DEBUG_printf(("1http_content_coding_start: http->coding now %d.",
3891 		http->coding));
3892 }
3893 #endif /* HAVE_LIBZ */
3894 
3895 
3896 /*
3897  * 'http_create()' - Create an unconnected HTTP connection.
3898  */
3899 
3900 static http_t *				/* O - HTTP connection */
http_create(const char * host,int port,http_addrlist_t * addrlist,int family,http_encryption_t encryption,int blocking,_http_mode_t mode)3901 http_create(
3902     const char        *host,		/* I - Hostname */
3903     int               port,		/* I - Port number */
3904     http_addrlist_t   *addrlist,	/* I - Address list or @code NULL@ */
3905     int               family,		/* I - Address family or AF_UNSPEC */
3906     http_encryption_t encryption,	/* I - Encryption to use */
3907     int               blocking,		/* I - 1 for blocking mode */
3908     _http_mode_t      mode)		/* I - _HTTP_MODE_CLIENT or _SERVER */
3909 {
3910   http_t	*http;			/* New HTTP connection */
3911   char		service[255];		/* Service name */
3912   http_addrlist_t *myaddrlist = NULL;	/* My address list */
3913 
3914 
3915   DEBUG_printf(("4http_create(host=\"%s\", port=%d, addrlist=%p, family=%d, encryption=%d, blocking=%d, mode=%d)", host, port, (void *)addrlist, family, encryption, blocking, mode));
3916 
3917   if (!host && mode == _HTTP_MODE_CLIENT)
3918     return (NULL);
3919 
3920   httpInitialize();
3921 
3922  /*
3923   * Lookup the host...
3924   */
3925 
3926   if (addrlist)
3927   {
3928     myaddrlist = httpAddrCopyList(addrlist);
3929   }
3930   else
3931   {
3932     snprintf(service, sizeof(service), "%d", port);
3933 
3934     myaddrlist = httpAddrGetList(host, family, service);
3935   }
3936 
3937   if (!myaddrlist)
3938     return (NULL);
3939 
3940  /*
3941   * Allocate memory for the structure...
3942   */
3943 
3944   if ((http = calloc(sizeof(http_t), 1)) == NULL)
3945   {
3946     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
3947     httpAddrFreeList(addrlist);
3948     return (NULL);
3949   }
3950 
3951  /*
3952   * Initialize the HTTP data...
3953   */
3954 
3955   http->mode     = mode;
3956   http->activity = time(NULL);
3957   http->addrlist = myaddrlist;
3958   http->blocking = blocking;
3959   http->fd       = -1;
3960 #ifdef HAVE_GSSAPI
3961   http->gssctx   = GSS_C_NO_CONTEXT;
3962   http->gssname  = GSS_C_NO_NAME;
3963 #endif /* HAVE_GSSAPI */
3964   http->status   = HTTP_STATUS_CONTINUE;
3965   http->version  = HTTP_VERSION_1_1;
3966 
3967   if (host)
3968     strlcpy(http->hostname, host, sizeof(http->hostname));
3969 
3970   if (port == 443)			/* Always use encryption for https */
3971     http->encryption = HTTP_ENCRYPTION_ALWAYS;
3972   else
3973     http->encryption = encryption;
3974 
3975   http_set_wait(http);
3976 
3977  /*
3978   * Return the new structure...
3979   */
3980 
3981   return (http);
3982 }
3983 
3984 
3985 #ifdef DEBUG
3986 /*
3987  * 'http_debug_hex()' - Do a hex dump of a buffer.
3988  */
3989 
3990 static void
http_debug_hex(const char * prefix,const char * buffer,int bytes)3991 http_debug_hex(const char *prefix,	/* I - Prefix for line */
3992                const char *buffer,	/* I - Buffer to dump */
3993                int        bytes)	/* I - Bytes to dump */
3994 {
3995   int	i, j,				/* Looping vars */
3996 	ch;				/* Current character */
3997   char	line[255],			/* Line buffer */
3998 	*start,				/* Start of line after prefix */
3999 	*ptr;				/* Pointer into line */
4000 
4001 
4002   if (_cups_debug_fd < 0 || _cups_debug_level < 6)
4003     return;
4004 
4005   DEBUG_printf(("6%s: %d bytes:", prefix, bytes));
4006 
4007   snprintf(line, sizeof(line), "6%s: ", prefix);
4008   start = line + strlen(line);
4009 
4010   for (i = 0; i < bytes; i += 16)
4011   {
4012     for (j = 0, ptr = start; j < 16 && (i + j) < bytes; j ++, ptr += 2)
4013       snprintf(ptr, 3, "%02X", buffer[i + j] & 255);
4014 
4015     while (j < 16)
4016     {
4017       memcpy(ptr, "  ", 3);
4018       ptr += 2;
4019       j ++;
4020     }
4021 
4022     memcpy(ptr, "  ", 3);
4023     ptr += 2;
4024 
4025     for (j = 0; j < 16 && (i + j) < bytes; j ++)
4026     {
4027       ch = buffer[i + j] & 255;
4028 
4029       if (ch < ' ' || ch >= 127)
4030 	ch = '.';
4031 
4032       *ptr++ = (char)ch;
4033     }
4034 
4035     *ptr = '\0';
4036     DEBUG_puts(line);
4037   }
4038 }
4039 #endif /* DEBUG */
4040 
4041 
4042 /*
4043  * 'http_read()' - Read a buffer from a HTTP connection.
4044  *
4045  * This function does the low-level read from the socket, retrying and timing
4046  * out as needed.
4047  */
4048 
4049 static ssize_t				/* O - Number of bytes read or -1 on error */
http_read(http_t * http,char * buffer,size_t length)4050 http_read(http_t *http,			/* I - HTTP connection */
4051           char   *buffer,		/* I - Buffer */
4052           size_t length)		/* I - Maximum bytes to read */
4053 {
4054   ssize_t	bytes;			/* Bytes read */
4055 
4056 
4057   DEBUG_printf(("http_read(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4058 
4059   if (!http->blocking)
4060   {
4061     while (!httpWait(http, http->wait_value))
4062     {
4063       if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4064 	continue;
4065 
4066       DEBUG_puts("2http_read: Timeout.");
4067       return (0);
4068     }
4069   }
4070 
4071   DEBUG_printf(("2http_read: Reading %d bytes into buffer.", (int)length));
4072 
4073   do
4074   {
4075 #ifdef HAVE_SSL
4076     if (http->tls)
4077       bytes = _httpTLSRead(http, buffer, (int)length);
4078     else
4079 #endif /* HAVE_SSL */
4080     bytes = recv(http->fd, buffer, length, 0);
4081 
4082     if (bytes < 0)
4083     {
4084 #ifdef WIN32
4085       if (WSAGetLastError() != WSAEINTR)
4086       {
4087 	http->error = WSAGetLastError();
4088 	return (-1);
4089       }
4090       else if (WSAGetLastError() == WSAEWOULDBLOCK)
4091       {
4092 	if (!http->timeout_cb ||
4093 	    !(*http->timeout_cb)(http, http->timeout_data))
4094 	{
4095 	  http->error = WSAEWOULDBLOCK;
4096 	  return (-1);
4097 	}
4098       }
4099 #else
4100       DEBUG_printf(("2http_read: %s", strerror(errno)));
4101 
4102       if (errno == EWOULDBLOCK || errno == EAGAIN)
4103       {
4104 	if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data))
4105 	{
4106 	  http->error = errno;
4107 	  return (-1);
4108 	}
4109 	else if (!http->timeout_cb && errno != EAGAIN)
4110 	{
4111 	  http->error = errno;
4112 	  return (-1);
4113 	}
4114       }
4115       else if (errno != EINTR)
4116       {
4117 	http->error = errno;
4118 	return (-1);
4119       }
4120 #endif /* WIN32 */
4121     }
4122   }
4123   while (bytes < 0);
4124 
4125   DEBUG_printf(("2http_read: Read " CUPS_LLFMT " bytes into buffer.",
4126 		CUPS_LLCAST bytes));
4127 #ifdef DEBUG
4128   if (bytes > 0)
4129     http_debug_hex("http_read", buffer, (int)bytes);
4130 #endif /* DEBUG */
4131 
4132   if (bytes < 0)
4133   {
4134 #ifdef WIN32
4135     if (WSAGetLastError() == WSAEINTR)
4136       bytes = 0;
4137     else
4138       http->error = WSAGetLastError();
4139 #else
4140     if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb))
4141       bytes = 0;
4142     else
4143       http->error = errno;
4144 #endif /* WIN32 */
4145   }
4146   else if (bytes == 0)
4147   {
4148     http->error = EPIPE;
4149     return (0);
4150   }
4151 
4152   return (bytes);
4153 }
4154 
4155 
4156 /*
4157  * 'http_read_buffered()' - Do a buffered read from a HTTP connection.
4158  *
4159  * This function reads data from the HTTP buffer or from the socket, as needed.
4160  */
4161 
4162 static ssize_t				/* O - Number of bytes read or -1 on error */
http_read_buffered(http_t * http,char * buffer,size_t length)4163 http_read_buffered(http_t *http,	/* I - HTTP connection */
4164                    char   *buffer,	/* I - Buffer */
4165                    size_t length)	/* I - Maximum bytes to read */
4166 {
4167   ssize_t	bytes;			/* Bytes read */
4168 
4169 
4170   DEBUG_printf(("http_read_buffered(http=%p, buffer=%p, length=" CUPS_LLFMT ") used=%d", (void *)http, (void *)buffer, CUPS_LLCAST length, http->used));
4171 
4172   if (http->used > 0)
4173   {
4174     if (length > (size_t)http->used)
4175       bytes = (ssize_t)http->used;
4176     else
4177       bytes = (ssize_t)length;
4178 
4179     DEBUG_printf(("2http_read: Grabbing %d bytes from input buffer.",
4180                   (int)bytes));
4181 
4182     memcpy(buffer, http->buffer, (size_t)bytes);
4183     http->used -= (int)bytes;
4184 
4185     if (http->used > 0)
4186       memmove(http->buffer, http->buffer + bytes, (size_t)http->used);
4187   }
4188   else
4189     bytes = http_read(http, buffer, length);
4190 
4191   return (bytes);
4192 }
4193 
4194 
4195 /*
4196  * 'http_read_chunk()' - Read a chunk from a HTTP connection.
4197  *
4198  * This function reads and validates the chunk length, then does a buffered read
4199  * returning the number of bytes placed in the buffer.
4200  */
4201 
4202 static ssize_t				/* O - Number of bytes read or -1 on error */
http_read_chunk(http_t * http,char * buffer,size_t length)4203 http_read_chunk(http_t *http,		/* I - HTTP connection */
4204 		char   *buffer,		/* I - Buffer */
4205 		size_t length)		/* I - Maximum bytes to read */
4206 {
4207   DEBUG_printf(("http_read_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4208 
4209   if (http->data_remaining <= 0)
4210   {
4211     char	len[32];		/* Length string */
4212 
4213     if (!httpGets(len, sizeof(len), http))
4214     {
4215       DEBUG_puts("1http_read_chunk: Could not get chunk length.");
4216       return (0);
4217     }
4218 
4219     if (!len[0])
4220     {
4221       DEBUG_puts("1http_read_chunk: Blank chunk length, trying again...");
4222       if (!httpGets(len, sizeof(len), http))
4223       {
4224 	DEBUG_puts("1http_read_chunk: Could not get chunk length.");
4225 	return (0);
4226       }
4227     }
4228 
4229     http->data_remaining = strtoll(len, NULL, 16);
4230 
4231     if (http->data_remaining < 0)
4232     {
4233       DEBUG_printf(("1http_read_chunk: Negative chunk length \"%s\" ("
4234                     CUPS_LLFMT ")", len, CUPS_LLCAST http->data_remaining));
4235       return (0);
4236     }
4237 
4238     DEBUG_printf(("2http_read_chunk: Got chunk length \"%s\" (" CUPS_LLFMT ")",
4239                   len, CUPS_LLCAST http->data_remaining));
4240 
4241     if (http->data_remaining == 0)
4242     {
4243      /*
4244       * 0-length chunk, grab trailing blank line...
4245       */
4246 
4247       httpGets(len, sizeof(len), http);
4248     }
4249   }
4250 
4251   DEBUG_printf(("2http_read_chunk: data_remaining=" CUPS_LLFMT,
4252                 CUPS_LLCAST http->data_remaining));
4253 
4254   if (http->data_remaining <= 0)
4255     return (0);
4256   else if (length > (size_t)http->data_remaining)
4257     length = (size_t)http->data_remaining;
4258 
4259   return (http_read_buffered(http, buffer, length));
4260 }
4261 
4262 
4263 /*
4264  * 'http_send()' - Send a request with all fields and the trailing blank line.
4265  */
4266 
4267 static int				/* O - 0 on success, non-zero on error */
http_send(http_t * http,http_state_t request,const char * uri)4268 http_send(http_t       *http,		/* I - HTTP connection */
4269           http_state_t request,		/* I - Request code */
4270 	  const char   *uri)		/* I - URI */
4271 {
4272   int		i;			/* Looping var */
4273   char		buf[1024];		/* Encoded URI buffer */
4274   const char	*value;			/* Field value */
4275   static const char * const codes[] =	/* Request code strings */
4276 		{
4277 		  NULL,
4278 		  "OPTIONS",
4279 		  "GET",
4280 		  NULL,
4281 		  "HEAD",
4282 		  "POST",
4283 		  NULL,
4284 		  NULL,
4285 		  "PUT",
4286 		  NULL,
4287 		  "DELETE",
4288 		  "TRACE",
4289 		  "CLOSE",
4290 		  NULL,
4291 		  NULL
4292 		};
4293 
4294 
4295   DEBUG_printf(("4http_send(http=%p, request=HTTP_%s, uri=\"%s\")", (void *)http, codes[request], uri));
4296 
4297   if (http == NULL || uri == NULL)
4298     return (-1);
4299 
4300  /*
4301   * Set the User-Agent field if it isn't already...
4302   */
4303 
4304   if (!http->fields[HTTP_FIELD_USER_AGENT][0])
4305   {
4306     if (http->default_user_agent)
4307       httpSetField(http, HTTP_FIELD_USER_AGENT, http->default_user_agent);
4308     else
4309       httpSetField(http, HTTP_FIELD_USER_AGENT, cupsUserAgent());
4310   }
4311 
4312  /*
4313   * Set the Accept-Encoding field if it isn't already...
4314   */
4315 
4316   if (!http->accept_encoding && http->default_accept_encoding)
4317     httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING,
4318                  http->default_accept_encoding);
4319 
4320  /*
4321   * Encode the URI as needed...
4322   */
4323 
4324   _httpEncodeURI(buf, uri, sizeof(buf));
4325 
4326  /*
4327   * See if we had an error the last time around; if so, reconnect...
4328   */
4329 
4330   if (http->fd < 0 || http->status == HTTP_STATUS_ERROR ||
4331       http->status >= HTTP_STATUS_BAD_REQUEST)
4332   {
4333     DEBUG_printf(("5http_send: Reconnecting, fd=%d, status=%d, tls_upgrade=%d",
4334                   http->fd, http->status, http->tls_upgrade));
4335 
4336     if (httpReconnect2(http, 30000, NULL))
4337       return (-1);
4338   }
4339 
4340  /*
4341   * Flush any written data that is pending...
4342   */
4343 
4344   if (http->wused)
4345   {
4346     if (httpFlushWrite(http) < 0)
4347       if (httpReconnect2(http, 30000, NULL))
4348         return (-1);
4349   }
4350 
4351  /*
4352   * Send the request header...
4353   */
4354 
4355   http->state         = request;
4356   http->data_encoding = HTTP_ENCODING_FIELDS;
4357 
4358   if (request == HTTP_STATE_POST || request == HTTP_STATE_PUT)
4359     http->state ++;
4360 
4361   http->status = HTTP_STATUS_CONTINUE;
4362 
4363 #ifdef HAVE_SSL
4364   if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls)
4365   {
4366     httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
4367     httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
4368   }
4369 #endif /* HAVE_SSL */
4370 
4371   if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
4372   {
4373     http->status = HTTP_STATUS_ERROR;
4374     return (-1);
4375   }
4376 
4377   for (i = 0; i < HTTP_FIELD_MAX; i ++)
4378     if ((value = httpGetField(http, i)) != NULL && *value)
4379     {
4380       DEBUG_printf(("5http_send: %s: %s", http_fields[i], value));
4381 
4382       if (i == HTTP_FIELD_HOST)
4383       {
4384 	if (httpPrintf(http, "Host: %s:%d\r\n", value,
4385 	               httpAddrPort(http->hostaddr)) < 1)
4386 	{
4387 	  http->status = HTTP_STATUS_ERROR;
4388 	  return (-1);
4389 	}
4390       }
4391       else if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
4392       {
4393 	http->status = HTTP_STATUS_ERROR;
4394 	return (-1);
4395       }
4396     }
4397 
4398   if (http->cookie)
4399     if (httpPrintf(http, "Cookie: $Version=0; %s\r\n", http->cookie) < 1)
4400     {
4401       http->status = HTTP_STATUS_ERROR;
4402       return (-1);
4403     }
4404 
4405   DEBUG_printf(("5http_send: expect=%d, mode=%d, state=%d", http->expect,
4406                 http->mode, http->state));
4407 
4408   if (http->expect == HTTP_STATUS_CONTINUE && http->mode == _HTTP_MODE_CLIENT &&
4409       (http->state == HTTP_STATE_POST_RECV ||
4410        http->state == HTTP_STATE_PUT_RECV))
4411     if (httpPrintf(http, "Expect: 100-continue\r\n") < 1)
4412     {
4413       http->status = HTTP_STATUS_ERROR;
4414       return (-1);
4415     }
4416 
4417   if (httpPrintf(http, "\r\n") < 1)
4418   {
4419     http->status = HTTP_STATUS_ERROR;
4420     return (-1);
4421   }
4422 
4423   if (httpFlushWrite(http) < 0)
4424     return (-1);
4425 
4426   http_set_length(http);
4427   httpClearFields(http);
4428 
4429  /*
4430   * The Kerberos and AuthRef authentication strings can only be used once...
4431   */
4432 
4433   if (http->field_authorization && http->authstring &&
4434       (!strncmp(http->authstring, "Negotiate", 9) ||
4435        !strncmp(http->authstring, "AuthRef", 7)))
4436   {
4437     http->_authstring[0] = '\0';
4438 
4439     if (http->authstring != http->_authstring)
4440       free(http->authstring);
4441 
4442     http->authstring = http->_authstring;
4443   }
4444 
4445   return (0);
4446 }
4447 
4448 
4449 /*
4450  * 'http_set_length()' - Set the data_encoding and data_remaining values.
4451  */
4452 
4453 static off_t				/* O - Remainder or -1 on error */
http_set_length(http_t * http)4454 http_set_length(http_t *http)		/* I - Connection */
4455 {
4456   off_t	remaining;			/* Remainder */
4457 
4458 
4459   DEBUG_printf(("http_set_length(http=%p) mode=%d state=%s", (void *)http, http->mode, httpStateString(http->state)));
4460 
4461   if ((remaining = httpGetLength2(http)) >= 0)
4462   {
4463     if (http->mode == _HTTP_MODE_SERVER &&
4464 	http->state != HTTP_STATE_GET_SEND &&
4465 	http->state != HTTP_STATE_PUT &&
4466 	http->state != HTTP_STATE_POST &&
4467 	http->state != HTTP_STATE_POST_SEND)
4468     {
4469       DEBUG_puts("1http_set_length: Not setting data_encoding/remaining.");
4470       return (remaining);
4471     }
4472 
4473     if (!_cups_strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING],
4474                           "chunked"))
4475     {
4476       DEBUG_puts("1http_set_length: Setting data_encoding to "
4477                  "HTTP_ENCODING_CHUNKED.");
4478       http->data_encoding = HTTP_ENCODING_CHUNKED;
4479     }
4480     else
4481     {
4482       DEBUG_puts("1http_set_length: Setting data_encoding to "
4483                  "HTTP_ENCODING_LENGTH.");
4484       http->data_encoding = HTTP_ENCODING_LENGTH;
4485     }
4486 
4487     DEBUG_printf(("1http_set_length: Setting data_remaining to " CUPS_LLFMT ".",
4488                   CUPS_LLCAST remaining));
4489     http->data_remaining = remaining;
4490 
4491     if (remaining <= INT_MAX)
4492       http->_data_remaining = (int)remaining;
4493     else
4494       http->_data_remaining = INT_MAX;
4495   }
4496 
4497   return (remaining);
4498 }
4499 
4500 /*
4501  * 'http_set_timeout()' - Set the socket timeout values.
4502  */
4503 
4504 static void
http_set_timeout(int fd,double timeout)4505 http_set_timeout(int    fd,		/* I - File descriptor */
4506                  double timeout)	/* I - Timeout in seconds */
4507 {
4508 #ifdef WIN32
4509   DWORD tv = (DWORD)(timeout * 1000);
4510 				      /* Timeout in milliseconds */
4511 
4512   setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4513   setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4514 
4515 #else
4516   struct timeval tv;			/* Timeout in secs and usecs */
4517 
4518   tv.tv_sec  = (int)timeout;
4519   tv.tv_usec = (int)(1000000 * fmod(timeout, 1.0));
4520 
4521   setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4522   setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4523 #endif /* WIN32 */
4524 }
4525 
4526 
4527 /*
4528  * 'http_set_wait()' - Set the default wait value for reads.
4529  */
4530 
4531 static void
http_set_wait(http_t * http)4532 http_set_wait(http_t *http)		/* I - HTTP connection */
4533 {
4534   if (http->blocking)
4535   {
4536     http->wait_value = (int)(http->timeout_value * 1000);
4537 
4538     if (http->wait_value <= 0)
4539       http->wait_value = 60000;
4540   }
4541   else
4542     http->wait_value = 10000;
4543 }
4544 
4545 
4546 #ifdef HAVE_SSL
4547 /*
4548  * 'http_tls_upgrade()' - Force upgrade to TLS encryption.
4549  */
4550 
4551 static int				/* O - Status of connection */
http_tls_upgrade(http_t * http)4552 http_tls_upgrade(http_t *http)		/* I - HTTP connection */
4553 {
4554   int		ret;			/* Return value */
4555   http_t	myhttp;			/* Local copy of HTTP data */
4556 
4557 
4558   DEBUG_printf(("7http_tls_upgrade(%p)", (void *)http));
4559 
4560  /*
4561   * Flush the connection to make sure any previous "Upgrade" message
4562   * has been read.
4563   */
4564 
4565   httpFlush(http);
4566 
4567  /*
4568   * Copy the HTTP data to a local variable so we can do the OPTIONS
4569   * request without interfering with the existing request data...
4570   */
4571 
4572   memcpy(&myhttp, http, sizeof(myhttp));
4573 
4574  /*
4575   * Send an OPTIONS request to the server, requiring SSL or TLS
4576   * encryption on the link...
4577   */
4578 
4579   http->tls_upgrade         = 1;
4580   http->field_authorization = NULL;	/* Don't free the auth string */
4581 
4582   httpClearFields(http);
4583   httpSetField(http, HTTP_FIELD_CONNECTION, "upgrade");
4584   httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
4585 
4586   if ((ret = httpOptions(http, "*")) == 0)
4587   {
4588    /*
4589     * Wait for the secure connection...
4590     */
4591 
4592     while (httpUpdate(http) == HTTP_STATUS_CONTINUE);
4593   }
4594 
4595  /*
4596   * Restore the HTTP request data...
4597   */
4598 
4599   memcpy(http->fields, myhttp.fields, sizeof(http->fields));
4600   http->data_encoding       = myhttp.data_encoding;
4601   http->data_remaining      = myhttp.data_remaining;
4602   http->_data_remaining     = myhttp._data_remaining;
4603   http->expect              = myhttp.expect;
4604   http->field_authorization = myhttp.field_authorization;
4605   http->digest_tries        = myhttp.digest_tries;
4606   http->tls_upgrade         = 0;
4607 
4608  /*
4609   * See if we actually went secure...
4610   */
4611 
4612   if (!http->tls)
4613   {
4614    /*
4615     * Server does not support HTTP upgrade...
4616     */
4617 
4618     DEBUG_puts("8http_tls_upgrade: Server does not support HTTP upgrade!");
4619 
4620     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Encryption is not supported."), 1);
4621     httpAddrClose(NULL, http->fd);
4622 
4623     http->fd = -1;
4624 
4625     return (-1);
4626   }
4627   else
4628     return (ret);
4629 }
4630 #endif /* HAVE_SSL */
4631 
4632 
4633 /*
4634  * 'http_write()' - Write a buffer to a HTTP connection.
4635  */
4636 
4637 static ssize_t				/* O - Number of bytes written */
http_write(http_t * http,const char * buffer,size_t length)4638 http_write(http_t     *http,		/* I - HTTP connection */
4639            const char *buffer,		/* I - Buffer for data */
4640 	   size_t     length)		/* I - Number of bytes to write */
4641 {
4642   ssize_t	tbytes,			/* Total bytes sent */
4643 		bytes;			/* Bytes sent */
4644 
4645 
4646   DEBUG_printf(("2http_write(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4647   http->error = 0;
4648   tbytes      = 0;
4649 
4650   while (length > 0)
4651   {
4652     DEBUG_printf(("3http_write: About to write %d bytes.", (int)length));
4653 
4654     if (http->timeout_cb)
4655     {
4656 #ifdef HAVE_POLL
4657       struct pollfd	pfd;		/* Polled file descriptor */
4658 #else
4659       fd_set		output_set;	/* Output ready for write? */
4660       struct timeval	timeout;	/* Timeout value */
4661 #endif /* HAVE_POLL */
4662       int		nfds;		/* Result from select()/poll() */
4663 
4664       do
4665       {
4666 #ifdef HAVE_POLL
4667 	pfd.fd     = http->fd;
4668 	pfd.events = POLLOUT;
4669 
4670 	while ((nfds = poll(&pfd, 1, http->wait_value)) < 0 &&
4671 	       (errno == EINTR || errno == EAGAIN))
4672 	  /* do nothing */;
4673 
4674 #else
4675 	do
4676 	{
4677 	  FD_ZERO(&output_set);
4678 	  FD_SET(http->fd, &output_set);
4679 
4680 	  timeout.tv_sec  = http->wait_value / 1000;
4681 	  timeout.tv_usec = 1000 * (http->wait_value % 1000);
4682 
4683 	  nfds = select(http->fd + 1, NULL, &output_set, NULL, &timeout);
4684 	}
4685 #  ifdef WIN32
4686 	while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
4687 			    WSAGetLastError() == WSAEWOULDBLOCK));
4688 #  else
4689 	while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
4690 #  endif /* WIN32 */
4691 #endif /* HAVE_POLL */
4692 
4693         if (nfds < 0)
4694 	{
4695 	  http->error = errno;
4696 	  return (-1);
4697 	}
4698 	else if (nfds == 0 && !(*http->timeout_cb)(http, http->timeout_data))
4699 	{
4700 #ifdef WIN32
4701 	  http->error = WSAEWOULDBLOCK;
4702 #else
4703 	  http->error = EWOULDBLOCK;
4704 #endif /* WIN32 */
4705 	  return (-1);
4706 	}
4707       }
4708       while (nfds <= 0);
4709     }
4710 
4711 #ifdef HAVE_SSL
4712     if (http->tls)
4713       bytes = _httpTLSWrite(http, buffer, (int)length);
4714     else
4715 #endif /* HAVE_SSL */
4716     bytes = send(http->fd, buffer, length, 0);
4717 
4718     DEBUG_printf(("3http_write: Write of " CUPS_LLFMT " bytes returned "
4719                   CUPS_LLFMT ".", CUPS_LLCAST length, CUPS_LLCAST bytes));
4720 
4721     if (bytes < 0)
4722     {
4723 #ifdef WIN32
4724       if (WSAGetLastError() == WSAEINTR)
4725         continue;
4726       else if (WSAGetLastError() == WSAEWOULDBLOCK)
4727       {
4728         if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4729           continue;
4730 
4731         http->error = WSAGetLastError();
4732       }
4733       else if (WSAGetLastError() != http->error &&
4734                WSAGetLastError() != WSAECONNRESET)
4735       {
4736         http->error = WSAGetLastError();
4737 	continue;
4738       }
4739 
4740 #else
4741       if (errno == EINTR)
4742         continue;
4743       else if (errno == EWOULDBLOCK || errno == EAGAIN)
4744       {
4745 	if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4746           continue;
4747         else if (!http->timeout_cb && errno == EAGAIN)
4748 	  continue;
4749 
4750         http->error = errno;
4751       }
4752       else if (errno != http->error && errno != ECONNRESET)
4753       {
4754         http->error = errno;
4755 	continue;
4756       }
4757 #endif /* WIN32 */
4758 
4759       DEBUG_printf(("3http_write: error writing data (%s).",
4760                     strerror(http->error)));
4761 
4762       return (-1);
4763     }
4764 
4765     buffer += bytes;
4766     tbytes += bytes;
4767     length -= (size_t)bytes;
4768   }
4769 
4770 #ifdef DEBUG
4771   http_debug_hex("http_write", buffer - tbytes, (int)tbytes);
4772 #endif /* DEBUG */
4773 
4774   DEBUG_printf(("3http_write: Returning " CUPS_LLFMT ".", CUPS_LLCAST tbytes));
4775 
4776   return (tbytes);
4777 }
4778 
4779 
4780 /*
4781  * 'http_write_chunk()' - Write a chunked buffer.
4782  */
4783 
4784 static ssize_t				/* O - Number bytes written */
http_write_chunk(http_t * http,const char * buffer,size_t length)4785 http_write_chunk(http_t     *http,	/* I - HTTP connection */
4786                  const char *buffer,	/* I - Buffer to write */
4787 		 size_t        length)	/* I - Length of buffer */
4788 {
4789   char		header[16];		/* Chunk header */
4790   ssize_t	bytes;			/* Bytes written */
4791 
4792 
4793   DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4794 
4795  /*
4796   * Write the chunk header, data, and trailer.
4797   */
4798 
4799   snprintf(header, sizeof(header), "%x\r\n", (unsigned)length);
4800   if (http_write(http, header, strlen(header)) < 0)
4801   {
4802     DEBUG_puts("8http_write_chunk: http_write of length failed.");
4803     return (-1);
4804   }
4805 
4806   if ((bytes = http_write(http, buffer, length)) < 0)
4807   {
4808     DEBUG_puts("8http_write_chunk: http_write of buffer failed.");
4809     return (-1);
4810   }
4811 
4812   if (http_write(http, "\r\n", 2) < 0)
4813   {
4814     DEBUG_puts("8http_write_chunk: http_write of CR LF failed.");
4815     return (-1);
4816   }
4817 
4818   return (bytes);
4819 }
4820