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