]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/http.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / cups / http.c
CommitLineData
3840d6ba 1/*
92e48f04 2 * "$Id: http.c,v 1.82.2.32 2003/05/09 16:06:43 mike Exp $"
3840d6ba 3 *
99de6da0 4 * HTTP routines for the Common UNIX Printing System (CUPS).
fd8b1cf8 5 *
1d9595ab 6 * Copyright 1997-2003 by Easy Software Products, all rights reserved.
fd8b1cf8 7 *
b38fb7fc 8 * These coded instructions, statements, and computer programs are the
fd8b1cf8 9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
8784b6a6 17 * 44141 Airport View Drive, Suite 204
fd8b1cf8 18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
3840d6ba 23 *
dab1a4d8 24 * This file is subject to the Apple OS-Developed Software exception.
25 *
3840d6ba 26 * Contents:
27 *
b5cb0608 28 * httpInitialize() - Initialize the HTTP interface library and set the
29 * default HTTP proxy (if any).
30 * httpCheck() - Check to see if there is a pending response from
31 * the server.
d40085f1 32 * httpClearCookie() - Clear the cookie value(s).
b5cb0608 33 * httpClose() - Close an HTTP connection...
34 * httpConnect() - Connect to a HTTP server.
35 * httpConnectEncrypt() - Connect to a HTTP server using encryption.
36 * httpEncryption() - Set the required encryption on the link.
37 * httpReconnect() - Reconnect to a HTTP server...
b5cb0608 38 * httpSetField() - Set the value of an HTTP header.
39 * httpDelete() - Send a DELETE request to the server.
40 * httpGet() - Send a GET request to the server.
41 * httpHead() - Send a HEAD request to the server.
42 * httpOptions() - Send an OPTIONS request to the server.
43 * httpPost() - Send a POST request to the server.
44 * httpPut() - Send a PUT request to the server.
45 * httpTrace() - Send an TRACE request to the server.
46 * httpFlush() - Flush data from a HTTP connection.
47 * httpRead() - Read data from a HTTP connection.
d40085f1 48 * httpSetCookie() - Set the cookie value(s)...
2e32fcdb 49 * httpWait() - Wait for data available on a connection.
b5cb0608 50 * httpWrite() - Write data to a HTTP connection.
51 * httpGets() - Get a line of text from a HTTP connection.
52 * httpPrintf() - Print a formatted string to a HTTP connection.
53 * httpStatus() - Return a short string describing a HTTP status code.
54 * httpGetDateString() - Get a formatted date/time string from a time value.
55 * httpGetDateTime() - Get a time value from a formatted date/time string.
56 * httpUpdate() - Update the current HTTP state for incoming data.
57 * httpDecode64() - Base64-decode a string.
58 * httpEncode64() - Base64-encode a string.
59 * httpGetLength() - Get the amount of data remaining from the
60 * content-length or transfer-encoding fields.
61 * http_field() - Return the field index for a field name.
62 * http_send() - Send a request with all fields and the trailing
63 * blank line.
64 * http_upgrade() - Force upgrade to TLS encryption.
bcf61448 65 * http_setup_ssl() - Set up SSL/TLS on a connection.
66 * http_shutdown_ssl() - Shut down SSL/TLS on a connection.
67 * http_read_ssl() - Read from a SSL/TLS connection.
68 * http_write_ssl() - Write to a SSL/TLS connection.
dcfcaeac 69 * CDSAReadFunc() - Read function for CDSA decryption code.
70 * CDSAWriteFunc() - Write function for CDSA encryption code.
3840d6ba 71 */
72
73/*
74 * Include necessary headers...
75 */
76
3b960317 77#include <stdio.h>
78#include <stdlib.h>
3840d6ba 79#include <stdarg.h>
3b960317 80#include <ctype.h>
81#include "string.h"
3b960317 82#include <fcntl.h>
4e8f6c6a 83#include <errno.h>
992cf15a 84
bcf61448 85#include "http-private.h"
8a5aa628 86#include "ipp.h"
4a73831b 87#include "debug.h"
f4cafe91 88
c3026ddc 89#ifndef WIN32
5356dc5a 90# include <signal.h>
63d94476 91# include <sys/time.h>
92# include <sys/resource.h>
c3026ddc 93#endif /* !WIN32 */
5356dc5a 94
a75c006a 95
42d48bd2 96/*
97 * Some operating systems have done away with the Fxxxx constants for
98 * the fcntl() call; this works around that "feature"...
99 */
100
101#ifndef FNONBLK
102# define FNONBLK O_NONBLOCK
103#endif /* !FNONBLK */
104
992cf15a 105
106/*
3a193f5e 107 * Local functions...
992cf15a 108 */
109
063e1ac7 110static http_field_t http_field(const char *name);
111static int http_send(http_t *http, http_state_t request,
112 const char *uri);
bcf61448 113#ifdef HAVE_SSL
2a0ef17a 114static int http_upgrade(http_t *http);
bcf61448 115static int http_setup_ssl(http_t *http);
116static void http_shutdown_ssl(http_t *http);
117static int http_read_ssl(http_t *http, char *buf, int len);
118static int http_write_ssl(http_t *http, const char *buf, int len);
dcfcaeac 119# ifdef HAVE_CDSASSL
120static OSStatus CDSAReadFunc(SSLConnectionRef connection, void *data, size_t *dataLength);
121static OSStatus CDSAWriteFunc(SSLConnectionRef connection, const void *data, size_t *dataLength);
122# endif /* HAVE_CDSASSL */
bcf61448 123#endif /* HAVE_SSL */
3840d6ba 124
125
126/*
3a193f5e 127 * Local globals...
3840d6ba 128 */
129
6db7190f 130static const char * const http_fields[] =
3a193f5e 131 {
3a193f5e 132 "Accept-Language",
0542e38e 133 "Accept-Ranges",
3a193f5e 134 "Authorization",
3a193f5e 135 "Connection",
3a193f5e 136 "Content-Encoding",
137 "Content-Language",
138 "Content-Length",
139 "Content-Location",
140 "Content-MD5",
141 "Content-Range",
142 "Content-Type",
0d1f75a3 143 "Content-Version",
3a193f5e 144 "Date",
3a193f5e 145 "Host",
3a193f5e 146 "If-Modified-Since",
3a193f5e 147 "If-Unmodified-since",
0d1f75a3 148 "Keep-Alive",
3a193f5e 149 "Last-Modified",
0d1f75a3 150 "Link",
3a193f5e 151 "Location",
3a193f5e 152 "Range",
153 "Referer",
154 "Retry-After",
3a193f5e 155 "Transfer-Encoding",
156 "Upgrade",
157 "User-Agent",
3a193f5e 158 "WWW-Authenticate"
159 };
6db7190f 160static const char * const days[7] =
3a193f5e 161 {
162 "Sun",
163 "Mon",
164 "Tue",
165 "Wed",
166 "Thu",
167 "Fri",
168 "Sat"
169 };
6db7190f 170static const char * const months[12] =
3a193f5e 171 {
172 "Jan",
173 "Feb",
174 "Mar",
175 "Apr",
176 "May",
177 "Jun",
178 "Jul",
179 "Aug",
180 "Sep",
181 "Oct",
182 "Nov",
183 "Dec"
184 };
3840d6ba 185
186
9cba63f2 187/*
188 * 'httpInitialize()' - Initialize the HTTP interface library and set the
189 * default HTTP proxy (if any).
190 */
191
192void
0542e38e 193httpInitialize(void)
9cba63f2 194{
a75c006a 195#ifdef HAVE_LIBSSL
a75c006a 196 struct timeval curtime; /* Current time in microseconds */
1c6682dd 197 int i; /* Looping var */
198 unsigned char data[1024]; /* Seed data */
a75c006a 199#endif /* HAVE_LIBSSL */
200
c3026ddc 201#ifdef WIN32
50146867 202 WSADATA winsockdata; /* WinSock data */
203 static int initialized = 0;/* Has WinSock been initialized? */
204
205
206 if (!initialized)
207 WSAStartup(MAKEWORD(1,1), &winsockdata);
ca7e65c8 208#elif defined(HAVE_SIGSET)
209 sigset(SIGPIPE, SIG_IGN);
210#elif defined(HAVE_SIGACTION)
2bffb563 211 struct sigaction action; /* POSIX sigaction data */
212
213
214 /*
215 * Ignore SIGPIPE signals...
216 */
217
218 memset(&action, 0, sizeof(action));
219 action.sa_handler = SIG_IGN;
220 sigaction(SIGPIPE, &action, NULL);
ca7e65c8 221#else
222 signal(SIGPIPE, SIG_IGN);
c3026ddc 223#endif /* WIN32 */
a75c006a 224
bcf61448 225#ifdef HAVE_GNUTLS
226 gnutls_global_init();
227#endif /* HAVE_GNUTLS */
228
a75c006a 229#ifdef HAVE_LIBSSL
1c6682dd 230 SSL_load_error_strings();
a75c006a 231 SSL_library_init();
232
233 /*
234 * Using the current time is a dubious random seed, but on some systems
235 * it is the best we can do (on others, this seed isn't even used...)
236 */
237
a75c006a 238 gettimeofday(&curtime, NULL);
1c6682dd 239 srand(curtime.tv_sec + curtime.tv_usec);
240
241 for (i = 0; i < sizeof(data); i ++)
242 data[i] = rand(); /* Yes, this is a poor source of random data... */
243
244 RAND_seed(&data, sizeof(data));
a75c006a 245#endif /* HAVE_LIBSSL */
50146867 246}
247
248
c1918ec5 249/*
250 * 'httpCheck()' - Check to see if there is a pending response from the server.
251 */
252
253int /* O - 0 = no data, 1 = data available */
254httpCheck(http_t *http) /* I - HTTP connection */
255{
2e32fcdb 256 return (httpWait(http, 0));
c1918ec5 257}
258
259
d40085f1 260/*
261 * 'httpClearCookie()' - Clear the cookie value(s).
262 */
263
264void
265httpClearCookie(http_t *http) /* I - Connection */
266{
267 if (!http)
268 return;
269
270 if (http->cookie)
271 {
272 free(http->cookie);
273 http->cookie = NULL;
274 }
275}
276
277
50146867 278/*
279 * 'httpClose()' - Close an HTTP connection...
280 */
281
282void
283httpClose(http_t *http) /* I - Connection to close */
284{
2a0ef17a 285 if (!http)
50146867 286 return;
287
2e32fcdb 288 if (http->input_set)
289 free(http->input_set);
290
d40085f1 291 if (http->cookie)
292 free(http->cookie);
293
bcf61448 294#ifdef HAVE_SSL
2a0ef17a 295 if (http->tls)
bcf61448 296 http_shutdown_ssl(http);
297#endif /* HAVE_SSL */
2a0ef17a 298
50146867 299#ifdef WIN32
300 closesocket(http->fd);
301#else
302 close(http->fd);
303#endif /* WIN32 */
304
305 free(http);
9cba63f2 306}
307
308
3840d6ba 309/*
50146867 310 * 'httpConnect()' - Connect to a HTTP server.
3840d6ba 311 */
312
50146867 313http_t * /* O - New HTTP connection */
063e1ac7 314httpConnect(const char *host, /* I - Host to connect to */
315 int port) /* I - Port number */
b5cb0608 316{
317 http_encryption_t encrypt;/* Type of encryption to use */
318
319
320 /*
321 * Set the default encryption status...
322 */
323
324 if (port == 443)
325 encrypt = HTTP_ENCRYPT_ALWAYS;
326 else
327 encrypt = HTTP_ENCRYPT_IF_REQUESTED;
328
329 return (httpConnectEncrypt(host, port, encrypt));
330}
331
332
333/*
334 * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption.
335 */
336
337http_t * /* O - New HTTP connection */
338httpConnectEncrypt(const char *host, /* I - Host to connect to */
339 int port, /* I - Port number */
340 http_encryption_t encrypt)
341 /* I - Type of encryption to use */
3840d6ba 342{
99de6da0 343 int i; /* Looping var */
50146867 344 http_t *http; /* New HTTP connection */
345 struct hostent *hostaddr; /* Host address data */
346
347
db8c0a8c 348 if (host == NULL)
349 return (NULL);
350
0b83a6c8 351 httpInitialize();
352
50146867 353 /*
354 * Lookup the host...
355 */
356
753453e4 357 if ((hostaddr = httpGetHostByName(host)) == NULL)
627f4602 358 {
359 /*
360 * This hack to make users that don't have a localhost entry in
361 * their hosts file or DNS happy...
362 */
363
364 if (strcasecmp(host, "localhost") != 0)
365 return (NULL);
753453e4 366 else if ((hostaddr = httpGetHostByName("127.0.0.1")) == NULL)
627f4602 367 return (NULL);
368 }
3840d6ba 369
7e9dc5e9 370 /*
371 * Verify that it is an IPv4 address (IPv6 support will come in CUPS 1.2...)
372 */
373
99de6da0 374#ifdef AF_INET6
375 if ((hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4) &&
376 (hostaddr->h_addrtype != AF_INET6 || hostaddr->h_length != 16))
377 return (NULL);
378#else
7e9dc5e9 379 if (hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4)
380 return (NULL);
99de6da0 381#endif /* AF_INET6 */
7e9dc5e9 382
3840d6ba 383 /*
3a193f5e 384 * Allocate memory for the structure...
3840d6ba 385 */
386
3a193f5e 387 http = calloc(sizeof(http_t), 1);
388 if (http == NULL)
389 return (NULL);
3840d6ba 390
a8374e1e 391 http->version = HTTP_1_1;
0542e38e 392 http->blocking = 1;
3a193f5e 393 http->activity = time(NULL);
7e9dc5e9 394 http->fd = -1;
3840d6ba 395
b5cb0608 396 /*
397 * Set the encryption status...
398 */
399
753453e4 400 if (port == 443) /* Always use encryption for https */
401 http->encryption = HTTP_ENCRYPT_ALWAYS;
402 else
403 http->encryption = encrypt;
b5cb0608 404
a75c006a 405 /*
99de6da0 406 * Loop through the addresses we have until one of them connects...
a75c006a 407 */
408
def978d5 409 strlcpy(http->hostname, host, sizeof(http->hostname));
07c5adda 410
99de6da0 411 for (i = 0; hostaddr->h_addr_list[i]; i ++)
412 {
413 /*
414 * Load the address...
415 */
416
417 httpAddrLoad(hostaddr, port, i, &(http->hostaddr));
418
419 /*
420 * Connect to the remote system...
421 */
422
423 if (!httpReconnect(http))
424 break;
425 }
426
427 /*
428 * Return the new structure if we could connect; otherwise, bail out...
429 */
430
431 if (hostaddr->h_addr_list[i])
432 return (http);
433 else
3840d6ba 434 {
3a193f5e 435 free(http);
436 return (NULL);
3840d6ba 437 }
3a193f5e 438}
3840d6ba 439
3840d6ba 440
b38fb7fc 441/*
442 * 'httpEncryption()' - Set the required encryption on the link.
443 */
444
445int /* O - -1 on error, 0 on success */
446httpEncryption(http_t *http, /* I - HTTP data */
447 http_encryption_t e) /* I - New encryption preference */
448{
bcf61448 449#ifdef HAVE_SSL
b38fb7fc 450 if (!http)
2a0ef17a 451 return (0);
b38fb7fc 452
453 http->encryption = e;
454
455 if ((http->encryption == HTTP_ENCRYPT_ALWAYS && !http->tls) ||
456 (http->encryption == HTTP_ENCRYPT_NEVER && http->tls))
457 return (httpReconnect(http));
2a0ef17a 458 else if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
459 return (http_upgrade(http));
460 else
461 return (0);
462#else
463 if (e == HTTP_ENCRYPT_ALWAYS || e == HTTP_ENCRYPT_REQUIRED)
464 return (-1);
b38fb7fc 465 else
466 return (0);
bcf61448 467#endif /* HAVE_SSL */
b38fb7fc 468}
469
470
3a193f5e 471/*
50146867 472 * 'httpReconnect()' - Reconnect to a HTTP server...
3a193f5e 473 */
3840d6ba 474
50146867 475int /* O - 0 on success, non-zero on failure */
476httpReconnect(http_t *http) /* I - HTTP data */
3a193f5e 477{
a75c006a 478 int val; /* Socket option value */
3840d6ba 479
bcf61448 480#ifdef HAVE_SSL
a75c006a 481 if (http->tls)
bcf61448 482 http_shutdown_ssl(http);
483#endif /* HAVE_SSL */
a75c006a 484
50146867 485 /*
486 * Close any previously open socket...
487 */
488
7e9dc5e9 489 if (http->fd >= 0)
3a193f5e 490#ifdef WIN32
50146867 491 closesocket(http->fd);
3a193f5e 492#else
50146867 493 close(http->fd);
3a193f5e 494#endif /* WIN32 */
3840d6ba 495
50146867 496 /*
497 * Create the socket and set options to allow reuse.
498 */
3840d6ba 499
99de6da0 500 if ((http->fd = socket(http->hostaddr.addr.sa_family, SOCK_STREAM, 0)) < 0)
0bf5ae82 501 {
c3026ddc 502#ifdef WIN32
977acbd3 503 http->error = WSAGetLastError();
504#else
f44afac9 505 http->error = errno;
c3026ddc 506#endif /* WIN32 */
f44afac9 507 http->status = HTTP_ERROR;
50146867 508 return (-1);
0bf5ae82 509 }
fd8b1cf8 510
50146867 511#ifdef FD_CLOEXEC
512 fcntl(http->fd, F_SETFD, FD_CLOEXEC); /* Close this socket when starting *
513 * other processes... */
514#endif /* FD_CLOEXEC */
fd8b1cf8 515
50146867 516 val = 1;
2456b740 517 setsockopt(http->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
3840d6ba 518
50146867 519#ifdef SO_REUSEPORT
520 val = 1;
521 setsockopt(http->fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
522#endif /* SO_REUSEPORT */
3840d6ba 523
9ae34eb7 524 /*
525 * Using TCP_NODELAY improves responsiveness, especially on systems
526 * with a slow loopback interface... Since we write large buffers
527 * when sending print files and requests, there shouldn't be any
528 * performance penalty for this...
529 */
530
531 val = 1;
532 setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
533
50146867 534 /*
535 * Connect to the server...
536 */
537
a09840c5 538#ifdef AF_INET6
539 if (connect(http->fd, (struct sockaddr *)&(http->hostaddr),
540 http->hostaddr.addr.sa_family == AF_INET ?
541 sizeof(http->hostaddr.ipv4) :
542 sizeof(http->hostaddr.ipv6)) < 0)
543#else
50146867 544 if (connect(http->fd, (struct sockaddr *)&(http->hostaddr),
a09840c5 545 sizeof(http->hostaddr.ipv4)) < 0)
546#endif /* AF_INET6 */
50146867 547 {
c3026ddc 548#ifdef WIN32
977acbd3 549 http->error = WSAGetLastError();
550#else
f44afac9 551 http->error = errno;
c3026ddc 552#endif /* WIN32 */
f44afac9 553 http->status = HTTP_ERROR;
0bf5ae82 554
50146867 555#ifdef WIN32
556 closesocket(http->fd);
557#else
558 close(http->fd);
559#endif
560
7e9dc5e9 561 http->fd = -1;
562
50146867 563 return (-1);
e8fda7b9 564 }
f44afac9 565
566 http->error = 0;
567 http->status = HTTP_CONTINUE;
50146867 568
bcf61448 569#ifdef HAVE_SSL
a75c006a 570 if (http->encryption == HTTP_ENCRYPT_ALWAYS)
571 {
572 /*
2a0ef17a 573 * Always do encryption via SSL.
a75c006a 574 */
575
bcf61448 576 if (http_setup_ssl(http) != 0)
a75c006a 577 {
a75c006a 578#ifdef WIN32
579 closesocket(http->fd);
580#else
581 close(http->fd);
bcf61448 582#endif /* WIN32 */
a75c006a 583
584 return (-1);
585 }
a75c006a 586 }
2a0ef17a 587 else if (http->encryption == HTTP_ENCRYPT_REQUIRED)
588 return (http_upgrade(http));
bcf61448 589#endif /* HAVE_SSL */
a75c006a 590
50146867 591 return (0);
3a193f5e 592}
593
594
83e740a5 595/*
596 * 'httpGetSubField()' - Get a sub-field value.
597 */
598
599char * /* O - Value or NULL */
600httpGetSubField(http_t *http, /* I - HTTP data */
601 http_field_t field, /* I - Field index */
602 const char *name, /* I - Name of sub-field */
603 char *value) /* O - Value string */
604{
605 const char *fptr; /* Pointer into field */
606 char temp[HTTP_MAX_VALUE], /* Temporary buffer for name */
607 *ptr; /* Pointer into string buffer */
608
609
610 if (http == NULL ||
611 field < HTTP_FIELD_ACCEPT_LANGUAGE ||
612 field > HTTP_FIELD_WWW_AUTHENTICATE ||
613 name == NULL || value == NULL)
614 return (NULL);
615
616 for (fptr = http->fields[field]; *fptr;)
617 {
618 /*
619 * Skip leading whitespace...
620 */
621
3f4c4837 622 while (isspace(*fptr))
83e740a5 623 fptr ++;
624
625 if (*fptr == ',')
626 {
627 fptr ++;
628 continue;
629 }
630
631 /*
632 * Get the sub-field name...
633 */
634
635 for (ptr = temp;
636 *fptr && *fptr != '=' && !isspace(*fptr) && ptr < (temp + sizeof(temp) - 1);
637 *ptr++ = *fptr++);
638
639 *ptr = '\0';
640
641 /*
642 * Skip trailing chars up to the '='...
643 */
644
645 while (*fptr && *fptr != '=')
646 fptr ++;
647
648 if (!*fptr)
649 break;
650
651 /*
652 * Skip = and leading whitespace...
653 */
654
655 fptr ++;
656
3f4c4837 657 while (isspace(*fptr))
83e740a5 658 fptr ++;
659
660 if (*fptr == '\"')
661 {
662 /*
663 * Read quoted string...
664 */
665
666 for (ptr = value, fptr ++;
667 *fptr && *fptr != '\"' && ptr < (value + HTTP_MAX_VALUE - 1);
668 *ptr++ = *fptr++);
669
670 *ptr = '\0';
671
672 while (*fptr && *fptr != '\"')
673 fptr ++;
674
675 if (*fptr)
676 fptr ++;
677 }
678 else
679 {
680 /*
681 * Read unquoted string...
682 */
683
684 for (ptr = value;
685 *fptr && !isspace(*fptr) && *fptr != ',' && ptr < (value + HTTP_MAX_VALUE - 1);
686 *ptr++ = *fptr++);
687
688 *ptr = '\0';
689
690 while (*fptr && !isspace(*fptr) && *fptr != ',')
691 fptr ++;
692 }
693
694 /*
695 * See if this is the one...
696 */
697
698 if (strcmp(name, temp) == 0)
699 return (value);
700 }
701
702 value[0] = '\0';
703
704 return (NULL);
705}
706
707
50146867 708/*
709 * 'httpSetField()' - Set the value of an HTTP header.
710 */
3a193f5e 711
50146867 712void
713httpSetField(http_t *http, /* I - HTTP data */
714 http_field_t field, /* I - Field index */
063e1ac7 715 const char *value) /* I - Value */
3a193f5e 716{
83e740a5 717 if (http == NULL ||
718 field < HTTP_FIELD_ACCEPT_LANGUAGE ||
719 field > HTTP_FIELD_WWW_AUTHENTICATE ||
720 value == NULL)
721 return;
722
def978d5 723 strlcpy(http->fields[field], value, HTTP_MAX_VALUE);
3a193f5e 724}
725
726
50146867 727/*
728 * 'httpDelete()' - Send a DELETE request to the server.
729 */
730
731int /* O - Status of call (0 = success) */
063e1ac7 732httpDelete(http_t *http, /* I - HTTP data */
733 const char *uri) /* I - URI to delete */
3a193f5e 734{
a8374e1e 735 return (http_send(http, HTTP_DELETE, uri));
3a193f5e 736}
737
738
50146867 739/*
740 * 'httpGet()' - Send a GET request to the server.
741 */
742
743int /* O - Status of call (0 = success) */
063e1ac7 744httpGet(http_t *http, /* I - HTTP data */
745 const char *uri) /* I - URI to get */
3a193f5e 746{
a8374e1e 747 return (http_send(http, HTTP_GET, uri));
3a193f5e 748}
749
750
50146867 751/*
752 * 'httpHead()' - Send a HEAD request to the server.
753 */
754
755int /* O - Status of call (0 = success) */
063e1ac7 756httpHead(http_t *http, /* I - HTTP data */
757 const char *uri) /* I - URI for head */
3a193f5e 758{
a8374e1e 759 return (http_send(http, HTTP_HEAD, uri));
3a193f5e 760}
761
762
50146867 763/*
764 * 'httpOptions()' - Send an OPTIONS request to the server.
765 */
766
767int /* O - Status of call (0 = success) */
063e1ac7 768httpOptions(http_t *http, /* I - HTTP data */
769 const char *uri) /* I - URI for options */
3a193f5e 770{
a8374e1e 771 return (http_send(http, HTTP_OPTIONS, uri));
3a193f5e 772}
773
774
50146867 775/*
776 * 'httpPost()' - Send a POST request to the server.
777 */
778
779int /* O - Status of call (0 = success) */
063e1ac7 780httpPost(http_t *http, /* I - HTTP data */
781 const char *uri) /* I - URI for post */
3a193f5e 782{
4a73831b 783 httpGetLength(http);
0542e38e 784
a8374e1e 785 return (http_send(http, HTTP_POST, uri));
3a193f5e 786}
787
788
789/*
50146867 790 * 'httpPut()' - Send a PUT request to the server.
3a193f5e 791 */
792
50146867 793int /* O - Status of call (0 = success) */
063e1ac7 794httpPut(http_t *http, /* I - HTTP data */
795 const char *uri) /* I - URI to put */
3a193f5e 796{
4a73831b 797 httpGetLength(http);
0542e38e 798
a8374e1e 799 return (http_send(http, HTTP_PUT, uri));
3840d6ba 800}
801
802
803/*
50146867 804 * 'httpTrace()' - Send an TRACE request to the server.
3840d6ba 805 */
806
50146867 807int /* O - Status of call (0 = success) */
063e1ac7 808httpTrace(http_t *http, /* I - HTTP data */
809 const char *uri) /* I - URI for trace */
3840d6ba 810{
a8374e1e 811 return (http_send(http, HTTP_TRACE, uri));
3840d6ba 812}
813
814
69ee1496 815/*
816 * 'httpFlush()' - Flush data from a HTTP connection.
817 */
818
819void
820httpFlush(http_t *http) /* I - HTTP data */
821{
822 char buffer[8192]; /* Junk buffer */
823
824
dd63ebe2 825 if (http->state != HTTP_WAITING)
826 {
827 while (httpRead(http, buffer, sizeof(buffer)) > 0);
828 }
69ee1496 829}
830
831
3840d6ba 832/*
50146867 833 * 'httpRead()' - Read data from a HTTP connection.
3840d6ba 834 */
835
50146867 836int /* O - Number of bytes read */
837httpRead(http_t *http, /* I - HTTP data */
838 char *buffer, /* I - Buffer for data */
839 int length) /* I - Maximum number of bytes */
3840d6ba 840{
2456b740 841 int bytes; /* Bytes read */
50146867 842 char len[32]; /* Length string */
3840d6ba 843
844
0f33610c 845 DEBUG_printf(("httpRead(%p, %p, %d)\n", http, buffer, length));
4a73831b 846
50146867 847 if (http == NULL || buffer == NULL)
848 return (-1);
3840d6ba 849
50146867 850 http->activity = time(NULL);
3840d6ba 851
50146867 852 if (length <= 0)
853 return (0);
fd8b1cf8 854
0542e38e 855 if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
5e879034 856 http->data_remaining <= 0)
50146867 857 {
5e879034 858 DEBUG_puts("httpRead: Getting chunk length...");
859
50146867 860 if (httpGets(len, sizeof(len), http) == NULL)
5e879034 861 {
862 DEBUG_puts("httpRead: Could not get length!");
50146867 863 return (0);
5e879034 864 }
3840d6ba 865
0542e38e 866 http->data_remaining = strtol(len, NULL, 16);
901b295d 867 if (http->data_remaining < 0)
868 {
869 DEBUG_puts("httpRead: Negative chunk length!");
870 return (0);
871 }
50146867 872 }
3840d6ba 873
4a73831b 874 DEBUG_printf(("httpRead: data_remaining = %d\n", http->data_remaining));
875
901b295d 876 if (http->data_remaining <= 0)
3840d6ba 877 {
50146867 878 /*
879 * A zero-length chunk ends a transfer; unless we are reading POST
880 * data, go idle...
881 */
f736c0e3 882
5e879034 883 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
4355fb2f 884 httpGets(len, sizeof(len), http);
885
50146867 886 if (http->state == HTTP_POST_RECV)
887 http->state ++;
888 else
889 http->state = HTTP_WAITING;
3840d6ba 890
50146867 891 return (0);
892 }
0542e38e 893 else if (length > http->data_remaining)
894 length = http->data_remaining;
50146867 895
753453e4 896 if (http->used == 0 && length <= 256)
897 {
898 /*
899 * Buffer small reads for better performance...
900 */
901
902 if (http->data_remaining > sizeof(http->buffer))
903 bytes = sizeof(http->buffer);
904 else
905 bytes = http->data_remaining;
906
92e48f04 907 if (!http->blocking && !httpWait(http, 1000))
908 return (0);
909
bcf61448 910#ifdef HAVE_SSL
753453e4 911 if (http->tls)
bcf61448 912 bytes = http_read_ssl(http, http->buffer, bytes);
753453e4 913 else
bcf61448 914#endif /* HAVE_SSL */
753453e4 915 {
916 DEBUG_printf(("httpRead: reading %d bytes from socket into buffer...\n",
917 bytes));
918
919 bytes = recv(http->fd, http->buffer, bytes, 0);
920
921 DEBUG_printf(("httpRead: read %d bytes from socket into buffer...\n",
922 bytes));
923 }
924
925 if (bytes > 0)
926 http->used = bytes;
927 else if (bytes < 0)
928 {
c3026ddc 929#ifdef WIN32
753453e4 930 http->error = WSAGetLastError();
bdbaa675 931 return (-1);
753453e4 932#else
bdbaa675 933 if (errno != EINTR)
934 {
935 http->error = errno;
936 return (-1);
937 }
c3026ddc 938#endif /* WIN32 */
753453e4 939 }
92e48f04 940 else if (bytes == 0)
941 {
942 http->error = EPIPE;
753453e4 943 return (0);
92e48f04 944 }
753453e4 945 }
946
0542e38e 947 if (http->used > 0)
50146867 948 {
0542e38e 949 if (length > http->used)
950 length = http->used;
3840d6ba 951
0542e38e 952 bytes = length;
953
4a73831b 954 DEBUG_printf(("httpRead: grabbing %d bytes from input buffer...\n", bytes));
955
0542e38e 956 memcpy(buffer, http->buffer, length);
957 http->used -= length;
958
959 if (http->used > 0)
dfac1292 960 memmove(http->buffer, http->buffer + length, http->used);
50146867 961 }
bcf61448 962#ifdef HAVE_SSL
a75c006a 963 else if (http->tls)
92e48f04 964 {
965 if (!http->blocking && !httpWait(http, 1000))
966 return (0);
bcf61448 967 bytes = http_read_ssl(http, buffer, length);
92e48f04 968 }
bcf61448 969#endif /* HAVE_SSL */
0542e38e 970 else
4a73831b 971 {
92e48f04 972 if (!http->blocking && !httpWait(http, 1000))
973 return (0);
4a73831b 974 DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length));
0542e38e 975 bytes = recv(http->fd, buffer, length, 0);
4a73831b 976 DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes));
977 }
3840d6ba 978
0542e38e 979 if (bytes > 0)
980 http->data_remaining -= bytes;
0bf5ae82 981 else if (bytes < 0)
bdbaa675 982 {
c3026ddc 983#ifdef WIN32
977acbd3 984 http->error = WSAGetLastError();
985#else
bdbaa675 986 if (errno == EINTR)
987 bytes = 0;
988 else
989 http->error = errno;
c3026ddc 990#endif /* WIN32 */
bdbaa675 991 }
92e48f04 992 else if (bytes == 0)
993 {
994 http->error = EPIPE;
995 return 0;
996 }
0542e38e 997
4355fb2f 998 if (http->data_remaining == 0)
4a73831b 999 {
5e879034 1000 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
4355fb2f 1001 httpGets(len, sizeof(len), http);
1002
1003 if (http->data_encoding != HTTP_ENCODE_CHUNKED)
1004 {
1005 if (http->state == HTTP_POST_RECV)
1006 http->state ++;
1007 else
1008 http->state = HTTP_WAITING;
1009 }
4a73831b 1010 }
1011
0f33610c 1012#ifdef DEBUG
1013 {
1014 int i, j, ch;
1015 printf("httpRead: Read %d bytes:\n", bytes);
1016 for (i = 0; i < bytes; i += 16)
1017 {
1018 printf(" ");
1019
1020 for (j = 0; j < 16 && (i + j) < bytes; j ++)
1021 printf(" %02X", buffer[i + j] & 255);
1022
1023 while (j < 16)
1024 {
1025 printf(" ");
1026 j ++;
1027 }
1028
1029 printf(" ");
1030 for (j = 0; j < 16 && (i + j) < bytes; j ++)
1031 {
1032 ch = buffer[i + j] & 255;
1033
1034 if (ch < ' ' || ch == 127)
1035 ch = '.';
1036
1037 putchar(ch);
1038 }
1039 putchar('\n');
1040 }
1041 }
1042#endif /* DEBUG */
1043
0542e38e 1044 return (bytes);
3840d6ba 1045}
1046
1047
d40085f1 1048/*
1049 * 'httpSetCookie()' - Set the cookie value(s)...
1050 */
1051
1052void
1053httpSetCookie(http_t *http, /* I - Connection */
1054 const char *cookie) /* I - Cookie string */
1055{
1056 if (!http)
1057 return;
1058
1059 if (http->cookie)
1060 free(http->cookie);
1061
1062 if (cookie)
1063 http->cookie = strdup(cookie);
1064 else
1065 http->cookie = NULL;
1066}
1067
1068
2e32fcdb 1069/*
1070 * 'httpWait()' - Wait for data available on a connection.
1071 */
1072
1073int /* O - 1 if data is available, 0 otherwise */
1074httpWait(http_t *http, /* I - HTTP data */
1075 int msec) /* I - Milliseconds to wait */
1076{
63d94476 1077#ifndef WIN32
2e32fcdb 1078 struct rlimit limit; /* Runtime limit */
63d94476 1079#endif /* !WIN32 */
2e32fcdb 1080 struct timeval timeout; /* Timeout */
63d94476 1081 int nfds; /* Result from select() */
2e32fcdb 1082
1083
1084 /*
1085 * First see if there is data in the buffer...
1086 */
1087
1088 if (http == NULL)
1089 return (0);
1090
1091 if (http->used)
1092 return (1);
1093
1094 /*
1095 * Then try doing a select() to poll the socket...
1096 */
1097
1098 if (!http->input_set)
1099 {
63d94476 1100#ifdef WIN32
1101 /*
1102 * Windows has a fixed-size select() structure, different (surprise,
1103 * surprise!) from all UNIX implementations. Just allocate this
1104 * fixed structure...
1105 */
1106
1107 http->input_set = calloc(1, sizeof(fd_set));
1108#else
2e32fcdb 1109 /*
1110 * Allocate the select() input set based upon the max number of file
1111 * descriptors available for this process...
1112 */
1113
1114 getrlimit(RLIMIT_NOFILE, &limit);
1115
1116 http->input_set = calloc(1, (limit.rlim_cur + 7) / 8);
63d94476 1117#endif /* WIN32 */
2e32fcdb 1118
1119 if (!http->input_set)
1120 return (0);
1121 }
1122
1123 FD_SET(http->fd, http->input_set);
1124
1125 if (msec >= 0)
1126 {
1127 timeout.tv_sec = msec / 1000;
1128 timeout.tv_usec = (msec % 1000) * 1000;
1129
63d94476 1130 nfds = select(http->fd + 1, http->input_set, NULL, NULL, &timeout);
2e32fcdb 1131 }
1132 else
63d94476 1133 nfds = select(http->fd + 1, http->input_set, NULL, NULL, NULL);
1134
1135 FD_CLR(http->fd, http->input_set);
1136
1137 return (nfds > 0);
2e32fcdb 1138}
1139
1140
3840d6ba 1141/*
50146867 1142 * 'httpWrite()' - Write data to a HTTP connection.
3840d6ba 1143 */
50146867 1144
1145int /* O - Number of bytes written */
063e1ac7 1146httpWrite(http_t *http, /* I - HTTP data */
1147 const char *buffer, /* I - Buffer for data */
1148 int length) /* I - Number of bytes to write */
3840d6ba 1149{
977acbd3 1150 int tbytes, /* Total bytes sent */
1151 bytes; /* Bytes sent */
3840d6ba 1152
1153
50146867 1154 if (http == NULL || buffer == NULL)
1155 return (-1);
3840d6ba 1156
50146867 1157 http->activity = time(NULL);
1158
5e879034 1159 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
8d5f8b3e 1160 {
4355fb2f 1161 if (httpPrintf(http, "%x\r\n", length) < 0)
50146867 1162 return (-1);
3840d6ba 1163
8d5f8b3e 1164 if (length == 0)
1165 {
1166 /*
1167 * A zero-length chunk ends a transfer; unless we are sending POST
1168 * data, go idle...
1169 */
1170
1171 DEBUG_puts("httpWrite: changing states...");
1172
1173 if (http->state == HTTP_POST_RECV)
1174 http->state ++;
753453e4 1175 else if (http->state == HTTP_PUT_RECV)
1176 http->state = HTTP_STATUS;
8d5f8b3e 1177 else
1178 http->state = HTTP_WAITING;
1179
1180 if (httpPrintf(http, "\r\n") < 0)
1181 return (-1);
1182
1183 return (0);
1184 }
1185 }
1186
50146867 1187 tbytes = 0;
4a73831b 1188
50146867 1189 while (length > 0)
1190 {
bcf61448 1191#ifdef HAVE_SSL
a75c006a 1192 if (http->tls)
bcf61448 1193 bytes = http_write_ssl(http, buffer, length);
a75c006a 1194 else
bcf61448 1195#endif /* HAVE_SSL */
50146867 1196 bytes = send(http->fd, buffer, length, 0);
a75c006a 1197
50146867 1198 if (bytes < 0)
4a73831b 1199 {
bdbaa675 1200#ifdef WIN32
1201 if (WSAGetLastError() != http->error)
1202 {
1203 http->error = WSAGetLastError();
1204 continue;
1205 }
1206#else
1207 if (errno == EINTR)
1208 continue;
1209 else if (errno != http->error)
1210 {
1211 http->error = errno;
1212 continue;
1213 }
1214#endif /* WIN32 */
1215
4a73831b 1216 DEBUG_puts("httpWrite: error writing data...\n");
c1918ec5 1217
50146867 1218 return (-1);
4a73831b 1219 }
3840d6ba 1220
50146867 1221 buffer += bytes;
1222 tbytes += bytes;
1223 length -= bytes;
69ee1496 1224 if (http->data_encoding == HTTP_ENCODE_LENGTH)
1225 http->data_remaining -= bytes;
1226 }
1227
5e879034 1228 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
4355fb2f 1229 if (httpPrintf(http, "\r\n") < 0)
1230 return (-1);
1231
8d5f8b3e 1232 if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
69ee1496 1233 {
1234 /*
1235 * Finished with the transfer; unless we are sending POST data, go idle...
1236 */
1237
8d5f8b3e 1238 DEBUG_puts("httpWrite: changing states...");
1239
69ee1496 1240 if (http->state == HTTP_POST_RECV)
1241 http->state ++;
1242 else
1243 http->state = HTTP_WAITING;
50146867 1244 }
1245
0f33610c 1246#ifdef DEBUG
1247 {
1248 int i, j, ch;
1249 printf("httpWrite: wrote %d bytes: \n", tbytes);
1250 for (i = 0, buffer -= tbytes; i < tbytes; i += 16)
1251 {
1252 printf(" ");
1253
1254 for (j = 0; j < 16 && (i + j) < tbytes; j ++)
1255 printf(" %02X", buffer[i + j] & 255);
1256
1257 while (j < 16)
1258 {
1259 printf(" ");
1260 j ++;
1261 }
4a73831b 1262
0f33610c 1263 printf(" ");
1264 for (j = 0; j < 16 && (i + j) < tbytes; j ++)
1265 {
1266 ch = buffer[i + j] & 255;
1267
1268 if (ch < ' ' || ch == 127)
1269 ch = '.';
1270
1271 putchar(ch);
1272 }
1273 putchar('\n');
1274 }
1275 }
1276#endif /* DEBUG */
50146867 1277 return (tbytes);
1278}
1279
1280
1281/*
1282 * 'httpGets()' - Get a line of text from a HTTP connection.
1283 */
1284
1285char * /* O - Line or NULL */
1286httpGets(char *line, /* I - Line to read into */
1287 int length, /* I - Max length of buffer */
1288 http_t *http) /* I - HTTP data */
1289{
1290 char *lineptr, /* Pointer into line */
1291 *bufptr, /* Pointer into input buffer */
1292 *bufend; /* Pointer to end of buffer */
1293 int bytes; /* Number of bytes read */
1294
1295
0f33610c 1296 DEBUG_printf(("httpGets(%p, %d, %p)\n", line, length, http));
4a73831b 1297
50146867 1298 if (http == NULL || line == NULL)
1299 return (NULL);
1300
1301 /*
1302 * Pre-scan the buffer and see if there is a newline in there...
1303 */
1304
c3026ddc 1305#ifdef WIN32
977acbd3 1306 WSASetLastError(0);
1307#else
0bf5ae82 1308 errno = 0;
c3026ddc 1309#endif /* WIN32 */
f5174332 1310
0542e38e 1311 do
50146867 1312 {
0542e38e 1313 bufptr = http->buffer;
1314 bufend = http->buffer + http->used;
50146867 1315
0542e38e 1316 while (bufptr < bufend)
1317 if (*bufptr == 0x0a)
1318 break;
1319 else
1320 bufptr ++;
50146867 1321
27d555e8 1322 if (bufptr >= bufend && http->used < HTTP_MAX_BUFFER)
50146867 1323 {
1324 /*
0542e38e 1325 * No newline; see if there is more data to be read...
50146867 1326 */
1327
2e32fcdb 1328 if (!http->blocking && !httpWait(http, 1000))
1329 return (NULL);
1330
bcf61448 1331#ifdef HAVE_SSL
a75c006a 1332 if (http->tls)
bcf61448 1333 bytes = http_read_ssl(http, bufend, HTTP_MAX_BUFFER - http->used);
a75c006a 1334 else
bcf61448 1335#endif /* HAVE_SSL */
a75c006a 1336 bytes = recv(http->fd, bufend, HTTP_MAX_BUFFER - http->used, 0);
1337
1338 if (bytes < 0)
0542e38e 1339 {
1340 /*
1341 * Nope, can't get a line this time...
1342 */
1343
c3026ddc 1344#ifdef WIN32
977acbd3 1345 if (WSAGetLastError() != http->error)
1346 {
1347 http->error = WSAGetLastError();
1348 continue;
1349 }
1350
1351 DEBUG_printf(("httpGets(): recv() error %d!\n", WSAGetLastError()));
1352#else
bdbaa675 1353 if (errno == EINTR)
1354 continue;
1355 else if (errno != http->error)
f5174332 1356 {
0bf5ae82 1357 http->error = errno;
c1918ec5 1358 continue;
f5174332 1359 }
c1918ec5 1360
1361 DEBUG_printf(("httpGets(): recv() error %d!\n", errno));
c3026ddc 1362#endif /* WIN32 */
c1918ec5 1363
0542e38e 1364 return (NULL);
1365 }
f5174332 1366 else if (bytes == 0)
0bf5ae82 1367 {
0bf5ae82 1368 http->error = EPIPE;
1369
f5174332 1370 return (NULL);
0bf5ae82 1371 }
0542e38e 1372
f5174332 1373 /*
1374 * Yup, update the amount used and the end pointer...
1375 */
1376
1377 http->used += bytes;
1378 bufend += bytes;
dfac1292 1379 bufptr = bufend;
50146867 1380 }
1381 }
27d555e8 1382 while (bufptr >= bufend && http->used < HTTP_MAX_BUFFER);
50146867 1383
1384 http->activity = time(NULL);
1385
1386 /*
1387 * Read a line from the buffer...
1388 */
1389
1390 lineptr = line;
1391 bufptr = http->buffer;
1392 bytes = 0;
584886cb 1393 length --;
50146867 1394
1395 while (bufptr < bufend && bytes < length)
1396 {
1397 bytes ++;
1398
1399 if (*bufptr == 0x0a)
1400 {
1401 bufptr ++;
584886cb 1402 break;
50146867 1403 }
1404 else if (*bufptr == 0x0d)
1405 bufptr ++;
1406 else
1407 *lineptr++ = *bufptr++;
1408 }
1409
584886cb 1410 if (bytes > 0)
1411 {
1412 *lineptr = '\0';
1413
1414 http->used -= bytes;
1415 if (http->used > 0)
dfac1292 1416 memmove(http->buffer, bufptr, http->used);
584886cb 1417
1418 DEBUG_printf(("httpGets(): Returning \"%s\"\n", line));
1419 return (line);
1420 }
1421
c1918ec5 1422 DEBUG_puts("httpGets(): No new line available!");
1423
50146867 1424 return (NULL);
1425}
1426
1427
1428/*
1429 * 'httpPrintf()' - Print a formatted string to a HTTP connection.
1430 */
1431
1432int /* O - Number of bytes written */
1433httpPrintf(http_t *http, /* I - HTTP data */
1434 const char *format, /* I - printf-style format string */
1435 ...) /* I - Additional args as needed */
1436{
1118e338 1437 int bytes, /* Number of bytes to write */
1438 nbytes, /* Number of bytes written */
1439 tbytes; /* Number of bytes all together */
1440 char buf[HTTP_MAX_BUFFER], /* Buffer for formatted string */
1441 *bufptr; /* Pointer into buffer */
50146867 1442 va_list ap; /* Variable argument pointer */
1443
1444
1445 va_start(ap, format);
04de52f8 1446 bytes = vsnprintf(buf, sizeof(buf), format, ap);
50146867 1447 va_end(ap);
1448
5356dc5a 1449 DEBUG_printf(("httpPrintf: %s", buf));
1450
1118e338 1451 for (tbytes = 0, bufptr = buf; tbytes < bytes; tbytes += nbytes, bufptr += nbytes)
a75c006a 1452 {
bcf61448 1453#ifdef HAVE_SSL
a75c006a 1454 if (http->tls)
bcf61448 1455 nbytes = http_write_ssl(http, bufptr, bytes - tbytes);
a75c006a 1456 else
bcf61448 1457#endif /* HAVE_SSL */
a75c006a 1458 nbytes = send(http->fd, bufptr, bytes - tbytes, 0);
1459
1460 if (nbytes < 0)
bdbaa675 1461 {
1462 nbytes = 0;
1463
1464#ifdef WIN32
1465 if (WSAGetLastError() != http->error)
1466 {
1467 http->error = WSAGetLastError();
1468 continue;
1469 }
1470#else
1471 if (errno == EINTR)
1472 continue;
1473 else if (errno != http->error)
1474 {
1475 http->error = errno;
1476 continue;
1477 }
1478#endif /* WIN32 */
1479
1118e338 1480 return (-1);
bdbaa675 1481 }
a75c006a 1482 }
1118e338 1483
1484 return (bytes);
50146867 1485}
1486
1487
1488/*
1489 * 'httpStatus()' - Return a short string describing a HTTP status code.
1490 */
1491
063e1ac7 1492const char * /* O - String or NULL */
50146867 1493httpStatus(http_status_t status) /* I - HTTP status code */
1494{
1495 switch (status)
1496 {
b38fb7fc 1497 case HTTP_CONTINUE :
1498 return ("Continue");
1499 case HTTP_SWITCHING_PROTOCOLS :
1500 return ("Switching Protocols");
50146867 1501 case HTTP_OK :
1502 return ("OK");
1503 case HTTP_CREATED :
1504 return ("Created");
1505 case HTTP_ACCEPTED :
1506 return ("Accepted");
1507 case HTTP_NO_CONTENT :
1508 return ("No Content");
1509 case HTTP_NOT_MODIFIED :
1510 return ("Not Modified");
1511 case HTTP_BAD_REQUEST :
1512 return ("Bad Request");
1513 case HTTP_UNAUTHORIZED :
1514 return ("Unauthorized");
1515 case HTTP_FORBIDDEN :
1516 return ("Forbidden");
1517 case HTTP_NOT_FOUND :
1518 return ("Not Found");
1519 case HTTP_REQUEST_TOO_LARGE :
1520 return ("Request Entity Too Large");
1521 case HTTP_URI_TOO_LONG :
1522 return ("URI Too Long");
b38fb7fc 1523 case HTTP_UPGRADE_REQUIRED :
1524 return ("Upgrade Required");
50146867 1525 case HTTP_NOT_IMPLEMENTED :
1526 return ("Not Implemented");
1527 case HTTP_NOT_SUPPORTED :
1528 return ("Not Supported");
1529 default :
1530 return ("Unknown");
1531 }
1532}
1533
1534
50146867 1535/*
1536 * 'httpGetDateString()' - Get a formatted date/time string from a time value.
1537 */
1538
063e1ac7 1539const char * /* O - Date/time string */
50146867 1540httpGetDateString(time_t t) /* I - UNIX time */
1541{
1542 struct tm *tdate;
1543 static char datetime[256];
1544
1545
1546 tdate = gmtime(&t);
a6988fb1 1547 snprintf(datetime, sizeof(datetime), "%s, %02d %s %d %02d:%02d:%02d GMT",
1548 days[tdate->tm_wday], tdate->tm_mday, months[tdate->tm_mon],
1549 tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec);
50146867 1550
1551 return (datetime);
1552}
1553
1554
1555/*
1556 * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
1557 */
1558
1559time_t /* O - UNIX time */
063e1ac7 1560httpGetDateTime(const char *s) /* I - Date/time string */
50146867 1561{
a8374e1e 1562 int i; /* Looping var */
1563 struct tm tdate; /* Time/date structure */
1564 char mon[16]; /* Abbreviated month name */
1565 int day, year; /* Day of month and year */
1566 int hour, min, sec; /* Time */
1567
1568
04d61d56 1569 if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6)
a8374e1e 1570 return (0);
1571
1572 for (i = 0; i < 12; i ++)
1573 if (strcasecmp(mon, months[i]) == 0)
1574 break;
1575
1576 if (i >= 12)
1577 return (0);
1578
1579 tdate.tm_mon = i;
1580 tdate.tm_mday = day;
1581 tdate.tm_year = year - 1900;
1582 tdate.tm_hour = hour;
1583 tdate.tm_min = min;
1584 tdate.tm_sec = sec;
1585 tdate.tm_isdst = 0;
1586
1587 return (mktime(&tdate));
50146867 1588}
1589
1590
1591/*
1592 * 'httpUpdate()' - Update the current HTTP state for incoming data.
1593 */
1594
a8374e1e 1595http_status_t /* O - HTTP status */
50146867 1596httpUpdate(http_t *http) /* I - HTTP data */
1597{
a8374e1e 1598 char line[1024], /* Line from connection... */
1599 *value; /* Pointer to value on line */
1600 http_field_t field; /* Field index */
50146867 1601 int major, minor; /* HTTP version numbers */
50146867 1602 http_status_t status; /* Authorization status */
50146867 1603
50146867 1604
0f33610c 1605 DEBUG_printf(("httpUpdate(%p)\n", http));
4a73831b 1606
a8374e1e 1607 /*
1608 * If we haven't issued any commands, then there is nothing to "update"...
1609 */
3840d6ba 1610
a8374e1e 1611 if (http->state == HTTP_WAITING)
1612 return (HTTP_CONTINUE);
3840d6ba 1613
1614 /*
a8374e1e 1615 * Grab all of the lines we can from the connection...
3840d6ba 1616 */
1617
a8374e1e 1618 while (httpGets(line, sizeof(line), http) != NULL)
fd8b1cf8 1619 {
f4cafe91 1620 DEBUG_puts(line);
9ae9d67c 1621
a8374e1e 1622 if (line[0] == '\0')
fd8b1cf8 1623 {
a8374e1e 1624 /*
1625 * Blank line means the start of the data section (if any). Return
1626 * the result code, too...
11b9b0d7 1627 *
1628 * If we get status 100 (HTTP_CONTINUE), then we *don't* change states.
1629 * Instead, we just return HTTP_CONTINUE to the caller and keep on
1630 * tryin'...
a8374e1e 1631 */
1632
11b9b0d7 1633 if (http->status == HTTP_CONTINUE)
1634 return (http->status);
1635
bcf61448 1636#ifdef HAVE_SSL
b38fb7fc 1637 if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls)
a75c006a 1638 {
bcf61448 1639 if (http_setup_ssl(http) != 0)
a75c006a 1640 {
bcf61448 1641# ifdef WIN32
a75c006a 1642 closesocket(http->fd);
bcf61448 1643# else
a75c006a 1644 close(http->fd);
bcf61448 1645# endif /* WIN32 */
a75c006a 1646
1647 return (HTTP_ERROR);
1648 }
1649
a75c006a 1650 return (HTTP_CONTINUE);
1651 }
1652 else if (http->status == HTTP_UPGRADE_REQUIRED &&
1653 http->encryption != HTTP_ENCRYPT_NEVER)
2a0ef17a 1654 http->encryption = HTTP_ENCRYPT_REQUIRED;
bcf61448 1655#endif /* HAVE_SSL */
a75c006a 1656
5356dc5a 1657 httpGetLength(http);
0542e38e 1658
1659 switch (http->state)
1660 {
1661 case HTTP_GET :
1662 case HTTP_POST :
1663 case HTTP_POST_RECV :
1664 case HTTP_PUT :
1665 http->state ++;
dd63ebe2 1666 case HTTP_POST_SEND :
0542e38e 1667 break;
1668
1669 default :
1670 http->state = HTTP_WAITING;
1671 break;
1672 }
a8374e1e 1673
1674 return (http->status);
fd8b1cf8 1675 }
a8374e1e 1676 else if (strncmp(line, "HTTP/", 5) == 0)
fd8b1cf8 1677 {
1678 /*
a8374e1e 1679 * Got the beginning of a response...
fd8b1cf8 1680 */
1681
d21a7597 1682 if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, (int *)&status) != 3)
a8374e1e 1683 return (HTTP_ERROR);
1684
1685 http->version = (http_version_t)(major * 100 + minor);
1686 http->status = status;
fd8b1cf8 1687 }
a8374e1e 1688 else if ((value = strchr(line, ':')) != NULL)
3840d6ba 1689 {
a8374e1e 1690 /*
1691 * Got a value...
1692 */
3a193f5e 1693
a8374e1e 1694 *value++ = '\0';
1695 while (isspace(*value))
1696 value ++;
1697
0d1f75a3 1698 /*
1699 * Be tolerants of servers that send unknown attribute fields...
1700 */
1701
d40085f1 1702 if (!strcasecmp(line, "expect"))
1703 {
1704 /*
1705 * "Expect: 100-continue" or similar...
1706 */
1707
1708 http->expect = (http_status_t)atoi(value);
1709 }
1710 else if (!strcasecmp(line, "cookie"))
1711 {
1712 /*
1713 * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
1714 */
1715
1716 httpSetCookie(http, value);
1717 }
1718 else if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN)
f4cafe91 1719 {
4a73831b 1720 DEBUG_printf(("httpUpdate: unknown field %s seen!\n", line));
0d1f75a3 1721 continue;
f4cafe91 1722 }
d40085f1 1723 else
1724 httpSetField(http, field, value);
3840d6ba 1725 }
a8374e1e 1726 else
f44afac9 1727 {
1728 http->status = HTTP_ERROR;
a8374e1e 1729 return (HTTP_ERROR);
f44afac9 1730 }
fd8b1cf8 1731 }
3840d6ba 1732
4e8f6c6a 1733 /*
1734 * See if there was an error...
1735 */
1736
0bf5ae82 1737 if (http->error)
f44afac9 1738 {
1739 http->status = HTTP_ERROR;
4e8f6c6a 1740 return (HTTP_ERROR);
f44afac9 1741 }
4e8f6c6a 1742
3840d6ba 1743 /*
a8374e1e 1744 * If we haven't already returned, then there is nothing new...
3840d6ba 1745 */
1746
a8374e1e 1747 return (HTTP_CONTINUE);
3840d6ba 1748}
1749
1750
3a193f5e 1751/*
50146867 1752 * 'httpDecode64()' - Base64-decode a string.
3840d6ba 1753 */
1754
50146867 1755char * /* O - Decoded string */
063e1ac7 1756httpDecode64(char *out, /* I - String to write to */
1757 const char *in) /* I - String to read from */
3840d6ba 1758{
50146867 1759 int pos, /* Bit position */
1760 base64; /* Value of this character */
1761 char *outptr; /* Output pointer */
3840d6ba 1762
3840d6ba 1763
50146867 1764 for (outptr = out, pos = 0; *in != '\0'; in ++)
fd8b1cf8 1765 {
50146867 1766 /*
1767 * Decode this character into a number from 0 to 63...
1768 */
f736c0e3 1769
50146867 1770 if (*in >= 'A' && *in <= 'Z')
1771 base64 = *in - 'A';
1772 else if (*in >= 'a' && *in <= 'z')
1773 base64 = *in - 'a' + 26;
1774 else if (*in >= '0' && *in <= '9')
1775 base64 = *in - '0' + 52;
1776 else if (*in == '+')
1777 base64 = 62;
1778 else if (*in == '/')
1779 base64 = 63;
1780 else if (*in == '=')
1781 break;
1782 else
1783 continue;
3840d6ba 1784
50146867 1785 /*
1786 * Store the result in the appropriate chars...
1787 */
992cf15a 1788
1789 switch (pos)
1790 {
1791 case 0 :
50146867 1792 *outptr = base64 << 2;
1793 pos ++;
992cf15a 1794 break;
50146867 1795 case 1 :
1796 *outptr++ |= (base64 >> 4) & 3;
1797 *outptr = (base64 << 4) & 255;
1798 pos ++;
1799 break;
1800 case 2 :
1801 *outptr++ |= (base64 >> 2) & 15;
1802 *outptr = (base64 << 6) & 255;
1803 pos ++;
1804 break;
1805 case 3 :
1806 *outptr++ |= base64;
1807 pos = 0;
992cf15a 1808 break;
992cf15a 1809 }
1810 }
1811
50146867 1812 *outptr = '\0';
3840d6ba 1813
1814 /*
50146867 1815 * Return the decoded string...
3840d6ba 1816 */
1817
50146867 1818 return (out);
3840d6ba 1819}
1820
1821
f736c0e3 1822/*
50146867 1823 * 'httpEncode64()' - Base64-encode a string.
f736c0e3 1824 */
1825
50146867 1826char * /* O - Encoded string */
063e1ac7 1827httpEncode64(char *out, /* I - String to write to */
1828 const char *in) /* I - String to read from */
f736c0e3 1829{
50146867 1830 char *outptr; /* Output pointer */
6db7190f 1831 static const char base64[] = /* Base64 characters... */
50146867 1832 {
1833 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1834 "abcdefghijklmnopqrstuvwxyz"
1835 "0123456789"
1836 "+/"
1837 };
f736c0e3 1838
f736c0e3 1839
50146867 1840 for (outptr = out; *in != '\0'; in ++)
f736c0e3 1841 {
1842 /*
50146867 1843 * Encode the up to 3 characters as 4 Base64 numbers...
f736c0e3 1844 */
1845
50146867 1846 *outptr ++ = base64[in[0] >> 2];
1847 *outptr ++ = base64[((in[0] << 4) | (in[1] >> 4)) & 63];
f736c0e3 1848
50146867 1849 in ++;
1850 if (*in == '\0')
f0af4f8f 1851 {
1852 *outptr ++ = '=';
50146867 1853 break;
f0af4f8f 1854 }
f736c0e3 1855
50146867 1856 *outptr ++ = base64[((in[0] << 2) | (in[1] >> 6)) & 63];
f736c0e3 1857
50146867 1858 in ++;
1859 if (*in == '\0')
1860 break;
f736c0e3 1861
50146867 1862 *outptr ++ = base64[in[0] & 63];
f736c0e3 1863 }
f736c0e3 1864
50146867 1865 *outptr ++ = '=';
1866 *outptr = '\0';
f736c0e3 1867
50146867 1868 /*
1869 * Return the encoded string...
1870 */
f736c0e3 1871
50146867 1872 return (out);
f736c0e3 1873}
1874
1875
3a193f5e 1876/*
4a73831b 1877 * 'httpGetLength()' - Get the amount of data remaining from the
1878 * content-length or transfer-encoding fields.
0542e38e 1879 */
1880
063e1ac7 1881int /* O - Content length */
4a73831b 1882httpGetLength(http_t *http) /* I - HTTP data */
0542e38e 1883{
dd63ebe2 1884 DEBUG_printf(("httpGetLength(%p), state = %d\n", http, http->state));
5e879034 1885
0542e38e 1886 if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0)
1887 {
5e879034 1888 DEBUG_puts("httpGetLength: chunked request!");
1889
0542e38e 1890 http->data_encoding = HTTP_ENCODE_CHUNKED;
1891 http->data_remaining = 0;
1892 }
1893 else
1894 {
5e879034 1895 http->data_encoding = HTTP_ENCODE_LENGTH;
0542e38e 1896
1897 /*
1898 * The following is a hack for HTTP servers that don't send a
1899 * content-length or transfer-encoding field...
1900 *
1901 * If there is no content-length then the connection must close
1902 * after the transfer is complete...
1903 */
1904
1905 if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0')
1906 http->data_remaining = 2147483647;
1907 else
1908 http->data_remaining = atoi(http->fields[HTTP_FIELD_CONTENT_LENGTH]);
5e879034 1909
1910 DEBUG_printf(("httpGetLength: content_length = %d\n", http->data_remaining));
0542e38e 1911 }
4a73831b 1912
1913 return (http->data_remaining);
1914}
1915
1916
1917/*
1918 * 'http_field()' - Return the field index for a field name.
1919 */
1920
1921static http_field_t /* O - Field index */
063e1ac7 1922http_field(const char *name) /* I - String name */
4a73831b 1923{
1924 int i; /* Looping var */
1925
1926
1927 for (i = 0; i < HTTP_FIELD_MAX; i ++)
1928 if (strcasecmp(name, http_fields[i]) == 0)
1929 return ((http_field_t)i);
1930
1931 return (HTTP_FIELD_UNKNOWN);
0542e38e 1932}
1933
1934
a8374e1e 1935/*
1936 * 'http_send()' - Send a request with all fields and the trailing blank line.
1937 */
1938
1939static int /* O - 0 on success, non-zero on error */
1940http_send(http_t *http, /* I - HTTP data */
1941 http_state_t request, /* I - Request code */
063e1ac7 1942 const char *uri) /* I - URI */
a8374e1e 1943{
1944 int i; /* Looping var */
1945 char *ptr, /* Pointer in buffer */
1946 buf[1024]; /* Encoded URI buffer */
6db7190f 1947 static const char * const codes[] =
1948 { /* Request code strings */
a8374e1e 1949 NULL,
1950 "OPTIONS",
1951 "GET",
1952 NULL,
1953 "HEAD",
1954 "POST",
1955 NULL,
1956 NULL,
1957 "PUT",
1958 NULL,
1959 "DELETE",
1960 "TRACE",
1961 "CLOSE"
1962 };
6db7190f 1963 static const char hex[] = "0123456789ABCDEF";
a8374e1e 1964 /* Hex digits */
1965
1966
1967 if (http == NULL || uri == NULL)
1968 return (-1);
1969
1970 /*
1971 * Encode the URI as needed...
1972 */
1973
d2e58bfa 1974 for (ptr = buf; *uri != '\0' && ptr < (buf + sizeof(buf) - 1); uri ++)
a8374e1e 1975 if (*uri <= ' ' || *uri >= 127)
1976 {
d2e58bfa 1977 if (ptr < (buf + sizeof(buf) - 1))
1978 *ptr ++ = '%';
1979 if (ptr < (buf + sizeof(buf) - 1))
1980 *ptr ++ = hex[(*uri >> 4) & 15];
1981 if (ptr < (buf + sizeof(buf) - 1))
1982 *ptr ++ = hex[*uri & 15];
a8374e1e 1983 }
1984 else
1985 *ptr ++ = *uri;
1986
1987 *ptr = '\0';
1988
f44afac9 1989 /*
1990 * See if we had an error the last time around; if so, reconnect...
1991 */
1992
1993 if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST)
1994 httpReconnect(http);
1995
a8374e1e 1996 /*
1997 * Send the request header...
1998 */
1999
2000 http->state = request;
5356dc5a 2001 if (request == HTTP_POST || request == HTTP_PUT)
2002 http->state ++;
2003
c1918ec5 2004 http->status = HTTP_CONTINUE;
2005
bcf61448 2006#ifdef HAVE_SSL
2a0ef17a 2007 if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
a75c006a 2008 {
2009 httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
2010 httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0,SSL/2.0,SSL/3.0");
2011 }
bcf61448 2012#endif /* HAVE_SSL */
a75c006a 2013
406971d9 2014 if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
a8374e1e 2015 {
f44afac9 2016 http->status = HTTP_ERROR;
2017 return (-1);
a8374e1e 2018 }
2019
2020 for (i = 0; i < HTTP_FIELD_MAX; i ++)
2021 if (http->fields[i][0] != '\0')
4a73831b 2022 {
2023 DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i]));
2024
406971d9 2025 if (httpPrintf(http, "%s: %s\r\n", http_fields[i], http->fields[i]) < 1)
f44afac9 2026 {
2027 http->status = HTTP_ERROR;
2028 return (-1);
2029 }
4a73831b 2030 }
a8374e1e 2031
406971d9 2032 if (httpPrintf(http, "\r\n") < 1)
f44afac9 2033 {
2034 http->status = HTTP_ERROR;
a8374e1e 2035 return (-1);
f44afac9 2036 }
a8374e1e 2037
2038 httpClearFields(http);
2039
a8374e1e 2040 return (0);
2041}
2042
2043
bcf61448 2044#ifdef HAVE_SSL
2a0ef17a 2045/*
2046 * 'http_upgrade()' - Force upgrade to TLS encryption.
2047 */
2048
2049static int /* O - Status of connection */
2050http_upgrade(http_t *http) /* I - HTTP data */
2051{
1c6682dd 2052 int ret; /* Return value */
2053 http_t myhttp; /* Local copy of HTTP data */
2054
2a0ef17a 2055
1c6682dd 2056 DEBUG_printf(("http_upgrade(%p)\n", http));
2057
2058 /*
2059 * Copy the HTTP data to a local variable so we can do the OPTIONS
2060 * request without interfering with the existing request data...
2061 */
2062
2063 memcpy(&myhttp, http, sizeof(myhttp));
2a0ef17a 2064
2065 /*
2066 * Send an OPTIONS request to the server, requiring SSL or TLS
2067 * encryption on the link...
2068 */
2069
1c6682dd 2070 httpClearFields(&myhttp);
2071 httpSetField(&myhttp, HTTP_FIELD_CONNECTION, "upgrade");
2072 httpSetField(&myhttp, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0");
2073
2074 if ((ret = httpOptions(&myhttp, "*")) == 0)
2075 {
2076 /*
2077 * Wait for the secure connection...
2078 */
2079
2080 while (httpUpdate(&myhttp) == HTTP_CONTINUE);
2081 }
2082
2083 httpFlush(&myhttp);
2a0ef17a 2084
2085 /*
1c6682dd 2086 * Copy the HTTP data back over, if any...
2a0ef17a 2087 */
2088
1c6682dd 2089 http->fd = myhttp.fd;
2090 http->error = myhttp.error;
2091 http->activity = myhttp.activity;
2092 http->status = myhttp.status;
2093 http->version = myhttp.version;
2094 http->keep_alive = myhttp.keep_alive;
2095 http->used = myhttp.used;
2a0ef17a 2096
1c6682dd 2097 if (http->used)
2098 memcpy(http->buffer, myhttp.buffer, http->used);
2099
2100 http->auth_type = myhttp.auth_type;
2101 http->nonce_count = myhttp.nonce_count;
2102
2103 memcpy(http->nonce, myhttp.nonce, sizeof(http->nonce));
2a0ef17a 2104
1c6682dd 2105 http->tls = myhttp.tls;
2106 http->encryption = myhttp.encryption;
2107
2108 /*
2109 * See if we actually went secure...
2110 */
2111
2112 if (!http->tls)
2a0ef17a 2113 {
1c6682dd 2114 /*
2115 * Server does not support HTTP upgrade...
2116 */
2a0ef17a 2117
1c6682dd 2118 DEBUG_puts("Server does not support HTTP upgrade!");
2a0ef17a 2119
dcfcaeac 2120# ifdef WIN32
2a0ef17a 2121 closesocket(http->fd);
dcfcaeac 2122# else
2a0ef17a 2123 close(http->fd);
dcfcaeac 2124# endif
2a0ef17a 2125
1c6682dd 2126 http->fd = -1;
2127
2a0ef17a 2128 return (-1);
2129 }
1c6682dd 2130 else
2131 return (ret);
2a0ef17a 2132}
2a0ef17a 2133
2134
3840d6ba 2135/*
bcf61448 2136 * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
2137 */
2138
2139static int /* O - Status of connection */
2140http_setup_ssl(http_t *http) /* I - HTTP data */
2141{
dcfcaeac 2142# ifdef HAVE_LIBSSL
bcf61448 2143 SSL_CTX *context; /* Context for encryption */
2144 SSL *conn; /* Connection for encryption */
dcfcaeac 2145# elif defined(HAVE_GNUTLS)
bcf61448 2146 http_tls_t *conn; /* TLS session object */
dcfcaeac 2147 gnutls_certificate_client_credentials *credentials;
2148 /* TLS credentials */
2149# elif defined(HAVE_CDSASSL)
2150 SSLContextRef conn; /* Context for encryption */
2151 OSStatus error; /* Error info */
2152# endif /* HAVE_LIBSSL */
bcf61448 2153
bcf61448 2154
dcfcaeac 2155# ifdef HAVE_LIBSSL
bcf61448 2156 context = SSL_CTX_new(SSLv23_client_method());
2157 conn = SSL_new(context);
2158
2159 SSL_set_fd(conn, http->fd);
2160 if (SSL_connect(conn) != 1)
2161 {
2162 SSL_CTX_free(context);
2163 SSL_free(conn);
2164
dcfcaeac 2165# ifdef WIN32
bcf61448 2166 http->error = WSAGetLastError();
dcfcaeac 2167# else
bcf61448 2168 http->error = errno;
dcfcaeac 2169# endif /* WIN32 */
bcf61448 2170 http->status = HTTP_ERROR;
2171
2172 return (HTTP_ERROR);
2173 }
2174
dcfcaeac 2175# elif defined(HAVE_GNUTLS)
bcf61448 2176 conn = (http_tls_t *)malloc(sizeof(http_tls_t));
dcfcaeac 2177
bcf61448 2178 if (conn == NULL)
2179 {
2180 http->error = errno;
2181 http->status = HTTP_ERROR;
2182
2183 return (-1);
2184 }
dcfcaeac 2185
bcf61448 2186 credentials = (gnutls_certificate_client_credentials *)
dcfcaeac 2187 malloc(sizeof(gnutls_certificate_client_credentials));
bcf61448 2188 if (credentials == NULL)
2189 {
2190 free(conn);
2191
2192 http->error = errno;
2193 http->status = HTTP_ERROR;
2194
2195 return (-1);
2196 }
2197
2198 gnutls_certificate_allocate_credentials(credentials);
2199
2200 gnutls_init(&(conn->session), GNUTLS_CLIENT);
2201 gnutls_set_default_priority(conn->session);
2202 gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials);
2203 gnutls_transport_set_ptr(conn->session, http->fd);
2204
2205 if ((gnutls_handshake(conn->session)) != GNUTLS_E_SUCCESS)
2206 {
2207 http->error = errno;
2208 http->status = HTTP_ERROR;
2209
2210 return (-1);
2211 }
2212
2213 conn->credentials = credentials;
2214
dcfcaeac 2215# elif defined(HAVE_CDSASSL)
2216 error = SSLNewContext(false, &conn);
2217
2218 if (!error)
2219 error = SSLSetIOFuncs(conn, CDSAReadFunc, CDSAWriteFunc);
2220
2221 if (!error)
2222 error = SSLSetConnection(conn, (SSLConnectionRef)http->fd);
2223
2224 if (!error)
2225 error = SSLSetAllowsExpiredCerts(conn, true);
2226
2227 if (!error)
2228 error = SSLSetAllowsAnyRoot(conn, true);
2229
2230 if (!error)
2231 error = SSLHandshake(conn);
2232
2233 if (error != 0)
2234 {
2235 http->error = error;
2236 http->status = HTTP_ERROR;
2237
2238 SSLDisposeContext(conn);
2239
2240 close(http->fd);
2241
2242 return (-1);
2243 }
2244# endif /* HAVE_CDSASSL */
bcf61448 2245
2246 http->tls = conn;
2247 return (0);
2248}
2249
2250
2251/*
2252 * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection.
2253 */
2254
2255static void
2256http_shutdown_ssl(http_t *http) /* I - HTTP data */
2257{
dcfcaeac 2258# ifdef HAVE_LIBSSL
bcf61448 2259 SSL_CTX *context; /* Context for encryption */
2260 SSL *conn; /* Connection for encryption */
2261
dcfcaeac 2262
bcf61448 2263 conn = (SSL *)(http->tls);
2264 context = SSL_get_SSL_CTX(conn);
2265
2266 SSL_shutdown(conn);
2267 SSL_CTX_free(context);
2268 SSL_free(conn);
dcfcaeac 2269
2270# elif defined(HAVE_GNUTLS)
2271 http_tls_t *conn; /* Encryption session */
2272 gnutls_certificate_client_credentials *credentials;
2273 /* TLS credentials */
2274
bcf61448 2275
2276 conn = (http_tls_t *)(http->tls);
2277 credentials = (gnutls_certificate_client_credentials *)(conn->credentials);
2278
2279 gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
2280 gnutls_deinit(conn->session);
2281 gnutls_certificate_free_credentials(*credentials);
2282 free(credentials);
2283 free(conn);
dcfcaeac 2284
2285# elif defined(HAVE_CDSASSL)
2286 SSLClose((SSLContextRef)http->tls);
2287 SSLDisposeContext((SSLContextRef)http->tls);
2288# endif /* HAVE_LIBSSL */
bcf61448 2289
2290 http->tls = NULL;
2291}
2292
2293
2294/*
2295 * 'http_read_ssl()' - Read from a SSL/TLS connection.
2296 */
2297
2298static int /* O - Bytes read */
2299http_read_ssl(http_t *http, /* I - HTTP data */
2300 char *buf, /* I - Buffer to store data */
2301 int len) /* I - Length of buffer */
2302{
dcfcaeac 2303# if defined(HAVE_LIBSSL)
bcf61448 2304 return (SSL_read((SSL *)(http->tls), buf, len));
dcfcaeac 2305
2306# elif defined(HAVE_GNUTLS)
bcf61448 2307 return (gnutls_record_recv(((http_tls_t *)(http->tls))->session, buf, len));
dcfcaeac 2308
2309# elif defined(HAVE_CDSASSL)
2310 OSStatus error; /* Error info */
2311 size_t processed; /* Number of bytes processed */
2312
2313
2314 error = SSLRead((SSLContextRef)http->tls, buf, len, &processed);
2315
2316 if (error == 0)
2317 return (processed);
2318 else
2319 {
2320 http->error = error;
2321
2322 return (-1);
2323 }
2324# endif /* HAVE_LIBSSL */
bcf61448 2325}
2326
2327
2328/*
2329 * 'http_write_ssl()' - Write to a SSL/TLS connection.
2330 */
2331
2332static int /* O - Bytes written */
2333http_write_ssl(http_t *http, /* I - HTTP data */
2334 const char *buf, /* I - Buffer holding data */
2335 int len) /* I - Length of buffer */
2336{
dcfcaeac 2337# if defined(HAVE_LIBSSL)
bcf61448 2338 return (SSL_write((SSL *)(http->tls), buf, len));
dcfcaeac 2339
2340# elif defined(HAVE_GNUTLS)
bcf61448 2341 return (gnutls_record_send(((http_tls_t *)(http->tls))->session, buf, len));
dcfcaeac 2342# elif defined(HAVE_CDSASSL)
2343 OSStatus error; /* Error info */
2344 size_t processed; /* Number of bytes processed */
2345
2346
2347 error = SSLWrite((SSLContextRef)http->tls, buf, len, &processed);
2348
2349 if (error == 0)
2350 return (processed);
2351 else
2352 {
2353 http->error = error;
2354 return (-1);
2355 }
2356# endif /* HAVE_LIBSSL */
2357}
2358
2359
2360# if defined(HAVE_CDSASSL)
2361/*
2362 * 'CDSAReadFunc()' - Read function for CDSA decryption code.
2363 */
2364
2365static OSStatus /* O - -1 on error, 0 on success */
2366CDSAReadFunc(SSLConnectionRef connection, /* I - SSL/TLS connection */
2367 void *data, /* I - Data buffer */
2368 size_t *dataLength) /* IO - Number of bytes */
2369{
2370 ssize_t bytes; /* Number of bytes read */
2371
2372
2373 bytes = recv((int)connection, data, *dataLength, 0);
2374 if (bytes >= 0)
2375 {
2376 *dataLength = bytes;
2377 return (0);
2378 }
2379 else
2380 return (-1);
bcf61448 2381}
2382
dcfcaeac 2383
2384/*
2385 * 'CDSAWriteFunc()' - Write function for CDSA encryption code.
2386 */
2387
2388static OSStatus /* O - -1 on error, 0 on success */
2389CDSAWriteFunc(SSLConnectionRef connection, /* I - SSL/TLS connection */
2390 const void *data, /* I - Data buffer */
2391 size_t *dataLength) /* IO - Number of bytes */
2392{
2393 ssize_t bytes;
2394
2395
2396 bytes = write((int)connection, data, *dataLength);
2397 if (bytes >= 0)
2398 {
2399 *dataLength = bytes;
2400 return (0);
2401 }
2402 else
2403 return (-1);
2404}
2405# endif /* HAVE_CDSASSL */
bcf61448 2406#endif /* HAVE_SSL */
2407
dcfcaeac 2408
bcf61448 2409/*
92e48f04 2410 * End of "$Id: http.c,v 1.82.2.32 2003/05/09 16:06:43 mike Exp $".
3840d6ba 2411 */