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