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