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