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