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