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