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