]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/http.c
<rdar://problem/15313228> "Canceling stuck job after XXX seconds" message should...
[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 ++;
dfc45c1b
MS
3456 else if (http->state == HTTP_STATE_POST_SEND ||
3457 http->state == HTTP_STATE_GET_SEND)
ad29aeab 3458 http->state = HTTP_STATE_WAITING;
db8b865d 3459 else
cb7f98ee 3460 http->state = HTTP_STATE_STATUS;
a469f8a5 3461
db8b865d 3462 DEBUG_printf(("2httpWrite2: Changed state to %s.",
48bd1142 3463 httpStateString(http->state)));
ef416fc2 3464 }
3465
a469f8a5
MS
3466 DEBUG_printf(("1httpWrite2: Returning " CUPS_LLFMT ".", CUPS_LLCAST bytes));
3467
ef416fc2 3468 return (bytes);
3469}
3470
3471
a469f8a5
MS
3472/*
3473 * 'httpWriteResponse()' - Write a HTTP response to a client connection.
3474 *
9c0e8e5d 3475 * @since CUPS 1.7/OS X 10.9@
a469f8a5
MS
3476 */
3477
3478int /* O - 0 on success, -1 on error */
3479httpWriteResponse(http_t *http, /* I - HTTP connection */
3480 http_status_t status) /* I - Status code */
3481{
3482 http_encoding_t old_encoding; /* Old data_encoding value */
3483 off_t old_remaining; /* Old data_remaining value */
3484
3485
3486 /*
3487 * Range check input...
3488 */
3489
3490 DEBUG_printf(("httpWriteResponse(http=%p, status=%d)", http, status));
3491
3492 if (!http || status < HTTP_STATUS_CONTINUE)
3493 {
3494 DEBUG_puts("1httpWriteResponse: Bad input.");
3495 return (-1);
3496 }
3497
3498 /*
3499 * Set the various standard fields if they aren't already...
3500 */
3501
3502 if (!http->fields[HTTP_FIELD_DATE][0])
3503 httpSetField(http, HTTP_FIELD_DATE, httpGetDateString(time(NULL)));
3504
cb7f98ee 3505 if (status >= HTTP_STATUS_BAD_REQUEST && http->keep_alive)
a469f8a5 3506 {
5ec1fd3d 3507 http->keep_alive = HTTP_KEEPALIVE_OFF;
a469f8a5
MS
3508 httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "");
3509 }
3510
3511 if (http->version == HTTP_VERSION_1_1)
3512 {
3513 if (!http->fields[HTTP_FIELD_CONNECTION][0])
3514 {
3515 if (http->keep_alive)
3516 httpSetField(http, HTTP_FIELD_CONNECTION, "Keep-Alive");
3517 else
3518 httpSetField(http, HTTP_FIELD_CONNECTION, "close");
3519 }
3520
3521 if (http->keep_alive && !http->fields[HTTP_FIELD_KEEP_ALIVE][0])
3522 httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "timeout=10");
3523 }
3524
3525#ifdef HAVE_SSL
e200616a
MS
3526 if (status == HTTP_STATUS_UPGRADE_REQUIRED ||
3527 status == HTTP_STATUS_SWITCHING_PROTOCOLS)
a469f8a5
MS
3528 {
3529 if (!http->fields[HTTP_FIELD_CONNECTION][0])
3530 httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
3531
3532 if (!http->fields[HTTP_FIELD_UPGRADE][0])
3533 httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
e200616a
MS
3534
3535 if (!http->fields[HTTP_FIELD_CONTENT_LENGTH][0])
3536 httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "0");
a469f8a5
MS
3537 }
3538#endif /* HAVE_SSL */
3539
3540 if (!http->server)
c1420c87
MS
3541 httpSetField(http, HTTP_FIELD_SERVER,
3542 http->default_server ? http->default_server : CUPS_MINIMAL);
a469f8a5 3543
a469f8a5
MS
3544 /*
3545 * Set the Accept-Encoding field if it isn't already...
3546 */
3547
3548 if (!http->accept_encoding)
c1420c87
MS
3549 httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING,
3550 http->default_accept_encoding ? http->default_accept_encoding :
3551#ifdef HAVE_LIBZ
3552 "gzip, deflate, identity");
3553#else
3554 "identity");
a469f8a5
MS
3555#endif /* HAVE_LIBZ */
3556
3557 /*
3558 * Send the response header...
3559 */
3560
3561 old_encoding = http->data_encoding;
3562 old_remaining = http->data_remaining;
3563 http->data_encoding = HTTP_ENCODING_FIELDS;
3564
3565 if (httpPrintf(http, "HTTP/%d.%d %d %s\r\n", http->version / 100,
3566 http->version % 100, (int)status, httpStatus(status)) < 0)
3567 {
3568 http->status = HTTP_STATUS_ERROR;
3569 return (-1);
3570 }
3571
3572 if (status != HTTP_STATUS_CONTINUE)
3573 {
3574 /*
3575 * 100 Continue doesn't have the rest of the response headers...
3576 */
3577
3578 int i; /* Looping var */
3579 const char *value; /* Field value */
3580
3581 for (i = 0; i < HTTP_FIELD_MAX; i ++)
3582 {
3583 if ((value = httpGetField(http, i)) != NULL && *value)
3584 {
3585 if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
3586 {
3587 http->status = HTTP_STATUS_ERROR;
3588 return (-1);
3589 }
3590 }
3591 }
3592
3593 if (http->cookie)
3594 {
e200616a
MS
3595 if (httpPrintf(http, "Set-Cookie: %s path=/ httponly%s\r\n",
3596 http->cookie, http->tls ? " secure" : "") < 1)
a469f8a5 3597 {
cb7f98ee 3598 http->status = HTTP_STATUS_ERROR;
a469f8a5
MS
3599 return (-1);
3600 }
3601 }
3602 }
3603
3604 if (httpWrite2(http, "\r\n", 2) < 2)
3605 {
cb7f98ee 3606 http->status = HTTP_STATUS_ERROR;
a469f8a5
MS
3607 return (-1);
3608 }
3609
3610 if (httpFlushWrite(http) < 0)
3611 {
cb7f98ee 3612 http->status = HTTP_STATUS_ERROR;
a469f8a5
MS
3613 return (-1);
3614 }
3615
e200616a
MS
3616 if (status == HTTP_STATUS_CONTINUE ||
3617 status == HTTP_STATUS_SWITCHING_PROTOCOLS)
a469f8a5
MS
3618 {
3619 /*
3620 * Restore the old data_encoding and data_length values...
3621 */
3622
3623 http->data_encoding = old_encoding;
3624 http->data_remaining = old_remaining;
3625
3626 if (old_remaining <= INT_MAX)
3627 http->_data_remaining = (int)old_remaining;
3628 else
3629 http->_data_remaining = INT_MAX;
3630 }
3631 else if (http->state == HTTP_STATE_OPTIONS ||
3632 http->state == HTTP_STATE_HEAD ||
3633 http->state == HTTP_STATE_PUT ||
3634 http->state == HTTP_STATE_TRACE ||
cb7f98ee
MS
3635 http->state == HTTP_STATE_CONNECT ||
3636 http->state == HTTP_STATE_STATUS)
a469f8a5
MS
3637 {
3638 DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, "
48bd1142 3639 "was %s.", httpStateString(http->state)));
a469f8a5
MS
3640 http->state = HTTP_STATE_WAITING;
3641 }
3642 else
3643 {
3644 /*
3645 * Force data_encoding and data_length to be set according to the response
3646 * headers...
3647 */
3648
3649 http_set_length(http);
3650
dfc45c1b
MS
3651 if (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0)
3652 {
3653 DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, "
3654 "was %s.", httpStateString(http->state)));
3655 http->state = HTTP_STATE_WAITING;
3656 return (0);
3657 }
3658
db8b865d 3659#ifdef HAVE_LIBZ
a469f8a5
MS
3660 /*
3661 * Then start any content encoding...
3662 */
3663
3664 DEBUG_puts("1httpWriteResponse: Calling http_content_coding_start.");
3665 http_content_coding_start(http,
3666 httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
db8b865d 3667#endif /* HAVE_LIBZ */
dfc45c1b 3668
a469f8a5
MS
3669 }
3670
3671 return (0);
3672}
3673
3674
2c85b752 3675#ifdef HAVE_LIBZ
411affcf 3676/*
2c85b752 3677 * 'http_content_coding_finish()' - Finish doing any content encoding.
411affcf 3678 */
3679
2c85b752
MS
3680static void
3681http_content_coding_finish(
3682 http_t *http) /* I - HTTP connection */
a469f8a5
MS
3683{
3684 int zerr; /* Compression status */
d2263221 3685 Byte dummy[1]; /* Dummy read buffer */
a469f8a5
MS
3686
3687
3688 switch (http->coding)
3689 {
3690 case _HTTP_CODING_DEFLATE :
3691 case _HTTP_CODING_GZIP :
d2263221
MS
3692 http->stream.next_in = dummy;
3693 http->stream.avail_in = 0;
3694
a469f8a5
MS
3695 do
3696 {
3697 http->stream.next_out = (Bytef *)http->wbuffer + http->wused;
3698 http->stream.avail_out = sizeof(http->wbuffer) - http->wused;
3699
3700 zerr = deflate(&(http->stream), Z_FINISH);
3701
3702 http->wused = sizeof(http->wbuffer) - http->stream.avail_out;
3703 if (http->wused == sizeof(http->wbuffer))
3704 httpFlushWrite(http);
3705 }
3706 while (zerr == Z_OK);
3707
3708 deflateEnd(&(http->stream));
3709
3710 if (http->wused)
3711 httpFlushWrite(http);
3712 break;
3713
3714 case _HTTP_CODING_INFLATE :
3715 case _HTTP_CODING_GUNZIP :
3716 inflateEnd(&(http->stream));
0fa6c7fa
MS
3717 free(http->dbuffer);
3718 http->dbuffer = NULL;
a469f8a5
MS
3719 break;
3720
3721 default :
3722 break;
3723 }
3724
3725 http->coding = _HTTP_CODING_IDENTITY;
3726}
3727
3728
3729/*
3730 * 'http_content_coding_start()' - Start doing content encoding.
3731 */
3732
3733static void
3734http_content_coding_start(
3735 http_t *http, /* I - HTTP connection */
3736 const char *value) /* I - Value of Content-Encoding */
3737{
3738 int zerr; /* Error/status */
3739 _http_coding_t coding; /* Content coding value */
3740
3741
3742 DEBUG_printf(("http_content_coding_start(http=%p, value=\"%s\")", http,
3743 value));
3744
3745 if (http->coding != _HTTP_CODING_IDENTITY)
3746 {
3747 DEBUG_printf(("1http_content_coding_start: http->coding already %d.",
3748 http->coding));
3749 return;
3750 }
3751 else if (!strcmp(value, "x-gzip") || !strcmp(value, "gzip"))
3752 {
cb7f98ee
MS
3753 if (http->state == HTTP_STATE_GET_SEND ||
3754 http->state == HTTP_STATE_POST_SEND)
a469f8a5
MS
3755 coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_GZIP :
3756 _HTTP_CODING_GUNZIP;
cb7f98ee
MS
3757 else if (http->state == HTTP_STATE_POST_RECV ||
3758 http->state == HTTP_STATE_PUT_RECV)
a469f8a5
MS
3759 coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_GZIP :
3760 _HTTP_CODING_GUNZIP;
3761 else
3762 {
3763 DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3764 return;
3765 }
3766 }
3767 else if (!strcmp(value, "x-deflate") || !strcmp(value, "deflate"))
3768 {
cb7f98ee
MS
3769 if (http->state == HTTP_STATE_GET_SEND ||
3770 http->state == HTTP_STATE_POST_SEND)
a469f8a5
MS
3771 coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_DEFLATE :
3772 _HTTP_CODING_INFLATE;
cb7f98ee
MS
3773 else if (http->state == HTTP_STATE_POST_RECV ||
3774 http->state == HTTP_STATE_PUT_RECV)
a469f8a5
MS
3775 coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_DEFLATE :
3776 _HTTP_CODING_INFLATE;
3777 else
3778 {
3779 DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3780 return;
3781 }
3782 }
3783 else
3784 {
3785 DEBUG_puts("1http_content_coding_start: Not doing content coding.");
3786 return;
3787 }
3788
3789 memset(&(http->stream), 0, sizeof(http->stream));
3790
3791 switch (coding)
3792 {
3793 case _HTTP_CODING_DEFLATE :
3794 case _HTTP_CODING_GZIP :
3795 if (http->wused)
3796 httpFlushWrite(http);
3797
db8b865d
MS
3798 /*
3799 * Window size for compression is 11 bits - optimal based on PWG Raster
3800 * sample files on pwg.org. -11 is raw deflate, 27 is gzip, per ZLIB
3801 * documentation.
3802 */
3803
a469f8a5
MS
3804 if ((zerr = deflateInit2(&(http->stream), Z_DEFAULT_COMPRESSION,
3805 Z_DEFLATED,
db8b865d 3806 coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7,
a469f8a5
MS
3807 Z_DEFAULT_STRATEGY)) < Z_OK)
3808 {
cb7f98ee 3809 http->status = HTTP_STATUS_ERROR;
a469f8a5
MS
3810 http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
3811 return;
3812 }
3813 break;
3814
3815 case _HTTP_CODING_INFLATE :
3816 case _HTTP_CODING_GUNZIP :
0fa6c7fa 3817 if ((http->dbuffer = malloc(HTTP_MAX_BUFFER)) == NULL)
a469f8a5 3818 {
cb7f98ee 3819 http->status = HTTP_STATUS_ERROR;
0fa6c7fa 3820 http->error = errno;
a469f8a5
MS
3821 return;
3822 }
0fa6c7fa 3823
db8b865d
MS
3824 /*
3825 * Window size for decompression is up to 15 bits (maximum supported).
3826 * -15 is raw inflate, 31 is gunzip, per ZLIB documentation.
3827 */
3828
0fa6c7fa 3829 if ((zerr = inflateInit2(&(http->stream),
db8b865d 3830 coding == _HTTP_CODING_INFLATE ? -15 : 31))
0fa6c7fa
MS
3831 < Z_OK)
3832 {
3833 free(http->dbuffer);
3834 http->dbuffer = NULL;
cb7f98ee 3835 http->status = HTTP_STATUS_ERROR;
0fa6c7fa
MS
3836 http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
3837 return;
3838 }
3839
3840 http->stream.avail_in = 0;
3841 http->stream.next_in = http->dbuffer;
a469f8a5
MS
3842 break;
3843
3844 default :
3845 break;
3846 }
3847
3848 http->coding = coding;
3849
3850 DEBUG_printf(("1http_content_coding_start: http->coding now %d.",
3851 http->coding));
3852}
3853#endif /* HAVE_LIBZ */
3854
3855
db8b865d
MS
3856/*
3857 * 'http_create()' - Create an unconnected HTTP connection.
3858 */
3859
3860static http_t * /* O - HTTP connection */
3861http_create(
3862 const char *host, /* I - Hostname */
3863 int port, /* I - Port number */
3864 http_addrlist_t *addrlist, /* I - Address list or NULL */
3865 int family, /* I - Address family or AF_UNSPEC */
3866 http_encryption_t encryption, /* I - Encryption to use */
3867 int blocking, /* I - 1 for blocking mode */
3868 _http_mode_t mode) /* I - _HTTP_MODE_CLIENT or _SERVER */
3869{
3870 http_t *http; /* New HTTP connection */
3871 char service[255]; /* Service name */
3872 http_addrlist_t *myaddrlist = NULL; /* My address list */
3873
3874
3875 DEBUG_printf(("4http_create(host=\"%s\", port=%d, addrlist=%p, family=%d, "
3876 "encryption=%d, blocking=%d, mode=%d)", host, port, addrlist,
3877 family, encryption, blocking, mode));
3878
3879 if (!host && mode == _HTTP_MODE_CLIENT)
3880 return (NULL);
3881
3882 httpInitialize();
3883
3884 /*
3885 * Lookup the host...
3886 */
3887
3888 if (addrlist)
3889 {
3890 myaddrlist = httpAddrCopyList(addrlist);
3891 }
3892 else
3893 {
3894 snprintf(service, sizeof(service), "%d", port);
3895
3896 myaddrlist = httpAddrGetList(host, family, service);
3897 }
3898
3899 if (!myaddrlist)
3900 return (NULL);
3901
3902 /*
3903 * Allocate memory for the structure...
3904 */
3905
3906 if ((http = calloc(sizeof(http_t), 1)) == NULL)
3907 {
cb7f98ee 3908 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
db8b865d
MS
3909 httpAddrFreeList(addrlist);
3910 return (NULL);
3911 }
3912
3913 /*
3914 * Initialize the HTTP data...
3915 */
3916
3917 http->mode = mode;
3918 http->activity = time(NULL);
3919 http->addrlist = myaddrlist;
3920 http->blocking = blocking;
3921 http->fd = -1;
3922#ifdef HAVE_GSSAPI
3923 http->gssctx = GSS_C_NO_CONTEXT;
3924 http->gssname = GSS_C_NO_NAME;
3925#endif /* HAVE_GSSAPI */
cb7f98ee 3926 http->status = HTTP_STATUS_CONTINUE;
db8b865d
MS
3927 http->version = HTTP_VERSION_1_1;
3928
3929 if (host)
3930 strlcpy(http->hostname, host, sizeof(http->hostname));
3931
3932 if (port == 443) /* Always use encryption for https */
3933 http->encryption = HTTP_ENCRYPTION_ALWAYS;
3934 else
3935 http->encryption = encryption;
3936
3937 http_set_wait(http);
3938
3939 /*
3940 * Return the new structure...
3941 */
3942
3943 return (http);
3944}
3945
db8b865d 3946
ae71f5de
MS
3947#ifdef DEBUG
3948/*
3949 * 'http_debug_hex()' - Do a hex dump of a buffer.
3950 */
3951
3952static void
3953http_debug_hex(const char *prefix, /* I - Prefix for line */
3954 const char *buffer, /* I - Buffer to dump */
3955 int bytes) /* I - Bytes to dump */
3956{
3957 int i, j, /* Looping vars */
3958 ch; /* Current character */
3959 char line[255], /* Line buffer */
3960 *start, /* Start of line after prefix */
3961 *ptr; /* Pointer into line */
3962
3963
f11a948a 3964 if (_cups_debug_fd < 0 || _cups_debug_level < 6)
dd1abb6b
MS
3965 return;
3966
83e08001 3967 DEBUG_printf(("6%s: %d bytes:", prefix, bytes));
ae71f5de 3968
f11a948a 3969 snprintf(line, sizeof(line), "6%s: ", prefix);
ae71f5de
MS
3970 start = line + strlen(line);
3971
3972 for (i = 0; i < bytes; i += 16)
3973 {
3974 for (j = 0, ptr = start; j < 16 && (i + j) < bytes; j ++, ptr += 2)
3975 sprintf(ptr, "%02X", buffer[i + j] & 255);
3976
3977 while (j < 16)
3978 {
5a9febac 3979 memcpy(ptr, " ", 3);
ae71f5de
MS
3980 ptr += 2;
3981 j ++;
3982 }
3983
5a9febac 3984 memcpy(ptr, " ", 3);
ae71f5de
MS
3985 ptr += 2;
3986
3987 for (j = 0; j < 16 && (i + j) < bytes; j ++)
3988 {
3989 ch = buffer[i + j] & 255;
3990
3991 if (ch < ' ' || ch >= 127)
3992 ch = '.';
3993
3994 *ptr++ = ch;
3995 }
3996
3997 *ptr = '\0';
3998 DEBUG_puts(line);
3999 }
4000}
4001#endif /* DEBUG */
4002
4003
0fa6c7fa
MS
4004/*
4005 * 'http_read()' - Read a buffer from a HTTP connection.
4006 *
4007 * This function does the low-level read from the socket, retrying and timing
4008 * out as needed.
4009 */
4010
4011static ssize_t /* O - Number of bytes read or -1 on error */
e6b1a6a9 4012http_read(http_t *http, /* I - HTTP connection */
0fa6c7fa
MS
4013 char *buffer, /* I - Buffer */
4014 size_t length) /* I - Maximum bytes to read */
4015{
4016 ssize_t bytes; /* Bytes read */
4017
4018
4019 DEBUG_printf(("http_read(http=%p, buffer=%p, length=" CUPS_LLFMT ")", http,
4020 buffer, CUPS_LLCAST length));
4021
4022 if (!http->blocking)
4023 {
4024 while (!httpWait(http, http->wait_value))
4025 {
4026 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4027 continue;
4028
4029 DEBUG_puts("2http_read: Timeout.");
4030 return (0);
4031 }
4032 }
4033
4034 DEBUG_printf(("2http_read: Reading %d bytes into buffer.", (int)length));
4035
4036 do
4037 {
4038#ifdef HAVE_SSL
4039 if (http->tls)
2c85b752 4040 bytes = http_tls_read(http, buffer, length);
0fa6c7fa
MS
4041 else
4042#endif /* HAVE_SSL */
4043 bytes = recv(http->fd, buffer, length, 0);
4044
4045 if (bytes < 0)
4046 {
4047#ifdef WIN32
4048 if (WSAGetLastError() != WSAEINTR)
4049 {
4050 http->error = WSAGetLastError();
4051 return (-1);
4052 }
4053 else if (WSAGetLastError() == WSAEWOULDBLOCK)
4054 {
4055 if (!http->timeout_cb ||
4056 !(*http->timeout_cb)(http, http->timeout_data))
4057 {
4058 http->error = WSAEWOULDBLOCK;
4059 return (-1);
4060 }
4061 }
4062#else
4063 DEBUG_printf(("2http_read: %s", strerror(errno)));
4064
4065 if (errno == EWOULDBLOCK || errno == EAGAIN)
4066 {
4067 if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data))
4068 {
4069 http->error = errno;
4070 return (-1);
4071 }
4072 else if (!http->timeout_cb && errno != EAGAIN)
4073 {
4074 http->error = errno;
4075 return (-1);
4076 }
4077 }
4078 else if (errno != EINTR)
4079 {
4080 http->error = errno;
4081 return (-1);
4082 }
4083#endif /* WIN32 */
4084 }
4085 }
4086 while (bytes < 0);
4087
4088 DEBUG_printf(("2http_read: Read " CUPS_LLFMT " bytes into buffer.",
4089 CUPS_LLCAST bytes));
4090#ifdef DEBUG
4091 if (bytes > 0)
6961465f 4092 http_debug_hex("http_read", buffer, (int)bytes);
0fa6c7fa
MS
4093#endif /* DEBUG */
4094
4095 if (bytes < 0)
4096 {
4097#ifdef WIN32
4098 if (WSAGetLastError() == WSAEINTR)
4099 bytes = 0;
4100 else
4101 http->error = WSAGetLastError();
4102#else
4103 if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb))
4104 bytes = 0;
4105 else
4106 http->error = errno;
4107#endif /* WIN32 */
4108 }
4109 else if (bytes == 0)
4110 {
4111 http->error = EPIPE;
4112 return (0);
4113 }
4114
4115 return (bytes);
4116}
4117
4118
4119/*
4120 * 'http_read_buffered()' - Do a buffered read from a HTTP connection.
4121 *
4122 * This function reads data from the HTTP buffer or from the socket, as needed.
4123 */
4124
4125static ssize_t /* O - Number of bytes read or -1 on error */
e6b1a6a9 4126http_read_buffered(http_t *http, /* I - HTTP connection */
0fa6c7fa
MS
4127 char *buffer, /* I - Buffer */
4128 size_t length) /* I - Maximum bytes to read */
4129{
4130 ssize_t bytes; /* Bytes read */
4131
4132
4133 DEBUG_printf(("http_read_buffered(http=%p, buffer=%p, length=" CUPS_LLFMT
4134 ") used=%d",
4135 http, buffer, CUPS_LLCAST length, http->used));
4136
4137 if (http->used > 0)
4138 {
4139 if (length > (size_t)http->used)
4140 bytes = (size_t)http->used;
4141 else
4142 bytes = length;
4143
4144 DEBUG_printf(("2http_read: Grabbing %d bytes from input buffer.",
4145 (int)bytes));
4146
4147 memcpy(buffer, http->buffer, bytes);
4148 http->used -= (int)bytes;
4149
4150 if (http->used > 0)
4151 memmove(http->buffer, http->buffer + bytes, http->used);
4152 }
4153 else
4154 bytes = http_read(http, buffer, length);
4155
4156 return (bytes);
4157}
4158
4159
4160/*
4161 * 'http_read_chunk()' - Read a chunk from a HTTP connection.
4162 *
4163 * This function reads and validates the chunk length, then does a buffered read
4164 * returning the number of bytes placed in the buffer.
4165 */
4166
4167static ssize_t /* O - Number of bytes read or -1 on error */
e6b1a6a9 4168http_read_chunk(http_t *http, /* I - HTTP connection */
0fa6c7fa
MS
4169 char *buffer, /* I - Buffer */
4170 size_t length) /* I - Maximum bytes to read */
4171{
4172 DEBUG_printf(("http_read_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")",
4173 http, buffer, CUPS_LLCAST length));
4174
4175 if (http->data_remaining <= 0)
4176 {
4177 char len[32]; /* Length string */
4178
4179 if (!httpGets(len, sizeof(len), http))
4180 {
4181 DEBUG_puts("1http_read_chunk: Could not get chunk length.");
4182 return (0);
4183 }
4184
4185 if (!len[0])
4186 {
4187 DEBUG_puts("1http_read_chunk: Blank chunk length, trying again...");
4188 if (!httpGets(len, sizeof(len), http))
4189 {
4190 DEBUG_puts("1http_read_chunk: Could not get chunk length.");
4191 return (0);
4192 }
4193 }
4194
4195 http->data_remaining = strtoll(len, NULL, 16);
4196
4197 if (http->data_remaining < 0)
4198 {
4199 DEBUG_printf(("1http_read_chunk: Negative chunk length \"%s\" ("
4200 CUPS_LLFMT ")", len, CUPS_LLCAST http->data_remaining));
4201 return (0);
4202 }
4203
4204 DEBUG_printf(("2http_read_chunk: Got chunk length \"%s\" (" CUPS_LLFMT ")",
4205 len, CUPS_LLCAST http->data_remaining));
4206
4207 if (http->data_remaining == 0)
4208 {
4209 /*
4210 * 0-length chunk, grab trailing blank line...
4211 */
4212
4213 httpGets(len, sizeof(len), http);
4214 }
4215 }
4216
4217 DEBUG_printf(("2http_read_chunk: data_remaining=" CUPS_LLFMT,
4218 CUPS_LLCAST http->data_remaining));
4219
4220 if (http->data_remaining <= 0)
4221 return (0);
4222 else if (length > (size_t)http->data_remaining)
4223 length = (size_t)http->data_remaining;
4224
4225 return (http_read_buffered(http, buffer, length));
4226}
4227
4228
ef416fc2 4229/*
4230 * 'http_send()' - Send a request with all fields and the trailing blank line.
4231 */
4232
a469f8a5 4233static int /* O - 0 on success, non-zero on error */
e6b1a6a9 4234http_send(http_t *http, /* I - HTTP connection */
a469f8a5
MS
4235 http_state_t request, /* I - Request code */
4236 const char *uri) /* I - URI */
ef416fc2 4237{
a469f8a5
MS
4238 int i; /* Looping var */
4239 char buf[1024]; /* Encoded URI buffer */
4240 const char *value; /* Field value */
4241 static const char * const codes[] = /* Request code strings */
4242 {
ef416fc2 4243 NULL,
4244 "OPTIONS",
4245 "GET",
4246 NULL,
4247 "HEAD",
4248 "POST",
4249 NULL,
4250 NULL,
4251 "PUT",
4252 NULL,
4253 "DELETE",
4254 "TRACE",
a469f8a5
MS
4255 "CLOSE",
4256 NULL,
4257 NULL
ef416fc2 4258 };
ef416fc2 4259
4260
cb7f98ee 4261 DEBUG_printf(("4http_send(http=%p, request=HTTP_%s, uri=\"%s\")",
ef416fc2 4262 http, codes[request], uri));
4263
4264 if (http == NULL || uri == NULL)
4265 return (-1);
4266
4267 /*
4268 * Set the User-Agent field if it isn't already...
4269 */
4270
4271 if (!http->fields[HTTP_FIELD_USER_AGENT][0])
db8b865d
MS
4272 {
4273 if (http->default_user_agent)
4274 httpSetField(http, HTTP_FIELD_USER_AGENT, http->default_user_agent);
4275 else
4276 httpSetField(http, HTTP_FIELD_USER_AGENT, cupsUserAgent());
4277 }
ef416fc2 4278
a469f8a5
MS
4279 /*
4280 * Set the Accept-Encoding field if it isn't already...
4281 */
4282
c1420c87
MS
4283 if (!http->accept_encoding && http->default_accept_encoding)
4284 httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING,
4285 http->default_accept_encoding);
a469f8a5 4286
ef416fc2 4287 /*
4288 * Encode the URI as needed...
4289 */
4290
839a51c8 4291 _httpEncodeURI(buf, uri, sizeof(buf));
ef416fc2 4292
4293 /*
4294 * See if we had an error the last time around; if so, reconnect...
4295 */
4296
cb7f98ee
MS
4297 if (http->fd < 0 || http->status == HTTP_STATUS_ERROR ||
4298 http->status >= HTTP_STATUS_BAD_REQUEST)
4299 {
4300 DEBUG_printf(("5http_send: Reconnecting, fd=%d, status=%d, tls_upgrade=%d",
4301 http->fd, http->status, http->tls_upgrade));
4302
4303 if (httpReconnect2(http, 30000, NULL))
fa73b229 4304 return (-1);
cb7f98ee 4305 }
ef416fc2 4306
d09495fa 4307 /*
4308 * Flush any written data that is pending...
4309 */
4310
4311 if (http->wused)
536bc2c6
MS
4312 {
4313 if (httpFlushWrite(http) < 0)
cb7f98ee 4314 if (httpReconnect2(http, 30000, NULL))
536bc2c6
MS
4315 return (-1);
4316 }
d09495fa 4317
ef416fc2 4318 /*
4319 * Send the request header...
4320 */
4321
d09495fa 4322 http->state = request;
a469f8a5 4323 http->data_encoding = HTTP_ENCODING_FIELDS;
d09495fa 4324
cb7f98ee 4325 if (request == HTTP_STATE_POST || request == HTTP_STATE_PUT)
ef416fc2 4326 http->state ++;
4327
cb7f98ee 4328 http->status = HTTP_STATUS_CONTINUE;
ef416fc2 4329
4330#ifdef HAVE_SSL
cb7f98ee 4331 if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls)
ef416fc2 4332 {
4333 httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
a469f8a5 4334 httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
ef416fc2 4335 }
4336#endif /* HAVE_SSL */
4337
4338 if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
4339 {
cb7f98ee 4340 http->status = HTTP_STATUS_ERROR;
ef416fc2 4341 return (-1);
4342 }
4343
4344 for (i = 0; i < HTTP_FIELD_MAX; i ++)
a469f8a5 4345 if ((value = httpGetField(http, i)) != NULL && *value)
ef416fc2 4346 {
cb7f98ee 4347 DEBUG_printf(("5http_send: %s: %s", http_fields[i], value));
ef416fc2 4348
37e7e6e0
MS
4349 if (i == HTTP_FIELD_HOST)
4350 {
a469f8a5
MS
4351 if (httpPrintf(http, "Host: %s:%d\r\n", value,
4352 httpAddrPort(http->hostaddr)) < 1)
37e7e6e0 4353 {
cb7f98ee 4354 http->status = HTTP_STATUS_ERROR;
37e7e6e0
MS
4355 return (-1);
4356 }
4357 }
a469f8a5 4358 else if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
ef416fc2 4359 {
cb7f98ee 4360 http->status = HTTP_STATUS_ERROR;
ef416fc2 4361 return (-1);
4362 }
4363 }
4364
4365 if (http->cookie)
4366 if (httpPrintf(http, "Cookie: $Version=0; %s\r\n", http->cookie) < 1)
4367 {
cb7f98ee 4368 http->status = HTTP_STATUS_ERROR;
ef416fc2 4369 return (-1);
4370 }
4371
cb7f98ee
MS
4372 DEBUG_printf(("5http_send: expect=%d, mode=%d, state=%d", http->expect,
4373 http->mode, http->state));
4374
4375 if (http->expect == HTTP_STATUS_CONTINUE && http->mode == _HTTP_MODE_CLIENT &&
4376 (http->state == HTTP_STATE_POST_RECV ||
4377 http->state == HTTP_STATE_PUT_RECV))
b423cd4c 4378 if (httpPrintf(http, "Expect: 100-continue\r\n") < 1)
4379 {
cb7f98ee 4380 http->status = HTTP_STATUS_ERROR;
b423cd4c 4381 return (-1);
4382 }
4383
ef416fc2 4384 if (httpPrintf(http, "\r\n") < 1)
4385 {
cb7f98ee 4386 http->status = HTTP_STATUS_ERROR;
ef416fc2 4387 return (-1);
4388 }
4389
536bc2c6
MS
4390 if (httpFlushWrite(http) < 0)
4391 return (-1);
4392
a469f8a5 4393 http_set_length(http);
ef416fc2 4394 httpClearFields(http);
4395
f7deaa1a 4396 /*
b94498cf 4397 * The Kerberos and AuthRef authentication strings can only be used once...
f7deaa1a 4398 */
4399
ef55b745
MS
4400 if (http->field_authorization && http->authstring &&
4401 (!strncmp(http->authstring, "Negotiate", 9) ||
b94498cf 4402 !strncmp(http->authstring, "AuthRef", 7)))
f7deaa1a 4403 {
4404 http->_authstring[0] = '\0';
4405
4406 if (http->authstring != http->_authstring)
4407 free(http->authstring);
ef55b745 4408
f7deaa1a 4409 http->authstring = http->_authstring;
4410 }
4411
ef416fc2 4412 return (0);
4413}
4414
4415
a469f8a5
MS
4416/*
4417 * 'http_set_length()' - Set the data_encoding and data_remaining values.
4418 */
4419
4420static off_t /* O - Remainder or -1 on error */
4421http_set_length(http_t *http) /* I - Connection */
4422{
4423 off_t remaining; /* Remainder */
4424
4425
4426 DEBUG_printf(("http_set_length(http=%p) mode=%d state=%s", http, http->mode,
48bd1142 4427 httpStateString(http->state)));
a469f8a5
MS
4428
4429 if ((remaining = httpGetLength2(http)) >= 0)
4430 {
4431 if (http->mode == _HTTP_MODE_SERVER &&
4432 http->state != HTTP_STATE_GET_SEND &&
c41769ff 4433 http->state != HTTP_STATE_PUT &&
a469f8a5
MS
4434 http->state != HTTP_STATE_POST &&
4435 http->state != HTTP_STATE_POST_SEND)
4436 {
4437 DEBUG_puts("1http_set_length: Not setting data_encoding/remaining.");
4438 return (remaining);
4439 }
4440
4441 if (!_cups_strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING],
4442 "chunked"))
4443 {
4444 DEBUG_puts("1http_set_length: Setting data_encoding to "
4445 "HTTP_ENCODING_CHUNKED.");
4446 http->data_encoding = HTTP_ENCODING_CHUNKED;
4447 }
4448 else
4449 {
4450 DEBUG_puts("1http_set_length: Setting data_encoding to "
4451 "HTTP_ENCODING_LENGTH.");
4452 http->data_encoding = HTTP_ENCODING_LENGTH;
4453 }
4454
4455 DEBUG_printf(("1http_set_length: Setting data_remaining to " CUPS_LLFMT ".",
4456 CUPS_LLCAST remaining));
4457 http->data_remaining = remaining;
4458
4459 if (remaining <= INT_MAX)
4460 http->_data_remaining = remaining;
4461 else
4462 http->_data_remaining = INT_MAX;
4463 }
4464
4465 return (remaining);
4466}
4467
85dda01c
MS
4468/*
4469 * 'http_set_timeout()' - Set the socket timeout values.
4470 */
4471
4472static void
4473http_set_timeout(int fd, /* I - File descriptor */
4474 double timeout) /* I - Timeout in seconds */
4475{
4476#ifdef WIN32
4477 DWORD tv = (DWORD)(timeout * 1000);
4478 /* Timeout in milliseconds */
4479
db8b865d
MS
4480 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4481 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
85dda01c
MS
4482
4483#else
4484 struct timeval tv; /* Timeout in secs and usecs */
4485
4486 tv.tv_sec = (int)timeout;
4487 tv.tv_usec = (int)(1000000 * fmod(timeout, 1.0));
4488
db8b865d
MS
4489 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
4490 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
85dda01c
MS
4491#endif /* WIN32 */
4492}
4493
4494
4495/*
4496 * 'http_set_wait()' - Set the default wait value for reads.
4497 */
4498
4499static void
e6b1a6a9 4500http_set_wait(http_t *http) /* I - HTTP connection */
85dda01c
MS
4501{
4502 if (http->blocking)
4503 {
4504 http->wait_value = (int)(http->timeout_value * 1000);
4505
4506 if (http->wait_value <= 0)
4507 http->wait_value = 60000;
4508 }
4509 else
4510 http->wait_value = 10000;
4511}
4512
4513
9b66acc5 4514#ifdef HAVE_SSL
ef416fc2 4515/*
2c85b752 4516 * 'http_tls_upgrade()' - Force upgrade to TLS encryption.
ef416fc2 4517 */
4518
89d46774 4519static int /* O - Status of connection */
2c85b752 4520http_tls_upgrade(http_t *http) /* I - HTTP connection */
ef416fc2 4521{
89d46774 4522 int ret; /* Return value */
4523 http_t myhttp; /* Local copy of HTTP data */
ef416fc2 4524
4525
2c85b752 4526 DEBUG_printf(("7http_tls_upgrade(%p)", http));
ef416fc2 4527
85b5d1df
MS
4528 /*
4529 * Flush the connection to make sure any previous "Upgrade" message
4530 * has been read.
4531 */
4532
4533 httpFlush(http);
4534
ef416fc2 4535 /*
4536 * Copy the HTTP data to a local variable so we can do the OPTIONS
4537 * request without interfering with the existing request data...
4538 */
4539
4540 memcpy(&myhttp, http, sizeof(myhttp));
4541
4542 /*
4543 * Send an OPTIONS request to the server, requiring SSL or TLS
4544 * encryption on the link...
4545 */
4546
cb7f98ee 4547 http->tls_upgrade = 1;
f7deaa1a 4548 http->field_authorization = NULL; /* Don't free the auth string */
4549
b86bc4cf 4550 httpClearFields(http);
4551 httpSetField(http, HTTP_FIELD_CONNECTION, "upgrade");
a469f8a5 4552 httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
ef416fc2 4553
b86bc4cf 4554 if ((ret = httpOptions(http, "*")) == 0)
ef416fc2 4555 {
4556 /*
4557 * Wait for the secure connection...
4558 */
4559
cb7f98ee 4560 while (httpUpdate(http) == HTTP_STATUS_CONTINUE);
ef416fc2 4561 }
4562
ef416fc2 4563 /*
b86bc4cf 4564 * Restore the HTTP request data...
ef416fc2 4565 */
4566
b86bc4cf 4567 memcpy(http->fields, myhttp.fields, sizeof(http->fields));
f7deaa1a 4568 http->data_encoding = myhttp.data_encoding;
4569 http->data_remaining = myhttp.data_remaining;
4570 http->_data_remaining = myhttp._data_remaining;
4571 http->expect = myhttp.expect;
4572 http->field_authorization = myhttp.field_authorization;
bc44d920 4573 http->digest_tries = myhttp.digest_tries;
cb7f98ee 4574 http->tls_upgrade = 0;
ef416fc2 4575
4576 /*
4577 * See if we actually went secure...
4578 */
4579
4580 if (!http->tls)
4581 {
4582 /*
4583 * Server does not support HTTP upgrade...
4584 */
4585
2c85b752 4586 DEBUG_puts("8http_tls_upgrade: Server does not support HTTP upgrade!");
ef416fc2 4587
87e98392 4588 httpAddrClose(NULL, http->fd);
ef416fc2 4589
4590 http->fd = -1;
4591
4592 return (-1);
4593 }
4594 else
4595 return (ret);
4596}
4597#endif /* HAVE_SSL */
4598
4599
ef416fc2 4600/*
4601 * 'http_write()' - Write a buffer to a HTTP connection.
4602 */
ef55b745 4603
0fa6c7fa 4604static ssize_t /* O - Number of bytes written */
e6b1a6a9 4605http_write(http_t *http, /* I - HTTP connection */
f11a948a 4606 const char *buffer, /* I - Buffer for data */
0fa6c7fa 4607 size_t length) /* I - Number of bytes to write */
ef416fc2 4608{
0fa6c7fa
MS
4609 ssize_t tbytes, /* Total bytes sent */
4610 bytes; /* Bytes sent */
ef416fc2 4611
4612
0fa6c7fa
MS
4613 DEBUG_printf(("2http_write(http=%p, buffer=%p, length=" CUPS_LLFMT ")", http,
4614 buffer, CUPS_LLCAST length));
f11a948a
MS
4615 http->error = 0;
4616 tbytes = 0;
ef416fc2 4617
4618 while (length > 0)
4619 {
12f89d24
MS
4620 DEBUG_printf(("3http_write: About to write %d bytes.", (int)length));
4621
85dda01c
MS
4622 if (http->timeout_cb)
4623 {
4624#ifdef HAVE_POLL
4625 struct pollfd pfd; /* Polled file descriptor */
4626#else
4627 fd_set output_set; /* Output ready for write? */
4628 struct timeval timeout; /* Timeout value */
4629#endif /* HAVE_POLL */
4630 int nfds; /* Result from select()/poll() */
4631
4632 do
4633 {
4634#ifdef HAVE_POLL
4635 pfd.fd = http->fd;
4636 pfd.events = POLLOUT;
4637
4638 while ((nfds = poll(&pfd, 1, http->wait_value)) < 0 &&
82cc1f9a
MS
4639 (errno == EINTR || errno == EAGAIN))
4640 /* do nothing */;
85dda01c
MS
4641
4642#else
4643 do
4644 {
4645 FD_ZERO(&output_set);
4646 FD_SET(http->fd, &output_set);
4647
4648 timeout.tv_sec = http->wait_value / 1000;
4649 timeout.tv_usec = 1000 * (http->wait_value % 1000);
4650
4651 nfds = select(http->fd + 1, NULL, &output_set, NULL, &timeout);
4652 }
4653# ifdef WIN32
4654 while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
4655 WSAGetLastError() == WSAEWOULDBLOCK));
4656# else
4657 while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
4658# endif /* WIN32 */
4659#endif /* HAVE_POLL */
4660
4661 if (nfds < 0)
4662 {
4663 http->error = errno;
4664 return (-1);
4665 }
4666 else if (nfds == 0 && !(*http->timeout_cb)(http, http->timeout_data))
4667 {
4668#ifdef WIN32
83e08001 4669 http->error = WSAEWOULDBLOCK;
85dda01c
MS
4670#else
4671 http->error = EWOULDBLOCK;
4672#endif /* WIN32 */
4673 return (-1);
4674 }
4675 }
4676 while (nfds <= 0);
4677 }
4678
ef416fc2 4679#ifdef HAVE_SSL
4680 if (http->tls)
2c85b752 4681 bytes = http_tls_write(http, buffer, length);
ef416fc2 4682 else
4683#endif /* HAVE_SSL */
4684 bytes = send(http->fd, buffer, length, 0);
4685
0fa6c7fa
MS
4686 DEBUG_printf(("3http_write: Write of " CUPS_LLFMT " bytes returned "
4687 CUPS_LLFMT ".", CUPS_LLCAST length, CUPS_LLCAST bytes));
12f89d24 4688
ef416fc2 4689 if (bytes < 0)
4690 {
4691#ifdef WIN32
10d09e33 4692 if (WSAGetLastError() == WSAEINTR)
cc754834 4693 continue;
10d09e33
MS
4694 else if (WSAGetLastError() == WSAEWOULDBLOCK)
4695 {
4696 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4697 continue;
4698
4699 http->error = WSAGetLastError();
4700 }
4701 else if (WSAGetLastError() != http->error &&
4702 WSAGetLastError() != WSAECONNRESET)
ef416fc2 4703 {
4704 http->error = WSAGetLastError();
4705 continue;
4706 }
10d09e33 4707
ef416fc2 4708#else
10d09e33 4709 if (errno == EINTR)
ef416fc2 4710 continue;
10d09e33
MS
4711 else if (errno == EWOULDBLOCK || errno == EAGAIN)
4712 {
4713 if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
4714 continue;
4715 else if (!http->timeout_cb && errno == EAGAIN)
4716 continue;
4717
4718 http->error = errno;
4719 }
ef416fc2 4720 else if (errno != http->error && errno != ECONNRESET)
4721 {
4722 http->error = errno;
4723 continue;
4724 }
4725#endif /* WIN32 */
4726
f8b3a85b
MS
4727 DEBUG_printf(("3http_write: error writing data (%s).",
4728 strerror(http->error)));
ef416fc2 4729
4730 return (-1);
4731 }
4732
4733 buffer += bytes;
4734 tbytes += bytes;
4735 length -= bytes;
4736 }
4737
4738#ifdef DEBUG
ae71f5de 4739 http_debug_hex("http_write", buffer - tbytes, tbytes);
ef416fc2 4740#endif /* DEBUG */
4741
0fa6c7fa 4742 DEBUG_printf(("3http_write: Returning " CUPS_LLFMT ".", CUPS_LLCAST tbytes));
f8b3a85b 4743
ef416fc2 4744 return (tbytes);
4745}
4746
4747
4748/*
4749 * 'http_write_chunk()' - Write a chunked buffer.
4750 */
4751
0fa6c7fa 4752static ssize_t /* O - Number bytes written */
e6b1a6a9 4753http_write_chunk(http_t *http, /* I - HTTP connection */
ef416fc2 4754 const char *buffer, /* I - Buffer to write */
0fa6c7fa 4755 size_t length) /* I - Length of buffer */
ef416fc2 4756{
0fa6c7fa
MS
4757 char header[16]; /* Chunk header */
4758 ssize_t bytes; /* Bytes written */
ef416fc2 4759
f11a948a 4760
0fa6c7fa
MS
4761 DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")",
4762 http, buffer, CUPS_LLCAST length));
ef416fc2 4763
4764 /*
4765 * Write the chunk header, data, and trailer.
4766 */
4767
0fa6c7fa
MS
4768 snprintf(header, sizeof(header), "%x\r\n", (unsigned)length);
4769 if (http_write(http, header, strlen(header)) < 0)
ef416fc2 4770 {
0fa6c7fa 4771 DEBUG_puts("8http_write_chunk: http_write of length failed.");
ef416fc2 4772 return (-1);
4773 }
4774
4775 if ((bytes = http_write(http, buffer, length)) < 0)
4776 {
0fa6c7fa 4777 DEBUG_puts("8http_write_chunk: http_write of buffer failed.");
ef416fc2 4778 return (-1);
4779 }
4780
4781 if (http_write(http, "\r\n", 2) < 0)
4782 {
0fa6c7fa 4783 DEBUG_puts("8http_write_chunk: http_write of CR LF failed.");
ef416fc2 4784 return (-1);
4785 }
4786
4787 return (bytes);
4788}
4789
4790
ef416fc2 4791/*
f2d18633 4792 * End of "$Id$".
ef416fc2 4793 */