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