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