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