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