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