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