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