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