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