1 /*
2  * HTTP routines for CUPS.
3  *
4  * Copyright 2007-2015 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@
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 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@
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 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 in write buffer.
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 UNIX time 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 cupsDoAuthentication() and
770  * httpSetAuthString().  Use httpGetAuthString() to retrieve the
771  * string to use with httpSetField() for the HTTP_FIELD_AUTHORIZATION
772  * 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 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@
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 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@
1350  */
1351 
1352 char *					/* O - Value or 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 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 httpRead@ or @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@
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@
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 httpSetField() to set
2471  * HTTP_FIELD_AUTHORIZATION prior to issuing a HTTP request using httpGet(),
2472  * httpHead(), httpOptions(), httpPost, or httpPut().
2473  *
2474  * @since CUPS 1.3/macOS 10.5@
2475  */
2476 
2477 void
httpSetAuthString(http_t * http,const char * scheme,const char * data)2478 httpSetAuthString(http_t     *http,	/* I - HTTP connection */
2479                   const char *scheme,	/* I - Auth scheme (NULL to clear it) */
2480 		  const char *data)	/* I - Auth data (NULL for none) */
2481 {
2482  /*
2483   * Range check input...
2484   */
2485 
2486   if (!http)
2487     return;
2488 
2489   if (http->authstring && http->authstring != http->_authstring)
2490     free(http->authstring);
2491 
2492   http->authstring = http->_authstring;
2493 
2494   if (scheme)
2495   {
2496    /*
2497     * Set the current authorization string...
2498     */
2499 
2500     size_t len = strlen(scheme) + (data ? strlen(data) + 1 : 0) + 1;
2501     char *temp;
2502 
2503     if (len > sizeof(http->_authstring))
2504     {
2505       if ((temp = malloc(len)) == NULL)
2506         len = sizeof(http->_authstring);
2507       else
2508         http->authstring = temp;
2509     }
2510 
2511     if (data)
2512       snprintf(http->authstring, len, "%s %s", scheme, data);
2513     else
2514       strlcpy(http->authstring, scheme, len);
2515   }
2516   else
2517   {
2518    /*
2519     * Clear the current authorization string...
2520     */
2521 
2522     http->_authstring[0] = '\0';
2523   }
2524 }
2525 
2526 
2527 /*
2528  * 'httpSetCredentials()' - Set the credentials associated with an encrypted
2529  *			    connection.
2530  *
2531  * @since CUPS 1.5/macOS 10.7@
2532  */
2533 
2534 int						/* O - Status of call (0 = success) */
httpSetCredentials(http_t * http,cups_array_t * credentials)2535 httpSetCredentials(http_t	*http,		/* I - HTTP connection */
2536 		   cups_array_t *credentials)	/* I - Array of credentials */
2537 {
2538   if (!http || cupsArrayCount(credentials) < 1)
2539     return (-1);
2540 
2541 #ifdef HAVE_SSL
2542   _httpFreeCredentials(http->tls_credentials);
2543 
2544   http->tls_credentials = _httpCreateCredentials(credentials);
2545 #endif /* HAVE_SSL */
2546 
2547   return (http->tls_credentials ? 0 : -1);
2548 }
2549 
2550 
2551 /*
2552  * 'httpSetCookie()' - Set the cookie value(s).
2553  *
2554  * @since CUPS 1.1.19/macOS 10.3@
2555  */
2556 
2557 void
httpSetCookie(http_t * http,const char * cookie)2558 httpSetCookie(http_t     *http,		/* I - Connection */
2559               const char *cookie)	/* I - Cookie string */
2560 {
2561   if (!http)
2562     return;
2563 
2564   if (http->cookie)
2565     free(http->cookie);
2566 
2567   if (cookie)
2568     http->cookie = strdup(cookie);
2569   else
2570     http->cookie = NULL;
2571 }
2572 
2573 
2574 /*
2575  * 'httpSetDefaultField()' - Set the default value of an HTTP header.
2576  *
2577  * Currently only @code HTTP_FIELD_ACCEPT_ENCODING@, @code HTTP_FIELD_SERVER@,
2578  * and @code HTTP_FIELD_USER_AGENT@ can be set.
2579  *
2580  * @since CUPS 1.7/macOS 10.9@
2581  */
2582 
2583 void
httpSetDefaultField(http_t * http,http_field_t field,const char * value)2584 httpSetDefaultField(http_t       *http,	/* I - HTTP connection */
2585                     http_field_t field,	/* I - Field index */
2586 	            const char   *value)/* I - Value */
2587 {
2588   DEBUG_printf(("httpSetDefaultField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));
2589 
2590   if (!http)
2591     return;
2592 
2593   switch (field)
2594   {
2595     case HTTP_FIELD_ACCEPT_ENCODING :
2596         if (http->default_accept_encoding)
2597           _cupsStrFree(http->default_accept_encoding);
2598 
2599         http->default_accept_encoding = value ? _cupsStrAlloc(value) : NULL;
2600         break;
2601 
2602     case HTTP_FIELD_SERVER :
2603         if (http->default_server)
2604           _cupsStrFree(http->default_server);
2605 
2606         http->default_server = value ? _cupsStrAlloc(value) : NULL;
2607         break;
2608 
2609     case HTTP_FIELD_USER_AGENT :
2610         if (http->default_user_agent)
2611           _cupsStrFree(http->default_user_agent);
2612 
2613         http->default_user_agent = value ? _cupsStrAlloc(value) : NULL;
2614         break;
2615 
2616     default :
2617         DEBUG_puts("1httpSetDefaultField: Ignored.");
2618 	break;
2619   }
2620 }
2621 
2622 
2623 /*
2624  * 'httpSetExpect()' - Set the Expect: header in a request.
2625  *
2626  * Currently only @code HTTP_STATUS_CONTINUE@ is supported for the "expect"
2627  * argument.
2628  *
2629  * @since CUPS 1.2/macOS 10.5@
2630  */
2631 
2632 void
httpSetExpect(http_t * http,http_status_t expect)2633 httpSetExpect(http_t        *http,	/* I - HTTP connection */
2634               http_status_t expect)	/* I - HTTP status to expect
2635               				       (@code HTTP_STATUS_CONTINUE@) */
2636 {
2637   DEBUG_printf(("httpSetExpect(http=%p, expect=%d)", (void *)http, expect));
2638 
2639   if (http)
2640     http->expect = expect;
2641 }
2642 
2643 
2644 /*
2645  * 'httpSetField()' - Set the value of an HTTP header.
2646  */
2647 
2648 void
httpSetField(http_t * http,http_field_t field,const char * value)2649 httpSetField(http_t       *http,	/* I - HTTP connection */
2650              http_field_t field,	/* I - Field index */
2651 	     const char   *value)	/* I - Value */
2652 {
2653   DEBUG_printf(("httpSetField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));
2654 
2655   if (http == NULL ||
2656       field < HTTP_FIELD_ACCEPT_LANGUAGE ||
2657       field >= HTTP_FIELD_MAX ||
2658       value == NULL)
2659     return;
2660 
2661   switch (field)
2662   {
2663     case HTTP_FIELD_ACCEPT_ENCODING :
2664         if (http->accept_encoding)
2665           _cupsStrFree(http->accept_encoding);
2666 
2667         http->accept_encoding = _cupsStrAlloc(value);
2668         break;
2669 
2670     case HTTP_FIELD_ALLOW :
2671         if (http->allow)
2672           _cupsStrFree(http->allow);
2673 
2674         http->allow = _cupsStrAlloc(value);
2675         break;
2676 
2677     case HTTP_FIELD_SERVER :
2678         if (http->server)
2679           _cupsStrFree(http->server);
2680 
2681         http->server = _cupsStrAlloc(value);
2682         break;
2683 
2684     case HTTP_FIELD_WWW_AUTHENTICATE :
2685        /* CUPS STR #4503 - don't override WWW-Authenticate for unknown auth schemes */
2686         if (http->fields[HTTP_FIELD_WWW_AUTHENTICATE][0] &&
2687 	    _cups_strncasecmp(value, "Basic ", 6) &&
2688 	    _cups_strncasecmp(value, "Digest ", 7) &&
2689 	    _cups_strncasecmp(value, "Negotiate ", 10))
2690 	{
2691 	  DEBUG_printf(("1httpSetField: Ignoring unknown auth scheme in \"%s\".", value));
2692           return;
2693 	}
2694 
2695 	/* Fall through to copy */
2696 
2697     default :
2698 	strlcpy(http->fields[field], value, HTTP_MAX_VALUE);
2699 	break;
2700   }
2701 
2702   if (field == HTTP_FIELD_AUTHORIZATION)
2703   {
2704    /*
2705     * Special case for Authorization: as its contents can be
2706     * longer than HTTP_MAX_VALUE
2707     */
2708 
2709     if (http->field_authorization)
2710       free(http->field_authorization);
2711 
2712     http->field_authorization = strdup(value);
2713   }
2714   else if (field == HTTP_FIELD_HOST)
2715   {
2716    /*
2717     * Special-case for Host: as we don't want a trailing "." on the hostname and
2718     * need to bracket IPv6 numeric addresses.
2719     */
2720 
2721     char *ptr = strchr(value, ':');
2722 
2723     if (value[0] != '[' && ptr && strchr(ptr + 1, ':'))
2724     {
2725      /*
2726       * Bracket IPv6 numeric addresses...
2727       *
2728       * This is slightly inefficient (basically copying twice), but is an edge
2729       * case and not worth optimizing...
2730       */
2731 
2732       snprintf(http->fields[HTTP_FIELD_HOST],
2733                sizeof(http->fields[HTTP_FIELD_HOST]), "[%s]", value);
2734     }
2735     else
2736     {
2737      /*
2738       * Check for a trailing dot on the hostname...
2739       */
2740 
2741       ptr = http->fields[HTTP_FIELD_HOST];
2742 
2743       if (*ptr)
2744       {
2745 	ptr += strlen(ptr) - 1;
2746 
2747 	if (*ptr == '.')
2748 	  *ptr = '\0';
2749       }
2750     }
2751   }
2752 #ifdef HAVE_LIBZ
2753   else if (field == HTTP_FIELD_CONTENT_ENCODING &&
2754            http->data_encoding != HTTP_ENCODING_FIELDS)
2755   {
2756     DEBUG_puts("1httpSetField: Calling http_content_coding_start.");
2757     http_content_coding_start(http, value);
2758   }
2759 #endif /* HAVE_LIBZ */
2760 }
2761 
2762 
2763 /*
2764  * 'httpSetKeepAlive()' - Set the current Keep-Alive state of a connection.
2765  *
2766  * @since CUPS 2.0/OS 10.10@
2767  */
2768 
2769 void
httpSetKeepAlive(http_t * http,http_keepalive_t keep_alive)2770 httpSetKeepAlive(
2771     http_t           *http,		/* I - HTTP connection */
2772     http_keepalive_t keep_alive)	/* I - New Keep-Alive value */
2773 {
2774   if (http)
2775     http->keep_alive = keep_alive;
2776 }
2777 
2778 
2779 /*
2780  * 'httpSetLength()' - Set the content-length and content-encoding.
2781  *
2782  * @since CUPS 1.2/macOS 10.5@
2783  */
2784 
2785 void
httpSetLength(http_t * http,size_t length)2786 httpSetLength(http_t *http,		/* I - HTTP connection */
2787               size_t length)		/* I - Length (0 for chunked) */
2788 {
2789   DEBUG_printf(("httpSetLength(http=%p, length=" CUPS_LLFMT ")", (void *)http, CUPS_LLCAST length));
2790 
2791   if (!http)
2792     return;
2793 
2794   if (!length)
2795   {
2796     strlcpy(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked",
2797             HTTP_MAX_VALUE);
2798     http->fields[HTTP_FIELD_CONTENT_LENGTH][0] = '\0';
2799   }
2800   else
2801   {
2802     http->fields[HTTP_FIELD_TRANSFER_ENCODING][0] = '\0';
2803     snprintf(http->fields[HTTP_FIELD_CONTENT_LENGTH], HTTP_MAX_VALUE,
2804              CUPS_LLFMT, CUPS_LLCAST length);
2805   }
2806 }
2807 
2808 
2809 /*
2810  * 'httpSetTimeout()' - Set read/write timeouts and an optional callback.
2811  *
2812  * The optional timeout callback receives both the HTTP connection and a user
2813  * data pointer and must return 1 to continue or 0 to error (time) out.
2814  *
2815  * @since CUPS 1.5/macOS 10.7@
2816  */
2817 
2818 void
httpSetTimeout(http_t * http,double timeout,http_timeout_cb_t cb,void * user_data)2819 httpSetTimeout(
2820     http_t            *http,		/* I - HTTP connection */
2821     double            timeout,		/* I - Number of seconds for timeout,
2822                                                must be greater than 0 */
2823     http_timeout_cb_t cb,		/* I - Callback function or NULL */
2824     void              *user_data)	/* I - User data pointer */
2825 {
2826   if (!http || timeout <= 0.0)
2827     return;
2828 
2829   http->timeout_cb    = cb;
2830   http->timeout_data  = user_data;
2831   http->timeout_value = timeout;
2832 
2833   if (http->fd >= 0)
2834     http_set_timeout(http->fd, timeout);
2835 
2836   http_set_wait(http);
2837 }
2838 
2839 
2840 /*
2841  * 'httpShutdown()' - Shutdown one side of an HTTP connection.
2842  *
2843  * @since CUPS 2.0/OS 10.10@
2844  */
2845 
2846 void
httpShutdown(http_t * http)2847 httpShutdown(http_t *http)		/* I - HTTP connection */
2848 {
2849   if (!http || http->fd < 0)
2850     return;
2851 
2852 #ifdef HAVE_SSL
2853   if (http->tls)
2854     _httpTLSStop(http);
2855 #endif /* HAVE_SSL */
2856 
2857 #ifdef WIN32
2858   shutdown(http->fd, SD_RECEIVE);	/* Microsoft-ism... */
2859 #else
2860   shutdown(http->fd, SHUT_RD);
2861 #endif /* WIN32 */
2862 }
2863 
2864 
2865 /*
2866  * 'httpTrace()' - Send an TRACE request to the server.
2867  */
2868 
2869 int					/* O - Status of call (0 = success) */
httpTrace(http_t * http,const char * uri)2870 httpTrace(http_t     *http,		/* I - HTTP connection */
2871           const char *uri)		/* I - URI for trace */
2872 {
2873   return (http_send(http, HTTP_STATE_TRACE, uri));
2874 }
2875 
2876 
2877 /*
2878  * '_httpUpdate()' - Update the current HTTP status for incoming data.
2879  *
2880  * Note: Unlike httpUpdate(), this function does not flush pending write data
2881  * and only retrieves a single status line from the HTTP connection.
2882  */
2883 
2884 int					/* O - 1 to continue, 0 to stop */
_httpUpdate(http_t * http,http_status_t * status)2885 _httpUpdate(http_t        *http,	/* I - HTTP connection */
2886             http_status_t *status)	/* O - Current HTTP status */
2887 {
2888   char		line[32768],		/* Line from connection... */
2889 		*value;			/* Pointer to value on line */
2890   http_field_t	field;			/* Field index */
2891   int		major, minor;		/* HTTP version numbers */
2892 
2893 
2894   DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", (void *)http, (void *)status, httpStateString(http->state)));
2895 
2896  /*
2897   * Grab a single line from the connection...
2898   */
2899 
2900   if (!httpGets(line, sizeof(line), http))
2901   {
2902     *status = HTTP_STATUS_ERROR;
2903     return (0);
2904   }
2905 
2906   DEBUG_printf(("2_httpUpdate: Got \"%s\"", line));
2907 
2908   if (line[0] == '\0')
2909   {
2910    /*
2911     * Blank line means the start of the data section (if any).  Return
2912     * the result code, too...
2913     *
2914     * If we get status 100 (HTTP_STATUS_CONTINUE), then we *don't* change
2915     * states.  Instead, we just return HTTP_STATUS_CONTINUE to the caller and
2916     * keep on tryin'...
2917     */
2918 
2919     if (http->status == HTTP_STATUS_CONTINUE)
2920     {
2921       *status = http->status;
2922       return (0);
2923     }
2924 
2925     if (http->status < HTTP_STATUS_BAD_REQUEST)
2926       http->digest_tries = 0;
2927 
2928 #ifdef HAVE_SSL
2929     if (http->status == HTTP_STATUS_SWITCHING_PROTOCOLS && !http->tls)
2930     {
2931       if (_httpTLSStart(http) != 0)
2932       {
2933         httpAddrClose(NULL, http->fd);
2934 
2935 	*status = http->status = HTTP_STATUS_ERROR;
2936 	return (0);
2937       }
2938 
2939       *status = HTTP_STATUS_CONTINUE;
2940       return (0);
2941     }
2942 #endif /* HAVE_SSL */
2943 
2944     if (http_set_length(http) < 0)
2945     {
2946       DEBUG_puts("1_httpUpdate: Bad Content-Length.");
2947       http->error  = EINVAL;
2948       http->status = *status = HTTP_STATUS_ERROR;
2949       return (0);
2950     }
2951 
2952     switch (http->state)
2953     {
2954       case HTTP_STATE_GET :
2955       case HTTP_STATE_POST :
2956       case HTTP_STATE_POST_RECV :
2957       case HTTP_STATE_PUT :
2958 	  http->state ++;
2959 
2960 	  DEBUG_printf(("1_httpUpdate: Set state to %s.",
2961 	                httpStateString(http->state)));
2962 
2963       case HTTP_STATE_POST_SEND :
2964       case HTTP_STATE_HEAD :
2965 	  break;
2966 
2967       default :
2968 	  http->state = HTTP_STATE_WAITING;
2969 
2970 	  DEBUG_puts("1_httpUpdate: Reset state to HTTP_STATE_WAITING.");
2971 	  break;
2972     }
2973 
2974 #ifdef HAVE_LIBZ
2975     DEBUG_puts("1_httpUpdate: Calling http_content_coding_start.");
2976     http_content_coding_start(http,
2977                               httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
2978 #endif /* HAVE_LIBZ */
2979 
2980     *status = http->status;
2981     return (0);
2982   }
2983   else if (!strncmp(line, "HTTP/", 5) && http->mode == _HTTP_MODE_CLIENT)
2984   {
2985    /*
2986     * Got the beginning of a response...
2987     */
2988 
2989     int	intstatus;			/* Status value as an integer */
2990 
2991     if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &intstatus) != 3)
2992     {
2993       *status = http->status = HTTP_STATUS_ERROR;
2994       return (0);
2995     }
2996 
2997     httpClearFields(http);
2998 
2999     http->version = (http_version_t)(major * 100 + minor);
3000     *status       = http->status = (http_status_t)intstatus;
3001   }
3002   else if ((value = strchr(line, ':')) != NULL)
3003   {
3004    /*
3005     * Got a value...
3006     */
3007 
3008     *value++ = '\0';
3009     while (_cups_isspace(*value))
3010       value ++;
3011 
3012     DEBUG_printf(("1_httpUpdate: Header %s: %s", line, value));
3013 
3014    /*
3015     * Be tolerants of servers that send unknown attribute fields...
3016     */
3017 
3018     if (!_cups_strcasecmp(line, "expect"))
3019     {
3020      /*
3021       * "Expect: 100-continue" or similar...
3022       */
3023 
3024       http->expect = (http_status_t)atoi(value);
3025     }
3026     else if (!_cups_strcasecmp(line, "cookie"))
3027     {
3028      /*
3029       * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
3030       */
3031 
3032       httpSetCookie(http, value);
3033     }
3034     else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN)
3035       httpSetField(http, field, value);
3036 #ifdef DEBUG
3037     else
3038       DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line));
3039 #endif /* DEBUG */
3040   }
3041   else
3042   {
3043     DEBUG_printf(("1_httpUpdate: Bad response line \"%s\"!", line));
3044     http->error  = EINVAL;
3045     http->status = *status = HTTP_STATUS_ERROR;
3046     return (0);
3047   }
3048 
3049   return (1);
3050 }
3051 
3052 
3053 /*
3054  * 'httpUpdate()' - Update the current HTTP state for incoming data.
3055  */
3056 
3057 http_status_t				/* O - HTTP status */
httpUpdate(http_t * http)3058 httpUpdate(http_t *http)		/* I - HTTP connection */
3059 {
3060   http_status_t	status;			/* Request status */
3061 
3062 
3063   DEBUG_printf(("httpUpdate(http=%p), state=%s", (void *)http, httpStateString(http->state)));
3064 
3065  /*
3066   * Flush pending data, if any...
3067   */
3068 
3069   if (http->wused)
3070   {
3071     DEBUG_puts("2httpUpdate: flushing buffer...");
3072 
3073     if (httpFlushWrite(http) < 0)
3074       return (HTTP_STATUS_ERROR);
3075   }
3076 
3077  /*
3078   * If we haven't issued any commands, then there is nothing to "update"...
3079   */
3080 
3081   if (http->state == HTTP_STATE_WAITING)
3082     return (HTTP_STATUS_CONTINUE);
3083 
3084  /*
3085   * Grab all of the lines we can from the connection...
3086   */
3087 
3088   while (_httpUpdate(http, &status));
3089 
3090  /*
3091   * See if there was an error...
3092   */
3093 
3094   if (http->error == EPIPE && http->status > HTTP_STATUS_CONTINUE)
3095   {
3096     DEBUG_printf(("1httpUpdate: Returning status %d...", http->status));
3097     return (http->status);
3098   }
3099 
3100   if (http->error)
3101   {
3102     DEBUG_printf(("1httpUpdate: socket error %d - %s", http->error,
3103                   strerror(http->error)));
3104     http->status = HTTP_STATUS_ERROR;
3105     return (HTTP_STATUS_ERROR);
3106   }
3107 
3108  /*
3109   * Return the current status...
3110   */
3111 
3112   return (status);
3113 }
3114 
3115 
3116 /*
3117  * '_httpWait()' - Wait for data available on a connection (no flush).
3118  */
3119 
3120 int					/* O - 1 if data is available, 0 otherwise */
_httpWait(http_t * http,int msec,int usessl)3121 _httpWait(http_t *http,			/* I - HTTP connection */
3122           int    msec,			/* I - Milliseconds to wait */
3123 	  int    usessl)		/* I - Use SSL context? */
3124 {
3125 #ifdef HAVE_POLL
3126   struct pollfd		pfd;		/* Polled file descriptor */
3127 #else
3128   fd_set		input_set;	/* select() input set */
3129   struct timeval	timeout;	/* Timeout */
3130 #endif /* HAVE_POLL */
3131   int			nfds;		/* Result from select()/poll() */
3132 
3133 
3134   DEBUG_printf(("4_httpWait(http=%p, msec=%d, usessl=%d)", (void *)http, msec, usessl));
3135 
3136   if (http->fd < 0)
3137   {
3138     DEBUG_printf(("5_httpWait: Returning 0 since fd=%d", http->fd));
3139     return (0);
3140   }
3141 
3142  /*
3143   * Check the SSL/TLS buffers for data first...
3144   */
3145 
3146 #ifdef HAVE_SSL
3147   if (http->tls && _httpTLSPending(http))
3148   {
3149     DEBUG_puts("5_httpWait: Return 1 since there is pending TLS data.");
3150     return (1);
3151   }
3152 #endif /* HAVE_SSL */
3153 
3154  /*
3155   * Then try doing a select() or poll() to poll the socket...
3156   */
3157 
3158 #ifdef HAVE_POLL
3159   pfd.fd     = http->fd;
3160   pfd.events = POLLIN;
3161 
3162   do
3163   {
3164     nfds = poll(&pfd, 1, msec);
3165   }
3166   while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
3167 
3168 #else
3169   do
3170   {
3171     FD_ZERO(&input_set);
3172     FD_SET(http->fd, &input_set);
3173 
3174     DEBUG_printf(("6_httpWait: msec=%d, http->fd=%d", msec, http->fd));
3175 
3176     if (msec >= 0)
3177     {
3178       timeout.tv_sec  = msec / 1000;
3179       timeout.tv_usec = (msec % 1000) * 1000;
3180 
3181       nfds = select(http->fd + 1, &input_set, NULL, NULL, &timeout);
3182     }
3183     else
3184       nfds = select(http->fd + 1, &input_set, NULL, NULL, NULL);
3185 
3186     DEBUG_printf(("6_httpWait: select() returned %d...", nfds));
3187   }
3188 #  ifdef WIN32
3189   while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
3190                       WSAGetLastError() == WSAEWOULDBLOCK));
3191 #  else
3192   while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
3193 #  endif /* WIN32 */
3194 #endif /* HAVE_POLL */
3195 
3196   DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds,
3197                 errno));
3198 
3199   return (nfds > 0);
3200 }
3201 
3202 
3203 /*
3204  * 'httpWait()' - Wait for data available on a connection.
3205  *
3206  * @since CUPS 1.1.19/macOS 10.3@
3207  */
3208 
3209 int					/* O - 1 if data is available, 0 otherwise */
httpWait(http_t * http,int msec)3210 httpWait(http_t *http,			/* I - HTTP connection */
3211          int    msec)			/* I - Milliseconds to wait */
3212 {
3213  /*
3214   * First see if there is data in the buffer...
3215   */
3216 
3217   DEBUG_printf(("2httpWait(http=%p, msec=%d)", (void *)http, msec));
3218 
3219   if (http == NULL)
3220     return (0);
3221 
3222   if (http->used)
3223   {
3224     DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
3225     return (1);
3226   }
3227 
3228 #ifdef HAVE_LIBZ
3229   if (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in > 0)
3230   {
3231     DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
3232     return (1);
3233   }
3234 #endif /* HAVE_LIBZ */
3235 
3236  /*
3237   * Flush pending data, if any...
3238   */
3239 
3240   if (http->wused)
3241   {
3242     DEBUG_puts("3httpWait: Flushing write buffer.");
3243 
3244     if (httpFlushWrite(http) < 0)
3245       return (0);
3246   }
3247 
3248  /*
3249   * If not, check the SSL/TLS buffers and do a select() on the connection...
3250   */
3251 
3252   return (_httpWait(http, msec, 1));
3253 }
3254 
3255 
3256 /*
3257  * 'httpWrite()' - Write data to a HTTP connection.
3258  *
3259  * This function is deprecated. Use the httpWrite2() function which can
3260  * write more than 2GB of data.
3261  *
3262  * @deprecated@
3263  */
3264 
3265 int					/* O - Number of bytes written */
httpWrite(http_t * http,const char * buffer,int length)3266 httpWrite(http_t     *http,		/* I - HTTP connection */
3267           const char *buffer,		/* I - Buffer for data */
3268 	  int        length)		/* I - Number of bytes to write */
3269 {
3270   return ((int)httpWrite2(http, buffer, (size_t)length));
3271 }
3272 
3273 
3274 /*
3275  * 'httpWrite2()' - Write data to a HTTP connection.
3276  *
3277  * @since CUPS 1.2/macOS 10.5@
3278  */
3279 
3280 ssize_t					/* O - Number of bytes written */
httpWrite2(http_t * http,const char * buffer,size_t length)3281 httpWrite2(http_t     *http,		/* I - HTTP connection */
3282            const char *buffer,		/* I - Buffer for data */
3283 	   size_t     length)		/* I - Number of bytes to write */
3284 {
3285   ssize_t	bytes;			/* Bytes written */
3286 
3287 
3288   DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
3289 
3290  /*
3291   * Range check input...
3292   */
3293 
3294   if (!http || !buffer)
3295   {
3296     DEBUG_puts("1httpWrite2: Returning -1 due to bad input.");
3297     return (-1);
3298   }
3299 
3300  /*
3301   * Mark activity on the connection...
3302   */
3303 
3304   http->activity = time(NULL);
3305 
3306  /*
3307   * Buffer small writes for better performance...
3308   */
3309 
3310 #ifdef HAVE_LIBZ
3311   if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
3312   {
3313     DEBUG_printf(("1httpWrite2: http->coding=%d", http->coding));
3314 
3315     if (length == 0)
3316     {
3317       http_content_coding_finish(http);
3318       bytes = 0;
3319     }
3320     else
3321     {
3322       size_t	slen;			/* Bytes to write */
3323       ssize_t	sret;			/* Bytes written */
3324 
3325       http->stream.next_in   = (Bytef *)buffer;
3326       http->stream.avail_in  = (uInt)length;
3327 
3328       while (deflate(&(http->stream), Z_NO_FLUSH) == Z_OK)
3329       {
3330         DEBUG_printf(("1httpWrite2: avail_out=%d", http->stream.avail_out));
3331 
3332         if (http->stream.avail_out > 0)
3333 	  continue;
3334 
3335 	slen = _HTTP_MAX_SBUFFER - http->stream.avail_out;
3336 
3337         DEBUG_printf(("1httpWrite2: Writing intermediate chunk, len=%d", (int)slen));
3338 
3339 	if (slen > 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
3340 	  sret = http_write_chunk(http, (char *)http->sbuffer, slen);
3341 	else if (slen > 0)
3342 	  sret = http_write(http, (char *)http->sbuffer, slen);
3343 	else
3344 	  sret = 0;
3345 
3346         if (sret < 0)
3347 	{
3348 	  DEBUG_puts("1httpWrite2: Unable to write, returning -1.");
3349 	  return (-1);
3350 	}
3351 
3352 	http->stream.next_out  = (Bytef *)http->sbuffer;
3353 	http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER;
3354       }
3355 
3356       bytes = (ssize_t)length;
3357     }
3358   }
3359   else
3360 #endif /* HAVE_LIBZ */
3361   if (length > 0)
3362   {
3363     if (http->wused && (length + (size_t)http->wused) > sizeof(http->wbuffer))
3364     {
3365       DEBUG_printf(("2httpWrite2: Flushing buffer (wused=%d, length="
3366                     CUPS_LLFMT ")", http->wused, CUPS_LLCAST length));
3367 
3368       httpFlushWrite(http);
3369     }
3370 
3371     if ((length + (size_t)http->wused) <= sizeof(http->wbuffer) && length < sizeof(http->wbuffer))
3372     {
3373      /*
3374       * Write to buffer...
3375       */
3376 
3377       DEBUG_printf(("2httpWrite2: Copying " CUPS_LLFMT " bytes to wbuffer...",
3378                     CUPS_LLCAST length));
3379 
3380       memcpy(http->wbuffer + http->wused, buffer, length);
3381       http->wused += (int)length;
3382       bytes = (ssize_t)length;
3383     }
3384     else
3385     {
3386      /*
3387       * Otherwise write the data directly...
3388       */
3389 
3390       DEBUG_printf(("2httpWrite2: Writing " CUPS_LLFMT " bytes to socket...",
3391                     CUPS_LLCAST length));
3392 
3393       if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3394 	bytes = (ssize_t)http_write_chunk(http, buffer, length);
3395       else
3396 	bytes = (ssize_t)http_write(http, buffer, length);
3397 
3398       DEBUG_printf(("2httpWrite2: Wrote " CUPS_LLFMT " bytes...",
3399                     CUPS_LLCAST bytes));
3400     }
3401 
3402     if (http->data_encoding == HTTP_ENCODING_LENGTH)
3403       http->data_remaining -= bytes;
3404   }
3405   else
3406     bytes = 0;
3407 
3408  /*
3409   * Handle end-of-request processing...
3410   */
3411 
3412   if ((http->data_encoding == HTTP_ENCODING_CHUNKED && length == 0) ||
3413       (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0))
3414   {
3415    /*
3416     * Finished with the transfer; unless we are sending POST or PUT
3417     * data, go idle...
3418     */
3419 
3420 #ifdef HAVE_LIBZ
3421     if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
3422       http_content_coding_finish(http);
3423 #endif /* HAVE_LIBZ */
3424 
3425     if (http->wused)
3426     {
3427       if (httpFlushWrite(http) < 0)
3428         return (-1);
3429     }
3430 
3431     if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3432     {
3433      /*
3434       * Send a 0-length chunk at the end of the request...
3435       */
3436 
3437       http_write(http, "0\r\n\r\n", 5);
3438 
3439      /*
3440       * Reset the data state...
3441       */
3442 
3443       http->data_encoding  = HTTP_ENCODING_FIELDS;
3444       http->data_remaining = 0;
3445     }
3446 
3447     if (http->state == HTTP_STATE_POST_RECV)
3448       http->state ++;
3449     else if (http->state == HTTP_STATE_POST_SEND ||
3450              http->state == HTTP_STATE_GET_SEND)
3451       http->state = HTTP_STATE_WAITING;
3452     else
3453       http->state = HTTP_STATE_STATUS;
3454 
3455     DEBUG_printf(("2httpWrite2: Changed state to %s.",
3456 		  httpStateString(http->state)));
3457   }
3458 
3459   DEBUG_printf(("1httpWrite2: Returning " CUPS_LLFMT ".", CUPS_LLCAST bytes));
3460 
3461   return (bytes);
3462 }
3463 
3464 
3465 /*
3466  * 'httpWriteResponse()' - Write a HTTP response to a client connection.
3467  *
3468  * @since CUPS 1.7/macOS 10.9@
3469  */
3470 
3471 int					/* O - 0 on success, -1 on error */
httpWriteResponse(http_t * http,http_status_t status)3472 httpWriteResponse(http_t        *http,	/* I - HTTP connection */
3473 		  http_status_t status)	/* I - Status code */
3474 {
3475   http_encoding_t	old_encoding;	/* Old data_encoding value */
3476   off_t			old_remaining;	/* Old data_remaining value */
3477 
3478 
3479  /*
3480   * Range check input...
3481   */
3482 
3483   DEBUG_printf(("httpWriteResponse(http=%p, status=%d)", (void *)http, status));
3484 
3485   if (!http || status < HTTP_STATUS_CONTINUE)
3486   {
3487     DEBUG_puts("1httpWriteResponse: Bad input.");
3488     return (-1);
3489   }
3490 
3491  /*
3492   * Set the various standard fields if they aren't already...
3493   */
3494 
3495   if (!http->fields[HTTP_FIELD_DATE][0])
3496     httpSetField(http, HTTP_FIELD_DATE, httpGetDateString(time(NULL)));
3497 
3498   if (status >= HTTP_STATUS_BAD_REQUEST && http->keep_alive)
3499   {
3500     http->keep_alive = HTTP_KEEPALIVE_OFF;
3501     httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "");
3502   }
3503 
3504   if (http->version == HTTP_VERSION_1_1)
3505   {
3506     if (!http->fields[HTTP_FIELD_CONNECTION][0])
3507     {
3508       if (http->keep_alive)
3509 	httpSetField(http, HTTP_FIELD_CONNECTION, "Keep-Alive");
3510       else
3511 	httpSetField(http, HTTP_FIELD_CONNECTION, "close");
3512     }
3513 
3514     if (http->keep_alive && !http->fields[HTTP_FIELD_KEEP_ALIVE][0])
3515       httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "timeout=10");
3516   }
3517 
3518 #ifdef HAVE_SSL
3519   if (status == HTTP_STATUS_UPGRADE_REQUIRED ||
3520       status == HTTP_STATUS_SWITCHING_PROTOCOLS)
3521   {
3522     if (!http->fields[HTTP_FIELD_CONNECTION][0])
3523       httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
3524 
3525     if (!http->fields[HTTP_FIELD_UPGRADE][0])
3526       httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
3527 
3528     if (!http->fields[HTTP_FIELD_CONTENT_LENGTH][0])
3529       httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "0");
3530   }
3531 #endif /* HAVE_SSL */
3532 
3533   if (!http->server)
3534     httpSetField(http, HTTP_FIELD_SERVER,
3535                  http->default_server ? http->default_server : CUPS_MINIMAL);
3536 
3537  /*
3538   * Set the Accept-Encoding field if it isn't already...
3539   */
3540 
3541   if (!http->accept_encoding)
3542     httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING,
3543                  http->default_accept_encoding ? http->default_accept_encoding :
3544 #ifdef HAVE_LIBZ
3545                                                  "gzip, deflate, identity");
3546 #else
3547                                                  "identity");
3548 #endif /* HAVE_LIBZ */
3549 
3550  /*
3551   * Send the response header...
3552   */
3553 
3554   old_encoding        = http->data_encoding;
3555   old_remaining       = http->data_remaining;
3556   http->data_encoding = HTTP_ENCODING_FIELDS;
3557 
3558   if (httpPrintf(http, "HTTP/%d.%d %d %s\r\n", http->version / 100,
3559                  http->version % 100, (int)status, httpStatus(status)) < 0)
3560   {
3561     http->status = HTTP_STATUS_ERROR;
3562     return (-1);
3563   }
3564 
3565   if (status != HTTP_STATUS_CONTINUE)
3566   {
3567    /*
3568     * 100 Continue doesn't have the rest of the response headers...
3569     */
3570 
3571     int		i;			/* Looping var */
3572     const char	*value;			/* Field value */
3573 
3574     for (i = 0; i < HTTP_FIELD_MAX; i ++)
3575     {
3576       if ((value = httpGetField(http, i)) != NULL && *value)
3577       {
3578 	if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
3579 	{
3580 	  http->status = HTTP_STATUS_ERROR;
3581 	  return (-1);
3582 	}
3583       }
3584     }
3585 
3586     if (http->cookie)
3587     {
3588       if (strchr(http->cookie, ';'))
3589       {
3590         if (httpPrintf(http, "Set-Cookie: %s\r\n", http->cookie) < 1)
3591 	{
3592 	  http->status = HTTP_STATUS_ERROR;
3593 	  return (-1);
3594 	}
3595       }
3596       else if (httpPrintf(http, "Set-Cookie: %s; path=/; httponly;%s\r\n", http->cookie, http->tls ? " secure;" : "") < 1)
3597       {
3598 	http->status = HTTP_STATUS_ERROR;
3599 	return (-1);
3600       }
3601     }
3602 
3603    /*
3604     * "Click-jacking" defense (STR #4492)...
3605     */
3606 
3607     if (httpPrintf(http, "X-Frame-Options: DENY\r\n"
3608                          "Content-Security-Policy: frame-ancestors 'none'\r\n") < 1)
3609     {
3610       http->status = HTTP_STATUS_ERROR;
3611       return (-1);
3612     }
3613   }
3614 
3615   if (httpWrite2(http, "\r\n", 2) < 2)
3616   {
3617     http->status = HTTP_STATUS_ERROR;
3618     return (-1);
3619   }
3620 
3621   if (httpFlushWrite(http) < 0)
3622   {
3623     http->status = HTTP_STATUS_ERROR;
3624     return (-1);
3625   }
3626 
3627   if (status == HTTP_STATUS_CONTINUE ||
3628       status == HTTP_STATUS_SWITCHING_PROTOCOLS)
3629   {
3630    /*
3631     * Restore the old data_encoding and data_length values...
3632     */
3633 
3634     http->data_encoding  = old_encoding;
3635     http->data_remaining = old_remaining;
3636 
3637     if (old_remaining <= INT_MAX)
3638       http->_data_remaining = (int)old_remaining;
3639     else
3640       http->_data_remaining = INT_MAX;
3641   }
3642   else if (http->state == HTTP_STATE_OPTIONS ||
3643            http->state == HTTP_STATE_HEAD ||
3644            http->state == HTTP_STATE_PUT ||
3645            http->state == HTTP_STATE_TRACE ||
3646            http->state == HTTP_STATE_CONNECT ||
3647            http->state == HTTP_STATE_STATUS)
3648   {
3649     DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, "
3650                   "was %s.", httpStateString(http->state)));
3651     http->state = HTTP_STATE_WAITING;
3652   }
3653   else
3654   {
3655    /*
3656     * Force data_encoding and data_length to be set according to the response
3657     * headers...
3658     */
3659 
3660     http_set_length(http);
3661 
3662     if (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0)
3663     {
3664       DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, "
3665                     "was %s.", httpStateString(http->state)));
3666       http->state = HTTP_STATE_WAITING;
3667       return (0);
3668     }
3669 
3670     if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_GET)
3671       http->state ++;
3672 
3673 #ifdef HAVE_LIBZ
3674    /*
3675     * Then start any content encoding...
3676     */
3677 
3678     DEBUG_puts("1httpWriteResponse: Calling http_content_coding_start.");
3679     http_content_coding_start(http,
3680 			      httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
3681 #endif /* HAVE_LIBZ */
3682 
3683   }
3684 
3685   return (0);
3686 }
3687 
3688 
3689 #ifdef HAVE_LIBZ
3690 /*
3691  * 'http_content_coding_finish()' - Finish doing any content encoding.
3692  */
3693 
3694 static void
http_content_coding_finish(http_t * http)3695 http_content_coding_finish(
3696     http_t *http)			/* I - HTTP connection */
3697 {
3698   int		zerr;			/* Compression status */
3699   Byte		dummy[1];		/* Dummy read buffer */
3700   size_t	bytes;			/* Number of bytes to write */
3701 
3702 
3703   DEBUG_printf(("http_content_coding_finish(http=%p)", (void *)http));
3704   DEBUG_printf(("1http_content_coding_finishing: http->coding=%d", http->coding));
3705 
3706   switch (http->coding)
3707   {
3708     case _HTTP_CODING_DEFLATE :
3709     case _HTTP_CODING_GZIP :
3710         http->stream.next_in  = dummy;
3711         http->stream.avail_in = 0;
3712 
3713         do
3714         {
3715           zerr  = deflate(&(http->stream), Z_FINISH);
3716 	  bytes = _HTTP_MAX_SBUFFER - http->stream.avail_out;
3717 
3718           if (bytes > 0)
3719 	  {
3720 	    DEBUG_printf(("1http_content_coding_finish: Writing trailing chunk, len=%d", (int)bytes));
3721 
3722 	    if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3723 	      http_write_chunk(http, (char *)http->sbuffer, bytes);
3724 	    else
3725 	      http_write(http, (char *)http->sbuffer, bytes);
3726           }
3727 
3728           http->stream.next_out  = (Bytef *)http->sbuffer;
3729           http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER;
3730 	}
3731         while (zerr == Z_OK);
3732 
3733         deflateEnd(&(http->stream));
3734 
3735         free(http->sbuffer);
3736         http->sbuffer = NULL;
3737 
3738         if (http->wused)
3739           httpFlushWrite(http);
3740         break;
3741 
3742     case _HTTP_CODING_INFLATE :
3743     case _HTTP_CODING_GUNZIP :
3744         inflateEnd(&(http->stream));
3745         free(http->sbuffer);
3746         http->sbuffer = NULL;
3747         break;
3748 
3749     default :
3750         break;
3751   }
3752 
3753   http->coding = _HTTP_CODING_IDENTITY;
3754 }
3755 
3756 
3757 /*
3758  * 'http_content_coding_start()' - Start doing content encoding.
3759  */
3760 
3761 static void
http_content_coding_start(http_t * http,const char * value)3762 http_content_coding_start(
3763     http_t     *http,			/* I - HTTP connection */
3764     const char *value)			/* I - Value of Content-Encoding */
3765 {
3766   int			zerr;		/* Error/status */
3767   _http_coding_t	coding;		/* Content coding value */
3768 
3769 
3770   DEBUG_printf(("http_content_coding_start(http=%p, value=\"%s\")", (void *)http, value));
3771 
3772   if (http->coding != _HTTP_CODING_IDENTITY)
3773   {
3774     DEBUG_printf(("1http_content_coding_start: http->coding already %d.",
3775                   http->coding));
3776     return;
3777   }
3778   else if (!strcmp(value, "x-gzip") || !strcmp(value, "gzip"))
3779   {
3780     if (http->state == HTTP_STATE_GET_SEND ||
3781         http->state == HTTP_STATE_POST_SEND)
3782       coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_GZIP :
3783                                                  _HTTP_CODING_GUNZIP;
3784     else if (http->state == HTTP_STATE_POST_RECV ||
3785              http->state == HTTP_STATE_PUT_RECV)
3786       coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_GZIP :
3787                                                  _HTTP_CODING_GUNZIP;
3788     else
3789     {
3790       DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3791       return;
3792     }
3793   }
3794   else if (!strcmp(value, "x-deflate") || !strcmp(value, "deflate"))
3795   {
3796     if (http->state == HTTP_STATE_GET_SEND ||
3797         http->state == HTTP_STATE_POST_SEND)
3798       coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_DEFLATE :
3799                                                  _HTTP_CODING_INFLATE;
3800     else if (http->state == HTTP_STATE_POST_RECV ||
3801              http->state == HTTP_STATE_PUT_RECV)
3802       coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_DEFLATE :
3803                                                  _HTTP_CODING_INFLATE;
3804     else
3805     {
3806       DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3807       return;
3808     }
3809   }
3810   else
3811   {
3812     DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3813     return;
3814   }
3815 
3816   memset(&(http->stream), 0, sizeof(http->stream));
3817 
3818   switch (coding)
3819   {
3820     case _HTTP_CODING_DEFLATE :
3821     case _HTTP_CODING_GZIP :
3822         if (http->wused)
3823           httpFlushWrite(http);
3824 
3825         if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL)
3826         {
3827           http->status = HTTP_STATUS_ERROR;
3828           http->error  = errno;
3829           return;
3830         }
3831 
3832        /*
3833         * Window size for compression is 11 bits - optimal based on PWG Raster
3834         * sample files on pwg.org.  -11 is raw deflate, 27 is gzip, per ZLIB
3835         * documentation.
3836         */
3837 
3838         if ((zerr = deflateInit2(&(http->stream), Z_DEFAULT_COMPRESSION,
3839                                  Z_DEFLATED,
3840 				 coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7,
3841 				 Z_DEFAULT_STRATEGY)) < Z_OK)
3842         {
3843           http->status = HTTP_STATUS_ERROR;
3844           http->error  = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
3845           return;
3846         }
3847 
3848 	http->stream.next_out  = (Bytef *)http->sbuffer;
3849 	http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER;
3850         break;
3851 
3852     case _HTTP_CODING_INFLATE :
3853     case _HTTP_CODING_GUNZIP :
3854         if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL)
3855         {
3856           http->status = HTTP_STATUS_ERROR;
3857           http->error  = errno;
3858           return;
3859         }
3860 
3861        /*
3862         * Window size for decompression is up to 15 bits (maximum supported).
3863         * -15 is raw inflate, 31 is gunzip, per ZLIB documentation.
3864         */
3865 
3866         if ((zerr = inflateInit2(&(http->stream),
3867                                  coding == _HTTP_CODING_INFLATE ? -15 : 31))
3868 		< Z_OK)
3869         {
3870           free(http->sbuffer);
3871           http->sbuffer = NULL;
3872           http->status  = HTTP_STATUS_ERROR;
3873           http->error   = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
3874           return;
3875         }
3876 
3877         http->stream.avail_in = 0;
3878         http->stream.next_in  = http->sbuffer;
3879         break;
3880 
3881     default :
3882         break;
3883   }
3884 
3885   http->coding = coding;
3886 
3887   DEBUG_printf(("1http_content_coding_start: http->coding now %d.",
3888 		http->coding));
3889 }
3890 #endif /* HAVE_LIBZ */
3891 
3892 
3893 /*
3894  * 'http_create()' - Create an unconnected HTTP connection.
3895  */
3896 
3897 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)3898 http_create(
3899     const char        *host,		/* I - Hostname */
3900     int               port,		/* I - Port number */
3901     http_addrlist_t   *addrlist,	/* I - Address list or NULL */
3902     int               family,		/* I - Address family or AF_UNSPEC */
3903     http_encryption_t encryption,	/* I - Encryption to use */
3904     int               blocking,		/* I - 1 for blocking mode */
3905     _http_mode_t      mode)		/* I - _HTTP_MODE_CLIENT or _SERVER */
3906 {
3907   http_t	*http;			/* New HTTP connection */
3908   char		service[255];		/* Service name */
3909   http_addrlist_t *myaddrlist = NULL;	/* My address list */
3910 
3911 
3912   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));
3913 
3914   if (!host && mode == _HTTP_MODE_CLIENT)
3915     return (NULL);
3916 
3917   httpInitialize();
3918 
3919  /*
3920   * Lookup the host...
3921   */
3922 
3923   if (addrlist)
3924   {
3925     myaddrlist = httpAddrCopyList(addrlist);
3926   }
3927   else
3928   {
3929     snprintf(service, sizeof(service), "%d", port);
3930 
3931     myaddrlist = httpAddrGetList(host, family, service);
3932   }
3933 
3934   if (!myaddrlist)
3935     return (NULL);
3936 
3937  /*
3938   * Allocate memory for the structure...
3939   */
3940 
3941   if ((http = calloc(sizeof(http_t), 1)) == NULL)
3942   {
3943     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
3944     httpAddrFreeList(addrlist);
3945     return (NULL);
3946   }
3947 
3948  /*
3949   * Initialize the HTTP data...
3950   */
3951 
3952   http->mode     = mode;
3953   http->activity = time(NULL);
3954   http->addrlist = myaddrlist;
3955   http->blocking = blocking;
3956   http->fd       = -1;
3957 #ifdef HAVE_GSSAPI
3958   http->gssctx   = GSS_C_NO_CONTEXT;
3959   http->gssname  = GSS_C_NO_NAME;
3960 #endif /* HAVE_GSSAPI */
3961   http->status   = HTTP_STATUS_CONTINUE;
3962   http->version  = HTTP_VERSION_1_1;
3963 
3964   if (host)
3965     strlcpy(http->hostname, host, sizeof(http->hostname));
3966 
3967   if (port == 443)			/* Always use encryption for https */
3968     http->encryption = HTTP_ENCRYPTION_ALWAYS;
3969   else
3970     http->encryption = encryption;
3971 
3972   http_set_wait(http);
3973 
3974  /*
3975   * Return the new structure...
3976   */
3977 
3978   return (http);
3979 }
3980 
3981 
3982 #ifdef DEBUG
3983 /*
3984  * 'http_debug_hex()' - Do a hex dump of a buffer.
3985  */
3986 
3987 static void
http_debug_hex(const char * prefix,const char * buffer,int bytes)3988 http_debug_hex(const char *prefix,	/* I - Prefix for line */
3989                const char *buffer,	/* I - Buffer to dump */
3990                int        bytes)	/* I - Bytes to dump */
3991 {
3992   int	i, j,				/* Looping vars */
3993 	ch;				/* Current character */
3994   char	line[255],			/* Line buffer */
3995 	*start,				/* Start of line after prefix */
3996 	*ptr;				/* Pointer into line */
3997 
3998 
3999   if (_cups_debug_fd < 0 || _cups_debug_level < 6)
4000     return;
4001 
4002   DEBUG_printf(("6%s: %d bytes:", prefix, bytes));
4003 
4004   snprintf(line, sizeof(line), "6%s: ", prefix);
4005   start = line + strlen(line);
4006 
4007   for (i = 0; i < bytes; i += 16)
4008   {
4009     for (j = 0, ptr = start; j < 16 && (i + j) < bytes; j ++, ptr += 2)
4010       snprintf(ptr, 3, "%02X", buffer[i + j] & 255);
4011 
4012     while (j < 16)
4013     {
4014       memcpy(ptr, "  ", 3);
4015       ptr += 2;
4016       j ++;
4017     }
4018 
4019     memcpy(ptr, "  ", 3);
4020     ptr += 2;
4021 
4022     for (j = 0; j < 16 && (i + j) < bytes; j ++)
4023     {
4024       ch = buffer[i + j] & 255;
4025 
4026       if (ch < ' ' || ch >= 127)
4027 	ch = '.';
4028 
4029       *ptr++ = (char)ch;
4030     }
4031 
4032     *ptr = '\0';
4033     DEBUG_puts(line);
4034   }
4035 }
4036 #endif /* DEBUG */
4037 
4038 
4039 /*
4040  * 'http_read()' - Read a buffer from a HTTP connection.
4041  *
4042  * This function does the low-level read from the socket, retrying and timing
4043  * out as needed.
4044  */
4045 
4046 static ssize_t				/* O - Number of bytes read or -1 on error */
http_read(http_t * http,char * buffer,size_t length)4047 http_read(http_t *http,			/* I - HTTP connection */
4048           char   *buffer,		/* I - Buffer */
4049           size_t length)		/* I - Maximum bytes to read */
4050 {
4051   ssize_t	bytes;			/* Bytes read */
4052 
4053 
4054   DEBUG_printf(("http_read(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4055 
4056   if (!http->blocking)
4057   {
4058     while (!httpWait(http, http->wait_value))
4059     {
4060       if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4061 	continue;
4062 
4063       DEBUG_puts("2http_read: Timeout.");
4064       return (0);
4065     }
4066   }
4067 
4068   DEBUG_printf(("2http_read: Reading %d bytes into buffer.", (int)length));
4069 
4070   do
4071   {
4072 #ifdef HAVE_SSL
4073     if (http->tls)
4074       bytes = _httpTLSRead(http, buffer, (int)length);
4075     else
4076 #endif /* HAVE_SSL */
4077     bytes = recv(http->fd, buffer, length, 0);
4078 
4079     if (bytes < 0)
4080     {
4081 #ifdef WIN32
4082       if (WSAGetLastError() != WSAEINTR)
4083       {
4084 	http->error = WSAGetLastError();
4085 	return (-1);
4086       }
4087       else if (WSAGetLastError() == WSAEWOULDBLOCK)
4088       {
4089 	if (!http->timeout_cb ||
4090 	    !(*http->timeout_cb)(http, http->timeout_data))
4091 	{
4092 	  http->error = WSAEWOULDBLOCK;
4093 	  return (-1);
4094 	}
4095       }
4096 #else
4097       DEBUG_printf(("2http_read: %s", strerror(errno)));
4098 
4099       if (errno == EWOULDBLOCK || errno == EAGAIN)
4100       {
4101 	if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data))
4102 	{
4103 	  http->error = errno;
4104 	  return (-1);
4105 	}
4106 	else if (!http->timeout_cb && errno != EAGAIN)
4107 	{
4108 	  http->error = errno;
4109 	  return (-1);
4110 	}
4111       }
4112       else if (errno != EINTR)
4113       {
4114 	http->error = errno;
4115 	return (-1);
4116       }
4117 #endif /* WIN32 */
4118     }
4119   }
4120   while (bytes < 0);
4121 
4122   DEBUG_printf(("2http_read: Read " CUPS_LLFMT " bytes into buffer.",
4123 		CUPS_LLCAST bytes));
4124 #ifdef DEBUG
4125   if (bytes > 0)
4126     http_debug_hex("http_read", buffer, (int)bytes);
4127 #endif /* DEBUG */
4128 
4129   if (bytes < 0)
4130   {
4131 #ifdef WIN32
4132     if (WSAGetLastError() == WSAEINTR)
4133       bytes = 0;
4134     else
4135       http->error = WSAGetLastError();
4136 #else
4137     if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb))
4138       bytes = 0;
4139     else
4140       http->error = errno;
4141 #endif /* WIN32 */
4142   }
4143   else if (bytes == 0)
4144   {
4145     http->error = EPIPE;
4146     return (0);
4147   }
4148 
4149   return (bytes);
4150 }
4151 
4152 
4153 /*
4154  * 'http_read_buffered()' - Do a buffered read from a HTTP connection.
4155  *
4156  * This function reads data from the HTTP buffer or from the socket, as needed.
4157  */
4158 
4159 static ssize_t				/* O - Number of bytes read or -1 on error */
http_read_buffered(http_t * http,char * buffer,size_t length)4160 http_read_buffered(http_t *http,	/* I - HTTP connection */
4161                    char   *buffer,	/* I - Buffer */
4162                    size_t length)	/* I - Maximum bytes to read */
4163 {
4164   ssize_t	bytes;			/* Bytes read */
4165 
4166 
4167   DEBUG_printf(("http_read_buffered(http=%p, buffer=%p, length=" CUPS_LLFMT ") used=%d", (void *)http, (void *)buffer, CUPS_LLCAST length, http->used));
4168 
4169   if (http->used > 0)
4170   {
4171     if (length > (size_t)http->used)
4172       bytes = (ssize_t)http->used;
4173     else
4174       bytes = (ssize_t)length;
4175 
4176     DEBUG_printf(("2http_read: Grabbing %d bytes from input buffer.",
4177                   (int)bytes));
4178 
4179     memcpy(buffer, http->buffer, (size_t)bytes);
4180     http->used -= (int)bytes;
4181 
4182     if (http->used > 0)
4183       memmove(http->buffer, http->buffer + bytes, (size_t)http->used);
4184   }
4185   else
4186     bytes = http_read(http, buffer, length);
4187 
4188   return (bytes);
4189 }
4190 
4191 
4192 /*
4193  * 'http_read_chunk()' - Read a chunk from a HTTP connection.
4194  *
4195  * This function reads and validates the chunk length, then does a buffered read
4196  * returning the number of bytes placed in the buffer.
4197  */
4198 
4199 static ssize_t				/* O - Number of bytes read or -1 on error */
http_read_chunk(http_t * http,char * buffer,size_t length)4200 http_read_chunk(http_t *http,		/* I - HTTP connection */
4201 		char   *buffer,		/* I - Buffer */
4202 		size_t length)		/* I - Maximum bytes to read */
4203 {
4204   DEBUG_printf(("http_read_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4205 
4206   if (http->data_remaining <= 0)
4207   {
4208     char	len[32];		/* Length string */
4209 
4210     if (!httpGets(len, sizeof(len), http))
4211     {
4212       DEBUG_puts("1http_read_chunk: Could not get chunk length.");
4213       return (0);
4214     }
4215 
4216     if (!len[0])
4217     {
4218       DEBUG_puts("1http_read_chunk: Blank chunk length, trying again...");
4219       if (!httpGets(len, sizeof(len), http))
4220       {
4221 	DEBUG_puts("1http_read_chunk: Could not get chunk length.");
4222 	return (0);
4223       }
4224     }
4225 
4226     http->data_remaining = strtoll(len, NULL, 16);
4227 
4228     if (http->data_remaining < 0)
4229     {
4230       DEBUG_printf(("1http_read_chunk: Negative chunk length \"%s\" ("
4231                     CUPS_LLFMT ")", len, CUPS_LLCAST http->data_remaining));
4232       return (0);
4233     }
4234 
4235     DEBUG_printf(("2http_read_chunk: Got chunk length \"%s\" (" CUPS_LLFMT ")",
4236                   len, CUPS_LLCAST http->data_remaining));
4237 
4238     if (http->data_remaining == 0)
4239     {
4240      /*
4241       * 0-length chunk, grab trailing blank line...
4242       */
4243 
4244       httpGets(len, sizeof(len), http);
4245     }
4246   }
4247 
4248   DEBUG_printf(("2http_read_chunk: data_remaining=" CUPS_LLFMT,
4249                 CUPS_LLCAST http->data_remaining));
4250 
4251   if (http->data_remaining <= 0)
4252     return (0);
4253   else if (length > (size_t)http->data_remaining)
4254     length = (size_t)http->data_remaining;
4255 
4256   return (http_read_buffered(http, buffer, length));
4257 }
4258 
4259 
4260 /*
4261  * 'http_send()' - Send a request with all fields and the trailing blank line.
4262  */
4263 
4264 static int				/* O - 0 on success, non-zero on error */
http_send(http_t * http,http_state_t request,const char * uri)4265 http_send(http_t       *http,		/* I - HTTP connection */
4266           http_state_t request,		/* I - Request code */
4267 	  const char   *uri)		/* I - URI */
4268 {
4269   int		i;			/* Looping var */
4270   char		buf[1024];		/* Encoded URI buffer */
4271   const char	*value;			/* Field value */
4272   static const char * const codes[] =	/* Request code strings */
4273 		{
4274 		  NULL,
4275 		  "OPTIONS",
4276 		  "GET",
4277 		  NULL,
4278 		  "HEAD",
4279 		  "POST",
4280 		  NULL,
4281 		  NULL,
4282 		  "PUT",
4283 		  NULL,
4284 		  "DELETE",
4285 		  "TRACE",
4286 		  "CLOSE",
4287 		  NULL,
4288 		  NULL
4289 		};
4290 
4291 
4292   DEBUG_printf(("4http_send(http=%p, request=HTTP_%s, uri=\"%s\")", (void *)http, codes[request], uri));
4293 
4294   if (http == NULL || uri == NULL)
4295     return (-1);
4296 
4297  /*
4298   * Set the User-Agent field if it isn't already...
4299   */
4300 
4301   if (!http->fields[HTTP_FIELD_USER_AGENT][0])
4302   {
4303     if (http->default_user_agent)
4304       httpSetField(http, HTTP_FIELD_USER_AGENT, http->default_user_agent);
4305     else
4306       httpSetField(http, HTTP_FIELD_USER_AGENT, cupsUserAgent());
4307   }
4308 
4309  /*
4310   * Set the Accept-Encoding field if it isn't already...
4311   */
4312 
4313   if (!http->accept_encoding && http->default_accept_encoding)
4314     httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING,
4315                  http->default_accept_encoding);
4316 
4317  /*
4318   * Encode the URI as needed...
4319   */
4320 
4321   _httpEncodeURI(buf, uri, sizeof(buf));
4322 
4323  /*
4324   * See if we had an error the last time around; if so, reconnect...
4325   */
4326 
4327   if (http->fd < 0 || http->status == HTTP_STATUS_ERROR ||
4328       http->status >= HTTP_STATUS_BAD_REQUEST)
4329   {
4330     DEBUG_printf(("5http_send: Reconnecting, fd=%d, status=%d, tls_upgrade=%d",
4331                   http->fd, http->status, http->tls_upgrade));
4332 
4333     if (httpReconnect2(http, 30000, NULL))
4334       return (-1);
4335   }
4336 
4337  /*
4338   * Flush any written data that is pending...
4339   */
4340 
4341   if (http->wused)
4342   {
4343     if (httpFlushWrite(http) < 0)
4344       if (httpReconnect2(http, 30000, NULL))
4345         return (-1);
4346   }
4347 
4348  /*
4349   * Send the request header...
4350   */
4351 
4352   http->state         = request;
4353   http->data_encoding = HTTP_ENCODING_FIELDS;
4354 
4355   if (request == HTTP_STATE_POST || request == HTTP_STATE_PUT)
4356     http->state ++;
4357 
4358   http->status = HTTP_STATUS_CONTINUE;
4359 
4360 #ifdef HAVE_SSL
4361   if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls)
4362   {
4363     httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
4364     httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
4365   }
4366 #endif /* HAVE_SSL */
4367 
4368   if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
4369   {
4370     http->status = HTTP_STATUS_ERROR;
4371     return (-1);
4372   }
4373 
4374   for (i = 0; i < HTTP_FIELD_MAX; i ++)
4375     if ((value = httpGetField(http, i)) != NULL && *value)
4376     {
4377       DEBUG_printf(("5http_send: %s: %s", http_fields[i], value));
4378 
4379       if (i == HTTP_FIELD_HOST)
4380       {
4381 	if (httpPrintf(http, "Host: %s:%d\r\n", value,
4382 	               httpAddrPort(http->hostaddr)) < 1)
4383 	{
4384 	  http->status = HTTP_STATUS_ERROR;
4385 	  return (-1);
4386 	}
4387       }
4388       else if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
4389       {
4390 	http->status = HTTP_STATUS_ERROR;
4391 	return (-1);
4392       }
4393     }
4394 
4395   if (http->cookie)
4396     if (httpPrintf(http, "Cookie: $Version=0; %s\r\n", http->cookie) < 1)
4397     {
4398       http->status = HTTP_STATUS_ERROR;
4399       return (-1);
4400     }
4401 
4402   DEBUG_printf(("5http_send: expect=%d, mode=%d, state=%d", http->expect,
4403                 http->mode, http->state));
4404 
4405   if (http->expect == HTTP_STATUS_CONTINUE && http->mode == _HTTP_MODE_CLIENT &&
4406       (http->state == HTTP_STATE_POST_RECV ||
4407        http->state == HTTP_STATE_PUT_RECV))
4408     if (httpPrintf(http, "Expect: 100-continue\r\n") < 1)
4409     {
4410       http->status = HTTP_STATUS_ERROR;
4411       return (-1);
4412     }
4413 
4414   if (httpPrintf(http, "\r\n") < 1)
4415   {
4416     http->status = HTTP_STATUS_ERROR;
4417     return (-1);
4418   }
4419 
4420   if (httpFlushWrite(http) < 0)
4421     return (-1);
4422 
4423   http_set_length(http);
4424   httpClearFields(http);
4425 
4426  /*
4427   * The Kerberos and AuthRef authentication strings can only be used once...
4428   */
4429 
4430   if (http->field_authorization && http->authstring &&
4431       (!strncmp(http->authstring, "Negotiate", 9) ||
4432        !strncmp(http->authstring, "AuthRef", 7)))
4433   {
4434     http->_authstring[0] = '\0';
4435 
4436     if (http->authstring != http->_authstring)
4437       free(http->authstring);
4438 
4439     http->authstring = http->_authstring;
4440   }
4441 
4442   return (0);
4443 }
4444 
4445 
4446 /*
4447  * 'http_set_length()' - Set the data_encoding and data_remaining values.
4448  */
4449 
4450 static off_t				/* O - Remainder or -1 on error */
http_set_length(http_t * http)4451 http_set_length(http_t *http)		/* I - Connection */
4452 {
4453   off_t	remaining;			/* Remainder */
4454 
4455 
4456   DEBUG_printf(("http_set_length(http=%p) mode=%d state=%s", (void *)http, http->mode, httpStateString(http->state)));
4457 
4458   if ((remaining = httpGetLength2(http)) >= 0)
4459   {
4460     if (http->mode == _HTTP_MODE_SERVER &&
4461 	http->state != HTTP_STATE_GET_SEND &&
4462 	http->state != HTTP_STATE_PUT &&
4463 	http->state != HTTP_STATE_POST &&
4464 	http->state != HTTP_STATE_POST_SEND)
4465     {
4466       DEBUG_puts("1http_set_length: Not setting data_encoding/remaining.");
4467       return (remaining);
4468     }
4469 
4470     if (!_cups_strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING],
4471                           "chunked"))
4472     {
4473       DEBUG_puts("1http_set_length: Setting data_encoding to "
4474                  "HTTP_ENCODING_CHUNKED.");
4475       http->data_encoding = HTTP_ENCODING_CHUNKED;
4476     }
4477     else
4478     {
4479       DEBUG_puts("1http_set_length: Setting data_encoding to "
4480                  "HTTP_ENCODING_LENGTH.");
4481       http->data_encoding = HTTP_ENCODING_LENGTH;
4482     }
4483 
4484     DEBUG_printf(("1http_set_length: Setting data_remaining to " CUPS_LLFMT ".",
4485                   CUPS_LLCAST remaining));
4486     http->data_remaining = remaining;
4487 
4488     if (remaining <= INT_MAX)
4489       http->_data_remaining = (int)remaining;
4490     else
4491       http->_data_remaining = INT_MAX;
4492   }
4493 
4494   return (remaining);
4495 }
4496 
4497 /*
4498  * 'http_set_timeout()' - Set the socket timeout values.
4499  */
4500 
4501 static void
http_set_timeout(int fd,double timeout)4502 http_set_timeout(int    fd,		/* I - File descriptor */
4503                  double timeout)	/* I - Timeout in seconds */
4504 {
4505 #ifdef WIN32
4506   DWORD tv = (DWORD)(timeout * 1000);
4507 				      /* Timeout in milliseconds */
4508 
4509   setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4510   setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4511 
4512 #else
4513   struct timeval tv;			/* Timeout in secs and usecs */
4514 
4515   tv.tv_sec  = (int)timeout;
4516   tv.tv_usec = (int)(1000000 * fmod(timeout, 1.0));
4517 
4518   setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4519   setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4520 #endif /* WIN32 */
4521 }
4522 
4523 
4524 /*
4525  * 'http_set_wait()' - Set the default wait value for reads.
4526  */
4527 
4528 static void
http_set_wait(http_t * http)4529 http_set_wait(http_t *http)		/* I - HTTP connection */
4530 {
4531   if (http->blocking)
4532   {
4533     http->wait_value = (int)(http->timeout_value * 1000);
4534 
4535     if (http->wait_value <= 0)
4536       http->wait_value = 60000;
4537   }
4538   else
4539     http->wait_value = 10000;
4540 }
4541 
4542 
4543 #ifdef HAVE_SSL
4544 /*
4545  * 'http_tls_upgrade()' - Force upgrade to TLS encryption.
4546  */
4547 
4548 static int				/* O - Status of connection */
http_tls_upgrade(http_t * http)4549 http_tls_upgrade(http_t *http)		/* I - HTTP connection */
4550 {
4551   int		ret;			/* Return value */
4552   http_t	myhttp;			/* Local copy of HTTP data */
4553 
4554 
4555   DEBUG_printf(("7http_tls_upgrade(%p)", (void *)http));
4556 
4557  /*
4558   * Flush the connection to make sure any previous "Upgrade" message
4559   * has been read.
4560   */
4561 
4562   httpFlush(http);
4563 
4564  /*
4565   * Copy the HTTP data to a local variable so we can do the OPTIONS
4566   * request without interfering with the existing request data...
4567   */
4568 
4569   memcpy(&myhttp, http, sizeof(myhttp));
4570 
4571  /*
4572   * Send an OPTIONS request to the server, requiring SSL or TLS
4573   * encryption on the link...
4574   */
4575 
4576   http->tls_upgrade         = 1;
4577   http->field_authorization = NULL;	/* Don't free the auth string */
4578 
4579   httpClearFields(http);
4580   httpSetField(http, HTTP_FIELD_CONNECTION, "upgrade");
4581   httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
4582 
4583   if ((ret = httpOptions(http, "*")) == 0)
4584   {
4585    /*
4586     * Wait for the secure connection...
4587     */
4588 
4589     while (httpUpdate(http) == HTTP_STATUS_CONTINUE);
4590   }
4591 
4592  /*
4593   * Restore the HTTP request data...
4594   */
4595 
4596   memcpy(http->fields, myhttp.fields, sizeof(http->fields));
4597   http->data_encoding       = myhttp.data_encoding;
4598   http->data_remaining      = myhttp.data_remaining;
4599   http->_data_remaining     = myhttp._data_remaining;
4600   http->expect              = myhttp.expect;
4601   http->field_authorization = myhttp.field_authorization;
4602   http->digest_tries        = myhttp.digest_tries;
4603   http->tls_upgrade         = 0;
4604 
4605  /*
4606   * See if we actually went secure...
4607   */
4608 
4609   if (!http->tls)
4610   {
4611    /*
4612     * Server does not support HTTP upgrade...
4613     */
4614 
4615     DEBUG_puts("8http_tls_upgrade: Server does not support HTTP upgrade!");
4616 
4617     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Encryption is not supported."), 1);
4618     httpAddrClose(NULL, http->fd);
4619 
4620     http->fd = -1;
4621 
4622     return (-1);
4623   }
4624   else
4625     return (ret);
4626 }
4627 #endif /* HAVE_SSL */
4628 
4629 
4630 /*
4631  * 'http_write()' - Write a buffer to a HTTP connection.
4632  */
4633 
4634 static ssize_t				/* O - Number of bytes written */
http_write(http_t * http,const char * buffer,size_t length)4635 http_write(http_t     *http,		/* I - HTTP connection */
4636            const char *buffer,		/* I - Buffer for data */
4637 	   size_t     length)		/* I - Number of bytes to write */
4638 {
4639   ssize_t	tbytes,			/* Total bytes sent */
4640 		bytes;			/* Bytes sent */
4641 
4642 
4643   DEBUG_printf(("2http_write(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4644   http->error = 0;
4645   tbytes      = 0;
4646 
4647   while (length > 0)
4648   {
4649     DEBUG_printf(("3http_write: About to write %d bytes.", (int)length));
4650 
4651     if (http->timeout_cb)
4652     {
4653 #ifdef HAVE_POLL
4654       struct pollfd	pfd;		/* Polled file descriptor */
4655 #else
4656       fd_set		output_set;	/* Output ready for write? */
4657       struct timeval	timeout;	/* Timeout value */
4658 #endif /* HAVE_POLL */
4659       int		nfds;		/* Result from select()/poll() */
4660 
4661       do
4662       {
4663 #ifdef HAVE_POLL
4664 	pfd.fd     = http->fd;
4665 	pfd.events = POLLOUT;
4666 
4667 	while ((nfds = poll(&pfd, 1, http->wait_value)) < 0 &&
4668 	       (errno == EINTR || errno == EAGAIN))
4669 	  /* do nothing */;
4670 
4671 #else
4672 	do
4673 	{
4674 	  FD_ZERO(&output_set);
4675 	  FD_SET(http->fd, &output_set);
4676 
4677 	  timeout.tv_sec  = http->wait_value / 1000;
4678 	  timeout.tv_usec = 1000 * (http->wait_value % 1000);
4679 
4680 	  nfds = select(http->fd + 1, NULL, &output_set, NULL, &timeout);
4681 	}
4682 #  ifdef WIN32
4683 	while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
4684 			    WSAGetLastError() == WSAEWOULDBLOCK));
4685 #  else
4686 	while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
4687 #  endif /* WIN32 */
4688 #endif /* HAVE_POLL */
4689 
4690         if (nfds < 0)
4691 	{
4692 	  http->error = errno;
4693 	  return (-1);
4694 	}
4695 	else if (nfds == 0 && !(*http->timeout_cb)(http, http->timeout_data))
4696 	{
4697 #ifdef WIN32
4698 	  http->error = WSAEWOULDBLOCK;
4699 #else
4700 	  http->error = EWOULDBLOCK;
4701 #endif /* WIN32 */
4702 	  return (-1);
4703 	}
4704       }
4705       while (nfds <= 0);
4706     }
4707 
4708 #ifdef HAVE_SSL
4709     if (http->tls)
4710       bytes = _httpTLSWrite(http, buffer, (int)length);
4711     else
4712 #endif /* HAVE_SSL */
4713     bytes = send(http->fd, buffer, length, 0);
4714 
4715     DEBUG_printf(("3http_write: Write of " CUPS_LLFMT " bytes returned "
4716                   CUPS_LLFMT ".", CUPS_LLCAST length, CUPS_LLCAST bytes));
4717 
4718     if (bytes < 0)
4719     {
4720 #ifdef WIN32
4721       if (WSAGetLastError() == WSAEINTR)
4722         continue;
4723       else if (WSAGetLastError() == WSAEWOULDBLOCK)
4724       {
4725         if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4726           continue;
4727 
4728         http->error = WSAGetLastError();
4729       }
4730       else if (WSAGetLastError() != http->error &&
4731                WSAGetLastError() != WSAECONNRESET)
4732       {
4733         http->error = WSAGetLastError();
4734 	continue;
4735       }
4736 
4737 #else
4738       if (errno == EINTR)
4739         continue;
4740       else if (errno == EWOULDBLOCK || errno == EAGAIN)
4741       {
4742 	if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4743           continue;
4744         else if (!http->timeout_cb && errno == EAGAIN)
4745 	  continue;
4746 
4747         http->error = errno;
4748       }
4749       else if (errno != http->error && errno != ECONNRESET)
4750       {
4751         http->error = errno;
4752 	continue;
4753       }
4754 #endif /* WIN32 */
4755 
4756       DEBUG_printf(("3http_write: error writing data (%s).",
4757                     strerror(http->error)));
4758 
4759       return (-1);
4760     }
4761 
4762     buffer += bytes;
4763     tbytes += bytes;
4764     length -= (size_t)bytes;
4765   }
4766 
4767 #ifdef DEBUG
4768   http_debug_hex("http_write", buffer - tbytes, (int)tbytes);
4769 #endif /* DEBUG */
4770 
4771   DEBUG_printf(("3http_write: Returning " CUPS_LLFMT ".", CUPS_LLCAST tbytes));
4772 
4773   return (tbytes);
4774 }
4775 
4776 
4777 /*
4778  * 'http_write_chunk()' - Write a chunked buffer.
4779  */
4780 
4781 static ssize_t				/* O - Number bytes written */
http_write_chunk(http_t * http,const char * buffer,size_t length)4782 http_write_chunk(http_t     *http,	/* I - HTTP connection */
4783                  const char *buffer,	/* I - Buffer to write */
4784 		 size_t        length)	/* I - Length of buffer */
4785 {
4786   char		header[16];		/* Chunk header */
4787   ssize_t	bytes;			/* Bytes written */
4788 
4789 
4790   DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4791 
4792  /*
4793   * Write the chunk header, data, and trailer.
4794   */
4795 
4796   snprintf(header, sizeof(header), "%x\r\n", (unsigned)length);
4797   if (http_write(http, header, strlen(header)) < 0)
4798   {
4799     DEBUG_puts("8http_write_chunk: http_write of length failed.");
4800     return (-1);
4801   }
4802 
4803   if ((bytes = http_write(http, buffer, length)) < 0)
4804   {
4805     DEBUG_puts("8http_write_chunk: http_write of buffer failed.");
4806     return (-1);
4807   }
4808 
4809   if (http_write(http, "\r\n", 2) < 0)
4810   {
4811     DEBUG_puts("8http_write_chunk: http_write of CR LF failed.");
4812     return (-1);
4813   }
4814 
4815   return (bytes);
4816 }
4817