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