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