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