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