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