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