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