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