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