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