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