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