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