]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/http.c
Update ipp documentation to reflect the behavior of configuring WiFi on IPP USB printers.
[thirdparty/cups.git] / cups / http.c
1 /*
2 * HTTP routines for CUPS.
3 *
4 * Copyright © 2007-2021 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 (value)
1349 *value = '\0';
1350
1351 if (!http || !name || !value || valuelen < 2 ||
1352 field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX || !http->fields[field])
1353 return (NULL);
1354
1355 end = value + valuelen - 1;
1356
1357 for (fptr = http->fields[field]; *fptr;)
1358 {
1359 /*
1360 * Skip leading whitespace...
1361 */
1362
1363 while (_cups_isspace(*fptr))
1364 fptr ++;
1365
1366 if (*fptr == ',')
1367 {
1368 fptr ++;
1369 continue;
1370 }
1371
1372 /*
1373 * Get the sub-field name...
1374 */
1375
1376 for (ptr = temp;
1377 *fptr && *fptr != '=' && !_cups_isspace(*fptr) &&
1378 ptr < (temp + sizeof(temp) - 1);
1379 *ptr++ = *fptr++);
1380
1381 *ptr = '\0';
1382
1383 DEBUG_printf(("4httpGetSubField2: name=\"%s\"", temp));
1384
1385 /*
1386 * Skip trailing chars up to the '='...
1387 */
1388
1389 while (_cups_isspace(*fptr))
1390 fptr ++;
1391
1392 if (!*fptr)
1393 break;
1394
1395 if (*fptr != '=')
1396 continue;
1397
1398 /*
1399 * Skip = and leading whitespace...
1400 */
1401
1402 fptr ++;
1403
1404 while (_cups_isspace(*fptr))
1405 fptr ++;
1406
1407 if (*fptr == '\"')
1408 {
1409 /*
1410 * Read quoted string...
1411 */
1412
1413 for (ptr = value, fptr ++;
1414 *fptr && *fptr != '\"' && ptr < end;
1415 *ptr++ = *fptr++);
1416
1417 *ptr = '\0';
1418
1419 while (*fptr && *fptr != '\"')
1420 fptr ++;
1421
1422 if (*fptr)
1423 fptr ++;
1424 }
1425 else
1426 {
1427 /*
1428 * Read unquoted string...
1429 */
1430
1431 for (ptr = value;
1432 *fptr && !_cups_isspace(*fptr) && *fptr != ',' && ptr < end;
1433 *ptr++ = *fptr++);
1434
1435 *ptr = '\0';
1436
1437 while (*fptr && !_cups_isspace(*fptr) && *fptr != ',')
1438 fptr ++;
1439 }
1440
1441 DEBUG_printf(("4httpGetSubField2: value=\"%s\"", value));
1442
1443 /*
1444 * See if this is the one...
1445 */
1446
1447 if (!strcmp(name, temp))
1448 {
1449 DEBUG_printf(("3httpGetSubField2: Returning \"%s\"", value));
1450 return (value);
1451 }
1452 }
1453
1454 value[0] = '\0';
1455
1456 DEBUG_puts("3httpGetSubField2: Returning NULL");
1457
1458 return (NULL);
1459 }
1460
1461
1462 /*
1463 * 'httpGetVersion()' - Get the HTTP version at the other end.
1464 */
1465
1466 http_version_t /* O - Version number */
1467 httpGetVersion(http_t *http) /* I - HTTP connection */
1468 {
1469 return (http ? http->version : HTTP_VERSION_1_0);
1470 }
1471
1472
1473 /*
1474 * 'httpHead()' - Send a HEAD request to the server.
1475 */
1476
1477 int /* O - Status of call (0 = success) */
1478 httpHead(http_t *http, /* I - HTTP connection */
1479 const char *uri) /* I - URI for head */
1480 {
1481 DEBUG_printf(("httpHead(http=%p, uri=\"%s\")", (void *)http, uri));
1482 return (http_send(http, HTTP_STATE_HEAD, uri));
1483 }
1484
1485
1486 /*
1487 * 'httpInitialize()' - Initialize the HTTP interface library and set the
1488 * default HTTP proxy (if any).
1489 */
1490
1491 void
1492 httpInitialize(void)
1493 {
1494 static int initialized = 0; /* Have we been called before? */
1495 #ifdef _WIN32
1496 WSADATA winsockdata; /* WinSock data */
1497 #endif /* _WIN32 */
1498
1499
1500 _cupsGlobalLock();
1501 if (initialized)
1502 {
1503 _cupsGlobalUnlock();
1504 return;
1505 }
1506
1507 #ifdef _WIN32
1508 WSAStartup(MAKEWORD(2,2), &winsockdata);
1509
1510 #elif !defined(SO_NOSIGPIPE)
1511 /*
1512 * Ignore SIGPIPE signals...
1513 */
1514
1515 # ifdef HAVE_SIGSET
1516 sigset(SIGPIPE, SIG_IGN);
1517
1518 # elif defined(HAVE_SIGACTION)
1519 struct sigaction action; /* POSIX sigaction data */
1520
1521
1522 memset(&action, 0, sizeof(action));
1523 action.sa_handler = SIG_IGN;
1524 sigaction(SIGPIPE, &action, NULL);
1525
1526 # else
1527 signal(SIGPIPE, SIG_IGN);
1528 # endif /* !SO_NOSIGPIPE */
1529 #endif /* _WIN32 */
1530
1531 # ifdef HAVE_SSL
1532 _httpTLSInitialize();
1533 # endif /* HAVE_SSL */
1534
1535 initialized = 1;
1536 _cupsGlobalUnlock();
1537 }
1538
1539
1540 /*
1541 * 'httpIsChunked()' - Report whether a message body is chunked.
1542 *
1543 * This function returns non-zero if the message body is composed of
1544 * variable-length chunks.
1545 *
1546 * @since CUPS 2.0/OS 10.10@
1547 */
1548
1549 int /* O - 1 if chunked, 0 if not */
1550 httpIsChunked(http_t *http) /* I - HTTP connection */
1551 {
1552 return (http ? http->data_encoding == HTTP_ENCODING_CHUNKED : 0);
1553 }
1554
1555
1556 /*
1557 * 'httpIsEncrypted()' - Report whether a connection is encrypted.
1558 *
1559 * This function returns non-zero if the connection is currently encrypted.
1560 *
1561 * @since CUPS 2.0/OS 10.10@
1562 */
1563
1564 int /* O - 1 if encrypted, 0 if not */
1565 httpIsEncrypted(http_t *http) /* I - HTTP connection */
1566 {
1567 return (http ? http->tls != NULL : 0);
1568 }
1569
1570
1571 /*
1572 * 'httpOptions()' - Send an OPTIONS request to the server.
1573 */
1574
1575 int /* O - Status of call (0 = success) */
1576 httpOptions(http_t *http, /* I - HTTP connection */
1577 const char *uri) /* I - URI for options */
1578 {
1579 return (http_send(http, HTTP_STATE_OPTIONS, uri));
1580 }
1581
1582
1583 /*
1584 * 'httpPeek()' - Peek at data from a HTTP connection.
1585 *
1586 * This function copies available data from the given HTTP connection, reading
1587 * a buffer as needed. The data is still available for reading using
1588 * @link httpRead2@.
1589 *
1590 * For non-blocking connections the usual timeouts apply.
1591 *
1592 * @since CUPS 1.7/macOS 10.9@
1593 */
1594
1595 ssize_t /* O - Number of bytes copied */
1596 httpPeek(http_t *http, /* I - HTTP connection */
1597 char *buffer, /* I - Buffer for data */
1598 size_t length) /* I - Maximum number of bytes */
1599 {
1600 ssize_t bytes; /* Bytes read */
1601 char len[32]; /* Length string */
1602
1603
1604 DEBUG_printf(("httpPeek(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
1605
1606 if (http == NULL || buffer == NULL)
1607 return (-1);
1608
1609 http->activity = time(NULL);
1610 http->error = 0;
1611
1612 if (length <= 0)
1613 return (0);
1614
1615 if (http->data_encoding == HTTP_ENCODING_CHUNKED &&
1616 http->data_remaining <= 0)
1617 {
1618 DEBUG_puts("2httpPeek: Getting chunk length...");
1619
1620 if (httpGets(len, sizeof(len), http) == NULL)
1621 {
1622 DEBUG_puts("1httpPeek: Could not get length!");
1623 return (0);
1624 }
1625
1626 if (!len[0])
1627 {
1628 DEBUG_puts("1httpPeek: Blank chunk length, trying again...");
1629 if (!httpGets(len, sizeof(len), http))
1630 {
1631 DEBUG_puts("1httpPeek: Could not get chunk length.");
1632 return (0);
1633 }
1634 }
1635
1636 http->data_remaining = strtoll(len, NULL, 16);
1637
1638 if (http->data_remaining < 0)
1639 {
1640 DEBUG_puts("1httpPeek: Negative chunk length!");
1641 return (0);
1642 }
1643 }
1644
1645 DEBUG_printf(("2httpPeek: data_remaining=" CUPS_LLFMT,
1646 CUPS_LLCAST http->data_remaining));
1647
1648 if (http->data_remaining <= 0 && http->data_encoding != HTTP_ENCODING_FIELDS)
1649 {
1650 /*
1651 * A zero-length chunk ends a transfer; unless we are reading POST
1652 * data, go idle...
1653 */
1654
1655 #ifdef HAVE_LIBZ
1656 if (http->coding >= _HTTP_CODING_GUNZIP)
1657 http_content_coding_finish(http);
1658 #endif /* HAVE_LIBZ */
1659
1660 if (http->data_encoding == HTTP_ENCODING_CHUNKED)
1661 httpGets(len, sizeof(len), http);
1662
1663 if (http->state == HTTP_STATE_POST_RECV)
1664 http->state ++;
1665 else
1666 http->state = HTTP_STATE_STATUS;
1667
1668 DEBUG_printf(("1httpPeek: 0-length chunk, set state to %s.",
1669 httpStateString(http->state)));
1670
1671 /*
1672 * Prevent future reads for this request...
1673 */
1674
1675 http->data_encoding = HTTP_ENCODING_FIELDS;
1676
1677 return (0);
1678 }
1679 else if (length > (size_t)http->data_remaining)
1680 length = (size_t)http->data_remaining;
1681
1682 #ifdef HAVE_LIBZ
1683 if (http->used == 0 &&
1684 (http->coding == _HTTP_CODING_IDENTITY ||
1685 (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in == 0)))
1686 #else
1687 if (http->used == 0)
1688 #endif /* HAVE_LIBZ */
1689 {
1690 /*
1691 * Buffer small reads for better performance...
1692 */
1693
1694 ssize_t buflen; /* Length of read for buffer */
1695
1696 if (!http->blocking)
1697 {
1698 while (!httpWait(http, http->wait_value))
1699 {
1700 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
1701 continue;
1702
1703 return (0);
1704 }
1705 }
1706
1707 if ((size_t)http->data_remaining > sizeof(http->buffer))
1708 buflen = sizeof(http->buffer);
1709 else
1710 buflen = (ssize_t)http->data_remaining;
1711
1712 DEBUG_printf(("2httpPeek: Reading %d bytes into buffer.", (int)buflen));
1713 bytes = http_read(http, http->buffer, (size_t)buflen);
1714
1715 DEBUG_printf(("2httpPeek: Read " CUPS_LLFMT " bytes into buffer.",
1716 CUPS_LLCAST bytes));
1717 if (bytes > 0)
1718 {
1719 #ifdef DEBUG
1720 http_debug_hex("httpPeek", http->buffer, (int)bytes);
1721 #endif /* DEBUG */
1722
1723 http->used = (int)bytes;
1724 }
1725 }
1726
1727 #ifdef HAVE_LIBZ
1728 if (http->coding >= _HTTP_CODING_GUNZIP)
1729 {
1730 # ifdef HAVE_INFLATECOPY
1731 int zerr; /* Decompressor error */
1732 z_stream stream; /* Copy of decompressor stream */
1733
1734 if (http->used > 0 && ((z_stream *)http->stream)->avail_in < HTTP_MAX_BUFFER)
1735 {
1736 size_t buflen = HTTP_MAX_BUFFER - ((z_stream *)http->stream)->avail_in;
1737 /* Number of bytes to copy */
1738
1739 if (((z_stream *)http->stream)->avail_in > 0 &&
1740 ((z_stream *)http->stream)->next_in > http->sbuffer)
1741 memmove(http->sbuffer, ((z_stream *)http->stream)->next_in, ((z_stream *)http->stream)->avail_in);
1742
1743 ((z_stream *)http->stream)->next_in = http->sbuffer;
1744
1745 if (buflen > (size_t)http->data_remaining)
1746 buflen = (size_t)http->data_remaining;
1747
1748 if (buflen > (size_t)http->used)
1749 buflen = (size_t)http->used;
1750
1751 DEBUG_printf(("1httpPeek: Copying %d more bytes of data into "
1752 "decompression buffer.", (int)buflen));
1753
1754 memcpy(http->sbuffer + ((z_stream *)http->stream)->avail_in, http->buffer, buflen);
1755 ((z_stream *)http->stream)->avail_in += buflen;
1756 http->used -= (int)buflen;
1757 http->data_remaining -= (off_t)buflen;
1758
1759 if (http->used > 0)
1760 memmove(http->buffer, http->buffer + buflen, (size_t)http->used);
1761 }
1762
1763 DEBUG_printf(("2httpPeek: length=%d, avail_in=%d", (int)length,
1764 (int)((z_stream *)http->stream)->avail_in));
1765
1766 if (inflateCopy(&stream, (z_stream *)http->stream) != Z_OK)
1767 {
1768 DEBUG_puts("2httpPeek: Unable to copy decompressor stream.");
1769 http->error = ENOMEM;
1770 return (-1);
1771 }
1772
1773 stream.next_out = (Bytef *)buffer;
1774 stream.avail_out = (uInt)length;
1775
1776 zerr = inflate(&stream, Z_SYNC_FLUSH);
1777 inflateEnd(&stream);
1778
1779 if (zerr < Z_OK)
1780 {
1781 DEBUG_printf(("2httpPeek: zerr=%d", zerr));
1782 #ifdef DEBUG
1783 http_debug_hex("2httpPeek", (char *)http->sbuffer, (int)((z_stream *)http->stream)->avail_in);
1784 #endif /* DEBUG */
1785
1786 http->error = EIO;
1787 return (-1);
1788 }
1789
1790 bytes = (ssize_t)(length - ((z_stream *)http->stream)->avail_out);
1791
1792 # else
1793 DEBUG_puts("2httpPeek: No inflateCopy on this platform, httpPeek does not "
1794 "work with compressed streams.");
1795 return (-1);
1796 # endif /* HAVE_INFLATECOPY */
1797 }
1798 else
1799 #endif /* HAVE_LIBZ */
1800 if (http->used > 0)
1801 {
1802 if (length > (size_t)http->used)
1803 length = (size_t)http->used;
1804
1805 bytes = (ssize_t)length;
1806
1807 DEBUG_printf(("2httpPeek: grabbing %d bytes from input buffer...",
1808 (int)bytes));
1809
1810 memcpy(buffer, http->buffer, length);
1811 }
1812 else
1813 bytes = 0;
1814
1815 if (bytes < 0)
1816 {
1817 #ifdef _WIN32
1818 if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
1819 bytes = 0;
1820 else
1821 http->error = WSAGetLastError();
1822 #else
1823 if (errno == EINTR || errno == EAGAIN)
1824 bytes = 0;
1825 else
1826 http->error = errno;
1827 #endif /* _WIN32 */
1828 }
1829 else if (bytes == 0)
1830 {
1831 http->error = EPIPE;
1832 return (0);
1833 }
1834
1835 return (bytes);
1836 }
1837
1838
1839 /*
1840 * 'httpPost()' - Send a POST request to the server.
1841 */
1842
1843 int /* O - Status of call (0 = success) */
1844 httpPost(http_t *http, /* I - HTTP connection */
1845 const char *uri) /* I - URI for post */
1846 {
1847 return (http_send(http, HTTP_STATE_POST, uri));
1848 }
1849
1850
1851 /*
1852 * 'httpPrintf()' - Print a formatted string to a HTTP connection.
1853 *
1854 * @private@
1855 */
1856
1857 int /* O - Number of bytes written */
1858 httpPrintf(http_t *http, /* I - HTTP connection */
1859 const char *format, /* I - printf-style format string */
1860 ...) /* I - Additional args as needed */
1861 {
1862 ssize_t bytes; /* Number of bytes to write */
1863 char buf[65536]; /* Buffer for formatted string */
1864 va_list ap; /* Variable argument pointer */
1865
1866
1867 DEBUG_printf(("2httpPrintf(http=%p, format=\"%s\", ...)", (void *)http, format));
1868
1869 va_start(ap, format);
1870 bytes = vsnprintf(buf, sizeof(buf), format, ap);
1871 va_end(ap);
1872
1873 DEBUG_printf(("3httpPrintf: (" CUPS_LLFMT " bytes) %s", CUPS_LLCAST bytes, buf));
1874
1875 if (bytes > (ssize_t)(sizeof(buf) - 1))
1876 {
1877 http->error = ENOMEM;
1878 return (-1);
1879 }
1880 else if (http->data_encoding == HTTP_ENCODING_FIELDS)
1881 return ((int)httpWrite2(http, buf, (size_t)bytes));
1882 else
1883 {
1884 if (http->wused)
1885 {
1886 DEBUG_puts("4httpPrintf: flushing existing data...");
1887
1888 if (httpFlushWrite(http) < 0)
1889 return (-1);
1890 }
1891
1892 return ((int)http_write(http, buf, (size_t)bytes));
1893 }
1894 }
1895
1896
1897 /*
1898 * 'httpPut()' - Send a PUT request to the server.
1899 */
1900
1901 int /* O - Status of call (0 = success) */
1902 httpPut(http_t *http, /* I - HTTP connection */
1903 const char *uri) /* I - URI to put */
1904 {
1905 DEBUG_printf(("httpPut(http=%p, uri=\"%s\")", (void *)http, uri));
1906 return (http_send(http, HTTP_STATE_PUT, uri));
1907 }
1908
1909
1910 /*
1911 * 'httpRead()' - Read data from a HTTP connection.
1912 *
1913 * This function is deprecated. Use the httpRead2() function which can
1914 * read more than 2GB of data.
1915 *
1916 * @deprecated@ @exclude all@
1917 */
1918
1919 int /* O - Number of bytes read */
1920 httpRead(http_t *http, /* I - HTTP connection */
1921 char *buffer, /* I - Buffer for data */
1922 int length) /* I - Maximum number of bytes */
1923 {
1924 return ((int)httpRead2(http, buffer, (size_t)length));
1925 }
1926
1927
1928 /*
1929 * 'httpRead2()' - Read data from a HTTP connection.
1930 *
1931 * @since CUPS 1.2/macOS 10.5@
1932 */
1933
1934 ssize_t /* O - Number of bytes read */
1935 httpRead2(http_t *http, /* I - HTTP connection */
1936 char *buffer, /* I - Buffer for data */
1937 size_t length) /* I - Maximum number of bytes */
1938 {
1939 ssize_t bytes; /* Bytes read */
1940
1941
1942 #ifdef HAVE_LIBZ
1943 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));
1944 #else
1945 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));
1946 #endif /* HAVE_LIBZ */
1947
1948 if (http == NULL || buffer == NULL)
1949 return (-1);
1950
1951 http->activity = time(NULL);
1952 http->error = 0;
1953
1954 if (length <= 0)
1955 return (0);
1956
1957 #ifdef HAVE_LIBZ
1958 if (http->coding >= _HTTP_CODING_GUNZIP)
1959 {
1960 do
1961 {
1962 if (((z_stream *)http->stream)->avail_in > 0)
1963 {
1964 int zerr; /* Decompressor error */
1965
1966 DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d",
1967 (int)((z_stream *)http->stream)->avail_in, (int)length));
1968
1969 ((z_stream *)http->stream)->next_out = (Bytef *)buffer;
1970 ((z_stream *)http->stream)->avail_out = (uInt)length;
1971
1972 if ((zerr = inflate((z_stream *)http->stream, Z_SYNC_FLUSH)) < Z_OK)
1973 {
1974 DEBUG_printf(("2httpRead2: zerr=%d", zerr));
1975 #ifdef DEBUG
1976 http_debug_hex("2httpRead2", (char *)http->sbuffer, (int)((z_stream *)http->stream)->avail_in);
1977 #endif /* DEBUG */
1978
1979 http->error = EIO;
1980 return (-1);
1981 }
1982
1983 bytes = (ssize_t)(length - ((z_stream *)http->stream)->avail_out);
1984
1985 DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d, bytes=%d",
1986 ((z_stream *)http->stream)->avail_in, ((z_stream *)http->stream)->avail_out,
1987 (int)bytes));
1988 }
1989 else
1990 bytes = 0;
1991
1992 if (bytes == 0)
1993 {
1994 ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)((z_stream *)http->stream)->avail_in;
1995 /* Additional bytes for buffer */
1996
1997 if (buflen > 0)
1998 {
1999 if (((z_stream *)http->stream)->avail_in > 0 &&
2000 ((z_stream *)http->stream)->next_in > http->sbuffer)
2001 memmove(http->sbuffer, ((z_stream *)http->stream)->next_in, ((z_stream *)http->stream)->avail_in);
2002
2003 ((z_stream *)http->stream)->next_in = http->sbuffer;
2004
2005 DEBUG_printf(("1httpRead2: Reading up to %d more bytes of data into "
2006 "decompression buffer.", (int)buflen));
2007
2008 if (http->data_remaining > 0)
2009 {
2010 if (buflen > http->data_remaining)
2011 buflen = (ssize_t)http->data_remaining;
2012
2013 bytes = http_read_buffered(http, (char *)http->sbuffer + ((z_stream *)http->stream)->avail_in, (size_t)buflen);
2014 }
2015 else if (http->data_encoding == HTTP_ENCODING_CHUNKED)
2016 bytes = http_read_chunk(http, (char *)http->sbuffer + ((z_stream *)http->stream)->avail_in, (size_t)buflen);
2017 else
2018 bytes = 0;
2019
2020 if (bytes < 0)
2021 return (bytes);
2022 else if (bytes == 0)
2023 break;
2024
2025 DEBUG_printf(("1httpRead2: Adding " CUPS_LLFMT " bytes to "
2026 "decompression buffer.", CUPS_LLCAST bytes));
2027
2028 http->data_remaining -= bytes;
2029 ((z_stream *)http->stream)->avail_in += (uInt)bytes;
2030
2031 if (http->data_remaining <= 0 &&
2032 http->data_encoding == HTTP_ENCODING_CHUNKED)
2033 {
2034 /*
2035 * Read the trailing blank line now...
2036 */
2037
2038 char len[32]; /* Length string */
2039
2040 httpGets(len, sizeof(len), http);
2041 }
2042
2043 bytes = 0;
2044 }
2045 else
2046 return (0);
2047 }
2048 }
2049 while (bytes == 0);
2050 }
2051 else
2052 #endif /* HAVE_LIBZ */
2053 if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
2054 {
2055 if ((bytes = http_read_chunk(http, buffer, length)) > 0)
2056 {
2057 http->data_remaining -= bytes;
2058
2059 if (http->data_remaining <= 0)
2060 {
2061 /*
2062 * Read the trailing blank line now...
2063 */
2064
2065 char len[32]; /* Length string */
2066
2067 httpGets(len, sizeof(len), http);
2068 }
2069 }
2070 }
2071 else if (http->data_remaining <= 0)
2072 {
2073 /*
2074 * No more data to read...
2075 */
2076
2077 return (0);
2078 }
2079 else
2080 {
2081 DEBUG_printf(("1httpRead2: Reading up to %d bytes into buffer.",
2082 (int)length));
2083
2084 if (length > (size_t)http->data_remaining)
2085 length = (size_t)http->data_remaining;
2086
2087 if ((bytes = http_read_buffered(http, buffer, length)) > 0)
2088 {
2089 http->data_remaining -= bytes;
2090
2091 if (http->data_remaining <= 0 &&
2092 http->data_encoding == HTTP_ENCODING_CHUNKED)
2093 {
2094 /*
2095 * Read the trailing blank line now...
2096 */
2097
2098 char len[32]; /* Length string */
2099
2100 httpGets(len, sizeof(len), http);
2101 }
2102 }
2103 }
2104
2105 if (
2106 #ifdef HAVE_LIBZ
2107 (http->coding == _HTTP_CODING_IDENTITY ||
2108 (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in == 0)) &&
2109 #endif /* HAVE_LIBZ */
2110 ((http->data_remaining <= 0 &&
2111 http->data_encoding == HTTP_ENCODING_LENGTH) ||
2112 (http->data_encoding == HTTP_ENCODING_CHUNKED && bytes == 0)))
2113 {
2114 #ifdef HAVE_LIBZ
2115 if (http->coding >= _HTTP_CODING_GUNZIP)
2116 http_content_coding_finish(http);
2117 #endif /* HAVE_LIBZ */
2118
2119 if (http->state == HTTP_STATE_POST_RECV)
2120 http->state ++;
2121 else if (http->state == HTTP_STATE_GET_SEND ||
2122 http->state == HTTP_STATE_POST_SEND)
2123 http->state = HTTP_STATE_WAITING;
2124 else
2125 http->state = HTTP_STATE_STATUS;
2126
2127 DEBUG_printf(("1httpRead2: End of content, set state to %s.",
2128 httpStateString(http->state)));
2129 }
2130
2131 return (bytes);
2132 }
2133
2134
2135 /*
2136 * 'httpReadRequest()' - Read a HTTP request from a connection.
2137 *
2138 * @since CUPS 1.7/macOS 10.9@
2139 */
2140
2141 http_state_t /* O - New state of connection */
2142 httpReadRequest(http_t *http, /* I - HTTP connection */
2143 char *uri, /* I - URI buffer */
2144 size_t urilen) /* I - Size of URI buffer */
2145 {
2146 char line[4096], /* HTTP request line */
2147 *req_method, /* HTTP request method */
2148 *req_uri, /* HTTP request URI */
2149 *req_version; /* HTTP request version number string */
2150
2151
2152 /*
2153 * Range check input...
2154 */
2155
2156 DEBUG_printf(("httpReadRequest(http=%p, uri=%p, urilen=" CUPS_LLFMT ")", (void *)http, (void *)uri, CUPS_LLCAST urilen));
2157
2158 if (uri)
2159 *uri = '\0';
2160
2161 if (!http || !uri || urilen < 1)
2162 {
2163 DEBUG_puts("1httpReadRequest: Bad arguments, returning HTTP_STATE_ERROR.");
2164 return (HTTP_STATE_ERROR);
2165 }
2166 else if (http->state != HTTP_STATE_WAITING)
2167 {
2168 DEBUG_printf(("1httpReadRequest: Bad state %s, returning HTTP_STATE_ERROR.",
2169 httpStateString(http->state)));
2170 return (HTTP_STATE_ERROR);
2171 }
2172
2173 /*
2174 * Reset state...
2175 */
2176
2177 httpClearFields(http);
2178
2179 http->activity = time(NULL);
2180 http->data_encoding = HTTP_ENCODING_FIELDS;
2181 http->data_remaining = 0;
2182 http->keep_alive = HTTP_KEEPALIVE_OFF;
2183 http->status = HTTP_STATUS_OK;
2184 http->version = HTTP_VERSION_1_1;
2185
2186 /*
2187 * Read a line from the socket...
2188 */
2189
2190 if (!httpGets(line, sizeof(line), http))
2191 {
2192 DEBUG_puts("1httpReadRequest: Unable to read, returning HTTP_STATE_ERROR");
2193 return (HTTP_STATE_ERROR);
2194 }
2195
2196 if (!line[0])
2197 {
2198 DEBUG_puts("1httpReadRequest: Blank line, returning HTTP_STATE_WAITING");
2199 return (HTTP_STATE_WAITING);
2200 }
2201
2202 DEBUG_printf(("1httpReadRequest: %s", line));
2203
2204 /*
2205 * Parse it...
2206 */
2207
2208 req_method = line;
2209 req_uri = line;
2210
2211 while (*req_uri && !isspace(*req_uri & 255))
2212 req_uri ++;
2213
2214 if (!*req_uri)
2215 {
2216 DEBUG_puts("1httpReadRequest: No request URI.");
2217 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request URI."), 1);
2218 return (HTTP_STATE_ERROR);
2219 }
2220
2221 *req_uri++ = '\0';
2222
2223 while (*req_uri && isspace(*req_uri & 255))
2224 req_uri ++;
2225
2226 req_version = req_uri;
2227
2228 while (*req_version && !isspace(*req_version & 255))
2229 req_version ++;
2230
2231 if (!*req_version)
2232 {
2233 DEBUG_puts("1httpReadRequest: No request protocol version.");
2234 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request protocol version."), 1);
2235 return (HTTP_STATE_ERROR);
2236 }
2237
2238 *req_version++ = '\0';
2239
2240 while (*req_version && isspace(*req_version & 255))
2241 req_version ++;
2242
2243 /*
2244 * Validate...
2245 */
2246
2247 if (!strcmp(req_method, "OPTIONS"))
2248 http->state = HTTP_STATE_OPTIONS;
2249 else if (!strcmp(req_method, "GET"))
2250 http->state = HTTP_STATE_GET;
2251 else if (!strcmp(req_method, "HEAD"))
2252 http->state = HTTP_STATE_HEAD;
2253 else if (!strcmp(req_method, "POST"))
2254 http->state = HTTP_STATE_POST;
2255 else if (!strcmp(req_method, "PUT"))
2256 http->state = HTTP_STATE_PUT;
2257 else if (!strcmp(req_method, "DELETE"))
2258 http->state = HTTP_STATE_DELETE;
2259 else if (!strcmp(req_method, "TRACE"))
2260 http->state = HTTP_STATE_TRACE;
2261 else if (!strcmp(req_method, "CONNECT"))
2262 http->state = HTTP_STATE_CONNECT;
2263 else
2264 {
2265 DEBUG_printf(("1httpReadRequest: Unknown method \"%s\".", req_method));
2266 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request method."), 1);
2267 return (HTTP_STATE_UNKNOWN_METHOD);
2268 }
2269
2270 DEBUG_printf(("1httpReadRequest: Set state to %s.",
2271 httpStateString(http->state)));
2272
2273 if (!strcmp(req_version, "HTTP/1.0"))
2274 {
2275 http->version = HTTP_VERSION_1_0;
2276 http->keep_alive = HTTP_KEEPALIVE_OFF;
2277 }
2278 else if (!strcmp(req_version, "HTTP/1.1"))
2279 {
2280 http->version = HTTP_VERSION_1_1;
2281 http->keep_alive = HTTP_KEEPALIVE_ON;
2282 }
2283 else
2284 {
2285 DEBUG_printf(("1httpReadRequest: Unknown version \"%s\".", req_version));
2286 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request version."), 1);
2287 return (HTTP_STATE_UNKNOWN_VERSION);
2288 }
2289
2290 DEBUG_printf(("1httpReadRequest: URI is \"%s\".", req_uri));
2291 strlcpy(uri, req_uri, urilen);
2292
2293 return (http->state);
2294 }
2295
2296
2297 /*
2298 * 'httpReconnect()' - Reconnect to a HTTP server.
2299 *
2300 * This function is deprecated. Please use the @link httpReconnect2@ function
2301 * instead.
2302 *
2303 * @deprecated@ @exclude all@
2304 */
2305
2306 int /* O - 0 on success, non-zero on failure */
2307 httpReconnect(http_t *http) /* I - HTTP connection */
2308 {
2309 DEBUG_printf(("httpReconnect(http=%p)", (void *)http));
2310
2311 return (httpReconnect2(http, 30000, NULL));
2312 }
2313
2314
2315 /*
2316 * 'httpReconnect2()' - Reconnect to a HTTP server with timeout and optional
2317 * cancel.
2318 */
2319
2320 int /* O - 0 on success, non-zero on failure */
2321 httpReconnect2(http_t *http, /* I - HTTP connection */
2322 int msec, /* I - Timeout in milliseconds */
2323 int *cancel) /* I - Pointer to "cancel" variable */
2324 {
2325 http_addrlist_t *addr; /* Connected address */
2326 #ifdef DEBUG
2327 http_addrlist_t *current; /* Current address */
2328 char temp[256]; /* Temporary address string */
2329 #endif /* DEBUG */
2330
2331
2332 DEBUG_printf(("httpReconnect2(http=%p, msec=%d, cancel=%p)", (void *)http, msec, (void *)cancel));
2333
2334 if (!http)
2335 {
2336 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
2337 return (-1);
2338 }
2339
2340 #ifdef HAVE_SSL
2341 if (http->tls)
2342 {
2343 DEBUG_puts("2httpReconnect2: Shutting down SSL/TLS...");
2344 _httpTLSStop(http);
2345 }
2346 #endif /* HAVE_SSL */
2347
2348 /*
2349 * Close any previously open socket...
2350 */
2351
2352 if (http->fd >= 0)
2353 {
2354 DEBUG_printf(("2httpReconnect2: Closing socket %d...", http->fd));
2355
2356 httpAddrClose(NULL, http->fd);
2357
2358 http->fd = -1;
2359 }
2360
2361 /*
2362 * Reset all state (except fields, which may be reused)...
2363 */
2364
2365 http->state = HTTP_STATE_WAITING;
2366 http->version = HTTP_VERSION_1_1;
2367 http->keep_alive = HTTP_KEEPALIVE_OFF;
2368 memset(&http->_hostaddr, 0, sizeof(http->_hostaddr));
2369 http->data_encoding = HTTP_ENCODING_FIELDS;
2370 http->_data_remaining = 0;
2371 http->used = 0;
2372 http->data_remaining = 0;
2373 http->hostaddr = NULL;
2374 http->wused = 0;
2375
2376 /*
2377 * Connect to the server...
2378 */
2379
2380 #ifdef DEBUG
2381 for (current = http->addrlist; current; current = current->next)
2382 DEBUG_printf(("2httpReconnect2: Address %s:%d",
2383 httpAddrString(&(current->addr), temp, sizeof(temp)),
2384 httpAddrPort(&(current->addr))));
2385 #endif /* DEBUG */
2386
2387 if ((addr = httpAddrConnect2(http->addrlist, &(http->fd), msec, cancel)) == NULL)
2388 {
2389 /*
2390 * Unable to connect...
2391 */
2392
2393 #ifdef _WIN32
2394 http->error = WSAGetLastError();
2395 #else
2396 http->error = errno;
2397 #endif /* _WIN32 */
2398 http->status = HTTP_STATUS_ERROR;
2399
2400 DEBUG_printf(("1httpReconnect2: httpAddrConnect failed: %s",
2401 strerror(http->error)));
2402
2403 return (-1);
2404 }
2405
2406 DEBUG_printf(("2httpReconnect2: New socket=%d", http->fd));
2407
2408 if (http->timeout_value > 0)
2409 http_set_timeout(http->fd, http->timeout_value);
2410
2411 http->hostaddr = &(addr->addr);
2412 http->error = 0;
2413
2414 #ifdef HAVE_SSL
2415 if (http->encryption == HTTP_ENCRYPTION_ALWAYS)
2416 {
2417 /*
2418 * Always do encryption via SSL.
2419 */
2420
2421 if (_httpTLSStart(http) != 0)
2422 {
2423 httpAddrClose(NULL, http->fd);
2424 http->fd = -1;
2425
2426 return (-1);
2427 }
2428 }
2429 else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls_upgrade)
2430 return (http_tls_upgrade(http));
2431 #endif /* HAVE_SSL */
2432
2433 DEBUG_printf(("1httpReconnect2: Connected to %s:%d...",
2434 httpAddrString(http->hostaddr, temp, sizeof(temp)),
2435 httpAddrPort(http->hostaddr)));
2436
2437 return (0);
2438 }
2439
2440
2441 /*
2442 * 'httpSetAuthString()' - Set the current authorization string.
2443 *
2444 * This function just stores a copy of the current authorization string in
2445 * the HTTP connection object. You must still call @link httpSetField@ to set
2446 * @code HTTP_FIELD_AUTHORIZATION@ prior to issuing a HTTP request using
2447 * @link httpGet@, @link httpHead@, @link httpOptions@, @link httpPost@, or
2448 * @link httpPut@.
2449 *
2450 * @since CUPS 1.3/macOS 10.5@
2451 */
2452
2453 void
2454 httpSetAuthString(http_t *http, /* I - HTTP connection */
2455 const char *scheme, /* I - Auth scheme (NULL to clear it) */
2456 const char *data) /* I - Auth data (NULL for none) */
2457 {
2458 /*
2459 * Range check input...
2460 */
2461
2462 if (!http)
2463 return;
2464
2465 if (http->authstring && http->authstring != http->_authstring)
2466 free(http->authstring);
2467
2468 http->authstring = http->_authstring;
2469
2470 if (scheme)
2471 {
2472 /*
2473 * Set the current authorization string...
2474 */
2475
2476 size_t len = strlen(scheme) + (data ? strlen(data) + 1 : 0) + 1;
2477 char *temp;
2478
2479 if (len > sizeof(http->_authstring))
2480 {
2481 if ((temp = malloc(len)) == NULL)
2482 len = sizeof(http->_authstring);
2483 else
2484 http->authstring = temp;
2485 }
2486
2487 if (data)
2488 snprintf(http->authstring, len, "%s %s", scheme, data);
2489 else
2490 strlcpy(http->authstring, scheme, len);
2491 }
2492 else
2493 {
2494 /*
2495 * Clear the current authorization string...
2496 */
2497
2498 http->_authstring[0] = '\0';
2499 }
2500 }
2501
2502
2503 /*
2504 * 'httpSetCredentials()' - Set the credentials associated with an encrypted
2505 * connection.
2506 *
2507 * @since CUPS 1.5/macOS 10.7@
2508 */
2509
2510 int /* O - Status of call (0 = success) */
2511 httpSetCredentials(http_t *http, /* I - HTTP connection */
2512 cups_array_t *credentials) /* I - Array of credentials */
2513 {
2514 if (!http || cupsArrayCount(credentials) < 1)
2515 return (-1);
2516
2517 #ifdef HAVE_SSL
2518 _httpFreeCredentials(http->tls_credentials);
2519
2520 http->tls_credentials = _httpCreateCredentials(credentials);
2521 #endif /* HAVE_SSL */
2522
2523 return (http->tls_credentials ? 0 : -1);
2524 }
2525
2526
2527 /*
2528 * 'httpSetCookie()' - Set the cookie value(s).
2529 *
2530 * @since CUPS 1.1.19/macOS 10.3@
2531 */
2532
2533 void
2534 httpSetCookie(http_t *http, /* I - Connection */
2535 const char *cookie) /* I - Cookie string */
2536 {
2537 if (!http)
2538 return;
2539
2540 if (http->cookie)
2541 free(http->cookie);
2542
2543 if (cookie)
2544 http->cookie = strdup(cookie);
2545 else
2546 http->cookie = NULL;
2547 }
2548
2549
2550 /*
2551 * 'httpSetDefaultField()' - Set the default value of an HTTP header.
2552 *
2553 * Currently only @code HTTP_FIELD_ACCEPT_ENCODING@, @code HTTP_FIELD_SERVER@,
2554 * and @code HTTP_FIELD_USER_AGENT@ can be set.
2555 *
2556 * @since CUPS 1.7/macOS 10.9@
2557 */
2558
2559 void
2560 httpSetDefaultField(http_t *http, /* I - HTTP connection */
2561 http_field_t field, /* I - Field index */
2562 const char *value)/* I - Value */
2563 {
2564 DEBUG_printf(("httpSetDefaultField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));
2565
2566 if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
2567 return;
2568
2569 if (http->default_fields[field])
2570 free(http->default_fields[field]);
2571
2572 http->default_fields[field] = value ? strdup(value) : NULL;
2573 }
2574
2575
2576 /*
2577 * 'httpSetExpect()' - Set the Expect: header in a request.
2578 *
2579 * Currently only @code HTTP_STATUS_CONTINUE@ is supported for the "expect"
2580 * argument.
2581 *
2582 * @since CUPS 1.2/macOS 10.5@
2583 */
2584
2585 void
2586 httpSetExpect(http_t *http, /* I - HTTP connection */
2587 http_status_t expect) /* I - HTTP status to expect
2588 (@code HTTP_STATUS_CONTINUE@) */
2589 {
2590 DEBUG_printf(("httpSetExpect(http=%p, expect=%d)", (void *)http, expect));
2591
2592 if (http)
2593 http->expect = expect;
2594 }
2595
2596
2597 /*
2598 * 'httpSetField()' - Set the value of an HTTP header.
2599 */
2600
2601 void
2602 httpSetField(http_t *http, /* I - HTTP connection */
2603 http_field_t field, /* I - Field index */
2604 const char *value) /* I - Value */
2605 {
2606 DEBUG_printf(("httpSetField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));
2607
2608 if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX || !value)
2609 return;
2610
2611 http_add_field(http, field, value, 0);
2612 }
2613
2614
2615 /*
2616 * 'httpSetKeepAlive()' - Set the current Keep-Alive state of a connection.
2617 *
2618 * @since CUPS 2.0/OS 10.10@
2619 */
2620
2621 void
2622 httpSetKeepAlive(
2623 http_t *http, /* I - HTTP connection */
2624 http_keepalive_t keep_alive) /* I - New Keep-Alive value */
2625 {
2626 if (http)
2627 http->keep_alive = keep_alive;
2628 }
2629
2630
2631 /*
2632 * 'httpSetLength()' - Set the content-length and content-encoding.
2633 *
2634 * @since CUPS 1.2/macOS 10.5@
2635 */
2636
2637 void
2638 httpSetLength(http_t *http, /* I - HTTP connection */
2639 size_t length) /* I - Length (0 for chunked) */
2640 {
2641 DEBUG_printf(("httpSetLength(http=%p, length=" CUPS_LLFMT ")", (void *)http, CUPS_LLCAST length));
2642
2643 if (!http)
2644 return;
2645
2646 if (!length)
2647 {
2648 httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
2649 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "");
2650 }
2651 else
2652 {
2653 char len[32]; /* Length string */
2654
2655
2656 snprintf(len, sizeof(len), CUPS_LLFMT, CUPS_LLCAST length);
2657 httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "");
2658 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, len);
2659 }
2660 }
2661
2662
2663 /*
2664 * 'httpSetTimeout()' - Set read/write timeouts and an optional callback.
2665 *
2666 * The optional timeout callback receives both the HTTP connection and a user
2667 * data pointer and must return 1 to continue or 0 to error (time) out.
2668 *
2669 * @since CUPS 1.5/macOS 10.7@
2670 */
2671
2672 void
2673 httpSetTimeout(
2674 http_t *http, /* I - HTTP connection */
2675 double timeout, /* I - Number of seconds for timeout,
2676 must be greater than 0 */
2677 http_timeout_cb_t cb, /* I - Callback function or @code NULL@ */
2678 void *user_data) /* I - User data pointer */
2679 {
2680 if (!http || timeout <= 0.0)
2681 return;
2682
2683 http->timeout_cb = cb;
2684 http->timeout_data = user_data;
2685 http->timeout_value = timeout;
2686
2687 if (http->fd >= 0)
2688 http_set_timeout(http->fd, timeout);
2689
2690 http_set_wait(http);
2691 }
2692
2693
2694 /*
2695 * 'httpShutdown()' - Shutdown one side of an HTTP connection.
2696 *
2697 * @since CUPS 2.0/OS 10.10@
2698 */
2699
2700 void
2701 httpShutdown(http_t *http) /* I - HTTP connection */
2702 {
2703 if (!http || http->fd < 0)
2704 return;
2705
2706 #ifdef HAVE_SSL
2707 if (http->tls)
2708 _httpTLSStop(http);
2709 #endif /* HAVE_SSL */
2710
2711 #ifdef _WIN32
2712 shutdown(http->fd, SD_RECEIVE); /* Microsoft-ism... */
2713 #else
2714 shutdown(http->fd, SHUT_RD);
2715 #endif /* _WIN32 */
2716 }
2717
2718
2719 /*
2720 * 'httpTrace()' - Send an TRACE request to the server.
2721 *
2722 * @exclude all@
2723 */
2724
2725 int /* O - Status of call (0 = success) */
2726 httpTrace(http_t *http, /* I - HTTP connection */
2727 const char *uri) /* I - URI for trace */
2728 {
2729 return (http_send(http, HTTP_STATE_TRACE, uri));
2730 }
2731
2732
2733 /*
2734 * '_httpUpdate()' - Update the current HTTP status for incoming data.
2735 *
2736 * Note: Unlike httpUpdate(), this function does not flush pending write data
2737 * and only retrieves a single status line from the HTTP connection.
2738 */
2739
2740 int /* O - 1 to continue, 0 to stop */
2741 _httpUpdate(http_t *http, /* I - HTTP connection */
2742 http_status_t *status) /* O - Current HTTP status */
2743 {
2744 char line[32768], /* Line from connection... */
2745 *value; /* Pointer to value on line */
2746 http_field_t field; /* Field index */
2747 int major, minor; /* HTTP version numbers */
2748
2749
2750 DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", (void *)http, (void *)status, httpStateString(http->state)));
2751
2752 /*
2753 * Grab a single line from the connection...
2754 */
2755
2756 if (!httpGets(line, sizeof(line), http))
2757 {
2758 *status = HTTP_STATUS_ERROR;
2759 return (0);
2760 }
2761
2762 DEBUG_printf(("2_httpUpdate: Got \"%s\"", line));
2763
2764 if (line[0] == '\0')
2765 {
2766 /*
2767 * Blank line means the start of the data section (if any). Return
2768 * the result code, too...
2769 *
2770 * If we get status 100 (HTTP_STATUS_CONTINUE), then we *don't* change
2771 * states. Instead, we just return HTTP_STATUS_CONTINUE to the caller and
2772 * keep on tryin'...
2773 */
2774
2775 if (http->status == HTTP_STATUS_CONTINUE)
2776 {
2777 *status = http->status;
2778 return (0);
2779 }
2780
2781 if (http->status < HTTP_STATUS_BAD_REQUEST)
2782 http->digest_tries = 0;
2783
2784 #ifdef HAVE_SSL
2785 if (http->status == HTTP_STATUS_SWITCHING_PROTOCOLS && !http->tls)
2786 {
2787 if (_httpTLSStart(http) != 0)
2788 {
2789 httpAddrClose(NULL, http->fd);
2790 http->fd = -1;
2791
2792 *status = http->status = HTTP_STATUS_ERROR;
2793 return (0);
2794 }
2795
2796 *status = HTTP_STATUS_CONTINUE;
2797 return (0);
2798 }
2799 #endif /* HAVE_SSL */
2800
2801 if (http_set_length(http) < 0)
2802 {
2803 DEBUG_puts("1_httpUpdate: Bad Content-Length.");
2804 http->error = EINVAL;
2805 http->status = *status = HTTP_STATUS_ERROR;
2806 return (0);
2807 }
2808
2809 switch (http->state)
2810 {
2811 case HTTP_STATE_GET :
2812 case HTTP_STATE_POST :
2813 case HTTP_STATE_POST_RECV :
2814 case HTTP_STATE_PUT :
2815 http->state ++;
2816
2817 DEBUG_printf(("1_httpUpdate: Set state to %s.",
2818 httpStateString(http->state)));
2819
2820 case HTTP_STATE_POST_SEND :
2821 case HTTP_STATE_HEAD :
2822 break;
2823
2824 default :
2825 http->state = HTTP_STATE_WAITING;
2826
2827 DEBUG_puts("1_httpUpdate: Reset state to HTTP_STATE_WAITING.");
2828 break;
2829 }
2830
2831 #ifdef HAVE_LIBZ
2832 DEBUG_puts("1_httpUpdate: Calling http_content_coding_start.");
2833 http_content_coding_start(http,
2834 httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
2835 #endif /* HAVE_LIBZ */
2836
2837 *status = http->status;
2838 return (0);
2839 }
2840 else if (!strncmp(line, "HTTP/", 5) && http->mode == _HTTP_MODE_CLIENT)
2841 {
2842 /*
2843 * Got the beginning of a response...
2844 */
2845
2846 int intstatus; /* Status value as an integer */
2847
2848 if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &intstatus) != 3)
2849 {
2850 *status = http->status = HTTP_STATUS_ERROR;
2851 return (0);
2852 }
2853
2854 httpClearFields(http);
2855
2856 http->version = (http_version_t)(major * 100 + minor);
2857 *status = http->status = (http_status_t)intstatus;
2858 }
2859 else if ((value = strchr(line, ':')) != NULL)
2860 {
2861 /*
2862 * Got a value...
2863 */
2864
2865 *value++ = '\0';
2866 while (_cups_isspace(*value))
2867 value ++;
2868
2869 DEBUG_printf(("1_httpUpdate: Header %s: %s", line, value));
2870
2871 /*
2872 * Be tolerants of servers that send unknown attribute fields...
2873 */
2874
2875 if (!_cups_strcasecmp(line, "expect"))
2876 {
2877 /*
2878 * "Expect: 100-continue" or similar...
2879 */
2880
2881 http->expect = (http_status_t)atoi(value);
2882 }
2883 else if (!_cups_strcasecmp(line, "cookie"))
2884 {
2885 /*
2886 * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
2887 */
2888
2889 httpSetCookie(http, value);
2890 }
2891 else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN)
2892 {
2893 http_add_field(http, field, value, 1);
2894
2895 if (field == HTTP_FIELD_AUTHENTICATION_INFO)
2896 httpGetSubField2(http, HTTP_FIELD_AUTHENTICATION_INFO, "nextnonce", http->nextnonce, (int)sizeof(http->nextnonce));
2897 }
2898 #ifdef DEBUG
2899 else
2900 DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line));
2901 #endif /* DEBUG */
2902 }
2903 else
2904 {
2905 DEBUG_printf(("1_httpUpdate: Bad response line \"%s\"!", line));
2906 http->error = EINVAL;
2907 http->status = *status = HTTP_STATUS_ERROR;
2908 return (0);
2909 }
2910
2911 return (1);
2912 }
2913
2914
2915 /*
2916 * 'httpUpdate()' - Update the current HTTP state for incoming data.
2917 */
2918
2919 http_status_t /* O - HTTP status */
2920 httpUpdate(http_t *http) /* I - HTTP connection */
2921 {
2922 http_status_t status; /* Request status */
2923
2924
2925 DEBUG_printf(("httpUpdate(http=%p), state=%s", (void *)http, httpStateString(http->state)));
2926
2927 /*
2928 * Flush pending data, if any...
2929 */
2930
2931 if (http->wused)
2932 {
2933 DEBUG_puts("2httpUpdate: flushing buffer...");
2934
2935 if (httpFlushWrite(http) < 0)
2936 return (HTTP_STATUS_ERROR);
2937 }
2938
2939 /*
2940 * If we haven't issued any commands, then there is nothing to "update"...
2941 */
2942
2943 if (http->state == HTTP_STATE_WAITING)
2944 return (HTTP_STATUS_CONTINUE);
2945
2946 /*
2947 * Grab all of the lines we can from the connection...
2948 */
2949
2950 while (_httpUpdate(http, &status));
2951
2952 /*
2953 * See if there was an error...
2954 */
2955
2956 if (http->error == EPIPE && http->status > HTTP_STATUS_CONTINUE)
2957 {
2958 DEBUG_printf(("1httpUpdate: Returning status %d...", http->status));
2959 return (http->status);
2960 }
2961
2962 if (http->error)
2963 {
2964 DEBUG_printf(("1httpUpdate: socket error %d - %s", http->error,
2965 strerror(http->error)));
2966 http->status = HTTP_STATUS_ERROR;
2967 return (HTTP_STATUS_ERROR);
2968 }
2969
2970 /*
2971 * Return the current status...
2972 */
2973
2974 return (status);
2975 }
2976
2977
2978 /*
2979 * '_httpWait()' - Wait for data available on a connection (no flush).
2980 */
2981
2982 int /* O - 1 if data is available, 0 otherwise */
2983 _httpWait(http_t *http, /* I - HTTP connection */
2984 int msec, /* I - Milliseconds to wait */
2985 int usessl) /* I - Use SSL context? */
2986 {
2987 #ifdef HAVE_POLL
2988 struct pollfd pfd; /* Polled file descriptor */
2989 #else
2990 fd_set input_set; /* select() input set */
2991 struct timeval timeout; /* Timeout */
2992 #endif /* HAVE_POLL */
2993 int nfds; /* Result from select()/poll() */
2994
2995
2996 DEBUG_printf(("4_httpWait(http=%p, msec=%d, usessl=%d)", (void *)http, msec, usessl));
2997
2998 if (http->fd < 0)
2999 {
3000 DEBUG_printf(("5_httpWait: Returning 0 since fd=%d", http->fd));
3001 return (0);
3002 }
3003
3004 /*
3005 * Check the SSL/TLS buffers for data first...
3006 */
3007
3008 #ifdef HAVE_SSL
3009 if (http->tls && _httpTLSPending(http))
3010 {
3011 DEBUG_puts("5_httpWait: Return 1 since there is pending TLS data.");
3012 return (1);
3013 }
3014 #endif /* HAVE_SSL */
3015
3016 /*
3017 * Then try doing a select() or poll() to poll the socket...
3018 */
3019
3020 #ifdef HAVE_POLL
3021 pfd.fd = http->fd;
3022 pfd.events = POLLIN;
3023
3024 do
3025 {
3026 nfds = poll(&pfd, 1, msec);
3027 }
3028 while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
3029
3030 #else
3031 do
3032 {
3033 FD_ZERO(&input_set);
3034 FD_SET(http->fd, &input_set);
3035
3036 DEBUG_printf(("6_httpWait: msec=%d, http->fd=%d", msec, http->fd));
3037
3038 if (msec >= 0)
3039 {
3040 timeout.tv_sec = msec / 1000;
3041 timeout.tv_usec = (msec % 1000) * 1000;
3042
3043 nfds = select(http->fd + 1, &input_set, NULL, NULL, &timeout);
3044 }
3045 else
3046 nfds = select(http->fd + 1, &input_set, NULL, NULL, NULL);
3047
3048 DEBUG_printf(("6_httpWait: select() returned %d...", nfds));
3049 }
3050 # ifdef _WIN32
3051 while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
3052 WSAGetLastError() == WSAEWOULDBLOCK));
3053 # else
3054 while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
3055 # endif /* _WIN32 */
3056 #endif /* HAVE_POLL */
3057
3058 DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds,
3059 errno));
3060
3061 return (nfds > 0);
3062 }
3063
3064
3065 /*
3066 * 'httpWait()' - Wait for data available on a connection.
3067 *
3068 * @since CUPS 1.1.19/macOS 10.3@
3069 */
3070
3071 int /* O - 1 if data is available, 0 otherwise */
3072 httpWait(http_t *http, /* I - HTTP connection */
3073 int msec) /* I - Milliseconds to wait */
3074 {
3075 /*
3076 * First see if there is data in the buffer...
3077 */
3078
3079 DEBUG_printf(("2httpWait(http=%p, msec=%d)", (void *)http, msec));
3080
3081 if (http == NULL)
3082 return (0);
3083
3084 if (http->used)
3085 {
3086 DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
3087 return (1);
3088 }
3089
3090 #ifdef HAVE_LIBZ
3091 if (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in > 0)
3092 {
3093 DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
3094 return (1);
3095 }
3096 #endif /* HAVE_LIBZ */
3097
3098 /*
3099 * Flush pending data, if any...
3100 */
3101
3102 if (http->wused)
3103 {
3104 DEBUG_puts("3httpWait: Flushing write buffer.");
3105
3106 if (httpFlushWrite(http) < 0)
3107 return (0);
3108 }
3109
3110 /*
3111 * If not, check the SSL/TLS buffers and do a select() on the connection...
3112 */
3113
3114 return (_httpWait(http, msec, 1));
3115 }
3116
3117
3118 /*
3119 * 'httpWrite()' - Write data to a HTTP connection.
3120 *
3121 * This function is deprecated. Use the httpWrite2() function which can
3122 * write more than 2GB of data.
3123 *
3124 * @deprecated@ @exclude all@
3125 */
3126
3127 int /* O - Number of bytes written */
3128 httpWrite(http_t *http, /* I - HTTP connection */
3129 const char *buffer, /* I - Buffer for data */
3130 int length) /* I - Number of bytes to write */
3131 {
3132 return ((int)httpWrite2(http, buffer, (size_t)length));
3133 }
3134
3135
3136 /*
3137 * 'httpWrite2()' - Write data to a HTTP connection.
3138 *
3139 * @since CUPS 1.2/macOS 10.5@
3140 */
3141
3142 ssize_t /* O - Number of bytes written */
3143 httpWrite2(http_t *http, /* I - HTTP connection */
3144 const char *buffer, /* I - Buffer for data */
3145 size_t length) /* I - Number of bytes to write */
3146 {
3147 ssize_t bytes; /* Bytes written */
3148
3149
3150 DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
3151
3152 /*
3153 * Range check input...
3154 */
3155
3156 if (!http || !buffer)
3157 {
3158 DEBUG_puts("1httpWrite2: Returning -1 due to bad input.");
3159 return (-1);
3160 }
3161
3162 /*
3163 * Mark activity on the connection...
3164 */
3165
3166 http->activity = time(NULL);
3167
3168 /*
3169 * Buffer small writes for better performance...
3170 */
3171
3172 #ifdef HAVE_LIBZ
3173 if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
3174 {
3175 DEBUG_printf(("1httpWrite2: http->coding=%d", http->coding));
3176
3177 if (length == 0)
3178 {
3179 http_content_coding_finish(http);
3180 bytes = 0;
3181 }
3182 else
3183 {
3184 size_t slen; /* Bytes to write */
3185 ssize_t sret; /* Bytes written */
3186
3187 ((z_stream *)http->stream)->next_in = (Bytef *)buffer;
3188 ((z_stream *)http->stream)->avail_in = (uInt)length;
3189
3190 while (deflate((z_stream *)http->stream, Z_NO_FLUSH) == Z_OK)
3191 {
3192 DEBUG_printf(("1httpWrite2: avail_out=%d", ((z_stream *)http->stream)->avail_out));
3193
3194 if (((z_stream *)http->stream)->avail_out > 0)
3195 continue;
3196
3197 slen = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out;
3198
3199 DEBUG_printf(("1httpWrite2: Writing intermediate chunk, len=%d", (int)slen));
3200
3201 if (slen > 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
3202 sret = http_write_chunk(http, (char *)http->sbuffer, slen);
3203 else if (slen > 0)
3204 sret = http_write(http, (char *)http->sbuffer, slen);
3205 else
3206 sret = 0;
3207
3208 if (sret < 0)
3209 {
3210 DEBUG_puts("1httpWrite2: Unable to write, returning -1.");
3211 return (-1);
3212 }
3213
3214 ((z_stream *)http->stream)->next_out = (Bytef *)http->sbuffer;
3215 ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
3216 }
3217
3218 bytes = (ssize_t)length;
3219 }
3220 }
3221 else
3222 #endif /* HAVE_LIBZ */
3223 if (length > 0)
3224 {
3225 if (http->wused && (length + (size_t)http->wused) > sizeof(http->wbuffer))
3226 {
3227 DEBUG_printf(("2httpWrite2: Flushing buffer (wused=%d, length="
3228 CUPS_LLFMT ")", http->wused, CUPS_LLCAST length));
3229
3230 httpFlushWrite(http);
3231 }
3232
3233 if ((length + (size_t)http->wused) <= sizeof(http->wbuffer) && length < sizeof(http->wbuffer))
3234 {
3235 /*
3236 * Write to buffer...
3237 */
3238
3239 DEBUG_printf(("2httpWrite2: Copying " CUPS_LLFMT " bytes to wbuffer...",
3240 CUPS_LLCAST length));
3241
3242 memcpy(http->wbuffer + http->wused, buffer, length);
3243 http->wused += (int)length;
3244 bytes = (ssize_t)length;
3245 }
3246 else
3247 {
3248 /*
3249 * Otherwise write the data directly...
3250 */
3251
3252 DEBUG_printf(("2httpWrite2: Writing " CUPS_LLFMT " bytes to socket...",
3253 CUPS_LLCAST length));
3254
3255 if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3256 bytes = (ssize_t)http_write_chunk(http, buffer, length);
3257 else
3258 bytes = (ssize_t)http_write(http, buffer, length);
3259
3260 DEBUG_printf(("2httpWrite2: Wrote " CUPS_LLFMT " bytes...",
3261 CUPS_LLCAST bytes));
3262 }
3263
3264 if (http->data_encoding == HTTP_ENCODING_LENGTH)
3265 http->data_remaining -= bytes;
3266 }
3267 else
3268 bytes = 0;
3269
3270 /*
3271 * Handle end-of-request processing...
3272 */
3273
3274 if ((http->data_encoding == HTTP_ENCODING_CHUNKED && length == 0) ||
3275 (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0))
3276 {
3277 /*
3278 * Finished with the transfer; unless we are sending POST or PUT
3279 * data, go idle...
3280 */
3281
3282 #ifdef HAVE_LIBZ
3283 if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
3284 http_content_coding_finish(http);
3285 #endif /* HAVE_LIBZ */
3286
3287 if (http->wused)
3288 {
3289 if (httpFlushWrite(http) < 0)
3290 return (-1);
3291 }
3292
3293 if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3294 {
3295 /*
3296 * Send a 0-length chunk at the end of the request...
3297 */
3298
3299 http_write(http, "0\r\n\r\n", 5);
3300
3301 /*
3302 * Reset the data state...
3303 */
3304
3305 http->data_encoding = HTTP_ENCODING_FIELDS;
3306 http->data_remaining = 0;
3307 }
3308
3309 if (http->state == HTTP_STATE_POST_RECV)
3310 http->state ++;
3311 else if (http->state == HTTP_STATE_POST_SEND ||
3312 http->state == HTTP_STATE_GET_SEND)
3313 http->state = HTTP_STATE_WAITING;
3314 else
3315 http->state = HTTP_STATE_STATUS;
3316
3317 DEBUG_printf(("2httpWrite2: Changed state to %s.",
3318 httpStateString(http->state)));
3319 }
3320
3321 DEBUG_printf(("1httpWrite2: Returning " CUPS_LLFMT ".", CUPS_LLCAST bytes));
3322
3323 return (bytes);
3324 }
3325
3326
3327 /*
3328 * 'httpWriteResponse()' - Write a HTTP response to a client connection.
3329 *
3330 * @since CUPS 1.7/macOS 10.9@
3331 */
3332
3333 int /* O - 0 on success, -1 on error */
3334 httpWriteResponse(http_t *http, /* I - HTTP connection */
3335 http_status_t status) /* I - Status code */
3336 {
3337 http_encoding_t old_encoding; /* Old data_encoding value */
3338 off_t old_remaining; /* Old data_remaining value */
3339
3340
3341 /*
3342 * Range check input...
3343 */
3344
3345 DEBUG_printf(("httpWriteResponse(http=%p, status=%d)", (void *)http, status));
3346
3347 if (!http || status < HTTP_STATUS_CONTINUE)
3348 {
3349 DEBUG_puts("1httpWriteResponse: Bad input.");
3350 return (-1);
3351 }
3352
3353 /*
3354 * Set the various standard fields if they aren't already...
3355 */
3356
3357 if (!http->fields[HTTP_FIELD_DATE])
3358 httpSetField(http, HTTP_FIELD_DATE, httpGetDateString(time(NULL)));
3359
3360 if (status >= HTTP_STATUS_BAD_REQUEST && http->keep_alive)
3361 {
3362 http->keep_alive = HTTP_KEEPALIVE_OFF;
3363 httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "");
3364 }
3365
3366 if (http->version == HTTP_VERSION_1_1)
3367 {
3368 if (!http->fields[HTTP_FIELD_CONNECTION])
3369 {
3370 if (http->keep_alive)
3371 httpSetField(http, HTTP_FIELD_CONNECTION, "Keep-Alive");
3372 else
3373 httpSetField(http, HTTP_FIELD_CONNECTION, "close");
3374 }
3375
3376 if (http->keep_alive && !http->fields[HTTP_FIELD_KEEP_ALIVE])
3377 httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "timeout=10");
3378 }
3379
3380 #ifdef HAVE_SSL
3381 if (status == HTTP_STATUS_UPGRADE_REQUIRED ||
3382 status == HTTP_STATUS_SWITCHING_PROTOCOLS)
3383 {
3384 if (!http->fields[HTTP_FIELD_CONNECTION])
3385 httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
3386
3387 if (!http->fields[HTTP_FIELD_UPGRADE])
3388 httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
3389
3390 if (!http->fields[HTTP_FIELD_CONTENT_LENGTH])
3391 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "0");
3392 }
3393 #endif /* HAVE_SSL */
3394
3395 if (!http->fields[HTTP_FIELD_SERVER])
3396 httpSetField(http, HTTP_FIELD_SERVER, http->default_fields[HTTP_FIELD_SERVER] ? http->default_fields[HTTP_FIELD_SERVER] : CUPS_MINIMAL);
3397
3398 /*
3399 * Set the Accept-Encoding field if it isn't already...
3400 */
3401
3402 if (!http->fields[HTTP_FIELD_ACCEPT_ENCODING])
3403 httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, http->default_fields[HTTP_FIELD_ACCEPT_ENCODING] ? http->default_fields[HTTP_FIELD_ACCEPT_ENCODING] :
3404 #ifdef HAVE_LIBZ
3405 "gzip, deflate, identity");
3406 #else
3407 "identity");
3408 #endif /* HAVE_LIBZ */
3409
3410 /*
3411 * Send the response header...
3412 */
3413
3414 old_encoding = http->data_encoding;
3415 old_remaining = http->data_remaining;
3416 http->data_encoding = HTTP_ENCODING_FIELDS;
3417
3418 if (httpPrintf(http, "HTTP/%d.%d %d %s\r\n", http->version / 100, http->version % 100, (int)status, httpStatus(status)) < 0)
3419 {
3420 http->status = HTTP_STATUS_ERROR;
3421 return (-1);
3422 }
3423
3424 if (status != HTTP_STATUS_CONTINUE)
3425 {
3426 /*
3427 * 100 Continue doesn't have the rest of the response headers...
3428 */
3429
3430 int i; /* Looping var */
3431 const char *value; /* Field value */
3432
3433 for (i = 0; i < HTTP_FIELD_MAX; i ++)
3434 {
3435 if ((value = httpGetField(http, i)) != NULL && *value)
3436 {
3437 if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
3438 {
3439 http->status = HTTP_STATUS_ERROR;
3440 return (-1);
3441 }
3442 }
3443 }
3444
3445 if (http->cookie)
3446 {
3447 if (strchr(http->cookie, ';'))
3448 {
3449 if (httpPrintf(http, "Set-Cookie: %s\r\n", http->cookie) < 1)
3450 {
3451 http->status = HTTP_STATUS_ERROR;
3452 return (-1);
3453 }
3454 }
3455 else if (httpPrintf(http, "Set-Cookie: %s; path=/; httponly;%s\r\n", http->cookie, http->tls ? " secure;" : "") < 1)
3456 {
3457 http->status = HTTP_STATUS_ERROR;
3458 return (-1);
3459 }
3460 }
3461
3462 /*
3463 * "Click-jacking" defense (STR #4492)...
3464 */
3465
3466 if (httpPrintf(http, "X-Frame-Options: DENY\r\n"
3467 "Content-Security-Policy: frame-ancestors 'none'\r\n") < 1)
3468 {
3469 http->status = HTTP_STATUS_ERROR;
3470 return (-1);
3471 }
3472 }
3473
3474 if (httpWrite2(http, "\r\n", 2) < 2)
3475 {
3476 http->status = HTTP_STATUS_ERROR;
3477 return (-1);
3478 }
3479
3480 if (httpFlushWrite(http) < 0)
3481 {
3482 http->status = HTTP_STATUS_ERROR;
3483 return (-1);
3484 }
3485
3486 if (status == HTTP_STATUS_CONTINUE ||
3487 status == HTTP_STATUS_SWITCHING_PROTOCOLS)
3488 {
3489 /*
3490 * Restore the old data_encoding and data_length values...
3491 */
3492
3493 http->data_encoding = old_encoding;
3494 http->data_remaining = old_remaining;
3495
3496 if (old_remaining <= INT_MAX)
3497 http->_data_remaining = (int)old_remaining;
3498 else
3499 http->_data_remaining = INT_MAX;
3500 }
3501 else if (http->state == HTTP_STATE_OPTIONS ||
3502 http->state == HTTP_STATE_HEAD ||
3503 http->state == HTTP_STATE_PUT ||
3504 http->state == HTTP_STATE_TRACE ||
3505 http->state == HTTP_STATE_CONNECT ||
3506 http->state == HTTP_STATE_STATUS)
3507 {
3508 DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, "
3509 "was %s.", httpStateString(http->state)));
3510 http->state = HTTP_STATE_WAITING;
3511 }
3512 else
3513 {
3514 /*
3515 * Force data_encoding and data_length to be set according to the response
3516 * headers...
3517 */
3518
3519 http_set_length(http);
3520
3521 if (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0)
3522 {
3523 DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, "
3524 "was %s.", httpStateString(http->state)));
3525 http->state = HTTP_STATE_WAITING;
3526 return (0);
3527 }
3528
3529 if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_GET)
3530 http->state ++;
3531
3532 #ifdef HAVE_LIBZ
3533 /*
3534 * Then start any content encoding...
3535 */
3536
3537 DEBUG_puts("1httpWriteResponse: Calling http_content_coding_start.");
3538 http_content_coding_start(http,
3539 httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
3540 #endif /* HAVE_LIBZ */
3541
3542 }
3543
3544 return (0);
3545 }
3546
3547
3548 /*
3549 * 'http_add_field()' - Add a value for a HTTP field, appending if needed.
3550 */
3551
3552 static void
3553 http_add_field(http_t *http, /* I - HTTP connection */
3554 http_field_t field, /* I - HTTP field */
3555 const char *value, /* I - Value string */
3556 int append) /* I - Append value? */
3557 {
3558 char temp[1024]; /* Temporary value string */
3559 size_t fieldlen, /* Length of existing value */
3560 valuelen, /* Length of value string */
3561 total; /* Total length of string */
3562
3563
3564 if (field == HTTP_FIELD_HOST)
3565 {
3566 /*
3567 * Special-case for Host: as we don't want a trailing "." on the hostname and
3568 * need to bracket IPv6 numeric addresses.
3569 */
3570
3571 char *ptr = strchr(value, ':');
3572
3573 if (value[0] != '[' && ptr && strchr(ptr + 1, ':'))
3574 {
3575 /*
3576 * Bracket IPv6 numeric addresses...
3577 *
3578 * This is slightly inefficient (basically copying twice), but is an edge
3579 * case and not worth optimizing...
3580 */
3581
3582 snprintf(temp, sizeof(temp), "[%s]", value);
3583 value = temp;
3584 }
3585 else if (*value)
3586 {
3587 /*
3588 * Check for a trailing dot on the hostname...
3589 */
3590
3591 strlcpy(temp, value, sizeof(temp));
3592 value = temp;
3593 ptr = temp + strlen(temp) - 1;
3594
3595 if (*ptr == '.')
3596 *ptr = '\0';
3597 }
3598 }
3599
3600 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)
3601 append = 0;
3602
3603 if (!append && http->fields[field])
3604 {
3605 if (http->fields[field] != http->_fields[field])
3606 free(http->fields[field]);
3607
3608 http->fields[field] = NULL;
3609 }
3610
3611 valuelen = strlen(value);
3612
3613 if (!valuelen)
3614 {
3615 http->_fields[field][0] = '\0';
3616 return;
3617 }
3618
3619 if (http->fields[field])
3620 {
3621 fieldlen = strlen(http->fields[field]);
3622 total = fieldlen + 2 + valuelen;
3623 }
3624 else
3625 {
3626 fieldlen = 0;
3627 total = valuelen;
3628 }
3629
3630 if (total < HTTP_MAX_VALUE && field < HTTP_FIELD_ACCEPT_ENCODING)
3631 {
3632 /*
3633 * Copy short values to legacy char arrays (maintained for binary
3634 * compatibility with CUPS 1.2.x and earlier applications...)
3635 */
3636
3637 if (fieldlen)
3638 {
3639 char combined[HTTP_MAX_VALUE];
3640 /* Combined value string */
3641
3642 snprintf(combined, sizeof(combined), "%s, %s", http->_fields[field], value);
3643 value = combined;
3644 }
3645
3646 strlcpy(http->_fields[field], value, sizeof(http->_fields[field]));
3647 http->fields[field] = http->_fields[field];
3648 }
3649 else if (fieldlen)
3650 {
3651 /*
3652 * Expand the field value...
3653 */
3654
3655 char *combined; /* New value string */
3656
3657 if (http->fields[field] == http->_fields[field])
3658 {
3659 if ((combined = malloc(total + 1)) != NULL)
3660 {
3661 http->fields[field] = combined;
3662 snprintf(combined, total + 1, "%s, %s", http->_fields[field], value);
3663 }
3664 }
3665 else if ((combined = realloc(http->fields[field], total + 1)) != NULL)
3666 {
3667 http->fields[field] = combined;
3668 strlcat(combined, ", ", total + 1);
3669 strlcat(combined, value, total + 1);
3670 }
3671 }
3672 else
3673 {
3674 /*
3675 * Allocate the field value...
3676 */
3677
3678 http->fields[field] = strdup(value);
3679 }
3680
3681 #ifdef HAVE_LIBZ
3682 if (field == HTTP_FIELD_CONTENT_ENCODING && http->data_encoding != HTTP_ENCODING_FIELDS)
3683 {
3684 DEBUG_puts("1httpSetField: Calling http_content_coding_start.");
3685 http_content_coding_start(http, value);
3686 }
3687 #endif /* HAVE_LIBZ */
3688 }
3689
3690
3691 #ifdef HAVE_LIBZ
3692 /*
3693 * 'http_content_coding_finish()' - Finish doing any content encoding.
3694 */
3695
3696 static void
3697 http_content_coding_finish(
3698 http_t *http) /* I - HTTP connection */
3699 {
3700 int zerr; /* Compression status */
3701 Byte dummy[1]; /* Dummy read buffer */
3702 size_t bytes; /* Number of bytes to write */
3703
3704
3705 DEBUG_printf(("http_content_coding_finish(http=%p)", (void *)http));
3706 DEBUG_printf(("1http_content_coding_finishing: http->coding=%d", http->coding));
3707
3708 switch (http->coding)
3709 {
3710 case _HTTP_CODING_DEFLATE :
3711 case _HTTP_CODING_GZIP :
3712 ((z_stream *)http->stream)->next_in = dummy;
3713 ((z_stream *)http->stream)->avail_in = 0;
3714
3715 do
3716 {
3717 zerr = deflate((z_stream *)http->stream, Z_FINISH);
3718 bytes = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out;
3719
3720 if (bytes > 0)
3721 {
3722 DEBUG_printf(("1http_content_coding_finish: Writing trailing chunk, len=%d", (int)bytes));
3723
3724 if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3725 http_write_chunk(http, (char *)http->sbuffer, bytes);
3726 else
3727 http_write(http, (char *)http->sbuffer, bytes);
3728 }
3729
3730 ((z_stream *)http->stream)->next_out = (Bytef *)http->sbuffer;
3731 ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
3732 }
3733 while (zerr == Z_OK);
3734
3735 deflateEnd((z_stream *)http->stream);
3736
3737 free(http->sbuffer);
3738 free(http->stream);
3739
3740 http->sbuffer = NULL;
3741 http->stream = NULL;
3742
3743 if (http->wused)
3744 httpFlushWrite(http);
3745 break;
3746
3747 case _HTTP_CODING_INFLATE :
3748 case _HTTP_CODING_GUNZIP :
3749 inflateEnd((z_stream *)http->stream);
3750
3751 free(http->sbuffer);
3752 free(http->stream);
3753
3754 http->sbuffer = NULL;
3755 http->stream = NULL;
3756 break;
3757
3758 default :
3759 break;
3760 }
3761
3762 http->coding = _HTTP_CODING_IDENTITY;
3763 }
3764
3765
3766 /*
3767 * 'http_content_coding_start()' - Start doing content encoding.
3768 */
3769
3770 static void
3771 http_content_coding_start(
3772 http_t *http, /* I - HTTP connection */
3773 const char *value) /* I - Value of Content-Encoding */
3774 {
3775 int zerr; /* Error/status */
3776 _http_coding_t coding; /* Content coding value */
3777
3778
3779 DEBUG_printf(("http_content_coding_start(http=%p, value=\"%s\")", (void *)http, value));
3780
3781 if (http->coding != _HTTP_CODING_IDENTITY)
3782 {
3783 DEBUG_printf(("1http_content_coding_start: http->coding already %d.",
3784 http->coding));
3785 return;
3786 }
3787 else if (!strcmp(value, "x-gzip") || !strcmp(value, "gzip"))
3788 {
3789 if (http->state == HTTP_STATE_GET_SEND ||
3790 http->state == HTTP_STATE_POST_SEND)
3791 coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_GZIP :
3792 _HTTP_CODING_GUNZIP;
3793 else if (http->state == HTTP_STATE_POST_RECV ||
3794 http->state == HTTP_STATE_PUT_RECV)
3795 coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_GZIP :
3796 _HTTP_CODING_GUNZIP;
3797 else
3798 {
3799 DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3800 return;
3801 }
3802 }
3803 else if (!strcmp(value, "x-deflate") || !strcmp(value, "deflate"))
3804 {
3805 if (http->state == HTTP_STATE_GET_SEND ||
3806 http->state == HTTP_STATE_POST_SEND)
3807 coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_DEFLATE :
3808 _HTTP_CODING_INFLATE;
3809 else if (http->state == HTTP_STATE_POST_RECV ||
3810 http->state == HTTP_STATE_PUT_RECV)
3811 coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_DEFLATE :
3812 _HTTP_CODING_INFLATE;
3813 else
3814 {
3815 DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3816 return;
3817 }
3818 }
3819 else
3820 {
3821 DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3822 return;
3823 }
3824
3825 switch (coding)
3826 {
3827 case _HTTP_CODING_DEFLATE :
3828 case _HTTP_CODING_GZIP :
3829 if (http->wused)
3830 httpFlushWrite(http);
3831
3832 if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL)
3833 {
3834 http->status = HTTP_STATUS_ERROR;
3835 http->error = errno;
3836 return;
3837 }
3838
3839 /*
3840 * Window size for compression is 11 bits - optimal based on PWG Raster
3841 * sample files on pwg.org. -11 is raw deflate, 27 is gzip, per ZLIB
3842 * documentation.
3843 */
3844
3845 if ((http->stream = calloc(1, sizeof(z_stream))) == NULL)
3846 {
3847 free(http->sbuffer);
3848
3849 http->sbuffer = NULL;
3850 http->status = HTTP_STATUS_ERROR;
3851 http->error = errno;
3852 return;
3853 }
3854
3855 if ((zerr = deflateInit2((z_stream *)http->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7, Z_DEFAULT_STRATEGY)) < Z_OK)
3856 {
3857 free(http->sbuffer);
3858 free(http->stream);
3859
3860 http->sbuffer = NULL;
3861 http->stream = NULL;
3862 http->status = HTTP_STATUS_ERROR;
3863 http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
3864 return;
3865 }
3866
3867 ((z_stream *)http->stream)->next_out = (Bytef *)http->sbuffer;
3868 ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
3869 break;
3870
3871 case _HTTP_CODING_INFLATE :
3872 case _HTTP_CODING_GUNZIP :
3873 if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL)
3874 {
3875 http->status = HTTP_STATUS_ERROR;
3876 http->error = errno;
3877 return;
3878 }
3879
3880 /*
3881 * Window size for decompression is up to 15 bits (maximum supported).
3882 * -15 is raw inflate, 31 is gunzip, per ZLIB documentation.
3883 */
3884
3885 if ((http->stream = calloc(1, sizeof(z_stream))) == NULL)
3886 {
3887 free(http->sbuffer);
3888
3889 http->sbuffer = NULL;
3890 http->status = HTTP_STATUS_ERROR;
3891 http->error = errno;
3892 return;
3893 }
3894
3895 if ((zerr = inflateInit2((z_stream *)http->stream, coding == _HTTP_CODING_INFLATE ? -15 : 31)) < Z_OK)
3896 {
3897 free(http->sbuffer);
3898 free(http->stream);
3899
3900 http->sbuffer = NULL;
3901 http->stream = NULL;
3902 http->status = HTTP_STATUS_ERROR;
3903 http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
3904 return;
3905 }
3906
3907 ((z_stream *)http->stream)->avail_in = 0;
3908 ((z_stream *)http->stream)->next_in = http->sbuffer;
3909 break;
3910
3911 default :
3912 break;
3913 }
3914
3915 http->coding = coding;
3916
3917 DEBUG_printf(("1http_content_coding_start: http->coding now %d.",
3918 http->coding));
3919 }
3920 #endif /* HAVE_LIBZ */
3921
3922
3923 /*
3924 * 'http_create()' - Create an unconnected HTTP connection.
3925 */
3926
3927 static http_t * /* O - HTTP connection */
3928 http_create(
3929 const char *host, /* I - Hostname */
3930 int port, /* I - Port number */
3931 http_addrlist_t *addrlist, /* I - Address list or @code NULL@ */
3932 int family, /* I - Address family or AF_UNSPEC */
3933 http_encryption_t encryption, /* I - Encryption to use */
3934 int blocking, /* I - 1 for blocking mode */
3935 _http_mode_t mode) /* I - _HTTP_MODE_CLIENT or _SERVER */
3936 {
3937 http_t *http; /* New HTTP connection */
3938 char service[255]; /* Service name */
3939 http_addrlist_t *myaddrlist = NULL; /* My address list */
3940
3941
3942 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));
3943
3944 if (!host && mode == _HTTP_MODE_CLIENT)
3945 return (NULL);
3946
3947 httpInitialize();
3948
3949 /*
3950 * Lookup the host...
3951 */
3952
3953 if (addrlist)
3954 {
3955 myaddrlist = httpAddrCopyList(addrlist);
3956 }
3957 else
3958 {
3959 snprintf(service, sizeof(service), "%d", port);
3960
3961 myaddrlist = httpAddrGetList(host, family, service);
3962 }
3963
3964 if (!myaddrlist)
3965 return (NULL);
3966
3967 /*
3968 * Allocate memory for the structure...
3969 */
3970
3971 if ((http = calloc(sizeof(http_t), 1)) == NULL)
3972 {
3973 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
3974 httpAddrFreeList(myaddrlist);
3975 return (NULL);
3976 }
3977
3978 /*
3979 * Initialize the HTTP data...
3980 */
3981
3982 http->mode = mode;
3983 http->activity = time(NULL);
3984 http->addrlist = myaddrlist;
3985 http->blocking = blocking;
3986 http->fd = -1;
3987 #ifdef HAVE_GSSAPI
3988 http->gssctx = GSS_C_NO_CONTEXT;
3989 http->gssname = GSS_C_NO_NAME;
3990 #endif /* HAVE_GSSAPI */
3991 http->status = HTTP_STATUS_CONTINUE;
3992 http->version = HTTP_VERSION_1_1;
3993
3994 if (host)
3995 strlcpy(http->hostname, host, sizeof(http->hostname));
3996
3997 if (port == 443) /* Always use encryption for https */
3998 http->encryption = HTTP_ENCRYPTION_ALWAYS;
3999 else
4000 http->encryption = encryption;
4001
4002 http_set_wait(http);
4003
4004 /*
4005 * Return the new structure...
4006 */
4007
4008 return (http);
4009 }
4010
4011
4012 #ifdef DEBUG
4013 /*
4014 * 'http_debug_hex()' - Do a hex dump of a buffer.
4015 */
4016
4017 static void
4018 http_debug_hex(const char *prefix, /* I - Prefix for line */
4019 const char *buffer, /* I - Buffer to dump */
4020 int bytes) /* I - Bytes to dump */
4021 {
4022 int i, j, /* Looping vars */
4023 ch; /* Current character */
4024 char line[255], /* Line buffer */
4025 *start, /* Start of line after prefix */
4026 *ptr; /* Pointer into line */
4027
4028
4029 if (_cups_debug_fd < 0 || _cups_debug_level < 6)
4030 return;
4031
4032 DEBUG_printf(("6%s: %d bytes:", prefix, bytes));
4033
4034 snprintf(line, sizeof(line), "6%s: ", prefix);
4035 start = line + strlen(line);
4036
4037 for (i = 0; i < bytes; i += 16)
4038 {
4039 for (j = 0, ptr = start; j < 16 && (i + j) < bytes; j ++, ptr += 2)
4040 snprintf(ptr, 3, "%02X", buffer[i + j] & 255);
4041
4042 while (j < 16)
4043 {
4044 memcpy(ptr, " ", 3);
4045 ptr += 2;
4046 j ++;
4047 }
4048
4049 memcpy(ptr, " ", 3);
4050 ptr += 2;
4051
4052 for (j = 0; j < 16 && (i + j) < bytes; j ++)
4053 {
4054 ch = buffer[i + j] & 255;
4055
4056 if (ch < ' ' || ch >= 127)
4057 ch = '.';
4058
4059 *ptr++ = (char)ch;
4060 }
4061
4062 *ptr = '\0';
4063 DEBUG_puts(line);
4064 }
4065 }
4066 #endif /* DEBUG */
4067
4068
4069 /*
4070 * 'http_read()' - Read a buffer from a HTTP connection.
4071 *
4072 * This function does the low-level read from the socket, retrying and timing
4073 * out as needed.
4074 */
4075
4076 static ssize_t /* O - Number of bytes read or -1 on error */
4077 http_read(http_t *http, /* I - HTTP connection */
4078 char *buffer, /* I - Buffer */
4079 size_t length) /* I - Maximum bytes to read */
4080 {
4081 ssize_t bytes; /* Bytes read */
4082
4083
4084 DEBUG_printf(("http_read(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4085
4086 if (!http->blocking || http->timeout_value > 0.0)
4087 {
4088 while (!httpWait(http, http->wait_value))
4089 {
4090 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4091 continue;
4092
4093 DEBUG_puts("2http_read: Timeout.");
4094 return (0);
4095 }
4096 }
4097
4098 DEBUG_printf(("2http_read: Reading %d bytes into buffer.", (int)length));
4099
4100 do
4101 {
4102 #ifdef HAVE_SSL
4103 if (http->tls)
4104 bytes = _httpTLSRead(http, buffer, (int)length);
4105 else
4106 #endif /* HAVE_SSL */
4107 bytes = recv(http->fd, buffer, length, 0);
4108
4109 if (bytes < 0)
4110 {
4111 #ifdef _WIN32
4112 if (WSAGetLastError() != WSAEINTR)
4113 {
4114 http->error = WSAGetLastError();
4115 return (-1);
4116 }
4117 else if (WSAGetLastError() == WSAEWOULDBLOCK)
4118 {
4119 if (!http->timeout_cb ||
4120 !(*http->timeout_cb)(http, http->timeout_data))
4121 {
4122 http->error = WSAEWOULDBLOCK;
4123 return (-1);
4124 }
4125 }
4126 #else
4127 DEBUG_printf(("2http_read: %s", strerror(errno)));
4128
4129 if (errno == EWOULDBLOCK || errno == EAGAIN)
4130 {
4131 if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data))
4132 {
4133 http->error = errno;
4134 return (-1);
4135 }
4136 else if (!http->timeout_cb && errno != EAGAIN)
4137 {
4138 http->error = errno;
4139 return (-1);
4140 }
4141 }
4142 else if (errno != EINTR)
4143 {
4144 http->error = errno;
4145 return (-1);
4146 }
4147 #endif /* _WIN32 */
4148 }
4149 }
4150 while (bytes < 0);
4151
4152 DEBUG_printf(("2http_read: Read " CUPS_LLFMT " bytes into buffer.",
4153 CUPS_LLCAST bytes));
4154 #ifdef DEBUG
4155 if (bytes > 0)
4156 http_debug_hex("http_read", buffer, (int)bytes);
4157 #endif /* DEBUG */
4158
4159 if (bytes < 0)
4160 {
4161 #ifdef _WIN32
4162 if (WSAGetLastError() == WSAEINTR)
4163 bytes = 0;
4164 else
4165 http->error = WSAGetLastError();
4166 #else
4167 if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb))
4168 bytes = 0;
4169 else
4170 http->error = errno;
4171 #endif /* _WIN32 */
4172 }
4173 else if (bytes == 0)
4174 {
4175 http->error = EPIPE;
4176 return (0);
4177 }
4178
4179 return (bytes);
4180 }
4181
4182
4183 /*
4184 * 'http_read_buffered()' - Do a buffered read from a HTTP connection.
4185 *
4186 * This function reads data from the HTTP buffer or from the socket, as needed.
4187 */
4188
4189 static ssize_t /* O - Number of bytes read or -1 on error */
4190 http_read_buffered(http_t *http, /* I - HTTP connection */
4191 char *buffer, /* I - Buffer */
4192 size_t length) /* I - Maximum bytes to read */
4193 {
4194 ssize_t bytes; /* Bytes read */
4195
4196
4197 DEBUG_printf(("http_read_buffered(http=%p, buffer=%p, length=" CUPS_LLFMT ") used=%d", (void *)http, (void *)buffer, CUPS_LLCAST length, http->used));
4198
4199 if (http->used > 0)
4200 {
4201 if (length > (size_t)http->used)
4202 bytes = (ssize_t)http->used;
4203 else
4204 bytes = (ssize_t)length;
4205
4206 DEBUG_printf(("2http_read: Grabbing %d bytes from input buffer.",
4207 (int)bytes));
4208
4209 memcpy(buffer, http->buffer, (size_t)bytes);
4210 http->used -= (int)bytes;
4211
4212 if (http->used > 0)
4213 memmove(http->buffer, http->buffer + bytes, (size_t)http->used);
4214 }
4215 else
4216 bytes = http_read(http, buffer, length);
4217
4218 return (bytes);
4219 }
4220
4221
4222 /*
4223 * 'http_read_chunk()' - Read a chunk from a HTTP connection.
4224 *
4225 * This function reads and validates the chunk length, then does a buffered read
4226 * returning the number of bytes placed in the buffer.
4227 */
4228
4229 static ssize_t /* O - Number of bytes read or -1 on error */
4230 http_read_chunk(http_t *http, /* I - HTTP connection */
4231 char *buffer, /* I - Buffer */
4232 size_t length) /* I - Maximum bytes to read */
4233 {
4234 DEBUG_printf(("http_read_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4235
4236 if (http->data_remaining <= 0)
4237 {
4238 char len[32]; /* Length string */
4239
4240 if (!httpGets(len, sizeof(len), http))
4241 {
4242 DEBUG_puts("1http_read_chunk: Could not get chunk length.");
4243 return (0);
4244 }
4245
4246 if (!len[0])
4247 {
4248 DEBUG_puts("1http_read_chunk: Blank chunk length, trying again...");
4249 if (!httpGets(len, sizeof(len), http))
4250 {
4251 DEBUG_puts("1http_read_chunk: Could not get chunk length.");
4252 return (0);
4253 }
4254 }
4255
4256 http->data_remaining = strtoll(len, NULL, 16);
4257
4258 if (http->data_remaining < 0)
4259 {
4260 DEBUG_printf(("1http_read_chunk: Negative chunk length \"%s\" ("
4261 CUPS_LLFMT ")", len, CUPS_LLCAST http->data_remaining));
4262 return (0);
4263 }
4264
4265 DEBUG_printf(("2http_read_chunk: Got chunk length \"%s\" (" CUPS_LLFMT ")",
4266 len, CUPS_LLCAST http->data_remaining));
4267
4268 if (http->data_remaining == 0)
4269 {
4270 /*
4271 * 0-length chunk, grab trailing blank line...
4272 */
4273
4274 httpGets(len, sizeof(len), http);
4275 }
4276 }
4277
4278 DEBUG_printf(("2http_read_chunk: data_remaining=" CUPS_LLFMT,
4279 CUPS_LLCAST http->data_remaining));
4280
4281 if (http->data_remaining <= 0)
4282 return (0);
4283 else if (length > (size_t)http->data_remaining)
4284 length = (size_t)http->data_remaining;
4285
4286 return (http_read_buffered(http, buffer, length));
4287 }
4288
4289
4290 /*
4291 * 'http_send()' - Send a request with all fields and the trailing blank line.
4292 */
4293
4294 static int /* O - 0 on success, non-zero on error */
4295 http_send(http_t *http, /* I - HTTP connection */
4296 http_state_t request, /* I - Request code */
4297 const char *uri) /* I - URI */
4298 {
4299 int i; /* Looping var */
4300 char buf[1024]; /* Encoded URI buffer */
4301 const char *value; /* Field value */
4302 static const char * const codes[] = /* Request code strings */
4303 {
4304 NULL,
4305 "OPTIONS",
4306 "GET",
4307 NULL,
4308 "HEAD",
4309 "POST",
4310 NULL,
4311 NULL,
4312 "PUT",
4313 NULL,
4314 "DELETE",
4315 "TRACE",
4316 "CLOSE",
4317 NULL,
4318 NULL
4319 };
4320
4321
4322 DEBUG_printf(("4http_send(http=%p, request=HTTP_%s, uri=\"%s\")", (void *)http, codes[request], uri));
4323
4324 if (http == NULL || uri == NULL)
4325 return (-1);
4326
4327 /*
4328 * Set the User-Agent field if it isn't already...
4329 */
4330
4331 if (!http->fields[HTTP_FIELD_USER_AGENT])
4332 {
4333 if (http->default_fields[HTTP_FIELD_USER_AGENT])
4334 httpSetField(http, HTTP_FIELD_USER_AGENT, http->default_fields[HTTP_FIELD_USER_AGENT]);
4335 else
4336 httpSetField(http, HTTP_FIELD_USER_AGENT, cupsUserAgent());
4337 }
4338
4339 /*
4340 * Set the Accept-Encoding field if it isn't already...
4341 */
4342
4343 if (!http->fields[HTTP_FIELD_ACCEPT_ENCODING] && http->default_fields[HTTP_FIELD_ACCEPT_ENCODING])
4344 httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, http->default_fields[HTTP_FIELD_ACCEPT_ENCODING]);
4345
4346 /*
4347 * Encode the URI as needed...
4348 */
4349
4350 _httpEncodeURI(buf, uri, sizeof(buf));
4351
4352 /*
4353 * See if we had an error the last time around; if so, reconnect...
4354 */
4355
4356 if (http->fd < 0 || http->status == HTTP_STATUS_ERROR ||
4357 http->status >= HTTP_STATUS_BAD_REQUEST)
4358 {
4359 DEBUG_printf(("5http_send: Reconnecting, fd=%d, status=%d, tls_upgrade=%d",
4360 http->fd, http->status, http->tls_upgrade));
4361
4362 if (httpReconnect2(http, 30000, NULL))
4363 return (-1);
4364 }
4365
4366 /*
4367 * Flush any written data that is pending...
4368 */
4369
4370 if (http->wused)
4371 {
4372 if (httpFlushWrite(http) < 0)
4373 if (httpReconnect2(http, 30000, NULL))
4374 return (-1);
4375 }
4376
4377 /*
4378 * Send the request header...
4379 */
4380
4381 http->state = request;
4382 http->data_encoding = HTTP_ENCODING_FIELDS;
4383
4384 if (request == HTTP_STATE_POST || request == HTTP_STATE_PUT)
4385 http->state ++;
4386
4387 http->status = HTTP_STATUS_CONTINUE;
4388
4389 #ifdef HAVE_SSL
4390 if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls)
4391 {
4392 httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
4393 httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
4394 }
4395 #endif /* HAVE_SSL */
4396
4397 if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
4398 {
4399 http->status = HTTP_STATUS_ERROR;
4400 return (-1);
4401 }
4402
4403 for (i = 0; i < HTTP_FIELD_MAX; i ++)
4404 if ((value = httpGetField(http, i)) != NULL && *value)
4405 {
4406 DEBUG_printf(("5http_send: %s: %s", http_fields[i], value));
4407
4408 if (i == HTTP_FIELD_HOST)
4409 {
4410 if (httpPrintf(http, "Host: %s:%d\r\n", value,
4411 httpAddrPort(http->hostaddr)) < 1)
4412 {
4413 http->status = HTTP_STATUS_ERROR;
4414 return (-1);
4415 }
4416 }
4417 else if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
4418 {
4419 http->status = HTTP_STATUS_ERROR;
4420 return (-1);
4421 }
4422 }
4423
4424 if (http->cookie)
4425 if (httpPrintf(http, "Cookie: $Version=0; %s\r\n", http->cookie) < 1)
4426 {
4427 http->status = HTTP_STATUS_ERROR;
4428 return (-1);
4429 }
4430
4431 DEBUG_printf(("5http_send: expect=%d, mode=%d, state=%d", http->expect,
4432 http->mode, http->state));
4433
4434 if (http->expect == HTTP_STATUS_CONTINUE && http->mode == _HTTP_MODE_CLIENT &&
4435 (http->state == HTTP_STATE_POST_RECV ||
4436 http->state == HTTP_STATE_PUT_RECV))
4437 if (httpPrintf(http, "Expect: 100-continue\r\n") < 1)
4438 {
4439 http->status = HTTP_STATUS_ERROR;
4440 return (-1);
4441 }
4442
4443 if (httpPrintf(http, "\r\n") < 1)
4444 {
4445 http->status = HTTP_STATUS_ERROR;
4446 return (-1);
4447 }
4448
4449 if (httpFlushWrite(http) < 0)
4450 return (-1);
4451
4452 http_set_length(http);
4453 httpClearFields(http);
4454
4455 /*
4456 * The Kerberos and AuthRef authentication strings can only be used once...
4457 */
4458
4459 if (http->fields[HTTP_FIELD_AUTHORIZATION] && http->authstring &&
4460 (!strncmp(http->authstring, "Negotiate", 9) ||
4461 !strncmp(http->authstring, "AuthRef", 7)))
4462 {
4463 http->_authstring[0] = '\0';
4464
4465 if (http->authstring != http->_authstring)
4466 free(http->authstring);
4467
4468 http->authstring = http->_authstring;
4469 }
4470
4471 return (0);
4472 }
4473
4474
4475 /*
4476 * 'http_set_length()' - Set the data_encoding and data_remaining values.
4477 */
4478
4479 static off_t /* O - Remainder or -1 on error */
4480 http_set_length(http_t *http) /* I - Connection */
4481 {
4482 off_t remaining; /* Remainder */
4483
4484
4485 DEBUG_printf(("http_set_length(http=%p) mode=%d state=%s", (void *)http, http->mode, httpStateString(http->state)));
4486
4487 if ((remaining = httpGetLength2(http)) >= 0)
4488 {
4489 if (http->mode == _HTTP_MODE_SERVER &&
4490 http->state != HTTP_STATE_GET_SEND &&
4491 http->state != HTTP_STATE_PUT &&
4492 http->state != HTTP_STATE_POST &&
4493 http->state != HTTP_STATE_POST_SEND)
4494 {
4495 DEBUG_puts("1http_set_length: Not setting data_encoding/remaining.");
4496 return (remaining);
4497 }
4498
4499 if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_TRANSFER_ENCODING), "chunked"))
4500 {
4501 DEBUG_puts("1http_set_length: Setting data_encoding to "
4502 "HTTP_ENCODING_CHUNKED.");
4503 http->data_encoding = HTTP_ENCODING_CHUNKED;
4504 }
4505 else
4506 {
4507 DEBUG_puts("1http_set_length: Setting data_encoding to "
4508 "HTTP_ENCODING_LENGTH.");
4509 http->data_encoding = HTTP_ENCODING_LENGTH;
4510 }
4511
4512 DEBUG_printf(("1http_set_length: Setting data_remaining to " CUPS_LLFMT ".",
4513 CUPS_LLCAST remaining));
4514 http->data_remaining = remaining;
4515
4516 if (remaining <= INT_MAX)
4517 http->_data_remaining = (int)remaining;
4518 else
4519 http->_data_remaining = INT_MAX;
4520 }
4521
4522 return (remaining);
4523 }
4524
4525 /*
4526 * 'http_set_timeout()' - Set the socket timeout values.
4527 */
4528
4529 static void
4530 http_set_timeout(int fd, /* I - File descriptor */
4531 double timeout) /* I - Timeout in seconds */
4532 {
4533 #ifdef _WIN32
4534 DWORD tv = (DWORD)(timeout * 1000);
4535 /* Timeout in milliseconds */
4536
4537 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4538 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4539
4540 #else
4541 struct timeval tv; /* Timeout in secs and usecs */
4542
4543 tv.tv_sec = (int)timeout;
4544 tv.tv_usec = (int)(1000000 * fmod(timeout, 1.0));
4545
4546 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4547 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4548 #endif /* _WIN32 */
4549 }
4550
4551
4552 /*
4553 * 'http_set_wait()' - Set the default wait value for reads.
4554 */
4555
4556 static void
4557 http_set_wait(http_t *http) /* I - HTTP connection */
4558 {
4559 if (http->blocking)
4560 {
4561 http->wait_value = (int)(http->timeout_value * 1000);
4562
4563 if (http->wait_value <= 0)
4564 http->wait_value = 60000;
4565 }
4566 else
4567 http->wait_value = 10000;
4568 }
4569
4570
4571 #ifdef HAVE_SSL
4572 /*
4573 * 'http_tls_upgrade()' - Force upgrade to TLS encryption.
4574 */
4575
4576 static int /* O - Status of connection */
4577 http_tls_upgrade(http_t *http) /* I - HTTP connection */
4578 {
4579 int ret; /* Return value */
4580 http_t myhttp; /* Local copy of HTTP data */
4581
4582
4583 DEBUG_printf(("7http_tls_upgrade(%p)", (void *)http));
4584
4585 /*
4586 * Flush the connection to make sure any previous "Upgrade" message
4587 * has been read.
4588 */
4589
4590 httpFlush(http);
4591
4592 /*
4593 * Copy the HTTP data to a local variable so we can do the OPTIONS
4594 * request without interfering with the existing request data...
4595 */
4596
4597 memcpy(&myhttp, http, sizeof(myhttp));
4598
4599 /*
4600 * Send an OPTIONS request to the server, requiring SSL or TLS
4601 * encryption on the link...
4602 */
4603
4604 http->tls_upgrade = 1;
4605 memset(http->fields, 0, sizeof(http->fields));
4606 http->expect = (http_status_t)0;
4607
4608 if (http->hostname[0] == '/')
4609 httpSetField(http, HTTP_FIELD_HOST, "localhost");
4610 else
4611 httpSetField(http, HTTP_FIELD_HOST, http->hostname);
4612
4613 httpSetField(http, HTTP_FIELD_CONNECTION, "upgrade");
4614 httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
4615
4616 if ((ret = httpOptions(http, "*")) == 0)
4617 {
4618 /*
4619 * Wait for the secure connection...
4620 */
4621
4622 while (httpUpdate(http) == HTTP_STATUS_CONTINUE);
4623 }
4624
4625 /*
4626 * Restore the HTTP request data...
4627 */
4628
4629 memcpy(http->_fields, myhttp._fields, sizeof(http->_fields));
4630 memcpy(http->fields, myhttp.fields, sizeof(http->fields));
4631
4632 http->data_encoding = myhttp.data_encoding;
4633 http->data_remaining = myhttp.data_remaining;
4634 http->_data_remaining = myhttp._data_remaining;
4635 http->expect = myhttp.expect;
4636 http->digest_tries = myhttp.digest_tries;
4637 http->tls_upgrade = 0;
4638
4639 /*
4640 * See if we actually went secure...
4641 */
4642
4643 if (!http->tls)
4644 {
4645 /*
4646 * Server does not support HTTP upgrade...
4647 */
4648
4649 DEBUG_puts("8http_tls_upgrade: Server does not support HTTP upgrade!");
4650
4651 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Encryption is not supported."), 1);
4652 httpAddrClose(NULL, http->fd);
4653
4654 http->fd = -1;
4655
4656 return (-1);
4657 }
4658 else
4659 return (ret);
4660 }
4661 #endif /* HAVE_SSL */
4662
4663
4664 /*
4665 * 'http_write()' - Write a buffer to a HTTP connection.
4666 */
4667
4668 static ssize_t /* O - Number of bytes written */
4669 http_write(http_t *http, /* I - HTTP connection */
4670 const char *buffer, /* I - Buffer for data */
4671 size_t length) /* I - Number of bytes to write */
4672 {
4673 ssize_t tbytes, /* Total bytes sent */
4674 bytes; /* Bytes sent */
4675
4676
4677 DEBUG_printf(("2http_write(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4678 http->error = 0;
4679 tbytes = 0;
4680
4681 while (length > 0)
4682 {
4683 DEBUG_printf(("3http_write: About to write %d bytes.", (int)length));
4684
4685 if (http->timeout_value > 0.0)
4686 {
4687 #ifdef HAVE_POLL
4688 struct pollfd pfd; /* Polled file descriptor */
4689 #else
4690 fd_set output_set; /* Output ready for write? */
4691 struct timeval timeout; /* Timeout value */
4692 #endif /* HAVE_POLL */
4693 int nfds; /* Result from select()/poll() */
4694
4695 do
4696 {
4697 #ifdef HAVE_POLL
4698 pfd.fd = http->fd;
4699 pfd.events = POLLOUT;
4700
4701 while ((nfds = poll(&pfd, 1, http->wait_value)) < 0 &&
4702 (errno == EINTR || errno == EAGAIN))
4703 /* do nothing */;
4704
4705 #else
4706 do
4707 {
4708 FD_ZERO(&output_set);
4709 FD_SET(http->fd, &output_set);
4710
4711 timeout.tv_sec = http->wait_value / 1000;
4712 timeout.tv_usec = 1000 * (http->wait_value % 1000);
4713
4714 nfds = select(http->fd + 1, NULL, &output_set, NULL, &timeout);
4715 }
4716 # ifdef _WIN32
4717 while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
4718 WSAGetLastError() == WSAEWOULDBLOCK));
4719 # else
4720 while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
4721 # endif /* _WIN32 */
4722 #endif /* HAVE_POLL */
4723
4724 if (nfds < 0)
4725 {
4726 http->error = errno;
4727 return (-1);
4728 }
4729 else if (nfds == 0 && (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data)))
4730 {
4731 #ifdef _WIN32
4732 http->error = WSAEWOULDBLOCK;
4733 #else
4734 http->error = EWOULDBLOCK;
4735 #endif /* _WIN32 */
4736 return (-1);
4737 }
4738 }
4739 while (nfds <= 0);
4740 }
4741
4742 #ifdef HAVE_SSL
4743 if (http->tls)
4744 bytes = _httpTLSWrite(http, buffer, (int)length);
4745 else
4746 #endif /* HAVE_SSL */
4747 bytes = send(http->fd, buffer, length, 0);
4748
4749 DEBUG_printf(("3http_write: Write of " CUPS_LLFMT " bytes returned "
4750 CUPS_LLFMT ".", CUPS_LLCAST length, CUPS_LLCAST bytes));
4751
4752 if (bytes < 0)
4753 {
4754 #ifdef _WIN32
4755 if (WSAGetLastError() == WSAEINTR)
4756 continue;
4757 else if (WSAGetLastError() == WSAEWOULDBLOCK)
4758 {
4759 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4760 continue;
4761
4762 http->error = WSAGetLastError();
4763 }
4764 else if (WSAGetLastError() != http->error &&
4765 WSAGetLastError() != WSAECONNRESET)
4766 {
4767 http->error = WSAGetLastError();
4768 continue;
4769 }
4770
4771 #else
4772 if (errno == EINTR)
4773 continue;
4774 else if (errno == EWOULDBLOCK || errno == EAGAIN)
4775 {
4776 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4777 continue;
4778 else if (!http->timeout_cb && errno == EAGAIN)
4779 continue;
4780
4781 http->error = errno;
4782 }
4783 else if (errno != http->error && errno != ECONNRESET)
4784 {
4785 http->error = errno;
4786 continue;
4787 }
4788 #endif /* _WIN32 */
4789
4790 DEBUG_printf(("3http_write: error writing data (%s).",
4791 strerror(http->error)));
4792
4793 return (-1);
4794 }
4795
4796 buffer += bytes;
4797 tbytes += bytes;
4798 length -= (size_t)bytes;
4799 }
4800
4801 #ifdef DEBUG
4802 http_debug_hex("http_write", buffer - tbytes, (int)tbytes);
4803 #endif /* DEBUG */
4804
4805 DEBUG_printf(("3http_write: Returning " CUPS_LLFMT ".", CUPS_LLCAST tbytes));
4806
4807 return (tbytes);
4808 }
4809
4810
4811 /*
4812 * 'http_write_chunk()' - Write a chunked buffer.
4813 */
4814
4815 static ssize_t /* O - Number bytes written */
4816 http_write_chunk(http_t *http, /* I - HTTP connection */
4817 const char *buffer, /* I - Buffer to write */
4818 size_t length) /* I - Length of buffer */
4819 {
4820 char header[16]; /* Chunk header */
4821 ssize_t bytes; /* Bytes written */
4822
4823
4824 DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4825
4826 /*
4827 * Write the chunk header, data, and trailer.
4828 */
4829
4830 snprintf(header, sizeof(header), "%x\r\n", (unsigned)length);
4831 if (http_write(http, header, strlen(header)) < 0)
4832 {
4833 DEBUG_puts("8http_write_chunk: http_write of length failed.");
4834 return (-1);
4835 }
4836
4837 if ((bytes = http_write(http, buffer, length)) < 0)
4838 {
4839 DEBUG_puts("8http_write_chunk: http_write of buffer failed.");
4840 return (-1);
4841 }
4842
4843 if (http_write(http, "\r\n", 2) < 0)
4844 {
4845 DEBUG_puts("8http_write_chunk: http_write of CR LF failed.");
4846 return (-1);
4847 }
4848
4849 return (bytes);
4850 }