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