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