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