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