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