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