]> 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.9 2002/02/12 19:23:07 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 #if defined(__APPLE__)
633 /* OS X hack to avoid it's ocassional long delay in lookupd */
634 static char sLoopback[] = "127.0.0.1";
635 if (strcmp(name, "localhost") == 0)
636 name = sLoopback;
637 #endif /* __APPLE__ */
638
639 /*
640 * This function is needed because some operating systems have a
641 * buggy implementation of httpGetHostByName() that does not support
642 * IP addresses. If the first character of the name string is a
643 * number, then sscanf() is used to extract the IP components.
644 * We then pack the components into an IPv4 address manually,
645 * since the inet_aton() function is deprecated. We use the
646 * htonl() macro to get the right byte order for the address.
647 */
648
649 if (isdigit(name[0]))
650 {
651 /*
652 * We have an IP address; break it up and provide the host entry
653 * to the caller. Currently only supports IPv4 addresses, although
654 * it should be trivial to support IPv6 in CUPS 1.2.
655 */
656
657 if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
658 return (NULL); /* Must have 4 numbers */
659
660 packed_ip = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3]));
661
662 /*
663 * Fill in the host entry and return it...
664 */
665
666 host_ip.h_name = (char *)name;
667 host_ip.h_aliases = NULL;
668 host_ip.h_addrtype = AF_INET;
669 host_ip.h_length = 4;
670 host_ip.h_addr_list = packed_ptr;
671 packed_ptr[0] = (char *)(&packed_ip);
672 packed_ptr[1] = NULL;
673
674 return (&host_ip);
675 }
676 else
677 {
678 /*
679 * Use the gethostbyname() function to get the IP address for
680 * the name...
681 */
682
683 return (gethostbyname(name));
684 }
685 }
686
687
688 /*
689 * 'httpSeparate()' - Separate a Universal Resource Identifier into its
690 * components.
691 */
692
693 void
694 httpSeparate(const char *uri, /* I - Universal Resource Identifier */
695 char *method, /* O - Method [32] (http, https, etc.) */
696 char *username, /* O - Username [32] */
697 char *host, /* O - Hostname [32] */
698 int *port, /* O - Port number to use */
699 char *resource) /* O - Resource/filename [1024] */
700 {
701 char *ptr; /* Pointer into string... */
702 const char *atsign, /* @ sign */
703 *slash; /* Separator */
704 char safeuri[HTTP_MAX_URI]; /* "Safe" local copy of URI */
705
706
707 /*
708 * Range check input...
709 */
710
711 if (uri == NULL || method == NULL || username == NULL || host == NULL ||
712 port == NULL || resource == NULL)
713 return;
714
715 /*
716 * Copy the URL to a local string to make sure we don't have a URL
717 * longer than HTTP_MAX_URI characters long...
718 */
719
720 strncpy(safeuri, uri, sizeof(safeuri));
721 safeuri[sizeof(safeuri) - 1] = '\0';
722
723 uri = safeuri;
724
725 /*
726 * Grab the method portion of the URI...
727 */
728
729 if (strncmp(uri, "//", 2) == 0)
730 {
731 /*
732 * Workaround for HP IPP client bug...
733 */
734
735 strcpy(method, "ipp");
736 }
737 else
738 {
739 /*
740 * Standard URI with method...
741 */
742
743 for (ptr = host; *uri != ':' && *uri != '\0'; uri ++)
744 if (ptr < (host + HTTP_MAX_URI - 1))
745 *ptr++ = *uri;
746
747 *ptr = '\0';
748 if (*uri == ':')
749 uri ++;
750
751 /*
752 * If the method contains a period or slash, then it's probably
753 * hostname/filename...
754 */
755
756 if (strchr(host, '.') != NULL || strchr(host, '/') != NULL || *uri == '\0')
757 {
758 if ((ptr = strchr(host, '/')) != NULL)
759 {
760 strncpy(resource, ptr, HTTP_MAX_URI);
761 resource[HTTP_MAX_URI - 1] = '\0';
762 *ptr = '\0';
763 }
764 else
765 resource[0] = '\0';
766
767 if (isdigit(*uri))
768 {
769 /*
770 * OK, we have "hostname:port[/resource]"...
771 */
772
773 *port = strtol(uri, (char **)&uri, 10);
774
775 if (*uri == '/')
776 {
777 strncpy(resource, uri, HTTP_MAX_URI);
778 resource[HTTP_MAX_URI - 1] = '\0';
779 }
780 }
781 else
782 *port = 631;
783
784 strcpy(method, "http");
785 username[0] = '\0';
786 return;
787 }
788 else
789 {
790 strncpy(method, host, 31);
791 method[31] = '\0';
792 }
793 }
794
795 /*
796 * If the method starts with less than 2 slashes then it is a local resource...
797 */
798
799 if (strncmp(uri, "//", 2) != 0)
800 {
801 strncpy(resource, uri, 1023);
802 resource[1023] = '\0';
803
804 username[0] = '\0';
805 host[0] = '\0';
806 *port = 0;
807 return;
808 }
809
810 /*
811 * Grab the username, if any...
812 */
813
814 while (*uri == '/')
815 uri ++;
816
817 if ((slash = strchr(uri, '/')) == NULL)
818 slash = uri + strlen(uri);
819
820 if ((atsign = strchr(uri, '@')) != NULL && atsign < slash)
821 {
822 /*
823 * Got a username:password combo...
824 */
825
826 for (ptr = username; uri < atsign; uri ++)
827 if (ptr < (username + HTTP_MAX_URI - 1))
828 *ptr++ = *uri;
829
830 *ptr = '\0';
831
832 uri = atsign + 1;
833 }
834 else
835 username[0] = '\0';
836
837 /*
838 * Grab the hostname...
839 */
840
841 for (ptr = host; *uri != ':' && *uri != '/' && *uri != '\0'; uri ++)
842 if (ptr < (host + HTTP_MAX_URI - 1))
843 *ptr++ = *uri;
844
845 *ptr = '\0';
846
847 if (*uri != ':')
848 {
849 if (strcasecmp(method, "http") == 0)
850 *port = 80;
851 else if (strcasecmp(method, "https") == 0)
852 *port = 443;
853 else if (strcasecmp(method, "ipp") == 0)
854 *port = ippPort();
855 else if (strcasecmp(method, "socket") == 0) /* Not registered yet... */
856 *port = 9100;
857 else
858 *port = 0;
859 }
860 else
861 {
862 /*
863 * Parse port number...
864 */
865
866 *port = 0;
867 uri ++;
868 while (isdigit(*uri))
869 {
870 *port = (*port * 10) + *uri - '0';
871 uri ++;
872 }
873 }
874
875 if (*uri == '\0')
876 {
877 /*
878 * Hostname but no port or path...
879 */
880
881 resource[0] = '/';
882 resource[1] = '\0';
883 return;
884 }
885
886 /*
887 * The remaining portion is the resource string...
888 */
889
890 strncpy(resource, uri, HTTP_MAX_URI);
891 resource[HTTP_MAX_URI - 1] = '\0';
892 }
893
894
895 /*
896 * 'httpGetSubField()' - Get a sub-field value.
897 */
898
899 char * /* O - Value or NULL */
900 httpGetSubField(http_t *http, /* I - HTTP data */
901 http_field_t field, /* I - Field index */
902 const char *name, /* I - Name of sub-field */
903 char *value) /* O - Value string */
904 {
905 const char *fptr; /* Pointer into field */
906 char temp[HTTP_MAX_VALUE], /* Temporary buffer for name */
907 *ptr; /* Pointer into string buffer */
908
909
910 if (http == NULL ||
911 field < HTTP_FIELD_ACCEPT_LANGUAGE ||
912 field > HTTP_FIELD_WWW_AUTHENTICATE ||
913 name == NULL || value == NULL)
914 return (NULL);
915
916 for (fptr = http->fields[field]; *fptr;)
917 {
918 /*
919 * Skip leading whitespace...
920 */
921
922 while (isspace(*fptr))
923 fptr ++;
924
925 if (*fptr == ',')
926 {
927 fptr ++;
928 continue;
929 }
930
931 /*
932 * Get the sub-field name...
933 */
934
935 for (ptr = temp;
936 *fptr && *fptr != '=' && !isspace(*fptr) && ptr < (temp + sizeof(temp) - 1);
937 *ptr++ = *fptr++);
938
939 *ptr = '\0';
940
941 /*
942 * Skip trailing chars up to the '='...
943 */
944
945 while (*fptr && *fptr != '=')
946 fptr ++;
947
948 if (!*fptr)
949 break;
950
951 /*
952 * Skip = and leading whitespace...
953 */
954
955 fptr ++;
956
957 while (isspace(*fptr))
958 fptr ++;
959
960 if (*fptr == '\"')
961 {
962 /*
963 * Read quoted string...
964 */
965
966 for (ptr = value, fptr ++;
967 *fptr && *fptr != '\"' && ptr < (value + HTTP_MAX_VALUE - 1);
968 *ptr++ = *fptr++);
969
970 *ptr = '\0';
971
972 while (*fptr && *fptr != '\"')
973 fptr ++;
974
975 if (*fptr)
976 fptr ++;
977 }
978 else
979 {
980 /*
981 * Read unquoted string...
982 */
983
984 for (ptr = value;
985 *fptr && !isspace(*fptr) && *fptr != ',' && ptr < (value + HTTP_MAX_VALUE - 1);
986 *ptr++ = *fptr++);
987
988 *ptr = '\0';
989
990 while (*fptr && !isspace(*fptr) && *fptr != ',')
991 fptr ++;
992 }
993
994 /*
995 * See if this is the one...
996 */
997
998 if (strcmp(name, temp) == 0)
999 return (value);
1000 }
1001
1002 value[0] = '\0';
1003
1004 return (NULL);
1005 }
1006
1007
1008 /*
1009 * 'httpSetField()' - Set the value of an HTTP header.
1010 */
1011
1012 void
1013 httpSetField(http_t *http, /* I - HTTP data */
1014 http_field_t field, /* I - Field index */
1015 const char *value) /* I - Value */
1016 {
1017 if (http == NULL ||
1018 field < HTTP_FIELD_ACCEPT_LANGUAGE ||
1019 field > HTTP_FIELD_WWW_AUTHENTICATE ||
1020 value == NULL)
1021 return;
1022
1023 strncpy(http->fields[field], value, HTTP_MAX_VALUE - 1);
1024 http->fields[field][HTTP_MAX_VALUE - 1] = '\0';
1025 }
1026
1027
1028 /*
1029 * 'httpDelete()' - Send a DELETE request to the server.
1030 */
1031
1032 int /* O - Status of call (0 = success) */
1033 httpDelete(http_t *http, /* I - HTTP data */
1034 const char *uri) /* I - URI to delete */
1035 {
1036 return (http_send(http, HTTP_DELETE, uri));
1037 }
1038
1039
1040 /*
1041 * 'httpGet()' - Send a GET request to the server.
1042 */
1043
1044 int /* O - Status of call (0 = success) */
1045 httpGet(http_t *http, /* I - HTTP data */
1046 const char *uri) /* I - URI to get */
1047 {
1048 return (http_send(http, HTTP_GET, uri));
1049 }
1050
1051
1052 /*
1053 * 'httpHead()' - Send a HEAD request to the server.
1054 */
1055
1056 int /* O - Status of call (0 = success) */
1057 httpHead(http_t *http, /* I - HTTP data */
1058 const char *uri) /* I - URI for head */
1059 {
1060 return (http_send(http, HTTP_HEAD, uri));
1061 }
1062
1063
1064 /*
1065 * 'httpOptions()' - Send an OPTIONS request to the server.
1066 */
1067
1068 int /* O - Status of call (0 = success) */
1069 httpOptions(http_t *http, /* I - HTTP data */
1070 const char *uri) /* I - URI for options */
1071 {
1072 return (http_send(http, HTTP_OPTIONS, uri));
1073 }
1074
1075
1076 /*
1077 * 'httpPost()' - Send a POST request to the server.
1078 */
1079
1080 int /* O - Status of call (0 = success) */
1081 httpPost(http_t *http, /* I - HTTP data */
1082 const char *uri) /* I - URI for post */
1083 {
1084 httpGetLength(http);
1085
1086 return (http_send(http, HTTP_POST, uri));
1087 }
1088
1089
1090 /*
1091 * 'httpPut()' - Send a PUT request to the server.
1092 */
1093
1094 int /* O - Status of call (0 = success) */
1095 httpPut(http_t *http, /* I - HTTP data */
1096 const char *uri) /* I - URI to put */
1097 {
1098 httpGetLength(http);
1099
1100 return (http_send(http, HTTP_PUT, uri));
1101 }
1102
1103
1104 /*
1105 * 'httpTrace()' - Send an TRACE request to the server.
1106 */
1107
1108 int /* O - Status of call (0 = success) */
1109 httpTrace(http_t *http, /* I - HTTP data */
1110 const char *uri) /* I - URI for trace */
1111 {
1112 return (http_send(http, HTTP_TRACE, uri));
1113 }
1114
1115
1116 /*
1117 * 'httpFlush()' - Flush data from a HTTP connection.
1118 */
1119
1120 void
1121 httpFlush(http_t *http) /* I - HTTP data */
1122 {
1123 char buffer[8192]; /* Junk buffer */
1124
1125
1126 while (httpRead(http, buffer, sizeof(buffer)) > 0);
1127 }
1128
1129
1130 /*
1131 * 'httpRead()' - Read data from a HTTP connection.
1132 */
1133
1134 int /* O - Number of bytes read */
1135 httpRead(http_t *http, /* I - HTTP data */
1136 char *buffer, /* I - Buffer for data */
1137 int length) /* I - Maximum number of bytes */
1138 {
1139 int bytes; /* Bytes read */
1140 char len[32]; /* Length string */
1141
1142
1143 DEBUG_printf(("httpRead(%08x, %08x, %d)\n", http, buffer, length));
1144
1145 if (http == NULL || buffer == NULL)
1146 return (-1);
1147
1148 http->activity = time(NULL);
1149
1150 if (length <= 0)
1151 return (0);
1152
1153 if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
1154 http->data_remaining <= 0)
1155 {
1156 DEBUG_puts("httpRead: Getting chunk length...");
1157
1158 if (httpGets(len, sizeof(len), http) == NULL)
1159 {
1160 DEBUG_puts("httpRead: Could not get length!");
1161 return (0);
1162 }
1163
1164 http->data_remaining = strtol(len, NULL, 16);
1165 }
1166
1167 DEBUG_printf(("httpRead: data_remaining = %d\n", http->data_remaining));
1168
1169 if (http->data_remaining == 0)
1170 {
1171 /*
1172 * A zero-length chunk ends a transfer; unless we are reading POST
1173 * data, go idle...
1174 */
1175
1176 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1177 httpGets(len, sizeof(len), http);
1178
1179 if (http->state == HTTP_POST_RECV)
1180 http->state ++;
1181 else
1182 http->state = HTTP_WAITING;
1183
1184 return (0);
1185 }
1186 else if (length > http->data_remaining)
1187 length = http->data_remaining;
1188
1189 if (http->used == 0 && length <= 256)
1190 {
1191 /*
1192 * Buffer small reads for better performance...
1193 */
1194
1195 if (http->data_remaining > sizeof(http->buffer))
1196 bytes = sizeof(http->buffer);
1197 else
1198 bytes = http->data_remaining;
1199
1200 #ifdef HAVE_LIBSSL
1201 if (http->tls)
1202 bytes = SSL_read((SSL *)(http->tls), http->buffer, bytes);
1203 else
1204 #endif /* HAVE_LIBSSL */
1205 {
1206 DEBUG_printf(("httpRead: reading %d bytes from socket into buffer...\n",
1207 bytes));
1208
1209 bytes = recv(http->fd, http->buffer, bytes, 0);
1210
1211 DEBUG_printf(("httpRead: read %d bytes from socket into buffer...\n",
1212 bytes));
1213 }
1214
1215 if (bytes > 0)
1216 http->used = bytes;
1217 else if (bytes < 0)
1218 {
1219 #ifdef WIN32
1220 http->error = WSAGetLastError();
1221 #else
1222 http->error = errno;
1223 #endif /* WIN32 */
1224 return (-1);
1225 }
1226 else
1227 return (0);
1228 }
1229
1230 if (http->used > 0)
1231 {
1232 if (length > http->used)
1233 length = http->used;
1234
1235 bytes = length;
1236
1237 DEBUG_printf(("httpRead: grabbing %d bytes from input buffer...\n", bytes));
1238
1239 memcpy(buffer, http->buffer, length);
1240 http->used -= length;
1241
1242 if (http->used > 0)
1243 memcpy(http->buffer, http->buffer + length, http->used);
1244 }
1245 #ifdef HAVE_LIBSSL
1246 else if (http->tls)
1247 bytes = SSL_read((SSL *)(http->tls), buffer, length);
1248 #endif /* HAVE_LIBSSL */
1249 else
1250 {
1251 DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length));
1252 bytes = recv(http->fd, buffer, length, 0);
1253 DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes));
1254 }
1255
1256 if (bytes > 0)
1257 http->data_remaining -= bytes;
1258 else if (bytes < 0)
1259 #ifdef WIN32
1260 http->error = WSAGetLastError();
1261 #else
1262 http->error = errno;
1263 #endif /* WIN32 */
1264
1265 if (http->data_remaining == 0)
1266 {
1267 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1268 httpGets(len, sizeof(len), http);
1269
1270 if (http->data_encoding != HTTP_ENCODE_CHUNKED)
1271 {
1272 if (http->state == HTTP_POST_RECV)
1273 http->state ++;
1274 else
1275 http->state = HTTP_WAITING;
1276 }
1277 }
1278
1279 return (bytes);
1280 }
1281
1282
1283 /*
1284 * 'httpWrite()' - Write data to a HTTP connection.
1285 */
1286
1287 int /* O - Number of bytes written */
1288 httpWrite(http_t *http, /* I - HTTP data */
1289 const char *buffer, /* I - Buffer for data */
1290 int length) /* I - Number of bytes to write */
1291 {
1292 int tbytes, /* Total bytes sent */
1293 bytes; /* Bytes sent */
1294
1295
1296 if (http == NULL || buffer == NULL)
1297 return (-1);
1298
1299 http->activity = time(NULL);
1300
1301 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1302 {
1303 if (httpPrintf(http, "%x\r\n", length) < 0)
1304 return (-1);
1305
1306 if (length == 0)
1307 {
1308 /*
1309 * A zero-length chunk ends a transfer; unless we are sending POST
1310 * data, go idle...
1311 */
1312
1313 DEBUG_puts("httpWrite: changing states...");
1314
1315 if (http->state == HTTP_POST_RECV)
1316 http->state ++;
1317 else if (http->state == HTTP_PUT_RECV)
1318 http->state = HTTP_STATUS;
1319 else
1320 http->state = HTTP_WAITING;
1321
1322 if (httpPrintf(http, "\r\n") < 0)
1323 return (-1);
1324
1325 return (0);
1326 }
1327 }
1328
1329 tbytes = 0;
1330
1331 while (length > 0)
1332 {
1333 #ifdef HAVE_LIBSSL
1334 if (http->tls)
1335 bytes = SSL_write((SSL *)(http->tls), buffer, length);
1336 else
1337 #endif /* HAVE_LIBSSL */
1338 bytes = send(http->fd, buffer, length, 0);
1339
1340 if (bytes < 0)
1341 {
1342 DEBUG_puts("httpWrite: error writing data...\n");
1343
1344 return (-1);
1345 }
1346
1347 buffer += bytes;
1348 tbytes += bytes;
1349 length -= bytes;
1350 if (http->data_encoding == HTTP_ENCODE_LENGTH)
1351 http->data_remaining -= bytes;
1352 }
1353
1354 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
1355 if (httpPrintf(http, "\r\n") < 0)
1356 return (-1);
1357
1358 if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
1359 {
1360 /*
1361 * Finished with the transfer; unless we are sending POST data, go idle...
1362 */
1363
1364 DEBUG_puts("httpWrite: changing states...");
1365
1366 if (http->state == HTTP_POST_RECV)
1367 http->state ++;
1368 else
1369 http->state = HTTP_WAITING;
1370 }
1371
1372 DEBUG_printf(("httpWrite: wrote %d bytes...\n", tbytes));
1373
1374 return (tbytes);
1375 }
1376
1377
1378 /*
1379 * 'httpGets()' - Get a line of text from a HTTP connection.
1380 */
1381
1382 char * /* O - Line or NULL */
1383 httpGets(char *line, /* I - Line to read into */
1384 int length, /* I - Max length of buffer */
1385 http_t *http) /* I - HTTP data */
1386 {
1387 char *lineptr, /* Pointer into line */
1388 *bufptr, /* Pointer into input buffer */
1389 *bufend; /* Pointer to end of buffer */
1390 int bytes; /* Number of bytes read */
1391
1392
1393 DEBUG_printf(("httpGets(%08x, %d, %08x)\n", line, length, http));
1394
1395 if (http == NULL || line == NULL)
1396 return (NULL);
1397
1398 /*
1399 * Pre-scan the buffer and see if there is a newline in there...
1400 */
1401
1402 #ifdef WIN32
1403 WSASetLastError(0);
1404 #else
1405 errno = 0;
1406 #endif /* WIN32 */
1407
1408 do
1409 {
1410 bufptr = http->buffer;
1411 bufend = http->buffer + http->used;
1412
1413 while (bufptr < bufend)
1414 if (*bufptr == 0x0a)
1415 break;
1416 else
1417 bufptr ++;
1418
1419 if (bufptr >= bufend && http->used < HTTP_MAX_BUFFER)
1420 {
1421 /*
1422 * No newline; see if there is more data to be read...
1423 */
1424
1425 #ifdef HAVE_LIBSSL
1426 if (http->tls)
1427 bytes = SSL_read((SSL *)(http->tls), bufend,
1428 HTTP_MAX_BUFFER - http->used);
1429 else
1430 #endif /* HAVE_LIBSSL */
1431 bytes = recv(http->fd, bufend, HTTP_MAX_BUFFER - http->used, 0);
1432
1433 if (bytes < 0)
1434 {
1435 /*
1436 * Nope, can't get a line this time...
1437 */
1438
1439 #ifdef WIN32
1440 if (WSAGetLastError() != http->error)
1441 {
1442 http->error = WSAGetLastError();
1443 continue;
1444 }
1445
1446 DEBUG_printf(("httpGets(): recv() error %d!\n", WSAGetLastError()));
1447 #else
1448 if (errno != http->error)
1449 {
1450 http->error = errno;
1451 continue;
1452 }
1453
1454 DEBUG_printf(("httpGets(): recv() error %d!\n", errno));
1455 #endif /* WIN32 */
1456
1457 return (NULL);
1458 }
1459 else if (bytes == 0)
1460 {
1461 if (http->blocking)
1462 http->error = EPIPE;
1463
1464 return (NULL);
1465 }
1466
1467 /*
1468 * Yup, update the amount used and the end pointer...
1469 */
1470
1471 http->used += bytes;
1472 bufend += bytes;
1473 }
1474 }
1475 while (bufptr >= bufend && http->used < HTTP_MAX_BUFFER);
1476
1477 http->activity = time(NULL);
1478
1479 /*
1480 * Read a line from the buffer...
1481 */
1482
1483 lineptr = line;
1484 bufptr = http->buffer;
1485 bytes = 0;
1486 length --;
1487
1488 while (bufptr < bufend && bytes < length)
1489 {
1490 bytes ++;
1491
1492 if (*bufptr == 0x0a)
1493 {
1494 bufptr ++;
1495 break;
1496 }
1497 else if (*bufptr == 0x0d)
1498 bufptr ++;
1499 else
1500 *lineptr++ = *bufptr++;
1501 }
1502
1503 if (bytes > 0)
1504 {
1505 *lineptr = '\0';
1506
1507 http->used -= bytes;
1508 if (http->used > 0)
1509 memcpy(http->buffer, bufptr, http->used);
1510
1511 DEBUG_printf(("httpGets(): Returning \"%s\"\n", line));
1512 return (line);
1513 }
1514
1515 DEBUG_puts("httpGets(): No new line available!");
1516
1517 return (NULL);
1518 }
1519
1520
1521 /*
1522 * 'httpPrintf()' - Print a formatted string to a HTTP connection.
1523 */
1524
1525 int /* O - Number of bytes written */
1526 httpPrintf(http_t *http, /* I - HTTP data */
1527 const char *format, /* I - printf-style format string */
1528 ...) /* I - Additional args as needed */
1529 {
1530 int bytes, /* Number of bytes to write */
1531 nbytes, /* Number of bytes written */
1532 tbytes; /* Number of bytes all together */
1533 char buf[HTTP_MAX_BUFFER], /* Buffer for formatted string */
1534 *bufptr; /* Pointer into buffer */
1535 va_list ap; /* Variable argument pointer */
1536
1537
1538 va_start(ap, format);
1539 bytes = vsnprintf(buf, sizeof(buf), format, ap);
1540 va_end(ap);
1541
1542 DEBUG_printf(("httpPrintf: %s", buf));
1543
1544 for (tbytes = 0, bufptr = buf; tbytes < bytes; tbytes += nbytes, bufptr += nbytes)
1545 {
1546 #ifdef HAVE_LIBSSL
1547 if (http->tls)
1548 nbytes = SSL_write((SSL *)(http->tls), bufptr, bytes - tbytes);
1549 else
1550 #endif /* HAVE_LIBSSL */
1551 nbytes = send(http->fd, bufptr, bytes - tbytes, 0);
1552
1553 if (nbytes < 0)
1554 return (-1);
1555 }
1556
1557 return (bytes);
1558 }
1559
1560
1561 /*
1562 * 'httpStatus()' - Return a short string describing a HTTP status code.
1563 */
1564
1565 const char * /* O - String or NULL */
1566 httpStatus(http_status_t status) /* I - HTTP status code */
1567 {
1568 switch (status)
1569 {
1570 case HTTP_CONTINUE :
1571 return ("Continue");
1572 case HTTP_SWITCHING_PROTOCOLS :
1573 return ("Switching Protocols");
1574 case HTTP_OK :
1575 return ("OK");
1576 case HTTP_CREATED :
1577 return ("Created");
1578 case HTTP_ACCEPTED :
1579 return ("Accepted");
1580 case HTTP_NO_CONTENT :
1581 return ("No Content");
1582 case HTTP_NOT_MODIFIED :
1583 return ("Not Modified");
1584 case HTTP_BAD_REQUEST :
1585 return ("Bad Request");
1586 case HTTP_UNAUTHORIZED :
1587 return ("Unauthorized");
1588 case HTTP_FORBIDDEN :
1589 return ("Forbidden");
1590 case HTTP_NOT_FOUND :
1591 return ("Not Found");
1592 case HTTP_REQUEST_TOO_LARGE :
1593 return ("Request Entity Too Large");
1594 case HTTP_URI_TOO_LONG :
1595 return ("URI Too Long");
1596 case HTTP_UPGRADE_REQUIRED :
1597 return ("Upgrade Required");
1598 case HTTP_NOT_IMPLEMENTED :
1599 return ("Not Implemented");
1600 case HTTP_NOT_SUPPORTED :
1601 return ("Not Supported");
1602 default :
1603 return ("Unknown");
1604 }
1605 }
1606
1607
1608 /*
1609 * 'httpGetDateString()' - Get a formatted date/time string from a time value.
1610 */
1611
1612 const char * /* O - Date/time string */
1613 httpGetDateString(time_t t) /* I - UNIX time */
1614 {
1615 struct tm *tdate;
1616 static char datetime[256];
1617
1618
1619 tdate = gmtime(&t);
1620 snprintf(datetime, sizeof(datetime), "%s, %02d %s %d %02d:%02d:%02d GMT",
1621 days[tdate->tm_wday], tdate->tm_mday, months[tdate->tm_mon],
1622 tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec);
1623
1624 return (datetime);
1625 }
1626
1627
1628 /*
1629 * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
1630 */
1631
1632 time_t /* O - UNIX time */
1633 httpGetDateTime(const char *s) /* I - Date/time string */
1634 {
1635 int i; /* Looping var */
1636 struct tm tdate; /* Time/date structure */
1637 char mon[16]; /* Abbreviated month name */
1638 int day, year; /* Day of month and year */
1639 int hour, min, sec; /* Time */
1640
1641
1642 if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6)
1643 return (0);
1644
1645 for (i = 0; i < 12; i ++)
1646 if (strcasecmp(mon, months[i]) == 0)
1647 break;
1648
1649 if (i >= 12)
1650 return (0);
1651
1652 tdate.tm_mon = i;
1653 tdate.tm_mday = day;
1654 tdate.tm_year = year - 1900;
1655 tdate.tm_hour = hour;
1656 tdate.tm_min = min;
1657 tdate.tm_sec = sec;
1658 tdate.tm_isdst = 0;
1659
1660 return (mktime(&tdate));
1661 }
1662
1663
1664 /*
1665 * 'httpUpdate()' - Update the current HTTP state for incoming data.
1666 */
1667
1668 http_status_t /* O - HTTP status */
1669 httpUpdate(http_t *http) /* I - HTTP data */
1670 {
1671 char line[1024], /* Line from connection... */
1672 *value; /* Pointer to value on line */
1673 http_field_t field; /* Field index */
1674 int major, minor; /* HTTP version numbers */
1675 http_status_t status; /* Authorization status */
1676 #ifdef HAVE_LIBSSL
1677 SSL_CTX *context; /* Context for encryption */
1678 SSL *conn; /* Connection for encryption */
1679 #endif /* HAVE_LIBSSL */
1680
1681
1682 DEBUG_printf(("httpUpdate(%08x)\n", http));
1683
1684 /*
1685 * If we haven't issued any commands, then there is nothing to "update"...
1686 */
1687
1688 if (http->state == HTTP_WAITING)
1689 return (HTTP_CONTINUE);
1690
1691 /*
1692 * Grab all of the lines we can from the connection...
1693 */
1694
1695 while (httpGets(line, sizeof(line), http) != NULL)
1696 {
1697 DEBUG_puts(line);
1698
1699 if (line[0] == '\0')
1700 {
1701 /*
1702 * Blank line means the start of the data section (if any). Return
1703 * the result code, too...
1704 *
1705 * If we get status 100 (HTTP_CONTINUE), then we *don't* change states.
1706 * Instead, we just return HTTP_CONTINUE to the caller and keep on
1707 * tryin'...
1708 */
1709
1710 if (http->status == HTTP_CONTINUE)
1711 return (http->status);
1712
1713 #ifdef HAVE_LIBSSL
1714 if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls)
1715 {
1716 context = SSL_CTX_new(SSLv23_method());
1717 conn = SSL_new(context);
1718
1719 SSL_set_fd(conn, http->fd);
1720 if (SSL_connect(conn) != 1)
1721 {
1722 SSL_CTX_free(context);
1723 SSL_free(conn);
1724
1725 #ifdef WIN32
1726 http->error = WSAGetLastError();
1727 #else
1728 http->error = errno;
1729 #endif /* WIN32 */
1730 http->status = HTTP_ERROR;
1731
1732 #ifdef WIN32
1733 closesocket(http->fd);
1734 #else
1735 close(http->fd);
1736 #endif
1737
1738 return (HTTP_ERROR);
1739 }
1740
1741 http->tls = conn;
1742
1743 return (HTTP_CONTINUE);
1744 }
1745 else if (http->status == HTTP_UPGRADE_REQUIRED &&
1746 http->encryption != HTTP_ENCRYPT_NEVER)
1747 http->encryption = HTTP_ENCRYPT_REQUIRED;
1748 #endif /* HAVE_LIBSSL */
1749
1750 httpGetLength(http);
1751
1752 switch (http->state)
1753 {
1754 case HTTP_GET :
1755 case HTTP_POST :
1756 case HTTP_POST_RECV :
1757 case HTTP_PUT :
1758 http->state ++;
1759 break;
1760
1761 default :
1762 http->state = HTTP_WAITING;
1763 break;
1764 }
1765
1766 return (http->status);
1767 }
1768 else if (strncmp(line, "HTTP/", 5) == 0)
1769 {
1770 /*
1771 * Got the beginning of a response...
1772 */
1773
1774 if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, (int *)&status) != 3)
1775 return (HTTP_ERROR);
1776
1777 http->version = (http_version_t)(major * 100 + minor);
1778 http->status = status;
1779 }
1780 else if ((value = strchr(line, ':')) != NULL)
1781 {
1782 /*
1783 * Got a value...
1784 */
1785
1786 *value++ = '\0';
1787 while (isspace(*value))
1788 value ++;
1789
1790 /*
1791 * Be tolerants of servers that send unknown attribute fields...
1792 */
1793
1794 if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN)
1795 {
1796 DEBUG_printf(("httpUpdate: unknown field %s seen!\n", line));
1797 continue;
1798 }
1799
1800 httpSetField(http, field, value);
1801 }
1802 else
1803 {
1804 http->status = HTTP_ERROR;
1805 return (HTTP_ERROR);
1806 }
1807 }
1808
1809 /*
1810 * See if there was an error...
1811 */
1812
1813 if (http->error)
1814 {
1815 http->status = HTTP_ERROR;
1816 return (HTTP_ERROR);
1817 }
1818
1819 /*
1820 * If we haven't already returned, then there is nothing new...
1821 */
1822
1823 return (HTTP_CONTINUE);
1824 }
1825
1826
1827 /*
1828 * 'httpDecode64()' - Base64-decode a string.
1829 */
1830
1831 char * /* O - Decoded string */
1832 httpDecode64(char *out, /* I - String to write to */
1833 const char *in) /* I - String to read from */
1834 {
1835 int pos, /* Bit position */
1836 base64; /* Value of this character */
1837 char *outptr; /* Output pointer */
1838
1839
1840 for (outptr = out, pos = 0; *in != '\0'; in ++)
1841 {
1842 /*
1843 * Decode this character into a number from 0 to 63...
1844 */
1845
1846 if (*in >= 'A' && *in <= 'Z')
1847 base64 = *in - 'A';
1848 else if (*in >= 'a' && *in <= 'z')
1849 base64 = *in - 'a' + 26;
1850 else if (*in >= '0' && *in <= '9')
1851 base64 = *in - '0' + 52;
1852 else if (*in == '+')
1853 base64 = 62;
1854 else if (*in == '/')
1855 base64 = 63;
1856 else if (*in == '=')
1857 break;
1858 else
1859 continue;
1860
1861 /*
1862 * Store the result in the appropriate chars...
1863 */
1864
1865 switch (pos)
1866 {
1867 case 0 :
1868 *outptr = base64 << 2;
1869 pos ++;
1870 break;
1871 case 1 :
1872 *outptr++ |= (base64 >> 4) & 3;
1873 *outptr = (base64 << 4) & 255;
1874 pos ++;
1875 break;
1876 case 2 :
1877 *outptr++ |= (base64 >> 2) & 15;
1878 *outptr = (base64 << 6) & 255;
1879 pos ++;
1880 break;
1881 case 3 :
1882 *outptr++ |= base64;
1883 pos = 0;
1884 break;
1885 }
1886 }
1887
1888 *outptr = '\0';
1889
1890 /*
1891 * Return the decoded string...
1892 */
1893
1894 return (out);
1895 }
1896
1897
1898 /*
1899 * 'httpEncode64()' - Base64-encode a string.
1900 */
1901
1902 char * /* O - Encoded string */
1903 httpEncode64(char *out, /* I - String to write to */
1904 const char *in) /* I - String to read from */
1905 {
1906 char *outptr; /* Output pointer */
1907 static char base64[] = /* Base64 characters... */
1908 {
1909 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1910 "abcdefghijklmnopqrstuvwxyz"
1911 "0123456789"
1912 "+/"
1913 };
1914
1915
1916 for (outptr = out; *in != '\0'; in ++)
1917 {
1918 /*
1919 * Encode the up to 3 characters as 4 Base64 numbers...
1920 */
1921
1922 *outptr ++ = base64[in[0] >> 2];
1923 *outptr ++ = base64[((in[0] << 4) | (in[1] >> 4)) & 63];
1924
1925 in ++;
1926 if (*in == '\0')
1927 {
1928 *outptr ++ = '=';
1929 break;
1930 }
1931
1932 *outptr ++ = base64[((in[0] << 2) | (in[1] >> 6)) & 63];
1933
1934 in ++;
1935 if (*in == '\0')
1936 break;
1937
1938 *outptr ++ = base64[in[0] & 63];
1939 }
1940
1941 *outptr ++ = '=';
1942 *outptr = '\0';
1943
1944 /*
1945 * Return the encoded string...
1946 */
1947
1948 return (out);
1949 }
1950
1951
1952 /*
1953 * 'httpGetLength()' - Get the amount of data remaining from the
1954 * content-length or transfer-encoding fields.
1955 */
1956
1957 int /* O - Content length */
1958 httpGetLength(http_t *http) /* I - HTTP data */
1959 {
1960 DEBUG_printf(("httpGetLength(%08x)\n", http));
1961
1962 if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0)
1963 {
1964 DEBUG_puts("httpGetLength: chunked request!");
1965
1966 http->data_encoding = HTTP_ENCODE_CHUNKED;
1967 http->data_remaining = 0;
1968 }
1969 else
1970 {
1971 http->data_encoding = HTTP_ENCODE_LENGTH;
1972
1973 /*
1974 * The following is a hack for HTTP servers that don't send a
1975 * content-length or transfer-encoding field...
1976 *
1977 * If there is no content-length then the connection must close
1978 * after the transfer is complete...
1979 */
1980
1981 if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0')
1982 http->data_remaining = 2147483647;
1983 else
1984 http->data_remaining = atoi(http->fields[HTTP_FIELD_CONTENT_LENGTH]);
1985
1986 DEBUG_printf(("httpGetLength: content_length = %d\n", http->data_remaining));
1987 }
1988
1989 return (http->data_remaining);
1990 }
1991
1992
1993 /*
1994 * 'http_field()' - Return the field index for a field name.
1995 */
1996
1997 static http_field_t /* O - Field index */
1998 http_field(const char *name) /* I - String name */
1999 {
2000 int i; /* Looping var */
2001
2002
2003 for (i = 0; i < HTTP_FIELD_MAX; i ++)
2004 if (strcasecmp(name, http_fields[i]) == 0)
2005 return ((http_field_t)i);
2006
2007 return (HTTP_FIELD_UNKNOWN);
2008 }
2009
2010
2011 /*
2012 * 'http_send()' - Send a request with all fields and the trailing blank line.
2013 */
2014
2015 static int /* O - 0 on success, non-zero on error */
2016 http_send(http_t *http, /* I - HTTP data */
2017 http_state_t request, /* I - Request code */
2018 const char *uri) /* I - URI */
2019 {
2020 int i; /* Looping var */
2021 char *ptr, /* Pointer in buffer */
2022 buf[1024]; /* Encoded URI buffer */
2023 static const char *codes[] = /* Request code strings */
2024 {
2025 NULL,
2026 "OPTIONS",
2027 "GET",
2028 NULL,
2029 "HEAD",
2030 "POST",
2031 NULL,
2032 NULL,
2033 "PUT",
2034 NULL,
2035 "DELETE",
2036 "TRACE",
2037 "CLOSE"
2038 };
2039 static const char *hex = "0123456789ABCDEF";
2040 /* Hex digits */
2041
2042
2043 if (http == NULL || uri == NULL)
2044 return (-1);
2045
2046 /*
2047 * Encode the URI as needed...
2048 */
2049
2050 for (ptr = buf; *uri != '\0' && ptr < (buf + sizeof(buf) - 1); uri ++)
2051 if (*uri <= ' ' || *uri >= 127)
2052 {
2053 if (ptr < (buf + sizeof(buf) - 1))
2054 *ptr ++ = '%';
2055 if (ptr < (buf + sizeof(buf) - 1))
2056 *ptr ++ = hex[(*uri >> 4) & 15];
2057 if (ptr < (buf + sizeof(buf) - 1))
2058 *ptr ++ = hex[*uri & 15];
2059 }
2060 else
2061 *ptr ++ = *uri;
2062
2063 *ptr = '\0';
2064
2065 /*
2066 * See if we had an error the last time around; if so, reconnect...
2067 */
2068
2069 if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST)
2070 httpReconnect(http);
2071
2072 /*
2073 * Send the request header...
2074 */
2075
2076 http->state = request;
2077 if (request == HTTP_POST || request == HTTP_PUT)
2078 http->state ++;
2079
2080 http->status = HTTP_CONTINUE;
2081
2082 #ifdef HAVE_LIBSSL
2083 if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
2084 {
2085 httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
2086 httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0,SSL/2.0,SSL/3.0");
2087 }
2088 #endif /* HAVE_LIBSSL */
2089
2090 if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
2091 {
2092 http->status = HTTP_ERROR;
2093 return (-1);
2094 }
2095
2096 for (i = 0; i < HTTP_FIELD_MAX; i ++)
2097 if (http->fields[i][0] != '\0')
2098 {
2099 DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i]));
2100
2101 if (httpPrintf(http, "%s: %s\r\n", http_fields[i], http->fields[i]) < 1)
2102 {
2103 http->status = HTTP_ERROR;
2104 return (-1);
2105 }
2106 }
2107
2108 if (httpPrintf(http, "\r\n") < 1)
2109 {
2110 http->status = HTTP_ERROR;
2111 return (-1);
2112 }
2113
2114 httpClearFields(http);
2115
2116 return (0);
2117 }
2118
2119
2120 #ifdef HAVE_LIBSSL
2121 /*
2122 * 'http_upgrade()' - Force upgrade to TLS encryption.
2123 */
2124
2125 static int /* O - Status of connection */
2126 http_upgrade(http_t *http) /* I - HTTP data */
2127 {
2128 int ret; /* Return value */
2129 http_t myhttp; /* Local copy of HTTP data */
2130
2131
2132 DEBUG_printf(("http_upgrade(%p)\n", http));
2133
2134 /*
2135 * Copy the HTTP data to a local variable so we can do the OPTIONS
2136 * request without interfering with the existing request data...
2137 */
2138
2139 memcpy(&myhttp, http, sizeof(myhttp));
2140
2141 /*
2142 * Send an OPTIONS request to the server, requiring SSL or TLS
2143 * encryption on the link...
2144 */
2145
2146 httpClearFields(&myhttp);
2147 httpSetField(&myhttp, HTTP_FIELD_CONNECTION, "upgrade");
2148 httpSetField(&myhttp, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0");
2149
2150 if ((ret = httpOptions(&myhttp, "*")) == 0)
2151 {
2152 /*
2153 * Wait for the secure connection...
2154 */
2155
2156 while (httpUpdate(&myhttp) == HTTP_CONTINUE);
2157 }
2158
2159 httpFlush(&myhttp);
2160
2161 /*
2162 * Copy the HTTP data back over, if any...
2163 */
2164
2165 http->fd = myhttp.fd;
2166 http->error = myhttp.error;
2167 http->activity = myhttp.activity;
2168 http->status = myhttp.status;
2169 http->version = myhttp.version;
2170 http->keep_alive = myhttp.keep_alive;
2171 http->used = myhttp.used;
2172
2173 if (http->used)
2174 memcpy(http->buffer, myhttp.buffer, http->used);
2175
2176 http->auth_type = myhttp.auth_type;
2177 http->nonce_count = myhttp.nonce_count;
2178
2179 memcpy(http->nonce, myhttp.nonce, sizeof(http->nonce));
2180
2181 http->tls = myhttp.tls;
2182 http->encryption = myhttp.encryption;
2183
2184 /*
2185 * See if we actually went secure...
2186 */
2187
2188 if (!http->tls)
2189 {
2190 /*
2191 * Server does not support HTTP upgrade...
2192 */
2193
2194 DEBUG_puts("Server does not support HTTP upgrade!");
2195
2196 #ifdef WIN32
2197 closesocket(http->fd);
2198 #else
2199 close(http->fd);
2200 #endif
2201
2202 http->fd = -1;
2203
2204 return (-1);
2205 }
2206 else
2207 return (ret);
2208 }
2209 #endif /* HAVE_LIBSSL */
2210
2211
2212 /*
2213 * End of "$Id: http.c,v 1.82.2.9 2002/02/12 19:23:07 mike Exp $".
2214 */