]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/http.c
Fixed address to 44141 Airport View Drive...
[thirdparty/cups.git] / cups / http.c
1 /*
2 * "$Id: http.c,v 1.37 1999/06/18 18:36:08 mike Exp $"
3 *
4 * HTTP routines for the Common UNIX Printing System (CUPS) scheduler.
5 *
6 * Copyright 1997-1999 by Easy Software Products, all rights reserved.
7 *
8 * These statusd 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 * httpClose() - Close an HTTP connection...
29 * httpConnect() - Connect to a HTTP server.
30 * httpReconnect() - Reconnect to a HTTP server...
31 * httpSeparate() - Separate a Universal Resource Identifier into its
32 * components.
33 * httpSetField() - Set the value of an HTTP header.
34 * httpDelete() - Send a DELETE request to the server.
35 * httpGet() - Send a GET request to the server.
36 * httpHead() - Send a HEAD request to the server.
37 * httpOptions() - Send an OPTIONS request to the server.
38 * httpPost() - Send a POST request to the server.
39 * httpPut() - Send a PUT request to the server.
40 * httpTrace() - Send an TRACE request to the server.
41 * httpFlush() - Flush data from a HTTP connection.
42 * httpRead() - Read data from a HTTP connection.
43 * httpWrite() - Write data to a HTTP connection.
44 * httpGets() - Get a line of text from a HTTP connection.
45 * httpPrintf() - Print a formatted string to a HTTP connection.
46 * httpStatus() - Return a short string describing a HTTP status code.
47 * httpGetDateString() - Get a formatted date/time string from a time value.
48 * httpGetDateTime() - Get a time value from a formatted date/time string.
49 * httpUpdate() - Update the current HTTP state for incoming data.
50 * httpDecode64() - Base64-decode a string.
51 * httpEncode64() - Base64-encode a string.
52 * httpGetLength() - Get the amount of data remaining from the
53 * content-length or transfer-encoding fields.
54 * http_field() - Return the field index for a field name.
55 * http_send() - Send a request with all fields and the trailing
56 * blank line.
57 */
58
59 /*
60 * Include necessary headers...
61 */
62
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <stdarg.h>
66 #include <ctype.h>
67 #include "string.h"
68 #include <fcntl.h>
69
70 #include "http.h"
71 #include "ipp.h"
72 #include "debug.h"
73
74 #if !defined(WIN32) && !defined(__EMX__)
75 # include <signal.h>
76 #endif /* !WIN32 && !__EMX__ */
77
78 /*
79 * Some operating systems have done away with the Fxxxx constants for
80 * the fcntl() call; this works around that "feature"...
81 */
82
83 #ifndef FNONBLK
84 # define FNONBLK O_NONBLOCK
85 #endif /* !FNONBLK */
86
87
88 /*
89 * Local functions...
90 */
91
92 static http_field_t http_field(char *name);
93 static int http_send(http_t *http, http_state_t request, char *uri);
94
95
96 /*
97 * Local globals...
98 */
99
100 static char *http_fields[] =
101 {
102 "Accept",
103 "Accept-Charset",
104 "Accept-Encoding",
105 "Accept-Language",
106 "Accept-Ranges",
107 "Age",
108 "Allow",
109 "Alternates",
110 "Authorization",
111 "Cache-Control",
112 "Connection",
113 "Content-Base",
114 "Content-Encoding",
115 "Content-Language",
116 "Content-Length",
117 "Content-Location",
118 "Content-MD5",
119 "Content-Range",
120 "Content-Type",
121 "Content-Version",
122 "Date",
123 "Derived-From",
124 "Etag",
125 "Expires",
126 "From",
127 "Host",
128 "If-Match",
129 "If-Modified-Since",
130 "If-None-Match",
131 "If-Range",
132 "If-Unmodified-since",
133 "Keep-Alive",
134 "Last-Modified",
135 "Link",
136 "Location",
137 "Max-Forwards",
138 "Message-Id",
139 "MIME-Version",
140 "Pragma",
141 "Proxy-Authenticate",
142 "Proxy-Authorization",
143 "Public",
144 "Range",
145 "Referer",
146 "Retry-After",
147 "Server",
148 "Transfer-Encoding",
149 "Upgrade",
150 "URI",
151 "User-Agent",
152 "Vary",
153 "Via",
154 "Warning",
155 "WWW-Authenticate"
156 };
157 static char *days[7] =
158 {
159 "Sun",
160 "Mon",
161 "Tue",
162 "Wed",
163 "Thu",
164 "Fri",
165 "Sat"
166 };
167 static char *months[12] =
168 {
169 "Jan",
170 "Feb",
171 "Mar",
172 "Apr",
173 "May",
174 "Jun",
175 "Jul",
176 "Aug",
177 "Sep",
178 "Oct",
179 "Nov",
180 "Dec"
181 };
182
183
184 /*
185 * 'httpInitialize()' - Initialize the HTTP interface library and set the
186 * default HTTP proxy (if any).
187 */
188
189 void
190 httpInitialize(void)
191 {
192 #if defined(WIN32) || defined(__EMX__)
193 WSADATA winsockdata; /* WinSock data */
194 static int initialized = 0;/* Has WinSock been initialized? */
195
196
197 if (!initialized)
198 WSAStartup(MAKEWORD(1,1), &winsockdata);
199 #elif defined(HAVE_SIGSET)
200 sigset(SIGPIPE, SIG_IGN);
201 #elif defined(HAVE_SIGACTION)
202 struct sigaction action; /* POSIX sigaction data */
203
204
205 /*
206 * Ignore SIGPIPE signals...
207 */
208
209 memset(&action, 0, sizeof(action));
210 action.sa_handler = SIG_IGN;
211 sigaction(SIGPIPE, &action, NULL);
212 #else
213 signal(SIGPIPE, SIG_IGN);
214 #endif /* WIN32 || __EMX__ */
215 }
216
217
218 /*
219 * 'httpClose()' - Close an HTTP connection...
220 */
221
222 void
223 httpClose(http_t *http) /* I - Connection to close */
224 {
225 if (http == NULL)
226 return;
227
228 #ifdef WIN32
229 closesocket(http->fd);
230 #else
231 close(http->fd);
232 #endif /* WIN32 */
233
234 free(http);
235 }
236
237
238 /*
239 * 'httpConnect()' - Connect to a HTTP server.
240 */
241
242 http_t * /* O - New HTTP connection */
243 httpConnect(char *host, /* I - Host to connect to */
244 int port) /* I - Port number */
245 {
246 http_t *http; /* New HTTP connection */
247 struct hostent *hostaddr; /* Host address data */
248
249
250 httpInitialize();
251
252 /*
253 * Lookup the host...
254 */
255
256 if ((hostaddr = gethostbyname(host)) == NULL)
257 return (NULL);
258
259 /*
260 * Allocate memory for the structure...
261 */
262
263 http = calloc(sizeof(http_t), 1);
264 if (http == NULL)
265 return (NULL);
266
267 http->version = HTTP_1_1;
268 http->blocking = 1;
269 http->activity = time(NULL);
270
271 /*
272 * Copy the hostname and port and then "reconnect"...
273 */
274
275 strcpy(http->hostname, host);
276 memset((char *)&(http->hostaddr), 0, sizeof(http->hostaddr));
277 memcpy((char *)&(http->hostaddr.sin_addr), hostaddr->h_addr, hostaddr->h_length);
278 http->hostaddr.sin_family = hostaddr->h_addrtype;
279 #ifdef WIN32
280 http->hostaddr.sin_port = htons((u_short)port);
281 #else
282 http->hostaddr.sin_port = htons(port);
283 #endif /* WIN32 */
284 if (httpReconnect(http))
285 {
286 free(http);
287 return (NULL);
288 }
289 else
290 return (http);
291 }
292
293
294 /*
295 * 'httpReconnect()' - Reconnect to a HTTP server...
296 */
297
298 int /* O - 0 on success, non-zero on failure */
299 httpReconnect(http_t *http) /* I - HTTP data */
300 {
301 int val; /* Socket option value */
302
303
304 /*
305 * Close any previously open socket...
306 */
307
308 if (http->fd)
309 #ifdef WIN32
310 closesocket(http->fd);
311 #else
312 close(http->fd);
313 #endif /* WIN32 */
314
315 /*
316 * Create the socket and set options to allow reuse.
317 */
318
319 if ((http->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
320 return (-1);
321
322 #ifdef FD_CLOEXEC
323 fcntl(http->fd, F_SETFD, FD_CLOEXEC); /* Close this socket when starting *
324 * other processes... */
325 #endif /* FD_CLOEXEC */
326
327 val = 1;
328 setsockopt(http->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
329
330 #ifdef SO_REUSEPORT
331 val = 1;
332 setsockopt(http->fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
333 #endif /* SO_REUSEPORT */
334
335 /*
336 * Connect to the server...
337 */
338
339 if (connect(http->fd, (struct sockaddr *)&(http->hostaddr),
340 sizeof(http->hostaddr)) < 0)
341 {
342 #ifdef WIN32
343 closesocket(http->fd);
344 #else
345 close(http->fd);
346 #endif
347
348 return (-1);
349 }
350
351 return (0);
352 }
353
354
355 /*
356 * 'httpSeparate()' - Separate a Universal Resource Identifier into its
357 * components.
358 */
359
360 void
361 httpSeparate(char *uri, /* I - Universal Resource Identifier */
362 char *method, /* O - Method (http, https, etc.) */
363 char *username, /* O - Username */
364 char *host, /* O - Hostname */
365 int *port, /* O - Port number to use */
366 char *resource) /* O - Resource/filename */
367 {
368 char *ptr; /* Pointer into string... */
369
370
371 if (uri == NULL || method == NULL || username == NULL || host == NULL ||
372 port == NULL || resource == NULL)
373 return;
374
375 /*
376 * Grab the method portion of the URI...
377 */
378
379 ptr = host;
380 while (*uri != ':' && *uri != '\0')
381 *ptr++ = *uri++;
382
383 *ptr = '\0';
384 if (*uri == ':')
385 uri ++;
386
387 /*
388 * If the method contains a period or slash, then it's probably
389 * hostname/filename...
390 */
391
392 if (strchr(host, '.') != NULL || strchr(host, '/') != NULL || *uri == '\0')
393 {
394 if ((ptr = strchr(host, '/')) != NULL)
395 {
396 strcpy(resource, ptr);
397 *ptr = '\0';
398 }
399 else
400 resource[0] = '\0';
401
402 if (isdigit(*uri))
403 {
404 /*
405 * OK, we have "hostname:port[/resource]"...
406 */
407
408 *port = strtol(uri, &uri, 10);
409
410 if (*uri == '/')
411 strcpy(resource, uri);
412 }
413 else
414 *port = 0;
415
416 strcpy(method, "http");
417 username[0] = '\0';
418 return;
419 }
420 else
421 strcpy(method, host);
422
423 /*
424 * If the method starts with less than 2 slashes then it is a local resource...
425 */
426
427 if (strncmp(uri, "//", 2) != 0)
428 {
429 strcpy(resource, uri);
430 username[0] = '\0';
431 host[0] = '\0';
432 *port = 0;
433 return;
434 }
435
436 /*
437 * Grab the hostname...
438 */
439
440 while (*uri == '/')
441 uri ++;
442
443 ptr = host;
444 while (*uri != ':' && *uri != '@' && *uri != '/' && *uri != '\0')
445 *ptr ++ = *uri ++;
446
447 *ptr = '\0';
448
449 if (*uri == '@')
450 {
451 /*
452 * Got a username...
453 */
454
455 strcpy(username, host);
456
457 ptr = host;
458 while (*uri != ':' && *uri != '/' && *uri != '\0')
459 *ptr ++ = *uri ++;
460
461 *ptr = '\0';
462 }
463 else
464 username[0] = '\0';
465
466 if (*uri == '\0')
467 {
468 /*
469 * Hostname but no port or path...
470 */
471
472 *port = 0;
473 resource[0] = '/';
474 resource[1] = '\0';
475 return;
476 }
477 else if (*uri == ':')
478 {
479 /*
480 * Parse port number...
481 */
482
483 *port = 0;
484 uri ++;
485 while (isdigit(*uri))
486 {
487 *port = (*port * 10) + *uri - '0';
488 uri ++;
489 }
490 }
491 else
492 {
493 /*
494 * Figure out the default port number based on the method...
495 */
496
497 if (strcasecmp(method, "http") == 0)
498 *port = 80;
499 else if (strcasecmp(method, "https") == 0)
500 *port = 443;
501 else if (strcasecmp(method, "ipp") == 0) /* Not registered yet... */
502 *port = ippPort();
503 else
504 *port = 0;
505 }
506
507 /*
508 * The remaining portion is the resource string...
509 */
510
511 strcpy(resource, uri);
512 }
513
514
515 /*
516 * 'httpSetField()' - Set the value of an HTTP header.
517 */
518
519 void
520 httpSetField(http_t *http, /* I - HTTP data */
521 http_field_t field, /* I - Field index */
522 char *value) /* I - Value */
523 {
524 strncpy(http->fields[field], value, HTTP_MAX_VALUE - 1);
525 http->fields[field][HTTP_MAX_VALUE - 1] = '\0';
526 }
527
528
529 /*
530 * 'httpDelete()' - Send a DELETE request to the server.
531 */
532
533 int /* O - Status of call (0 = success) */
534 httpDelete(http_t *http, /* I - HTTP data */
535 char *uri) /* I - URI to delete */
536 {
537 return (http_send(http, HTTP_DELETE, uri));
538 }
539
540
541 /*
542 * 'httpGet()' - Send a GET request to the server.
543 */
544
545 int /* O - Status of call (0 = success) */
546 httpGet(http_t *http, /* I - HTTP data */
547 char *uri) /* I - URI to get */
548 {
549 return (http_send(http, HTTP_GET, uri));
550 }
551
552
553 /*
554 * 'httpHead()' - Send a HEAD request to the server.
555 */
556
557 int /* O - Status of call (0 = success) */
558 httpHead(http_t *http, /* I - HTTP data */
559 char *uri) /* I - URI for head */
560 {
561 return (http_send(http, HTTP_HEAD, uri));
562 }
563
564
565 /*
566 * 'httpOptions()' - Send an OPTIONS request to the server.
567 */
568
569 int /* O - Status of call (0 = success) */
570 httpOptions(http_t *http, /* I - HTTP data */
571 char *uri) /* I - URI for options */
572 {
573 return (http_send(http, HTTP_OPTIONS, uri));
574 }
575
576
577 /*
578 * 'httpPost()' - Send a POST request to the server.
579 */
580
581 int /* O - Status of call (0 = success) */
582 httpPost(http_t *http, /* I - HTTP data */
583 char *uri) /* I - URI for post */
584 {
585 httpGetLength(http);
586
587 return (http_send(http, HTTP_POST, uri));
588 }
589
590
591 /*
592 * 'httpPut()' - Send a PUT request to the server.
593 */
594
595 int /* O - Status of call (0 = success) */
596 httpPut(http_t *http, /* I - HTTP data */
597 char *uri) /* I - URI to put */
598 {
599 httpGetLength(http);
600
601 return (http_send(http, HTTP_PUT, uri));
602 }
603
604
605 /*
606 * 'httpTrace()' - Send an TRACE request to the server.
607 */
608
609 int /* O - Status of call (0 = success) */
610 httpTrace(http_t *http, /* I - HTTP data */
611 char *uri) /* I - URI for trace */
612 {
613 return (http_send(http, HTTP_TRACE, uri));
614 }
615
616
617 /*
618 * 'httpFlush()' - Flush data from a HTTP connection.
619 */
620
621 void
622 httpFlush(http_t *http) /* I - HTTP data */
623 {
624 char buffer[8192]; /* Junk buffer */
625
626
627 while (httpRead(http, buffer, sizeof(buffer)) > 0);
628 }
629
630
631 /*
632 * 'httpRead()' - Read data from a HTTP connection.
633 */
634
635 int /* O - Number of bytes read */
636 httpRead(http_t *http, /* I - HTTP data */
637 char *buffer, /* I - Buffer for data */
638 int length) /* I - Maximum number of bytes */
639 {
640 int bytes; /* Bytes read */
641 char len[32]; /* Length string */
642
643
644 DEBUG_printf(("httpRead(%08x, %08x, %d)\n", http, buffer, length));
645
646 if (http == NULL || buffer == NULL)
647 return (-1);
648
649 http->activity = time(NULL);
650
651 if (length <= 0)
652 return (0);
653
654 if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
655 http->data_remaining <= 0 &&
656 (http->state == HTTP_GET_SEND || http->state == HTTP_POST_RECV ||
657 http->state == HTTP_POST_SEND || http->state == HTTP_PUT_RECV))
658 {
659 if (httpGets(len, sizeof(len), http) == NULL)
660 return (0);
661
662 http->data_remaining = strtol(len, NULL, 16);
663 }
664
665 DEBUG_printf(("httpRead: data_remaining = %d\n", http->data_remaining));
666
667 if (http->data_remaining == 0)
668 {
669 /*
670 * A zero-length chunk ends a transfer; unless we are reading POST
671 * data, go idle...
672 */
673
674 if (http->state == HTTP_POST_RECV)
675 http->state ++;
676 else
677 http->state = HTTP_WAITING;
678
679 return (0);
680 }
681 else if (length > http->data_remaining)
682 length = http->data_remaining;
683
684 if (http->used > 0)
685 {
686 if (length > http->used)
687 length = http->used;
688
689 bytes = length;
690
691 DEBUG_printf(("httpRead: grabbing %d bytes from input buffer...\n", bytes));
692
693 memcpy(buffer, http->buffer, length);
694 http->used -= length;
695
696 if (http->used > 0)
697 memcpy(http->buffer, http->buffer + length, http->used);
698 }
699 else
700 {
701 DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length));
702 bytes = recv(http->fd, buffer, length, 0);
703 DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes));
704 }
705
706 if (bytes > 0)
707 http->data_remaining -= bytes;
708
709 if (http->data_remaining == 0 && http->data_encoding != HTTP_ENCODE_CHUNKED)
710 {
711 if (http->state == HTTP_POST_RECV)
712 http->state ++;
713 else
714 http->state = HTTP_WAITING;
715 }
716
717 return (bytes);
718 }
719
720
721 /*
722 * 'httpWrite()' - Write data to a HTTP connection.
723 */
724
725 int /* O - Number of bytes written */
726 httpWrite(http_t *http, /* I - HTTP data */
727 char *buffer, /* I - Buffer for data */
728 int length) /* I - Number of bytes to write */
729 {
730 int tbytes, /* Total bytes sent */
731 bytes; /* Bytes sent */
732 char len[32]; /* Length string */
733
734
735 if (http == NULL || buffer == NULL)
736 return (-1);
737
738 http->activity = time(NULL);
739
740 if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
741 (http->state == HTTP_GET_SEND || http->state == HTTP_POST_RECV ||
742 http->state == HTTP_POST_SEND || http->state == HTTP_PUT_RECV))
743 {
744 sprintf(len, "%x\r\n", length);
745 if (send(http->fd, len, strlen(len), 0) < 3)
746 return (-1);
747 }
748
749 if (length == 0)
750 {
751 /*
752 * A zero-length chunk ends a transfer; unless we are sending POST
753 * data, go idle...
754 */
755
756 if (http->state == HTTP_POST_RECV)
757 http->state ++;
758 else
759 http->state = HTTP_WAITING;
760
761 return (0);
762 }
763
764 tbytes = 0;
765
766 while (length > 0)
767 {
768 bytes = send(http->fd, buffer, length, 0);
769 if (bytes < 0)
770 {
771 DEBUG_puts("httpWrite: error writing data...\n");
772 return (-1);
773 }
774
775 buffer += bytes;
776 tbytes += bytes;
777 length -= bytes;
778 if (http->data_encoding == HTTP_ENCODE_LENGTH)
779 http->data_remaining -= bytes;
780 }
781
782 if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
783 {
784 /*
785 * Finished with the transfer; unless we are sending POST data, go idle...
786 */
787
788 if (http->state == HTTP_POST_RECV)
789 http->state ++;
790 else
791 http->state = HTTP_WAITING;
792 }
793
794 DEBUG_printf(("httpWrite: wrote %d bytes...\n", tbytes));
795
796 return (tbytes);
797 }
798
799
800 /*
801 * 'httpGets()' - Get a line of text from a HTTP connection.
802 */
803
804 char * /* O - Line or NULL */
805 httpGets(char *line, /* I - Line to read into */
806 int length, /* I - Max length of buffer */
807 http_t *http) /* I - HTTP data */
808 {
809 char *lineptr, /* Pointer into line */
810 *bufptr, /* Pointer into input buffer */
811 *bufend; /* Pointer to end of buffer */
812 int bytes; /* Number of bytes read */
813
814
815 DEBUG_printf(("httpGets(%08x, %d, %08x)\n", line, length, http));
816
817 if (http == NULL || line == NULL)
818 return (NULL);
819
820 /*
821 * Pre-scan the buffer and see if there is a newline in there...
822 */
823
824 do
825 {
826 bufptr = http->buffer;
827 bufend = http->buffer + http->used;
828
829 while (bufptr < bufend)
830 if (*bufptr == 0x0a)
831 break;
832 else
833 bufptr ++;
834
835 if (bufptr >= bufend)
836 {
837 /*
838 * No newline; see if there is more data to be read...
839 */
840
841 if ((bytes = recv(http->fd, bufend, HTTP_MAX_BUFFER - http->used, 0)) < 1)
842 {
843 /*
844 * Nope, can't get a line this time...
845 */
846
847 return (NULL);
848 }
849 else
850 {
851 /*
852 * Yup, update the amount used and the end pointer...
853 */
854
855 http->used += bytes;
856 bufend += bytes;
857 }
858 }
859 }
860 while (bufptr >= bufend);
861
862 http->activity = time(NULL);
863
864 /*
865 * Read a line from the buffer...
866 */
867
868 lineptr = line;
869 bufptr = http->buffer;
870 bytes = 0;
871
872 while (bufptr < bufend && bytes < length)
873 {
874 bytes ++;
875
876 if (*bufptr == 0x0a)
877 {
878 bufptr ++;
879 *lineptr = '\0';
880
881 http->used -= bytes;
882 if (http->used > 0)
883 memcpy(http->buffer, bufptr, http->used);
884
885 return (line);
886 }
887 else if (*bufptr == 0x0d)
888 bufptr ++;
889 else
890 *lineptr++ = *bufptr++;
891 }
892
893 return (NULL);
894 }
895
896
897 /*
898 * 'httpPrintf()' - Print a formatted string to a HTTP connection.
899 */
900
901 int /* O - Number of bytes written */
902 httpPrintf(http_t *http, /* I - HTTP data */
903 const char *format, /* I - printf-style format string */
904 ...) /* I - Additional args as needed */
905 {
906 int bytes; /* Number of bytes to write */
907 char buf[HTTP_MAX_BUFFER]; /* Buffer for formatted string */
908 va_list ap; /* Variable argument pointer */
909
910
911 va_start(ap, format);
912 bytes = vsprintf(buf, format, ap);
913 va_end(ap);
914
915 DEBUG_printf(("httpPrintf: %s", buf));
916
917 return (send(http->fd, buf, bytes, 0));
918 }
919
920
921 /*
922 * 'httpStatus()' - Return a short string describing a HTTP status code.
923 */
924
925 char * /* O - String or NULL */
926 httpStatus(http_status_t status) /* I - HTTP status code */
927 {
928 switch (status)
929 {
930 case HTTP_OK :
931 return ("OK");
932 case HTTP_CREATED :
933 return ("Created");
934 case HTTP_ACCEPTED :
935 return ("Accepted");
936 case HTTP_NO_CONTENT :
937 return ("No Content");
938 case HTTP_NOT_MODIFIED :
939 return ("Not Modified");
940 case HTTP_BAD_REQUEST :
941 return ("Bad Request");
942 case HTTP_UNAUTHORIZED :
943 return ("Unauthorized");
944 case HTTP_FORBIDDEN :
945 return ("Forbidden");
946 case HTTP_NOT_FOUND :
947 return ("Not Found");
948 case HTTP_REQUEST_TOO_LARGE :
949 return ("Request Entity Too Large");
950 case HTTP_URI_TOO_LONG :
951 return ("URI Too Long");
952 case HTTP_NOT_IMPLEMENTED :
953 return ("Not Implemented");
954 case HTTP_NOT_SUPPORTED :
955 return ("Not Supported");
956 default :
957 return ("Unknown");
958 }
959 }
960
961
962 /*
963 * 'httpGetDateString()' - Get a formatted date/time string from a time value.
964 */
965
966 char * /* O - Date/time string */
967 httpGetDateString(time_t t) /* I - UNIX time */
968 {
969 struct tm *tdate;
970 static char datetime[256];
971
972
973 tdate = gmtime(&t);
974 sprintf(datetime, "%s, %02d %s %d %02d:%02d:%02d GMT",
975 days[tdate->tm_wday], tdate->tm_mday, months[tdate->tm_mon],
976 tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec);
977
978 return (datetime);
979 }
980
981
982 /*
983 * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
984 */
985
986 time_t /* O - UNIX time */
987 httpGetDateTime(char *s) /* I - Date/time string */
988 {
989 int i; /* Looping var */
990 struct tm tdate; /* Time/date structure */
991 char mon[16]; /* Abbreviated month name */
992 int day, year; /* Day of month and year */
993 int hour, min, sec; /* Time */
994
995
996 if (sscanf(s, "%*s%d%s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6)
997 return (0);
998
999 for (i = 0; i < 12; i ++)
1000 if (strcasecmp(mon, months[i]) == 0)
1001 break;
1002
1003 if (i >= 12)
1004 return (0);
1005
1006 tdate.tm_mon = i;
1007 tdate.tm_mday = day;
1008 tdate.tm_year = year - 1900;
1009 tdate.tm_hour = hour;
1010 tdate.tm_min = min;
1011 tdate.tm_sec = sec;
1012 tdate.tm_isdst = 0;
1013
1014 return (mktime(&tdate));
1015 }
1016
1017
1018 /*
1019 * 'httpUpdate()' - Update the current HTTP state for incoming data.
1020 */
1021
1022 http_status_t /* O - HTTP status */
1023 httpUpdate(http_t *http) /* I - HTTP data */
1024 {
1025 char line[1024], /* Line from connection... */
1026 *value; /* Pointer to value on line */
1027 http_field_t field; /* Field index */
1028 int major, minor; /* HTTP version numbers */
1029 http_status_t status; /* Authorization status */
1030
1031
1032 DEBUG_printf(("httpUpdate(%08x)\n", http));
1033
1034 /*
1035 * If we haven't issued any commands, then there is nothing to "update"...
1036 */
1037
1038 if (http->state == HTTP_WAITING)
1039 return (HTTP_CONTINUE);
1040
1041 /*
1042 * Grab all of the lines we can from the connection...
1043 */
1044
1045 while (httpGets(line, sizeof(line), http) != NULL)
1046 {
1047 DEBUG_puts(line);
1048
1049 if (line[0] == '\0')
1050 {
1051 /*
1052 * Blank line means the start of the data section (if any). Return
1053 * the result code, too...
1054 *
1055 * If we get status 100 (HTTP_CONTINUE), then we *don't* change states.
1056 * Instead, we just return HTTP_CONTINUE to the caller and keep on
1057 * tryin'...
1058 */
1059
1060 if (http->status == HTTP_CONTINUE)
1061 return (http->status);
1062
1063 httpGetLength(http);
1064
1065 switch (http->state)
1066 {
1067 case HTTP_GET :
1068 case HTTP_POST :
1069 case HTTP_POST_RECV :
1070 case HTTP_PUT :
1071 http->state ++;
1072 break;
1073
1074 default :
1075 http->state = HTTP_WAITING;
1076 break;
1077 }
1078
1079 return (http->status);
1080 }
1081 else if (strncmp(line, "HTTP/", 5) == 0)
1082 {
1083 /*
1084 * Got the beginning of a response...
1085 */
1086
1087 if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &status) != 3)
1088 return (HTTP_ERROR);
1089
1090 http->version = (http_version_t)(major * 100 + minor);
1091 http->status = status;
1092 }
1093 else if ((value = strchr(line, ':')) != NULL)
1094 {
1095 /*
1096 * Got a value...
1097 */
1098
1099 *value++ = '\0';
1100 while (isspace(*value))
1101 value ++;
1102
1103 /*
1104 * Be tolerants of servers that send unknown attribute fields...
1105 */
1106
1107 if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN)
1108 {
1109 DEBUG_printf(("httpUpdate: unknown field %s seen!\n", line));
1110 continue;
1111 }
1112
1113 httpSetField(http, field, value);
1114 }
1115 else
1116 return (HTTP_ERROR);
1117 }
1118
1119 /*
1120 * If we haven't already returned, then there is nothing new...
1121 */
1122
1123 return (HTTP_CONTINUE);
1124 }
1125
1126
1127 /*
1128 * 'httpDecode64()' - Base64-decode a string.
1129 */
1130
1131 char * /* O - Decoded string */
1132 httpDecode64(char *out, /* I - String to write to */
1133 char *in) /* I - String to read from */
1134 {
1135 int pos, /* Bit position */
1136 base64; /* Value of this character */
1137 char *outptr; /* Output pointer */
1138
1139
1140 for (outptr = out, pos = 0; *in != '\0'; in ++)
1141 {
1142 /*
1143 * Decode this character into a number from 0 to 63...
1144 */
1145
1146 if (*in >= 'A' && *in <= 'Z')
1147 base64 = *in - 'A';
1148 else if (*in >= 'a' && *in <= 'z')
1149 base64 = *in - 'a' + 26;
1150 else if (*in >= '0' && *in <= '9')
1151 base64 = *in - '0' + 52;
1152 else if (*in == '+')
1153 base64 = 62;
1154 else if (*in == '/')
1155 base64 = 63;
1156 else if (*in == '=')
1157 break;
1158 else
1159 continue;
1160
1161 /*
1162 * Store the result in the appropriate chars...
1163 */
1164
1165 switch (pos)
1166 {
1167 case 0 :
1168 *outptr = base64 << 2;
1169 pos ++;
1170 break;
1171 case 1 :
1172 *outptr++ |= (base64 >> 4) & 3;
1173 *outptr = (base64 << 4) & 255;
1174 pos ++;
1175 break;
1176 case 2 :
1177 *outptr++ |= (base64 >> 2) & 15;
1178 *outptr = (base64 << 6) & 255;
1179 pos ++;
1180 break;
1181 case 3 :
1182 *outptr++ |= base64;
1183 pos = 0;
1184 break;
1185 }
1186 }
1187
1188 *outptr = '\0';
1189
1190 /*
1191 * Return the decoded string...
1192 */
1193
1194 return (out);
1195 }
1196
1197
1198 /*
1199 * 'httpEncode64()' - Base64-encode a string.
1200 */
1201
1202 char * /* O - Encoded string */
1203 httpEncode64(char *out, /* I - String to write to */
1204 char *in) /* I - String to read from */
1205 {
1206 char *outptr; /* Output pointer */
1207 static char base64[] = /* Base64 characters... */
1208 {
1209 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1210 "abcdefghijklmnopqrstuvwxyz"
1211 "0123456789"
1212 "+/"
1213 };
1214
1215
1216 for (outptr = out; *in != '\0'; in ++)
1217 {
1218 /*
1219 * Encode the up to 3 characters as 4 Base64 numbers...
1220 */
1221
1222 *outptr ++ = base64[in[0] >> 2];
1223 *outptr ++ = base64[((in[0] << 4) | (in[1] >> 4)) & 63];
1224
1225 in ++;
1226 if (*in == '\0')
1227 break;
1228
1229 *outptr ++ = base64[((in[0] << 2) | (in[1] >> 6)) & 63];
1230
1231 in ++;
1232 if (*in == '\0')
1233 break;
1234
1235 *outptr ++ = base64[in[0] & 63];
1236 }
1237
1238 *outptr ++ = '=';
1239 *outptr = '\0';
1240
1241 /*
1242 * Return the encoded string...
1243 */
1244
1245 return (out);
1246 }
1247
1248
1249 /*
1250 * 'httpGetLength()' - Get the amount of data remaining from the
1251 * content-length or transfer-encoding fields.
1252 */
1253
1254 int
1255 httpGetLength(http_t *http) /* I - HTTP data */
1256 {
1257 if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0)
1258 {
1259 http->data_encoding = HTTP_ENCODE_CHUNKED;
1260 http->data_remaining = 0;
1261 }
1262 else
1263 {
1264 http->data_encoding = HTTP_ENCODE_LENGTH;
1265
1266 /*
1267 * The following is a hack for HTTP servers that don't send a
1268 * content-length or transfer-encoding field...
1269 *
1270 * If there is no content-length then the connection must close
1271 * after the transfer is complete...
1272 */
1273
1274 if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0')
1275 http->data_remaining = 2147483647;
1276 else
1277 http->data_remaining = atoi(http->fields[HTTP_FIELD_CONTENT_LENGTH]);
1278 }
1279
1280 return (http->data_remaining);
1281 }
1282
1283
1284 /*
1285 * 'http_field()' - Return the field index for a field name.
1286 */
1287
1288 static http_field_t /* O - Field index */
1289 http_field(char *name) /* I - String name */
1290 {
1291 int i; /* Looping var */
1292
1293
1294 for (i = 0; i < HTTP_FIELD_MAX; i ++)
1295 if (strcasecmp(name, http_fields[i]) == 0)
1296 return ((http_field_t)i);
1297
1298 return (HTTP_FIELD_UNKNOWN);
1299 }
1300
1301
1302 /*
1303 * 'http_send()' - Send a request with all fields and the trailing blank line.
1304 */
1305
1306 static int /* O - 0 on success, non-zero on error */
1307 http_send(http_t *http, /* I - HTTP data */
1308 http_state_t request, /* I - Request code */
1309 char *uri) /* I - URI */
1310 {
1311 int i; /* Looping var */
1312 char *ptr, /* Pointer in buffer */
1313 buf[1024]; /* Encoded URI buffer */
1314 static char *codes[] = /* Request code strings */
1315 {
1316 NULL,
1317 "OPTIONS",
1318 "GET",
1319 NULL,
1320 "HEAD",
1321 "POST",
1322 NULL,
1323 NULL,
1324 "PUT",
1325 NULL,
1326 "DELETE",
1327 "TRACE",
1328 "CLOSE"
1329 };
1330 static char *hex = "0123456789ABCDEF";
1331 /* Hex digits */
1332
1333
1334 if (http == NULL || uri == NULL)
1335 return (-1);
1336
1337 /*
1338 * Encode the URI as needed...
1339 */
1340
1341 for (ptr = buf; *uri != '\0'; uri ++)
1342 if (*uri <= ' ' || *uri >= 127)
1343 {
1344 *ptr ++ = '%';
1345 *ptr ++ = hex[(*uri >> 4) & 15];
1346 *ptr ++ = hex[*uri & 15];
1347 }
1348 else
1349 *ptr ++ = *uri;
1350
1351 *ptr = '\0';
1352
1353 /*
1354 * Send the request header...
1355 */
1356
1357 http->state = request;
1358 if (request == HTTP_POST || request == HTTP_PUT)
1359 http->state ++;
1360
1361 if (httpPrintf(http, "%s %s HTTP/1.1\n", codes[request], buf) < 1)
1362 {
1363 /*
1364 * Might have lost connection; try to reconnect...
1365 */
1366
1367 if (httpReconnect(http))
1368 return (-1);
1369
1370 /*
1371 * OK, we've reconnected, send the request again...
1372 */
1373
1374 if (httpPrintf(http, "%s %s HTTP/%d.%d\n", codes[request], buf,
1375 http->version / 100, http->version % 100) < 1)
1376 return (-1);
1377 }
1378
1379 for (i = 0; i < HTTP_FIELD_MAX; i ++)
1380 if (http->fields[i][0] != '\0')
1381 {
1382 DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i]));
1383
1384 if (httpPrintf(http, "%s: %s\n", http_fields[i], http->fields[i]) < 1)
1385 return (-1);
1386 }
1387
1388 if (httpPrintf(http, "\n") < 1)
1389 return (-1);
1390
1391 httpClearFields(http);
1392
1393 return (0);
1394 }
1395
1396
1397 /*
1398 * End of "$Id: http.c,v 1.37 1999/06/18 18:36:08 mike Exp $".
1399 */