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