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