1 /*
2 * HTTP routines for CUPS.
3 *
4 * Copyright © 2007-2019 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@ */
httpAcceptConnection(int fd,int blocking)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 */
httpAddCredential(cups_array_t * credentials,const void * data,size_t datalen)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
httpBlocking(http_t * http,int b)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 */
httpCheck(http_t * http)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
httpClearCookie(http_t * http)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
httpClearFields(http_t * http)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
httpClose(http_t * http)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 */
httpCompareCredentials(cups_array_t * cred1,cups_array_t * cred2)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 */
httpConnect(const char * host,int port)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 */
httpConnect2(const char * host,int port,http_addrlist_t * addrlist,int family,http_encryption_t encryption,int blocking,int msec,int * cancel)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 */
httpConnectEncrypt(const char * host,int port,http_encryption_t encryption)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) */
httpDelete(http_t * http,const char * uri)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
_httpDisconnect(http_t * http)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 */
httpEncryption(http_t * http,http_encryption_t e)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 */
httpError(http_t * http)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 */
httpFieldValue(const char * name)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
httpFlush(http_t * http)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 */
httpFlushWrite(http_t * http)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
httpFreeCredentials(cups_array_t * credentials)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) */
httpGet(http_t * http,const char * uri)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 */
httpGetActivity(http_t * http)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 */
httpGetAuthString(http_t * http)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 */
httpGetBlocking(http_t * http)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. */
httpGetContentEncoding(http_t * http)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@ */
httpGetCookie(http_t * http)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 */
httpGetEncryption(http_t * http)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 */
httpGetExpect(http_t * http)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 */
httpGetFd(http_t * http)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 */
httpGetField(http_t * http,http_field_t field)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 */
httpGetKeepAlive(http_t * http)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 */
httpGetLength(http_t * http)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 */
httpGetLength2(http_t * http)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 */
httpGetPending(http_t * http)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 */
httpGetReady(http_t * http)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 */
httpGetRemaining(http_t * http)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@ */
httpGets(char * line,int length,http_t * http)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 */
httpGetState(http_t * http)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 */
httpGetStatus(http_t * http)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@ */
httpGetSubField(http_t * http,http_field_t field,const char * name,char * value)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@ */
httpGetSubField2(http_t * http,http_field_t field,const char * name,char * value,int valuelen)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 */
httpGetVersion(http_t * http)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) */
httpHead(http_t * http,const char * uri)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
httpInitialize(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 */
httpIsChunked(http_t * http)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 */
httpIsEncrypted(http_t * http)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) */
httpOptions(http_t * http,const char * uri)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 */
httpPeek(http_t * http,char * buffer,size_t length)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) */
httpPost(http_t * http,const char * uri)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 */
httpPrintf(http_t * http,const char * format,...)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) */
httpPut(http_t * http,const char * uri)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 */
httpRead(http_t * http,char * buffer,int length)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 */
httpRead2(http_t * http,char * buffer,size_t length)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 */
httpReadRequest(http_t * http,char * uri,size_t urilen)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 */
httpReconnect(http_t * http)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 */
httpReconnect2(http_t * http,int msec,int * cancel)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
2425 return (-1);
2426 }
2427 }
2428 else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls_upgrade)
2429 return (http_tls_upgrade(http));
2430 #endif /* HAVE_SSL */
2431
2432 DEBUG_printf(("1httpReconnect2: Connected to %s:%d...",
2433 httpAddrString(http->hostaddr, temp, sizeof(temp)),
2434 httpAddrPort(http->hostaddr)));
2435
2436 return (0);
2437 }
2438
2439
2440 /*
2441 * 'httpSetAuthString()' - Set the current authorization string.
2442 *
2443 * This function just stores a copy of the current authorization string in
2444 * the HTTP connection object. You must still call @link httpSetField@ to set
2445 * @code HTTP_FIELD_AUTHORIZATION@ prior to issuing a HTTP request using
2446 * @link httpGet@, @link httpHead@, @link httpOptions@, @link httpPost@, or
2447 * @link httpPut@.
2448 *
2449 * @since CUPS 1.3/macOS 10.5@
2450 */
2451
2452 void
httpSetAuthString(http_t * http,const char * scheme,const char * data)2453 httpSetAuthString(http_t *http, /* I - HTTP connection */
2454 const char *scheme, /* I - Auth scheme (NULL to clear it) */
2455 const char *data) /* I - Auth data (NULL for none) */
2456 {
2457 /*
2458 * Range check input...
2459 */
2460
2461 if (!http)
2462 return;
2463
2464 if (http->authstring && http->authstring != http->_authstring)
2465 free(http->authstring);
2466
2467 http->authstring = http->_authstring;
2468
2469 if (scheme)
2470 {
2471 /*
2472 * Set the current authorization string...
2473 */
2474
2475 size_t len = strlen(scheme) + (data ? strlen(data) + 1 : 0) + 1;
2476 char *temp;
2477
2478 if (len > sizeof(http->_authstring))
2479 {
2480 if ((temp = malloc(len)) == NULL)
2481 len = sizeof(http->_authstring);
2482 else
2483 http->authstring = temp;
2484 }
2485
2486 if (data)
2487 snprintf(http->authstring, len, "%s %s", scheme, data);
2488 else
2489 strlcpy(http->authstring, scheme, len);
2490 }
2491 else
2492 {
2493 /*
2494 * Clear the current authorization string...
2495 */
2496
2497 http->_authstring[0] = '\0';
2498 }
2499 }
2500
2501
2502 /*
2503 * 'httpSetCredentials()' - Set the credentials associated with an encrypted
2504 * connection.
2505 *
2506 * @since CUPS 1.5/macOS 10.7@
2507 */
2508
2509 int /* O - Status of call (0 = success) */
httpSetCredentials(http_t * http,cups_array_t * credentials)2510 httpSetCredentials(http_t *http, /* I - HTTP connection */
2511 cups_array_t *credentials) /* I - Array of credentials */
2512 {
2513 if (!http || cupsArrayCount(credentials) < 1)
2514 return (-1);
2515
2516 #ifdef HAVE_SSL
2517 _httpFreeCredentials(http->tls_credentials);
2518
2519 http->tls_credentials = _httpCreateCredentials(credentials);
2520 #endif /* HAVE_SSL */
2521
2522 return (http->tls_credentials ? 0 : -1);
2523 }
2524
2525
2526 /*
2527 * 'httpSetCookie()' - Set the cookie value(s).
2528 *
2529 * @since CUPS 1.1.19/macOS 10.3@
2530 */
2531
2532 void
httpSetCookie(http_t * http,const char * cookie)2533 httpSetCookie(http_t *http, /* I - Connection */
2534 const char *cookie) /* I - Cookie string */
2535 {
2536 if (!http)
2537 return;
2538
2539 if (http->cookie)
2540 free(http->cookie);
2541
2542 if (cookie)
2543 http->cookie = strdup(cookie);
2544 else
2545 http->cookie = NULL;
2546 }
2547
2548
2549 /*
2550 * 'httpSetDefaultField()' - Set the default value of an HTTP header.
2551 *
2552 * Currently only @code HTTP_FIELD_ACCEPT_ENCODING@, @code HTTP_FIELD_SERVER@,
2553 * and @code HTTP_FIELD_USER_AGENT@ can be set.
2554 *
2555 * @since CUPS 1.7/macOS 10.9@
2556 */
2557
2558 void
httpSetDefaultField(http_t * http,http_field_t field,const char * value)2559 httpSetDefaultField(http_t *http, /* I - HTTP connection */
2560 http_field_t field, /* I - Field index */
2561 const char *value)/* I - Value */
2562 {
2563 DEBUG_printf(("httpSetDefaultField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));
2564
2565 if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
2566 return;
2567
2568 if (http->default_fields[field])
2569 free(http->default_fields[field]);
2570
2571 http->default_fields[field] = value ? strdup(value) : NULL;
2572 }
2573
2574
2575 /*
2576 * 'httpSetExpect()' - Set the Expect: header in a request.
2577 *
2578 * Currently only @code HTTP_STATUS_CONTINUE@ is supported for the "expect"
2579 * argument.
2580 *
2581 * @since CUPS 1.2/macOS 10.5@
2582 */
2583
2584 void
httpSetExpect(http_t * http,http_status_t expect)2585 httpSetExpect(http_t *http, /* I - HTTP connection */
2586 http_status_t expect) /* I - HTTP status to expect
2587 (@code HTTP_STATUS_CONTINUE@) */
2588 {
2589 DEBUG_printf(("httpSetExpect(http=%p, expect=%d)", (void *)http, expect));
2590
2591 if (http)
2592 http->expect = expect;
2593 }
2594
2595
2596 /*
2597 * 'httpSetField()' - Set the value of an HTTP header.
2598 */
2599
2600 void
httpSetField(http_t * http,http_field_t field,const char * value)2601 httpSetField(http_t *http, /* I - HTTP connection */
2602 http_field_t field, /* I - Field index */
2603 const char *value) /* I - Value */
2604 {
2605 DEBUG_printf(("httpSetField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));
2606
2607 if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX || !value)
2608 return;
2609
2610 http_add_field(http, field, value, 0);
2611 }
2612
2613
2614 /*
2615 * 'httpSetKeepAlive()' - Set the current Keep-Alive state of a connection.
2616 *
2617 * @since CUPS 2.0/OS 10.10@
2618 */
2619
2620 void
httpSetKeepAlive(http_t * http,http_keepalive_t keep_alive)2621 httpSetKeepAlive(
2622 http_t *http, /* I - HTTP connection */
2623 http_keepalive_t keep_alive) /* I - New Keep-Alive value */
2624 {
2625 if (http)
2626 http->keep_alive = keep_alive;
2627 }
2628
2629
2630 /*
2631 * 'httpSetLength()' - Set the content-length and content-encoding.
2632 *
2633 * @since CUPS 1.2/macOS 10.5@
2634 */
2635
2636 void
httpSetLength(http_t * http,size_t length)2637 httpSetLength(http_t *http, /* I - HTTP connection */
2638 size_t length) /* I - Length (0 for chunked) */
2639 {
2640 DEBUG_printf(("httpSetLength(http=%p, length=" CUPS_LLFMT ")", (void *)http, CUPS_LLCAST length));
2641
2642 if (!http)
2643 return;
2644
2645 if (!length)
2646 {
2647 httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
2648 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "");
2649 }
2650 else
2651 {
2652 char len[32]; /* Length string */
2653
2654
2655 snprintf(len, sizeof(len), CUPS_LLFMT, CUPS_LLCAST length);
2656 httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "");
2657 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, len);
2658 }
2659 }
2660
2661
2662 /*
2663 * 'httpSetTimeout()' - Set read/write timeouts and an optional callback.
2664 *
2665 * The optional timeout callback receives both the HTTP connection and a user
2666 * data pointer and must return 1 to continue or 0 to error (time) out.
2667 *
2668 * @since CUPS 1.5/macOS 10.7@
2669 */
2670
2671 void
httpSetTimeout(http_t * http,double timeout,http_timeout_cb_t cb,void * user_data)2672 httpSetTimeout(
2673 http_t *http, /* I - HTTP connection */
2674 double timeout, /* I - Number of seconds for timeout,
2675 must be greater than 0 */
2676 http_timeout_cb_t cb, /* I - Callback function or @code NULL@ */
2677 void *user_data) /* I - User data pointer */
2678 {
2679 if (!http || timeout <= 0.0)
2680 return;
2681
2682 http->timeout_cb = cb;
2683 http->timeout_data = user_data;
2684 http->timeout_value = timeout;
2685
2686 if (http->fd >= 0)
2687 http_set_timeout(http->fd, timeout);
2688
2689 http_set_wait(http);
2690 }
2691
2692
2693 /*
2694 * 'httpShutdown()' - Shutdown one side of an HTTP connection.
2695 *
2696 * @since CUPS 2.0/OS 10.10@
2697 */
2698
2699 void
httpShutdown(http_t * http)2700 httpShutdown(http_t *http) /* I - HTTP connection */
2701 {
2702 if (!http || http->fd < 0)
2703 return;
2704
2705 #ifdef HAVE_SSL
2706 if (http->tls)
2707 _httpTLSStop(http);
2708 #endif /* HAVE_SSL */
2709
2710 #ifdef _WIN32
2711 shutdown(http->fd, SD_RECEIVE); /* Microsoft-ism... */
2712 #else
2713 shutdown(http->fd, SHUT_RD);
2714 #endif /* _WIN32 */
2715 }
2716
2717
2718 /*
2719 * 'httpTrace()' - Send an TRACE request to the server.
2720 *
2721 * @exclude all@
2722 */
2723
2724 int /* O - Status of call (0 = success) */
httpTrace(http_t * http,const char * uri)2725 httpTrace(http_t *http, /* I - HTTP connection */
2726 const char *uri) /* I - URI for trace */
2727 {
2728 return (http_send(http, HTTP_STATE_TRACE, uri));
2729 }
2730
2731
2732 /*
2733 * '_httpUpdate()' - Update the current HTTP status for incoming data.
2734 *
2735 * Note: Unlike httpUpdate(), this function does not flush pending write data
2736 * and only retrieves a single status line from the HTTP connection.
2737 */
2738
2739 int /* O - 1 to continue, 0 to stop */
_httpUpdate(http_t * http,http_status_t * status)2740 _httpUpdate(http_t *http, /* I - HTTP connection */
2741 http_status_t *status) /* O - Current HTTP status */
2742 {
2743 char line[32768], /* Line from connection... */
2744 *value; /* Pointer to value on line */
2745 http_field_t field; /* Field index */
2746 int major, minor; /* HTTP version numbers */
2747
2748
2749 DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", (void *)http, (void *)status, httpStateString(http->state)));
2750
2751 /*
2752 * Grab a single line from the connection...
2753 */
2754
2755 if (!httpGets(line, sizeof(line), http))
2756 {
2757 *status = HTTP_STATUS_ERROR;
2758 return (0);
2759 }
2760
2761 DEBUG_printf(("2_httpUpdate: Got \"%s\"", line));
2762
2763 if (line[0] == '\0')
2764 {
2765 /*
2766 * Blank line means the start of the data section (if any). Return
2767 * the result code, too...
2768 *
2769 * If we get status 100 (HTTP_STATUS_CONTINUE), then we *don't* change
2770 * states. Instead, we just return HTTP_STATUS_CONTINUE to the caller and
2771 * keep on tryin'...
2772 */
2773
2774 if (http->status == HTTP_STATUS_CONTINUE)
2775 {
2776 *status = http->status;
2777 return (0);
2778 }
2779
2780 if (http->status < HTTP_STATUS_BAD_REQUEST)
2781 http->digest_tries = 0;
2782
2783 #ifdef HAVE_SSL
2784 if (http->status == HTTP_STATUS_SWITCHING_PROTOCOLS && !http->tls)
2785 {
2786 if (_httpTLSStart(http) != 0)
2787 {
2788 httpAddrClose(NULL, http->fd);
2789
2790 *status = http->status = HTTP_STATUS_ERROR;
2791 return (0);
2792 }
2793
2794 *status = HTTP_STATUS_CONTINUE;
2795 return (0);
2796 }
2797 #endif /* HAVE_SSL */
2798
2799 if (http_set_length(http) < 0)
2800 {
2801 DEBUG_puts("1_httpUpdate: Bad Content-Length.");
2802 http->error = EINVAL;
2803 http->status = *status = HTTP_STATUS_ERROR;
2804 return (0);
2805 }
2806
2807 switch (http->state)
2808 {
2809 case HTTP_STATE_GET :
2810 case HTTP_STATE_POST :
2811 case HTTP_STATE_POST_RECV :
2812 case HTTP_STATE_PUT :
2813 http->state ++;
2814
2815 DEBUG_printf(("1_httpUpdate: Set state to %s.",
2816 httpStateString(http->state)));
2817
2818 case HTTP_STATE_POST_SEND :
2819 case HTTP_STATE_HEAD :
2820 break;
2821
2822 default :
2823 http->state = HTTP_STATE_WAITING;
2824
2825 DEBUG_puts("1_httpUpdate: Reset state to HTTP_STATE_WAITING.");
2826 break;
2827 }
2828
2829 #ifdef HAVE_LIBZ
2830 DEBUG_puts("1_httpUpdate: Calling http_content_coding_start.");
2831 http_content_coding_start(http,
2832 httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
2833 #endif /* HAVE_LIBZ */
2834
2835 *status = http->status;
2836 return (0);
2837 }
2838 else if (!strncmp(line, "HTTP/", 5) && http->mode == _HTTP_MODE_CLIENT)
2839 {
2840 /*
2841 * Got the beginning of a response...
2842 */
2843
2844 int intstatus; /* Status value as an integer */
2845
2846 if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &intstatus) != 3)
2847 {
2848 *status = http->status = HTTP_STATUS_ERROR;
2849 return (0);
2850 }
2851
2852 httpClearFields(http);
2853
2854 http->version = (http_version_t)(major * 100 + minor);
2855 *status = http->status = (http_status_t)intstatus;
2856 }
2857 else if ((value = strchr(line, ':')) != NULL)
2858 {
2859 /*
2860 * Got a value...
2861 */
2862
2863 *value++ = '\0';
2864 while (_cups_isspace(*value))
2865 value ++;
2866
2867 DEBUG_printf(("1_httpUpdate: Header %s: %s", line, value));
2868
2869 /*
2870 * Be tolerants of servers that send unknown attribute fields...
2871 */
2872
2873 if (!_cups_strcasecmp(line, "expect"))
2874 {
2875 /*
2876 * "Expect: 100-continue" or similar...
2877 */
2878
2879 http->expect = (http_status_t)atoi(value);
2880 }
2881 else if (!_cups_strcasecmp(line, "cookie"))
2882 {
2883 /*
2884 * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
2885 */
2886
2887 httpSetCookie(http, value);
2888 }
2889 else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN)
2890 {
2891 http_add_field(http, field, value, 1);
2892
2893 if (field == HTTP_FIELD_AUTHENTICATION_INFO)
2894 httpGetSubField2(http, HTTP_FIELD_AUTHENTICATION_INFO, "nextnonce", http->nextnonce, (int)sizeof(http->nextnonce));
2895 }
2896 #ifdef DEBUG
2897 else
2898 DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line));
2899 #endif /* DEBUG */
2900 }
2901 else
2902 {
2903 DEBUG_printf(("1_httpUpdate: Bad response line \"%s\"!", line));
2904 http->error = EINVAL;
2905 http->status = *status = HTTP_STATUS_ERROR;
2906 return (0);
2907 }
2908
2909 return (1);
2910 }
2911
2912
2913 /*
2914 * 'httpUpdate()' - Update the current HTTP state for incoming data.
2915 */
2916
2917 http_status_t /* O - HTTP status */
httpUpdate(http_t * http)2918 httpUpdate(http_t *http) /* I - HTTP connection */
2919 {
2920 http_status_t status; /* Request status */
2921
2922
2923 DEBUG_printf(("httpUpdate(http=%p), state=%s", (void *)http, httpStateString(http->state)));
2924
2925 /*
2926 * Flush pending data, if any...
2927 */
2928
2929 if (http->wused)
2930 {
2931 DEBUG_puts("2httpUpdate: flushing buffer...");
2932
2933 if (httpFlushWrite(http) < 0)
2934 return (HTTP_STATUS_ERROR);
2935 }
2936
2937 /*
2938 * If we haven't issued any commands, then there is nothing to "update"...
2939 */
2940
2941 if (http->state == HTTP_STATE_WAITING)
2942 return (HTTP_STATUS_CONTINUE);
2943
2944 /*
2945 * Grab all of the lines we can from the connection...
2946 */
2947
2948 while (_httpUpdate(http, &status));
2949
2950 /*
2951 * See if there was an error...
2952 */
2953
2954 if (http->error == EPIPE && http->status > HTTP_STATUS_CONTINUE)
2955 {
2956 DEBUG_printf(("1httpUpdate: Returning status %d...", http->status));
2957 return (http->status);
2958 }
2959
2960 if (http->error)
2961 {
2962 DEBUG_printf(("1httpUpdate: socket error %d - %s", http->error,
2963 strerror(http->error)));
2964 http->status = HTTP_STATUS_ERROR;
2965 return (HTTP_STATUS_ERROR);
2966 }
2967
2968 /*
2969 * Return the current status...
2970 */
2971
2972 return (status);
2973 }
2974
2975
2976 /*
2977 * '_httpWait()' - Wait for data available on a connection (no flush).
2978 */
2979
2980 int /* O - 1 if data is available, 0 otherwise */
_httpWait(http_t * http,int msec,int usessl)2981 _httpWait(http_t *http, /* I - HTTP connection */
2982 int msec, /* I - Milliseconds to wait */
2983 int usessl) /* I - Use SSL context? */
2984 {
2985 #ifdef HAVE_POLL
2986 struct pollfd pfd; /* Polled file descriptor */
2987 #else
2988 fd_set input_set; /* select() input set */
2989 struct timeval timeout; /* Timeout */
2990 #endif /* HAVE_POLL */
2991 int nfds; /* Result from select()/poll() */
2992
2993
2994 DEBUG_printf(("4_httpWait(http=%p, msec=%d, usessl=%d)", (void *)http, msec, usessl));
2995
2996 if (http->fd < 0)
2997 {
2998 DEBUG_printf(("5_httpWait: Returning 0 since fd=%d", http->fd));
2999 return (0);
3000 }
3001
3002 /*
3003 * Check the SSL/TLS buffers for data first...
3004 */
3005
3006 #ifdef HAVE_SSL
3007 if (http->tls && _httpTLSPending(http))
3008 {
3009 DEBUG_puts("5_httpWait: Return 1 since there is pending TLS data.");
3010 return (1);
3011 }
3012 #endif /* HAVE_SSL */
3013
3014 /*
3015 * Then try doing a select() or poll() to poll the socket...
3016 */
3017
3018 #ifdef HAVE_POLL
3019 pfd.fd = http->fd;
3020 pfd.events = POLLIN;
3021
3022 do
3023 {
3024 nfds = poll(&pfd, 1, msec);
3025 }
3026 while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
3027
3028 #else
3029 do
3030 {
3031 FD_ZERO(&input_set);
3032 FD_SET(http->fd, &input_set);
3033
3034 DEBUG_printf(("6_httpWait: msec=%d, http->fd=%d", msec, http->fd));
3035
3036 if (msec >= 0)
3037 {
3038 timeout.tv_sec = msec / 1000;
3039 timeout.tv_usec = (msec % 1000) * 1000;
3040
3041 nfds = select(http->fd + 1, &input_set, NULL, NULL, &timeout);
3042 }
3043 else
3044 nfds = select(http->fd + 1, &input_set, NULL, NULL, NULL);
3045
3046 DEBUG_printf(("6_httpWait: select() returned %d...", nfds));
3047 }
3048 # ifdef _WIN32
3049 while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
3050 WSAGetLastError() == WSAEWOULDBLOCK));
3051 # else
3052 while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
3053 # endif /* _WIN32 */
3054 #endif /* HAVE_POLL */
3055
3056 DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds,
3057 errno));
3058
3059 return (nfds > 0);
3060 }
3061
3062
3063 /*
3064 * 'httpWait()' - Wait for data available on a connection.
3065 *
3066 * @since CUPS 1.1.19/macOS 10.3@
3067 */
3068
3069 int /* O - 1 if data is available, 0 otherwise */
httpWait(http_t * http,int msec)3070 httpWait(http_t *http, /* I - HTTP connection */
3071 int msec) /* I - Milliseconds to wait */
3072 {
3073 /*
3074 * First see if there is data in the buffer...
3075 */
3076
3077 DEBUG_printf(("2httpWait(http=%p, msec=%d)", (void *)http, msec));
3078
3079 if (http == NULL)
3080 return (0);
3081
3082 if (http->used)
3083 {
3084 DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
3085 return (1);
3086 }
3087
3088 #ifdef HAVE_LIBZ
3089 if (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in > 0)
3090 {
3091 DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
3092 return (1);
3093 }
3094 #endif /* HAVE_LIBZ */
3095
3096 /*
3097 * Flush pending data, if any...
3098 */
3099
3100 if (http->wused)
3101 {
3102 DEBUG_puts("3httpWait: Flushing write buffer.");
3103
3104 if (httpFlushWrite(http) < 0)
3105 return (0);
3106 }
3107
3108 /*
3109 * If not, check the SSL/TLS buffers and do a select() on the connection...
3110 */
3111
3112 return (_httpWait(http, msec, 1));
3113 }
3114
3115
3116 /*
3117 * 'httpWrite()' - Write data to a HTTP connection.
3118 *
3119 * This function is deprecated. Use the httpWrite2() function which can
3120 * write more than 2GB of data.
3121 *
3122 * @deprecated@ @exclude all@
3123 */
3124
3125 int /* O - Number of bytes written */
httpWrite(http_t * http,const char * buffer,int length)3126 httpWrite(http_t *http, /* I - HTTP connection */
3127 const char *buffer, /* I - Buffer for data */
3128 int length) /* I - Number of bytes to write */
3129 {
3130 return ((int)httpWrite2(http, buffer, (size_t)length));
3131 }
3132
3133
3134 /*
3135 * 'httpWrite2()' - Write data to a HTTP connection.
3136 *
3137 * @since CUPS 1.2/macOS 10.5@
3138 */
3139
3140 ssize_t /* O - Number of bytes written */
httpWrite2(http_t * http,const char * buffer,size_t length)3141 httpWrite2(http_t *http, /* I - HTTP connection */
3142 const char *buffer, /* I - Buffer for data */
3143 size_t length) /* I - Number of bytes to write */
3144 {
3145 ssize_t bytes; /* Bytes written */
3146
3147
3148 DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
3149
3150 /*
3151 * Range check input...
3152 */
3153
3154 if (!http || !buffer)
3155 {
3156 DEBUG_puts("1httpWrite2: Returning -1 due to bad input.");
3157 return (-1);
3158 }
3159
3160 /*
3161 * Mark activity on the connection...
3162 */
3163
3164 http->activity = time(NULL);
3165
3166 /*
3167 * Buffer small writes for better performance...
3168 */
3169
3170 #ifdef HAVE_LIBZ
3171 if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
3172 {
3173 DEBUG_printf(("1httpWrite2: http->coding=%d", http->coding));
3174
3175 if (length == 0)
3176 {
3177 http_content_coding_finish(http);
3178 bytes = 0;
3179 }
3180 else
3181 {
3182 size_t slen; /* Bytes to write */
3183 ssize_t sret; /* Bytes written */
3184
3185 ((z_stream *)http->stream)->next_in = (Bytef *)buffer;
3186 ((z_stream *)http->stream)->avail_in = (uInt)length;
3187
3188 while (deflate((z_stream *)http->stream, Z_NO_FLUSH) == Z_OK)
3189 {
3190 DEBUG_printf(("1httpWrite2: avail_out=%d", ((z_stream *)http->stream)->avail_out));
3191
3192 if (((z_stream *)http->stream)->avail_out > 0)
3193 continue;
3194
3195 slen = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out;
3196
3197 DEBUG_printf(("1httpWrite2: Writing intermediate chunk, len=%d", (int)slen));
3198
3199 if (slen > 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
3200 sret = http_write_chunk(http, (char *)http->sbuffer, slen);
3201 else if (slen > 0)
3202 sret = http_write(http, (char *)http->sbuffer, slen);
3203 else
3204 sret = 0;
3205
3206 if (sret < 0)
3207 {
3208 DEBUG_puts("1httpWrite2: Unable to write, returning -1.");
3209 return (-1);
3210 }
3211
3212 ((z_stream *)http->stream)->next_out = (Bytef *)http->sbuffer;
3213 ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
3214 }
3215
3216 bytes = (ssize_t)length;
3217 }
3218 }
3219 else
3220 #endif /* HAVE_LIBZ */
3221 if (length > 0)
3222 {
3223 if (http->wused && (length + (size_t)http->wused) > sizeof(http->wbuffer))
3224 {
3225 DEBUG_printf(("2httpWrite2: Flushing buffer (wused=%d, length="
3226 CUPS_LLFMT ")", http->wused, CUPS_LLCAST length));
3227
3228 httpFlushWrite(http);
3229 }
3230
3231 if ((length + (size_t)http->wused) <= sizeof(http->wbuffer) && length < sizeof(http->wbuffer))
3232 {
3233 /*
3234 * Write to buffer...
3235 */
3236
3237 DEBUG_printf(("2httpWrite2: Copying " CUPS_LLFMT " bytes to wbuffer...",
3238 CUPS_LLCAST length));
3239
3240 memcpy(http->wbuffer + http->wused, buffer, length);
3241 http->wused += (int)length;
3242 bytes = (ssize_t)length;
3243 }
3244 else
3245 {
3246 /*
3247 * Otherwise write the data directly...
3248 */
3249
3250 DEBUG_printf(("2httpWrite2: Writing " CUPS_LLFMT " bytes to socket...",
3251 CUPS_LLCAST length));
3252
3253 if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3254 bytes = (ssize_t)http_write_chunk(http, buffer, length);
3255 else
3256 bytes = (ssize_t)http_write(http, buffer, length);
3257
3258 DEBUG_printf(("2httpWrite2: Wrote " CUPS_LLFMT " bytes...",
3259 CUPS_LLCAST bytes));
3260 }
3261
3262 if (http->data_encoding == HTTP_ENCODING_LENGTH)
3263 http->data_remaining -= bytes;
3264 }
3265 else
3266 bytes = 0;
3267
3268 /*
3269 * Handle end-of-request processing...
3270 */
3271
3272 if ((http->data_encoding == HTTP_ENCODING_CHUNKED && length == 0) ||
3273 (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0))
3274 {
3275 /*
3276 * Finished with the transfer; unless we are sending POST or PUT
3277 * data, go idle...
3278 */
3279
3280 #ifdef HAVE_LIBZ
3281 if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
3282 http_content_coding_finish(http);
3283 #endif /* HAVE_LIBZ */
3284
3285 if (http->wused)
3286 {
3287 if (httpFlushWrite(http) < 0)
3288 return (-1);
3289 }
3290
3291 if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3292 {
3293 /*
3294 * Send a 0-length chunk at the end of the request...
3295 */
3296
3297 http_write(http, "0\r\n\r\n", 5);
3298
3299 /*
3300 * Reset the data state...
3301 */
3302
3303 http->data_encoding = HTTP_ENCODING_FIELDS;
3304 http->data_remaining = 0;
3305 }
3306
3307 if (http->state == HTTP_STATE_POST_RECV)
3308 http->state ++;
3309 else if (http->state == HTTP_STATE_POST_SEND ||
3310 http->state == HTTP_STATE_GET_SEND)
3311 http->state = HTTP_STATE_WAITING;
3312 else
3313 http->state = HTTP_STATE_STATUS;
3314
3315 DEBUG_printf(("2httpWrite2: Changed state to %s.",
3316 httpStateString(http->state)));
3317 }
3318
3319 DEBUG_printf(("1httpWrite2: Returning " CUPS_LLFMT ".", CUPS_LLCAST bytes));
3320
3321 return (bytes);
3322 }
3323
3324
3325 /*
3326 * 'httpWriteResponse()' - Write a HTTP response to a client connection.
3327 *
3328 * @since CUPS 1.7/macOS 10.9@
3329 */
3330
3331 int /* O - 0 on success, -1 on error */
httpWriteResponse(http_t * http,http_status_t status)3332 httpWriteResponse(http_t *http, /* I - HTTP connection */
3333 http_status_t status) /* I - Status code */
3334 {
3335 http_encoding_t old_encoding; /* Old data_encoding value */
3336 off_t old_remaining; /* Old data_remaining value */
3337
3338
3339 /*
3340 * Range check input...
3341 */
3342
3343 DEBUG_printf(("httpWriteResponse(http=%p, status=%d)", (void *)http, status));
3344
3345 if (!http || status < HTTP_STATUS_CONTINUE)
3346 {
3347 DEBUG_puts("1httpWriteResponse: Bad input.");
3348 return (-1);
3349 }
3350
3351 /*
3352 * Set the various standard fields if they aren't already...
3353 */
3354
3355 if (!http->fields[HTTP_FIELD_DATE])
3356 httpSetField(http, HTTP_FIELD_DATE, httpGetDateString(time(NULL)));
3357
3358 if (status >= HTTP_STATUS_BAD_REQUEST && http->keep_alive)
3359 {
3360 http->keep_alive = HTTP_KEEPALIVE_OFF;
3361 httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "");
3362 }
3363
3364 if (http->version == HTTP_VERSION_1_1)
3365 {
3366 if (!http->fields[HTTP_FIELD_CONNECTION])
3367 {
3368 if (http->keep_alive)
3369 httpSetField(http, HTTP_FIELD_CONNECTION, "Keep-Alive");
3370 else
3371 httpSetField(http, HTTP_FIELD_CONNECTION, "close");
3372 }
3373
3374 if (http->keep_alive && !http->fields[HTTP_FIELD_KEEP_ALIVE])
3375 httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "timeout=10");
3376 }
3377
3378 #ifdef HAVE_SSL
3379 if (status == HTTP_STATUS_UPGRADE_REQUIRED ||
3380 status == HTTP_STATUS_SWITCHING_PROTOCOLS)
3381 {
3382 if (!http->fields[HTTP_FIELD_CONNECTION])
3383 httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
3384
3385 if (!http->fields[HTTP_FIELD_UPGRADE])
3386 httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
3387
3388 if (!http->fields[HTTP_FIELD_CONTENT_LENGTH])
3389 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "0");
3390 }
3391 #endif /* HAVE_SSL */
3392
3393 if (!http->fields[HTTP_FIELD_SERVER])
3394 httpSetField(http, HTTP_FIELD_SERVER, http->default_fields[HTTP_FIELD_SERVER] ? http->default_fields[HTTP_FIELD_SERVER] : CUPS_MINIMAL);
3395
3396 /*
3397 * Set the Accept-Encoding field if it isn't already...
3398 */
3399
3400 if (!http->fields[HTTP_FIELD_ACCEPT_ENCODING])
3401 httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, http->default_fields[HTTP_FIELD_ACCEPT_ENCODING] ? http->default_fields[HTTP_FIELD_ACCEPT_ENCODING] :
3402 #ifdef HAVE_LIBZ
3403 "gzip, deflate, identity");
3404 #else
3405 "identity");
3406 #endif /* HAVE_LIBZ */
3407
3408 /*
3409 * Send the response header...
3410 */
3411
3412 old_encoding = http->data_encoding;
3413 old_remaining = http->data_remaining;
3414 http->data_encoding = HTTP_ENCODING_FIELDS;
3415
3416 if (httpPrintf(http, "HTTP/%d.%d %d %s\r\n", http->version / 100, http->version % 100, (int)status, httpStatus(status)) < 0)
3417 {
3418 http->status = HTTP_STATUS_ERROR;
3419 return (-1);
3420 }
3421
3422 if (status != HTTP_STATUS_CONTINUE)
3423 {
3424 /*
3425 * 100 Continue doesn't have the rest of the response headers...
3426 */
3427
3428 int i; /* Looping var */
3429 const char *value; /* Field value */
3430
3431 for (i = 0; i < HTTP_FIELD_MAX; i ++)
3432 {
3433 if ((value = httpGetField(http, i)) != NULL && *value)
3434 {
3435 if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
3436 {
3437 http->status = HTTP_STATUS_ERROR;
3438 return (-1);
3439 }
3440 }
3441 }
3442
3443 if (http->cookie)
3444 {
3445 if (strchr(http->cookie, ';'))
3446 {
3447 if (httpPrintf(http, "Set-Cookie: %s\r\n", http->cookie) < 1)
3448 {
3449 http->status = HTTP_STATUS_ERROR;
3450 return (-1);
3451 }
3452 }
3453 else if (httpPrintf(http, "Set-Cookie: %s; path=/; httponly;%s\r\n", http->cookie, http->tls ? " secure;" : "") < 1)
3454 {
3455 http->status = HTTP_STATUS_ERROR;
3456 return (-1);
3457 }
3458 }
3459
3460 /*
3461 * "Click-jacking" defense (STR #4492)...
3462 */
3463
3464 if (httpPrintf(http, "X-Frame-Options: DENY\r\n"
3465 "Content-Security-Policy: frame-ancestors 'none'\r\n") < 1)
3466 {
3467 http->status = HTTP_STATUS_ERROR;
3468 return (-1);
3469 }
3470 }
3471
3472 if (httpWrite2(http, "\r\n", 2) < 2)
3473 {
3474 http->status = HTTP_STATUS_ERROR;
3475 return (-1);
3476 }
3477
3478 if (httpFlushWrite(http) < 0)
3479 {
3480 http->status = HTTP_STATUS_ERROR;
3481 return (-1);
3482 }
3483
3484 if (status == HTTP_STATUS_CONTINUE ||
3485 status == HTTP_STATUS_SWITCHING_PROTOCOLS)
3486 {
3487 /*
3488 * Restore the old data_encoding and data_length values...
3489 */
3490
3491 http->data_encoding = old_encoding;
3492 http->data_remaining = old_remaining;
3493
3494 if (old_remaining <= INT_MAX)
3495 http->_data_remaining = (int)old_remaining;
3496 else
3497 http->_data_remaining = INT_MAX;
3498 }
3499 else if (http->state == HTTP_STATE_OPTIONS ||
3500 http->state == HTTP_STATE_HEAD ||
3501 http->state == HTTP_STATE_PUT ||
3502 http->state == HTTP_STATE_TRACE ||
3503 http->state == HTTP_STATE_CONNECT ||
3504 http->state == HTTP_STATE_STATUS)
3505 {
3506 DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, "
3507 "was %s.", httpStateString(http->state)));
3508 http->state = HTTP_STATE_WAITING;
3509 }
3510 else
3511 {
3512 /*
3513 * Force data_encoding and data_length to be set according to the response
3514 * headers...
3515 */
3516
3517 http_set_length(http);
3518
3519 if (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0)
3520 {
3521 DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, "
3522 "was %s.", httpStateString(http->state)));
3523 http->state = HTTP_STATE_WAITING;
3524 return (0);
3525 }
3526
3527 if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_GET)
3528 http->state ++;
3529
3530 #ifdef HAVE_LIBZ
3531 /*
3532 * Then start any content encoding...
3533 */
3534
3535 DEBUG_puts("1httpWriteResponse: Calling http_content_coding_start.");
3536 http_content_coding_start(http,
3537 httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
3538 #endif /* HAVE_LIBZ */
3539
3540 }
3541
3542 return (0);
3543 }
3544
3545
3546 /*
3547 * 'http_add_field()' - Add a value for a HTTP field, appending if needed.
3548 */
3549
3550 static void
http_add_field(http_t * http,http_field_t field,const char * value,int append)3551 http_add_field(http_t *http, /* I - HTTP connection */
3552 http_field_t field, /* I - HTTP field */
3553 const char *value, /* I - Value string */
3554 int append) /* I - Append value? */
3555 {
3556 char temp[1024]; /* Temporary value string */
3557 size_t fieldlen, /* Length of existing value */
3558 valuelen, /* Length of value string */
3559 total; /* Total length of string */
3560
3561
3562 if (field == HTTP_FIELD_HOST)
3563 {
3564 /*
3565 * Special-case for Host: as we don't want a trailing "." on the hostname and
3566 * need to bracket IPv6 numeric addresses.
3567 */
3568
3569 char *ptr = strchr(value, ':');
3570
3571 if (value[0] != '[' && ptr && strchr(ptr + 1, ':'))
3572 {
3573 /*
3574 * Bracket IPv6 numeric addresses...
3575 *
3576 * This is slightly inefficient (basically copying twice), but is an edge
3577 * case and not worth optimizing...
3578 */
3579
3580 snprintf(temp, sizeof(temp), "[%s]", value);
3581 value = temp;
3582 }
3583 else if (*value)
3584 {
3585 /*
3586 * Check for a trailing dot on the hostname...
3587 */
3588
3589 strlcpy(temp, value, sizeof(temp));
3590 value = temp;
3591 ptr = temp + strlen(temp) - 1;
3592
3593 if (*ptr == '.')
3594 *ptr = '\0';
3595 }
3596 }
3597
3598 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)
3599 append = 0;
3600
3601 if (!append && http->fields[field])
3602 {
3603 if (http->fields[field] != http->_fields[field])
3604 free(http->fields[field]);
3605
3606 http->fields[field] = NULL;
3607 }
3608
3609 valuelen = strlen(value);
3610
3611 if (!valuelen)
3612 {
3613 http->_fields[field][0] = '\0';
3614 return;
3615 }
3616
3617 if (http->fields[field])
3618 {
3619 fieldlen = strlen(http->fields[field]);
3620 total = fieldlen + 2 + valuelen;
3621 }
3622 else
3623 {
3624 fieldlen = 0;
3625 total = valuelen;
3626 }
3627
3628 if (total < HTTP_MAX_VALUE && field < HTTP_FIELD_ACCEPT_ENCODING)
3629 {
3630 /*
3631 * Copy short values to legacy char arrays (maintained for binary
3632 * compatibility with CUPS 1.2.x and earlier applications...)
3633 */
3634
3635 if (fieldlen)
3636 {
3637 char combined[HTTP_MAX_VALUE];
3638 /* Combined value string */
3639
3640 snprintf(combined, sizeof(combined), "%s, %s", http->_fields[field], value);
3641 value = combined;
3642 }
3643
3644 strlcpy(http->_fields[field], value, sizeof(http->_fields[field]));
3645 http->fields[field] = http->_fields[field];
3646 }
3647 else if (fieldlen)
3648 {
3649 /*
3650 * Expand the field value...
3651 */
3652
3653 char *combined; /* New value string */
3654
3655 if (http->fields[field] == http->_fields[field])
3656 {
3657 if ((combined = malloc(total + 1)) != NULL)
3658 {
3659 http->fields[field] = combined;
3660 snprintf(combined, total + 1, "%s, %s", http->_fields[field], value);
3661 }
3662 }
3663 else if ((combined = realloc(http->fields[field], total + 1)) != NULL)
3664 {
3665 http->fields[field] = combined;
3666 strlcat(combined, ", ", total + 1);
3667 strlcat(combined, value, total + 1);
3668 }
3669 }
3670 else
3671 {
3672 /*
3673 * Allocate the field value...
3674 */
3675
3676 http->fields[field] = strdup(value);
3677 }
3678
3679 #ifdef HAVE_LIBZ
3680 if (field == HTTP_FIELD_CONTENT_ENCODING && http->data_encoding != HTTP_ENCODING_FIELDS)
3681 {
3682 DEBUG_puts("1httpSetField: Calling http_content_coding_start.");
3683 http_content_coding_start(http, value);
3684 }
3685 #endif /* HAVE_LIBZ */
3686 }
3687
3688
3689 #ifdef HAVE_LIBZ
3690 /*
3691 * 'http_content_coding_finish()' - Finish doing any content encoding.
3692 */
3693
3694 static void
http_content_coding_finish(http_t * http)3695 http_content_coding_finish(
3696 http_t *http) /* I - HTTP connection */
3697 {
3698 int zerr; /* Compression status */
3699 Byte dummy[1]; /* Dummy read buffer */
3700 size_t bytes; /* Number of bytes to write */
3701
3702
3703 DEBUG_printf(("http_content_coding_finish(http=%p)", (void *)http));
3704 DEBUG_printf(("1http_content_coding_finishing: http->coding=%d", http->coding));
3705
3706 switch (http->coding)
3707 {
3708 case _HTTP_CODING_DEFLATE :
3709 case _HTTP_CODING_GZIP :
3710 ((z_stream *)http->stream)->next_in = dummy;
3711 ((z_stream *)http->stream)->avail_in = 0;
3712
3713 do
3714 {
3715 zerr = deflate((z_stream *)http->stream, Z_FINISH);
3716 bytes = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out;
3717
3718 if (bytes > 0)
3719 {
3720 DEBUG_printf(("1http_content_coding_finish: Writing trailing chunk, len=%d", (int)bytes));
3721
3722 if (http->data_encoding == HTTP_ENCODING_CHUNKED)
3723 http_write_chunk(http, (char *)http->sbuffer, bytes);
3724 else
3725 http_write(http, (char *)http->sbuffer, bytes);
3726 }
3727
3728 ((z_stream *)http->stream)->next_out = (Bytef *)http->sbuffer;
3729 ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
3730 }
3731 while (zerr == Z_OK);
3732
3733 deflateEnd((z_stream *)http->stream);
3734
3735 free(http->sbuffer);
3736 free(http->stream);
3737
3738 http->sbuffer = NULL;
3739 http->stream = NULL;
3740
3741 if (http->wused)
3742 httpFlushWrite(http);
3743 break;
3744
3745 case _HTTP_CODING_INFLATE :
3746 case _HTTP_CODING_GUNZIP :
3747 inflateEnd((z_stream *)http->stream);
3748
3749 free(http->sbuffer);
3750 free(http->stream);
3751
3752 http->sbuffer = NULL;
3753 http->stream = NULL;
3754 break;
3755
3756 default :
3757 break;
3758 }
3759
3760 http->coding = _HTTP_CODING_IDENTITY;
3761 }
3762
3763
3764 /*
3765 * 'http_content_coding_start()' - Start doing content encoding.
3766 */
3767
3768 static void
http_content_coding_start(http_t * http,const char * value)3769 http_content_coding_start(
3770 http_t *http, /* I - HTTP connection */
3771 const char *value) /* I - Value of Content-Encoding */
3772 {
3773 int zerr; /* Error/status */
3774 _http_coding_t coding; /* Content coding value */
3775
3776
3777 DEBUG_printf(("http_content_coding_start(http=%p, value=\"%s\")", (void *)http, value));
3778
3779 if (http->coding != _HTTP_CODING_IDENTITY)
3780 {
3781 DEBUG_printf(("1http_content_coding_start: http->coding already %d.",
3782 http->coding));
3783 return;
3784 }
3785 else if (!strcmp(value, "x-gzip") || !strcmp(value, "gzip"))
3786 {
3787 if (http->state == HTTP_STATE_GET_SEND ||
3788 http->state == HTTP_STATE_POST_SEND)
3789 coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_GZIP :
3790 _HTTP_CODING_GUNZIP;
3791 else if (http->state == HTTP_STATE_POST_RECV ||
3792 http->state == HTTP_STATE_PUT_RECV)
3793 coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_GZIP :
3794 _HTTP_CODING_GUNZIP;
3795 else
3796 {
3797 DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3798 return;
3799 }
3800 }
3801 else if (!strcmp(value, "x-deflate") || !strcmp(value, "deflate"))
3802 {
3803 if (http->state == HTTP_STATE_GET_SEND ||
3804 http->state == HTTP_STATE_POST_SEND)
3805 coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_DEFLATE :
3806 _HTTP_CODING_INFLATE;
3807 else if (http->state == HTTP_STATE_POST_RECV ||
3808 http->state == HTTP_STATE_PUT_RECV)
3809 coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_DEFLATE :
3810 _HTTP_CODING_INFLATE;
3811 else
3812 {
3813 DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3814 return;
3815 }
3816 }
3817 else
3818 {
3819 DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3820 return;
3821 }
3822
3823 switch (coding)
3824 {
3825 case _HTTP_CODING_DEFLATE :
3826 case _HTTP_CODING_GZIP :
3827 if (http->wused)
3828 httpFlushWrite(http);
3829
3830 if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL)
3831 {
3832 http->status = HTTP_STATUS_ERROR;
3833 http->error = errno;
3834 return;
3835 }
3836
3837 /*
3838 * Window size for compression is 11 bits - optimal based on PWG Raster
3839 * sample files on pwg.org. -11 is raw deflate, 27 is gzip, per ZLIB
3840 * documentation.
3841 */
3842
3843 if ((http->stream = calloc(1, sizeof(z_stream))) == NULL)
3844 {
3845 free(http->sbuffer);
3846
3847 http->sbuffer = NULL;
3848 http->status = HTTP_STATUS_ERROR;
3849 http->error = errno;
3850 return;
3851 }
3852
3853 if ((zerr = deflateInit2((z_stream *)http->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7, Z_DEFAULT_STRATEGY)) < Z_OK)
3854 {
3855 free(http->sbuffer);
3856 free(http->stream);
3857
3858 http->sbuffer = NULL;
3859 http->stream = NULL;
3860 http->status = HTTP_STATUS_ERROR;
3861 http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
3862 return;
3863 }
3864
3865 ((z_stream *)http->stream)->next_out = (Bytef *)http->sbuffer;
3866 ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
3867 break;
3868
3869 case _HTTP_CODING_INFLATE :
3870 case _HTTP_CODING_GUNZIP :
3871 if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL)
3872 {
3873 http->status = HTTP_STATUS_ERROR;
3874 http->error = errno;
3875 return;
3876 }
3877
3878 /*
3879 * Window size for decompression is up to 15 bits (maximum supported).
3880 * -15 is raw inflate, 31 is gunzip, per ZLIB documentation.
3881 */
3882
3883 if ((http->stream = calloc(1, sizeof(z_stream))) == NULL)
3884 {
3885 free(http->sbuffer);
3886
3887 http->sbuffer = NULL;
3888 http->status = HTTP_STATUS_ERROR;
3889 http->error = errno;
3890 return;
3891 }
3892
3893 if ((zerr = inflateInit2((z_stream *)http->stream, coding == _HTTP_CODING_INFLATE ? -15 : 31)) < Z_OK)
3894 {
3895 free(http->sbuffer);
3896 free(http->stream);
3897
3898 http->sbuffer = NULL;
3899 http->stream = NULL;
3900 http->status = HTTP_STATUS_ERROR;
3901 http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
3902 return;
3903 }
3904
3905 ((z_stream *)http->stream)->avail_in = 0;
3906 ((z_stream *)http->stream)->next_in = http->sbuffer;
3907 break;
3908
3909 default :
3910 break;
3911 }
3912
3913 http->coding = coding;
3914
3915 DEBUG_printf(("1http_content_coding_start: http->coding now %d.",
3916 http->coding));
3917 }
3918 #endif /* HAVE_LIBZ */
3919
3920
3921 /*
3922 * 'http_create()' - Create an unconnected HTTP connection.
3923 */
3924
3925 static http_t * /* O - HTTP connection */
http_create(const char * host,int port,http_addrlist_t * addrlist,int family,http_encryption_t encryption,int blocking,_http_mode_t mode)3926 http_create(
3927 const char *host, /* I - Hostname */
3928 int port, /* I - Port number */
3929 http_addrlist_t *addrlist, /* I - Address list or @code NULL@ */
3930 int family, /* I - Address family or AF_UNSPEC */
3931 http_encryption_t encryption, /* I - Encryption to use */
3932 int blocking, /* I - 1 for blocking mode */
3933 _http_mode_t mode) /* I - _HTTP_MODE_CLIENT or _SERVER */
3934 {
3935 http_t *http; /* New HTTP connection */
3936 char service[255]; /* Service name */
3937 http_addrlist_t *myaddrlist = NULL; /* My address list */
3938
3939
3940 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));
3941
3942 if (!host && mode == _HTTP_MODE_CLIENT)
3943 return (NULL);
3944
3945 httpInitialize();
3946
3947 /*
3948 * Lookup the host...
3949 */
3950
3951 if (addrlist)
3952 {
3953 myaddrlist = httpAddrCopyList(addrlist);
3954 }
3955 else
3956 {
3957 snprintf(service, sizeof(service), "%d", port);
3958
3959 myaddrlist = httpAddrGetList(host, family, service);
3960 }
3961
3962 if (!myaddrlist)
3963 return (NULL);
3964
3965 /*
3966 * Allocate memory for the structure...
3967 */
3968
3969 if ((http = calloc(sizeof(http_t), 1)) == NULL)
3970 {
3971 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
3972 httpAddrFreeList(myaddrlist);
3973 return (NULL);
3974 }
3975
3976 /*
3977 * Initialize the HTTP data...
3978 */
3979
3980 http->mode = mode;
3981 http->activity = time(NULL);
3982 http->addrlist = myaddrlist;
3983 http->blocking = blocking;
3984 http->fd = -1;
3985 #ifdef HAVE_GSSAPI
3986 http->gssctx = GSS_C_NO_CONTEXT;
3987 http->gssname = GSS_C_NO_NAME;
3988 #endif /* HAVE_GSSAPI */
3989 http->status = HTTP_STATUS_CONTINUE;
3990 http->version = HTTP_VERSION_1_1;
3991
3992 if (host)
3993 strlcpy(http->hostname, host, sizeof(http->hostname));
3994
3995 if (port == 443) /* Always use encryption for https */
3996 http->encryption = HTTP_ENCRYPTION_ALWAYS;
3997 else
3998 http->encryption = encryption;
3999
4000 http_set_wait(http);
4001
4002 /*
4003 * Return the new structure...
4004 */
4005
4006 return (http);
4007 }
4008
4009
4010 #ifdef DEBUG
4011 /*
4012 * 'http_debug_hex()' - Do a hex dump of a buffer.
4013 */
4014
4015 static void
http_debug_hex(const char * prefix,const char * buffer,int bytes)4016 http_debug_hex(const char *prefix, /* I - Prefix for line */
4017 const char *buffer, /* I - Buffer to dump */
4018 int bytes) /* I - Bytes to dump */
4019 {
4020 int i, j, /* Looping vars */
4021 ch; /* Current character */
4022 char line[255], /* Line buffer */
4023 *start, /* Start of line after prefix */
4024 *ptr; /* Pointer into line */
4025
4026
4027 if (_cups_debug_fd < 0 || _cups_debug_level < 6)
4028 return;
4029
4030 DEBUG_printf(("6%s: %d bytes:", prefix, bytes));
4031
4032 snprintf(line, sizeof(line), "6%s: ", prefix);
4033 start = line + strlen(line);
4034
4035 for (i = 0; i < bytes; i += 16)
4036 {
4037 for (j = 0, ptr = start; j < 16 && (i + j) < bytes; j ++, ptr += 2)
4038 snprintf(ptr, 3, "%02X", buffer[i + j] & 255);
4039
4040 while (j < 16)
4041 {
4042 memcpy(ptr, " ", 3);
4043 ptr += 2;
4044 j ++;
4045 }
4046
4047 memcpy(ptr, " ", 3);
4048 ptr += 2;
4049
4050 for (j = 0; j < 16 && (i + j) < bytes; j ++)
4051 {
4052 ch = buffer[i + j] & 255;
4053
4054 if (ch < ' ' || ch >= 127)
4055 ch = '.';
4056
4057 *ptr++ = (char)ch;
4058 }
4059
4060 *ptr = '\0';
4061 DEBUG_puts(line);
4062 }
4063 }
4064 #endif /* DEBUG */
4065
4066
4067 /*
4068 * 'http_read()' - Read a buffer from a HTTP connection.
4069 *
4070 * This function does the low-level read from the socket, retrying and timing
4071 * out as needed.
4072 */
4073
4074 static ssize_t /* O - Number of bytes read or -1 on error */
http_read(http_t * http,char * buffer,size_t length)4075 http_read(http_t *http, /* I - HTTP connection */
4076 char *buffer, /* I - Buffer */
4077 size_t length) /* I - Maximum bytes to read */
4078 {
4079 ssize_t bytes; /* Bytes read */
4080
4081
4082 DEBUG_printf(("http_read(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4083
4084 if (!http->blocking || http->timeout_value > 0.0)
4085 {
4086 while (!httpWait(http, http->wait_value))
4087 {
4088 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4089 continue;
4090
4091 DEBUG_puts("2http_read: Timeout.");
4092 return (0);
4093 }
4094 }
4095
4096 DEBUG_printf(("2http_read: Reading %d bytes into buffer.", (int)length));
4097
4098 do
4099 {
4100 #ifdef HAVE_SSL
4101 if (http->tls)
4102 bytes = _httpTLSRead(http, buffer, (int)length);
4103 else
4104 #endif /* HAVE_SSL */
4105 bytes = recv(http->fd, buffer, length, 0);
4106
4107 if (bytes < 0)
4108 {
4109 #ifdef _WIN32
4110 if (WSAGetLastError() != WSAEINTR)
4111 {
4112 http->error = WSAGetLastError();
4113 return (-1);
4114 }
4115 else if (WSAGetLastError() == WSAEWOULDBLOCK)
4116 {
4117 if (!http->timeout_cb ||
4118 !(*http->timeout_cb)(http, http->timeout_data))
4119 {
4120 http->error = WSAEWOULDBLOCK;
4121 return (-1);
4122 }
4123 }
4124 #else
4125 DEBUG_printf(("2http_read: %s", strerror(errno)));
4126
4127 if (errno == EWOULDBLOCK || errno == EAGAIN)
4128 {
4129 if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data))
4130 {
4131 http->error = errno;
4132 return (-1);
4133 }
4134 else if (!http->timeout_cb && errno != EAGAIN)
4135 {
4136 http->error = errno;
4137 return (-1);
4138 }
4139 }
4140 else if (errno != EINTR)
4141 {
4142 http->error = errno;
4143 return (-1);
4144 }
4145 #endif /* _WIN32 */
4146 }
4147 }
4148 while (bytes < 0);
4149
4150 DEBUG_printf(("2http_read: Read " CUPS_LLFMT " bytes into buffer.",
4151 CUPS_LLCAST bytes));
4152 #ifdef DEBUG
4153 if (bytes > 0)
4154 http_debug_hex("http_read", buffer, (int)bytes);
4155 #endif /* DEBUG */
4156
4157 if (bytes < 0)
4158 {
4159 #ifdef _WIN32
4160 if (WSAGetLastError() == WSAEINTR)
4161 bytes = 0;
4162 else
4163 http->error = WSAGetLastError();
4164 #else
4165 if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb))
4166 bytes = 0;
4167 else
4168 http->error = errno;
4169 #endif /* _WIN32 */
4170 }
4171 else if (bytes == 0)
4172 {
4173 http->error = EPIPE;
4174 return (0);
4175 }
4176
4177 return (bytes);
4178 }
4179
4180
4181 /*
4182 * 'http_read_buffered()' - Do a buffered read from a HTTP connection.
4183 *
4184 * This function reads data from the HTTP buffer or from the socket, as needed.
4185 */
4186
4187 static ssize_t /* O - Number of bytes read or -1 on error */
http_read_buffered(http_t * http,char * buffer,size_t length)4188 http_read_buffered(http_t *http, /* I - HTTP connection */
4189 char *buffer, /* I - Buffer */
4190 size_t length) /* I - Maximum bytes to read */
4191 {
4192 ssize_t bytes; /* Bytes read */
4193
4194
4195 DEBUG_printf(("http_read_buffered(http=%p, buffer=%p, length=" CUPS_LLFMT ") used=%d", (void *)http, (void *)buffer, CUPS_LLCAST length, http->used));
4196
4197 if (http->used > 0)
4198 {
4199 if (length > (size_t)http->used)
4200 bytes = (ssize_t)http->used;
4201 else
4202 bytes = (ssize_t)length;
4203
4204 DEBUG_printf(("2http_read: Grabbing %d bytes from input buffer.",
4205 (int)bytes));
4206
4207 memcpy(buffer, http->buffer, (size_t)bytes);
4208 http->used -= (int)bytes;
4209
4210 if (http->used > 0)
4211 memmove(http->buffer, http->buffer + bytes, (size_t)http->used);
4212 }
4213 else
4214 bytes = http_read(http, buffer, length);
4215
4216 return (bytes);
4217 }
4218
4219
4220 /*
4221 * 'http_read_chunk()' - Read a chunk from a HTTP connection.
4222 *
4223 * This function reads and validates the chunk length, then does a buffered read
4224 * returning the number of bytes placed in the buffer.
4225 */
4226
4227 static ssize_t /* O - Number of bytes read or -1 on error */
http_read_chunk(http_t * http,char * buffer,size_t length)4228 http_read_chunk(http_t *http, /* I - HTTP connection */
4229 char *buffer, /* I - Buffer */
4230 size_t length) /* I - Maximum bytes to read */
4231 {
4232 DEBUG_printf(("http_read_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4233
4234 if (http->data_remaining <= 0)
4235 {
4236 char len[32]; /* Length string */
4237
4238 if (!httpGets(len, sizeof(len), http))
4239 {
4240 DEBUG_puts("1http_read_chunk: Could not get chunk length.");
4241 return (0);
4242 }
4243
4244 if (!len[0])
4245 {
4246 DEBUG_puts("1http_read_chunk: Blank chunk length, trying again...");
4247 if (!httpGets(len, sizeof(len), http))
4248 {
4249 DEBUG_puts("1http_read_chunk: Could not get chunk length.");
4250 return (0);
4251 }
4252 }
4253
4254 http->data_remaining = strtoll(len, NULL, 16);
4255
4256 if (http->data_remaining < 0)
4257 {
4258 DEBUG_printf(("1http_read_chunk: Negative chunk length \"%s\" ("
4259 CUPS_LLFMT ")", len, CUPS_LLCAST http->data_remaining));
4260 return (0);
4261 }
4262
4263 DEBUG_printf(("2http_read_chunk: Got chunk length \"%s\" (" CUPS_LLFMT ")",
4264 len, CUPS_LLCAST http->data_remaining));
4265
4266 if (http->data_remaining == 0)
4267 {
4268 /*
4269 * 0-length chunk, grab trailing blank line...
4270 */
4271
4272 httpGets(len, sizeof(len), http);
4273 }
4274 }
4275
4276 DEBUG_printf(("2http_read_chunk: data_remaining=" CUPS_LLFMT,
4277 CUPS_LLCAST http->data_remaining));
4278
4279 if (http->data_remaining <= 0)
4280 return (0);
4281 else if (length > (size_t)http->data_remaining)
4282 length = (size_t)http->data_remaining;
4283
4284 return (http_read_buffered(http, buffer, length));
4285 }
4286
4287
4288 /*
4289 * 'http_send()' - Send a request with all fields and the trailing blank line.
4290 */
4291
4292 static int /* O - 0 on success, non-zero on error */
http_send(http_t * http,http_state_t request,const char * uri)4293 http_send(http_t *http, /* I - HTTP connection */
4294 http_state_t request, /* I - Request code */
4295 const char *uri) /* I - URI */
4296 {
4297 int i; /* Looping var */
4298 char buf[1024]; /* Encoded URI buffer */
4299 const char *value; /* Field value */
4300 static const char * const codes[] = /* Request code strings */
4301 {
4302 NULL,
4303 "OPTIONS",
4304 "GET",
4305 NULL,
4306 "HEAD",
4307 "POST",
4308 NULL,
4309 NULL,
4310 "PUT",
4311 NULL,
4312 "DELETE",
4313 "TRACE",
4314 "CLOSE",
4315 NULL,
4316 NULL
4317 };
4318
4319
4320 DEBUG_printf(("4http_send(http=%p, request=HTTP_%s, uri=\"%s\")", (void *)http, codes[request], uri));
4321
4322 if (http == NULL || uri == NULL)
4323 return (-1);
4324
4325 /*
4326 * Set the User-Agent field if it isn't already...
4327 */
4328
4329 if (!http->fields[HTTP_FIELD_USER_AGENT])
4330 {
4331 if (http->default_fields[HTTP_FIELD_USER_AGENT])
4332 httpSetField(http, HTTP_FIELD_USER_AGENT, http->default_fields[HTTP_FIELD_USER_AGENT]);
4333 else
4334 httpSetField(http, HTTP_FIELD_USER_AGENT, cupsUserAgent());
4335 }
4336
4337 /*
4338 * Set the Accept-Encoding field if it isn't already...
4339 */
4340
4341 if (!http->fields[HTTP_FIELD_ACCEPT_ENCODING] && http->default_fields[HTTP_FIELD_ACCEPT_ENCODING])
4342 httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, http->default_fields[HTTP_FIELD_ACCEPT_ENCODING]);
4343
4344 /*
4345 * Encode the URI as needed...
4346 */
4347
4348 _httpEncodeURI(buf, uri, sizeof(buf));
4349
4350 /*
4351 * See if we had an error the last time around; if so, reconnect...
4352 */
4353
4354 if (http->fd < 0 || http->status == HTTP_STATUS_ERROR ||
4355 http->status >= HTTP_STATUS_BAD_REQUEST)
4356 {
4357 DEBUG_printf(("5http_send: Reconnecting, fd=%d, status=%d, tls_upgrade=%d",
4358 http->fd, http->status, http->tls_upgrade));
4359
4360 if (httpReconnect2(http, 30000, NULL))
4361 return (-1);
4362 }
4363
4364 /*
4365 * Flush any written data that is pending...
4366 */
4367
4368 if (http->wused)
4369 {
4370 if (httpFlushWrite(http) < 0)
4371 if (httpReconnect2(http, 30000, NULL))
4372 return (-1);
4373 }
4374
4375 /*
4376 * Send the request header...
4377 */
4378
4379 http->state = request;
4380 http->data_encoding = HTTP_ENCODING_FIELDS;
4381
4382 if (request == HTTP_STATE_POST || request == HTTP_STATE_PUT)
4383 http->state ++;
4384
4385 http->status = HTTP_STATUS_CONTINUE;
4386
4387 #ifdef HAVE_SSL
4388 if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls)
4389 {
4390 httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
4391 httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
4392 }
4393 #endif /* HAVE_SSL */
4394
4395 if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
4396 {
4397 http->status = HTTP_STATUS_ERROR;
4398 return (-1);
4399 }
4400
4401 for (i = 0; i < HTTP_FIELD_MAX; i ++)
4402 if ((value = httpGetField(http, i)) != NULL && *value)
4403 {
4404 DEBUG_printf(("5http_send: %s: %s", http_fields[i], value));
4405
4406 if (i == HTTP_FIELD_HOST)
4407 {
4408 if (httpPrintf(http, "Host: %s:%d\r\n", value,
4409 httpAddrPort(http->hostaddr)) < 1)
4410 {
4411 http->status = HTTP_STATUS_ERROR;
4412 return (-1);
4413 }
4414 }
4415 else if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
4416 {
4417 http->status = HTTP_STATUS_ERROR;
4418 return (-1);
4419 }
4420 }
4421
4422 if (http->cookie)
4423 if (httpPrintf(http, "Cookie: $Version=0; %s\r\n", http->cookie) < 1)
4424 {
4425 http->status = HTTP_STATUS_ERROR;
4426 return (-1);
4427 }
4428
4429 DEBUG_printf(("5http_send: expect=%d, mode=%d, state=%d", http->expect,
4430 http->mode, http->state));
4431
4432 if (http->expect == HTTP_STATUS_CONTINUE && http->mode == _HTTP_MODE_CLIENT &&
4433 (http->state == HTTP_STATE_POST_RECV ||
4434 http->state == HTTP_STATE_PUT_RECV))
4435 if (httpPrintf(http, "Expect: 100-continue\r\n") < 1)
4436 {
4437 http->status = HTTP_STATUS_ERROR;
4438 return (-1);
4439 }
4440
4441 if (httpPrintf(http, "\r\n") < 1)
4442 {
4443 http->status = HTTP_STATUS_ERROR;
4444 return (-1);
4445 }
4446
4447 if (httpFlushWrite(http) < 0)
4448 return (-1);
4449
4450 http_set_length(http);
4451 httpClearFields(http);
4452
4453 /*
4454 * The Kerberos and AuthRef authentication strings can only be used once...
4455 */
4456
4457 if (http->fields[HTTP_FIELD_AUTHORIZATION] && http->authstring &&
4458 (!strncmp(http->authstring, "Negotiate", 9) ||
4459 !strncmp(http->authstring, "AuthRef", 7)))
4460 {
4461 http->_authstring[0] = '\0';
4462
4463 if (http->authstring != http->_authstring)
4464 free(http->authstring);
4465
4466 http->authstring = http->_authstring;
4467 }
4468
4469 return (0);
4470 }
4471
4472
4473 /*
4474 * 'http_set_length()' - Set the data_encoding and data_remaining values.
4475 */
4476
4477 static off_t /* O - Remainder or -1 on error */
http_set_length(http_t * http)4478 http_set_length(http_t *http) /* I - Connection */
4479 {
4480 off_t remaining; /* Remainder */
4481
4482
4483 DEBUG_printf(("http_set_length(http=%p) mode=%d state=%s", (void *)http, http->mode, httpStateString(http->state)));
4484
4485 if ((remaining = httpGetLength2(http)) >= 0)
4486 {
4487 if (http->mode == _HTTP_MODE_SERVER &&
4488 http->state != HTTP_STATE_GET_SEND &&
4489 http->state != HTTP_STATE_PUT &&
4490 http->state != HTTP_STATE_POST &&
4491 http->state != HTTP_STATE_POST_SEND)
4492 {
4493 DEBUG_puts("1http_set_length: Not setting data_encoding/remaining.");
4494 return (remaining);
4495 }
4496
4497 if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_TRANSFER_ENCODING), "chunked"))
4498 {
4499 DEBUG_puts("1http_set_length: Setting data_encoding to "
4500 "HTTP_ENCODING_CHUNKED.");
4501 http->data_encoding = HTTP_ENCODING_CHUNKED;
4502 }
4503 else
4504 {
4505 DEBUG_puts("1http_set_length: Setting data_encoding to "
4506 "HTTP_ENCODING_LENGTH.");
4507 http->data_encoding = HTTP_ENCODING_LENGTH;
4508 }
4509
4510 DEBUG_printf(("1http_set_length: Setting data_remaining to " CUPS_LLFMT ".",
4511 CUPS_LLCAST remaining));
4512 http->data_remaining = remaining;
4513
4514 if (remaining <= INT_MAX)
4515 http->_data_remaining = (int)remaining;
4516 else
4517 http->_data_remaining = INT_MAX;
4518 }
4519
4520 return (remaining);
4521 }
4522
4523 /*
4524 * 'http_set_timeout()' - Set the socket timeout values.
4525 */
4526
4527 static void
http_set_timeout(int fd,double timeout)4528 http_set_timeout(int fd, /* I - File descriptor */
4529 double timeout) /* I - Timeout in seconds */
4530 {
4531 #ifdef _WIN32
4532 DWORD tv = (DWORD)(timeout * 1000);
4533 /* Timeout in milliseconds */
4534
4535 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4536 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4537
4538 #else
4539 struct timeval tv; /* Timeout in secs and usecs */
4540
4541 tv.tv_sec = (int)timeout;
4542 tv.tv_usec = (int)(1000000 * fmod(timeout, 1.0));
4543
4544 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4545 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4546 #endif /* _WIN32 */
4547 }
4548
4549
4550 /*
4551 * 'http_set_wait()' - Set the default wait value for reads.
4552 */
4553
4554 static void
http_set_wait(http_t * http)4555 http_set_wait(http_t *http) /* I - HTTP connection */
4556 {
4557 if (http->blocking)
4558 {
4559 http->wait_value = (int)(http->timeout_value * 1000);
4560
4561 if (http->wait_value <= 0)
4562 http->wait_value = 60000;
4563 }
4564 else
4565 http->wait_value = 10000;
4566 }
4567
4568
4569 #ifdef HAVE_SSL
4570 /*
4571 * 'http_tls_upgrade()' - Force upgrade to TLS encryption.
4572 */
4573
4574 static int /* O - Status of connection */
http_tls_upgrade(http_t * http)4575 http_tls_upgrade(http_t *http) /* I - HTTP connection */
4576 {
4577 int ret; /* Return value */
4578 http_t myhttp; /* Local copy of HTTP data */
4579
4580
4581 DEBUG_printf(("7http_tls_upgrade(%p)", (void *)http));
4582
4583 /*
4584 * Flush the connection to make sure any previous "Upgrade" message
4585 * has been read.
4586 */
4587
4588 httpFlush(http);
4589
4590 /*
4591 * Copy the HTTP data to a local variable so we can do the OPTIONS
4592 * request without interfering with the existing request data...
4593 */
4594
4595 memcpy(&myhttp, http, sizeof(myhttp));
4596
4597 /*
4598 * Send an OPTIONS request to the server, requiring SSL or TLS
4599 * encryption on the link...
4600 */
4601
4602 http->tls_upgrade = 1;
4603 memset(http->fields, 0, sizeof(http->fields));
4604 http->expect = (http_status_t)0;
4605
4606 if (http->hostname[0] == '/')
4607 httpSetField(http, HTTP_FIELD_HOST, "localhost");
4608 else
4609 httpSetField(http, HTTP_FIELD_HOST, http->hostname);
4610
4611 httpSetField(http, HTTP_FIELD_CONNECTION, "upgrade");
4612 httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
4613
4614 if ((ret = httpOptions(http, "*")) == 0)
4615 {
4616 /*
4617 * Wait for the secure connection...
4618 */
4619
4620 while (httpUpdate(http) == HTTP_STATUS_CONTINUE);
4621 }
4622
4623 /*
4624 * Restore the HTTP request data...
4625 */
4626
4627 memcpy(http->_fields, myhttp._fields, sizeof(http->_fields));
4628 memcpy(http->fields, myhttp.fields, sizeof(http->fields));
4629
4630 http->data_encoding = myhttp.data_encoding;
4631 http->data_remaining = myhttp.data_remaining;
4632 http->_data_remaining = myhttp._data_remaining;
4633 http->expect = myhttp.expect;
4634 http->digest_tries = myhttp.digest_tries;
4635 http->tls_upgrade = 0;
4636
4637 /*
4638 * See if we actually went secure...
4639 */
4640
4641 if (!http->tls)
4642 {
4643 /*
4644 * Server does not support HTTP upgrade...
4645 */
4646
4647 DEBUG_puts("8http_tls_upgrade: Server does not support HTTP upgrade!");
4648
4649 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Encryption is not supported."), 1);
4650 httpAddrClose(NULL, http->fd);
4651
4652 http->fd = -1;
4653
4654 return (-1);
4655 }
4656 else
4657 return (ret);
4658 }
4659 #endif /* HAVE_SSL */
4660
4661
4662 /*
4663 * 'http_write()' - Write a buffer to a HTTP connection.
4664 */
4665
4666 static ssize_t /* O - Number of bytes written */
http_write(http_t * http,const char * buffer,size_t length)4667 http_write(http_t *http, /* I - HTTP connection */
4668 const char *buffer, /* I - Buffer for data */
4669 size_t length) /* I - Number of bytes to write */
4670 {
4671 ssize_t tbytes, /* Total bytes sent */
4672 bytes; /* Bytes sent */
4673
4674
4675 DEBUG_printf(("2http_write(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4676 http->error = 0;
4677 tbytes = 0;
4678
4679 while (length > 0)
4680 {
4681 DEBUG_printf(("3http_write: About to write %d bytes.", (int)length));
4682
4683 if (http->timeout_value > 0.0)
4684 {
4685 #ifdef HAVE_POLL
4686 struct pollfd pfd; /* Polled file descriptor */
4687 #else
4688 fd_set output_set; /* Output ready for write? */
4689 struct timeval timeout; /* Timeout value */
4690 #endif /* HAVE_POLL */
4691 int nfds; /* Result from select()/poll() */
4692
4693 do
4694 {
4695 #ifdef HAVE_POLL
4696 pfd.fd = http->fd;
4697 pfd.events = POLLOUT;
4698
4699 while ((nfds = poll(&pfd, 1, http->wait_value)) < 0 &&
4700 (errno == EINTR || errno == EAGAIN))
4701 /* do nothing */;
4702
4703 #else
4704 do
4705 {
4706 FD_ZERO(&output_set);
4707 FD_SET(http->fd, &output_set);
4708
4709 timeout.tv_sec = http->wait_value / 1000;
4710 timeout.tv_usec = 1000 * (http->wait_value % 1000);
4711
4712 nfds = select(http->fd + 1, NULL, &output_set, NULL, &timeout);
4713 }
4714 # ifdef _WIN32
4715 while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
4716 WSAGetLastError() == WSAEWOULDBLOCK));
4717 # else
4718 while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
4719 # endif /* _WIN32 */
4720 #endif /* HAVE_POLL */
4721
4722 if (nfds < 0)
4723 {
4724 http->error = errno;
4725 return (-1);
4726 }
4727 else if (nfds == 0 && (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data)))
4728 {
4729 #ifdef _WIN32
4730 http->error = WSAEWOULDBLOCK;
4731 #else
4732 http->error = EWOULDBLOCK;
4733 #endif /* _WIN32 */
4734 return (-1);
4735 }
4736 }
4737 while (nfds <= 0);
4738 }
4739
4740 #ifdef HAVE_SSL
4741 if (http->tls)
4742 bytes = _httpTLSWrite(http, buffer, (int)length);
4743 else
4744 #endif /* HAVE_SSL */
4745 bytes = send(http->fd, buffer, length, 0);
4746
4747 DEBUG_printf(("3http_write: Write of " CUPS_LLFMT " bytes returned "
4748 CUPS_LLFMT ".", CUPS_LLCAST length, CUPS_LLCAST bytes));
4749
4750 if (bytes < 0)
4751 {
4752 #ifdef _WIN32
4753 if (WSAGetLastError() == WSAEINTR)
4754 continue;
4755 else if (WSAGetLastError() == WSAEWOULDBLOCK)
4756 {
4757 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4758 continue;
4759
4760 http->error = WSAGetLastError();
4761 }
4762 else if (WSAGetLastError() != http->error &&
4763 WSAGetLastError() != WSAECONNRESET)
4764 {
4765 http->error = WSAGetLastError();
4766 continue;
4767 }
4768
4769 #else
4770 if (errno == EINTR)
4771 continue;
4772 else if (errno == EWOULDBLOCK || errno == EAGAIN)
4773 {
4774 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4775 continue;
4776 else if (!http->timeout_cb && errno == EAGAIN)
4777 continue;
4778
4779 http->error = errno;
4780 }
4781 else if (errno != http->error && errno != ECONNRESET)
4782 {
4783 http->error = errno;
4784 continue;
4785 }
4786 #endif /* _WIN32 */
4787
4788 DEBUG_printf(("3http_write: error writing data (%s).",
4789 strerror(http->error)));
4790
4791 return (-1);
4792 }
4793
4794 buffer += bytes;
4795 tbytes += bytes;
4796 length -= (size_t)bytes;
4797 }
4798
4799 #ifdef DEBUG
4800 http_debug_hex("http_write", buffer - tbytes, (int)tbytes);
4801 #endif /* DEBUG */
4802
4803 DEBUG_printf(("3http_write: Returning " CUPS_LLFMT ".", CUPS_LLCAST tbytes));
4804
4805 return (tbytes);
4806 }
4807
4808
4809 /*
4810 * 'http_write_chunk()' - Write a chunked buffer.
4811 */
4812
4813 static ssize_t /* O - Number bytes written */
http_write_chunk(http_t * http,const char * buffer,size_t length)4814 http_write_chunk(http_t *http, /* I - HTTP connection */
4815 const char *buffer, /* I - Buffer to write */
4816 size_t length) /* I - Length of buffer */
4817 {
4818 char header[16]; /* Chunk header */
4819 ssize_t bytes; /* Bytes written */
4820
4821
4822 DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
4823
4824 /*
4825 * Write the chunk header, data, and trailer.
4826 */
4827
4828 snprintf(header, sizeof(header), "%x\r\n", (unsigned)length);
4829 if (http_write(http, header, strlen(header)) < 0)
4830 {
4831 DEBUG_puts("8http_write_chunk: http_write of length failed.");
4832 return (-1);
4833 }
4834
4835 if ((bytes = http_write(http, buffer, length)) < 0)
4836 {
4837 DEBUG_puts("8http_write_chunk: http_write of buffer failed.");
4838 return (-1);
4839 }
4840
4841 if (http_write(http, "\r\n", 2) < 0)
4842 {
4843 DEBUG_puts("8http_write_chunk: http_write of CR LF failed.");
4844 return (-1);
4845 }
4846
4847 return (bytes);
4848 }
4849