]> sjero.net Git - wget/blob - src/http.c
a180d9a13a7f3792997076f7a4a92d81204405c8
[wget] / src / http.c
1 /* HTTP support.
2    Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
3
4 This file is part of Wget.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #ifdef HAVE_STRING_H
26 # include <string.h>
27 #else
28 # include <strings.h>
29 #endif
30 #include <ctype.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #include <assert.h>
35 #include <errno.h>
36 #if TIME_WITH_SYS_TIME
37 # include <sys/time.h>
38 # include <time.h>
39 #else
40 # if HAVE_SYS_TIME_H
41 #  include <sys/time.h>
42 # else
43 #  include <time.h>
44 # endif
45 #endif
46
47 #ifdef WINDOWS
48 # include <winsock.h>
49 #endif
50
51 #include "wget.h"
52 #include "utils.h"
53 #include "url.h"
54 #include "host.h"
55 #include "rbuf.h"
56 #include "retr.h"
57 #include "headers.h"
58 #include "connect.h"
59 #include "fnmatch.h"
60 #include "netrc.h"
61 #if USE_DIGEST
62 # include "md5.h"
63 #endif
64
65 extern char *version_string;
66
67 #ifndef errno
68 extern int errno;
69 #endif
70 #ifndef h_errno
71 extern int h_errno;
72 #endif
73 \f
74
75 #define TEXTHTML_S "text/html"
76 #define HTTP_ACCEPT "*/*"
77
78 /* Some status code validation macros: */
79 #define H_20X(x)        (((x) >= 200) && ((x) < 300))
80 #define H_PARTIAL(x)    ((x) == HTTP_STATUS_PARTIAL_CONTENTS)
81 #define H_REDIRECTED(x) (((x) == HTTP_STATUS_MOVED_PERMANENTLY) \
82                          || ((x) == HTTP_STATUS_MOVED_TEMPORARILY))
83
84 /* HTTP/1.0 status codes from RFC1945, provided for reference.  */
85 /* Successful 2xx.  */
86 #define HTTP_STATUS_OK                  200
87 #define HTTP_STATUS_CREATED             201
88 #define HTTP_STATUS_ACCEPTED            202
89 #define HTTP_STATUS_NO_CONTENT          204
90 #define HTTP_STATUS_PARTIAL_CONTENTS    206
91
92 /* Redirection 3xx.  */
93 #define HTTP_STATUS_MULTIPLE_CHOICES    300
94 #define HTTP_STATUS_MOVED_PERMANENTLY   301
95 #define HTTP_STATUS_MOVED_TEMPORARILY   302
96 #define HTTP_STATUS_NOT_MODIFIED        304
97
98 /* Client error 4xx.  */
99 #define HTTP_STATUS_BAD_REQUEST         400
100 #define HTTP_STATUS_UNAUTHORIZED        401
101 #define HTTP_STATUS_FORBIDDEN           403
102 #define HTTP_STATUS_NOT_FOUND           404
103
104 /* Server errors 5xx.  */
105 #define HTTP_STATUS_INTERNAL            500
106 #define HTTP_STATUS_NOT_IMPLEMENTED     501
107 #define HTTP_STATUS_BAD_GATEWAY         502
108 #define HTTP_STATUS_UNAVAILABLE         503
109
110 \f
111 /* Parse the HTTP status line, which is of format:
112
113    HTTP-Version SP Status-Code SP Reason-Phrase
114
115    The function returns the status-code, or -1 if the status line is
116    malformed.  The pointer to reason-phrase is returned in RP.  */
117 static int
118 parse_http_status_line (const char *line, const char **reason_phrase_ptr)
119 {
120   /* (the variables must not be named `major' and `minor', because
121      that breaks compilation with SunOS4 cc.)  */
122   int mjr, mnr, statcode;
123   const char *p;
124
125   *reason_phrase_ptr = NULL;
126
127   /* The standard format of HTTP-Version is: `HTTP/X.Y', where X is
128      major version, and Y is minor version.  */
129   if (strncmp (line, "HTTP/", 5) != 0)
130     return -1;
131   line += 5;
132
133   /* Calculate major HTTP version.  */
134   p = line;
135   for (mjr = 0; ISDIGIT (*line); line++)
136     mjr = 10 * mjr + (*line - '0');
137   if (*line != '.' || p == line)
138     return -1;
139   ++line;
140
141   /* Calculate minor HTTP version.  */
142   p = line;
143   for (mnr = 0; ISDIGIT (*line); line++)
144     mnr = 10 * mnr + (*line - '0');
145   if (*line != ' ' || p == line)
146     return -1;
147   /* Wget will accept only 1.0 and higher HTTP-versions.  The value of
148      minor version can be safely ignored.  */
149   if (mjr < 1)
150     return -1;
151   ++line;
152
153   /* Calculate status code.  */
154   if (!(ISDIGIT (*line) && ISDIGIT (line[1]) && ISDIGIT (line[2])))
155     return -1;
156   statcode = 100 * (*line - '0') + 10 * (line[1] - '0') + (line[2] - '0');
157
158   /* Set up the reason phrase pointer.  */
159   line += 3;
160   /* RFC2068 requires SPC here, but we allow the string to finish
161      here, in case no reason-phrase is present.  */
162   if (*line != ' ')
163     {
164       if (!*line)
165         *reason_phrase_ptr = line;
166       else
167         return -1;
168     }
169   else
170     *reason_phrase_ptr = line + 1;
171
172   return statcode;
173 }
174 \f
175 /* Functions to be used as arguments to header_process(): */
176
177 struct http_process_range_closure {
178   long first_byte_pos;
179   long last_byte_pos;
180   long entity_length;
181 };
182
183 /* Parse the `Content-Range' header and extract the information it
184    contains.  Returns 1 if successful, -1 otherwise.  */
185 static int
186 http_process_range (const char *hdr, void *arg)
187 {
188   struct http_process_range_closure *closure
189     = (struct http_process_range_closure *)arg;
190   long num;
191
192   /* Certain versions of Nutscape proxy server send out
193      `Content-Length' without "bytes" specifier, which is a breach of
194      RFC2068 (as well as the HTTP/1.1 draft which was current at the
195      time).  But hell, I must support it...  */
196   if (!strncasecmp (hdr, "bytes", 5))
197     {
198       hdr += 5;
199       hdr += skip_lws (hdr);
200       if (!*hdr)
201         return 0;
202     }
203   if (!ISDIGIT (*hdr))
204     return 0;
205   for (num = 0; ISDIGIT (*hdr); hdr++)
206     num = 10 * num + (*hdr - '0');
207   if (*hdr != '-' || !ISDIGIT (*(hdr + 1)))
208     return 0;
209   closure->first_byte_pos = num;
210   ++hdr;
211   for (num = 0; ISDIGIT (*hdr); hdr++)
212     num = 10 * num + (*hdr - '0');
213   if (*hdr != '/' || !ISDIGIT (*(hdr + 1)))
214     return 0;
215   closure->last_byte_pos = num;
216   ++hdr;
217   for (num = 0; ISDIGIT (*hdr); hdr++)
218     num = 10 * num + (*hdr - '0');
219   closure->entity_length = num;
220   return 1;
221 }
222
223 /* Place 1 to ARG if the HDR contains the word "none", 0 otherwise.
224    Used for `Accept-Ranges'.  */
225 static int
226 http_process_none (const char *hdr, void *arg)
227 {
228   int *where = (int *)arg;
229
230   if (strstr (hdr, "none"))
231     *where = 1;
232   else
233     *where = 0;
234   return 1;
235 }
236
237 /* Place the malloc-ed copy of HDR hdr, to the first `;' to ARG.  */
238 static int
239 http_process_type (const char *hdr, void *arg)
240 {
241   char **result = (char **)arg;
242   char *p;
243
244   p = strrchr (hdr, ';');
245   if (p)
246     {
247       int len = p - hdr;
248       *result = (char *)xmalloc (len + 1);
249       memcpy (*result, hdr, len);
250       (*result)[len] = '\0';
251     }
252   else
253     *result = xstrdup (hdr);
254   return 1;
255 }
256
257 \f
258 struct http_stat
259 {
260   long len;                     /* received length */
261   long contlen;                 /* expected length */
262   long restval;                 /* the restart value */
263   int res;                      /* the result of last read */
264   char *newloc;                 /* new location (redirection) */
265   char *remote_time;            /* remote time-stamp string */
266   char *error;                  /* textual HTTP error */
267   int statcode;                 /* status code */
268   long dltime;                  /* time of the download */
269 };
270
271 /* Free the elements of hstat X.  */
272 #define FREEHSTAT(x) do                                 \
273 {                                                       \
274   FREE_MAYBE ((x).newloc);                              \
275   FREE_MAYBE ((x).remote_time);                         \
276   FREE_MAYBE ((x).error);                               \
277   (x).newloc = (x).remote_time = (x).error = NULL;      \
278 } while (0)
279
280 static char *create_authorization_line PARAMS ((const char *, const char *,
281                                                 const char *, const char *,
282                                                 const char *));
283 static char *basic_authentication_encode PARAMS ((const char *, const char *,
284                                                   const char *));
285 static int known_authentication_scheme_p PARAMS ((const char *));
286
287 static time_t http_atotm PARAMS ((char *));
288
289 /* Retrieve a document through HTTP protocol.  It recognizes status
290    code, and correctly handles redirections.  It closes the network
291    socket.  If it receives an error from the functions below it, it
292    will print it if there is enough information to do so (almost
293    always), returning the error to the caller (i.e. http_loop).
294
295    Various HTTP parameters are stored to hs.  Although it parses the
296    response code correctly, it is not used in a sane way.  The caller
297    can do that, though.
298
299    If u->proxy is non-NULL, the URL u will be taken as a proxy URL,
300    and u->proxy->url will be given to the proxy server (bad naming,
301    I'm afraid).  */
302 static uerr_t
303 gethttp (struct urlinfo *u, struct http_stat *hs, int *dt)
304 {
305   char *request, *type, *command, *path;
306   char *user, *passwd;
307   char *pragma_h, *referer, *useragent, *range, *wwwauth, *remhost;
308   char *authenticate_h;
309   char *proxyauth;
310   char *all_headers;
311   char *host_port;
312   int host_port_len;
313   int sock, hcount, num_written, all_length, remport, statcode;
314   long contlen, contrange;
315   struct urlinfo *ou;
316   uerr_t err;
317   FILE *fp;
318   int auth_tried_already;
319   struct rbuf rbuf;
320
321   /* Let the others worry about local filename...  */
322   if (!(*dt & HEAD_ONLY))
323     assert (u->local != NULL);
324
325   authenticate_h = 0;
326   auth_tried_already = 0;
327
328  again:
329   /* We need to come back here when the initial attempt to retrieve
330      without authorization header fails.  */
331
332   /* Initialize certain elements of struct hstat.  */
333   hs->len = 0L;
334   hs->contlen = -1;
335   hs->res = -1;
336   hs->newloc = NULL;
337   hs->remote_time = NULL;
338   hs->error = NULL;
339
340   /* Which structure to use to retrieve the original URL data.  */
341   if (u->proxy)
342     ou = u->proxy;
343   else
344     ou = u;
345
346   /* First: establish the connection.  */
347   logprintf (LOG_VERBOSE, _("Connecting to %s:%hu... "), u->host, u->port);
348   err = make_connection (&sock, u->host, u->port);
349   switch (err)
350     {
351     case HOSTERR:
352       logputs (LOG_VERBOSE, "\n");
353       logprintf (LOG_NOTQUIET, "%s: %s.\n", u->host, herrmsg (h_errno));
354       return HOSTERR;
355       break;
356     case CONSOCKERR:
357       logputs (LOG_VERBOSE, "\n");
358       logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
359       return CONSOCKERR;
360       break;
361     case CONREFUSED:
362       logputs (LOG_VERBOSE, "\n");
363       logprintf (LOG_NOTQUIET,
364                  _("Connection to %s:%hu refused.\n"), u->host, u->port);
365       CLOSE (sock);
366       return CONREFUSED;
367     case CONERROR:
368       logputs (LOG_VERBOSE, "\n");
369       logprintf (LOG_NOTQUIET, "connect: %s\n", strerror (errno));
370       CLOSE (sock);
371       return CONERROR;
372       break;
373     case NOCONERROR:
374       /* Everything is fine!  */
375       logputs (LOG_VERBOSE, _("connected!\n"));
376       break;
377     default:
378       abort ();
379       break;
380     } /* switch */
381
382   if (u->proxy)
383     path = u->proxy->url;
384   else
385     path = u->path;
386   
387   command = (*dt & HEAD_ONLY) ? "HEAD" : "GET";
388   referer = NULL;
389   if (ou->referer)
390     {
391       referer = (char *)alloca (9 + strlen (ou->referer) + 3);
392       sprintf (referer, "Referer: %s\r\n", ou->referer);
393     }
394   if (*dt & SEND_NOCACHE)
395     pragma_h = "Pragma: no-cache\r\n";
396   else
397     pragma_h = "";
398   if (hs->restval)
399     {
400       range = (char *)alloca (13 + numdigit (hs->restval) + 4);
401       /* #### Gag me!  Some servers (e.g. WebSitePro) have been known
402          to misinterpret the following `Range' format, and return the
403          document as multipart/x-byte-ranges MIME type!
404
405          #### TODO: Interpret MIME types, recognize bullshits similar
406          the one described above, and deal with them!  */
407       sprintf (range, "Range: bytes=%ld-\r\n", hs->restval);
408     }
409   else
410     range = NULL;
411   if (opt.useragent)
412     STRDUP_ALLOCA (useragent, opt.useragent);
413   else
414     {
415       useragent = (char *)alloca (10 + strlen (version_string));
416       sprintf (useragent, "Wget/%s", version_string);
417     }
418   /* Construct the authentication, if userid is present.  */
419   user = ou->user;
420   passwd = ou->passwd;
421   search_netrc (u->host, (const char **)&user, (const char **)&passwd, 0);
422   user = user ? user : opt.http_user;
423   passwd = passwd ? passwd : opt.http_passwd;
424
425   wwwauth = NULL;
426   if (authenticate_h && user && passwd)
427     {
428       wwwauth = create_authorization_line (authenticate_h, user, passwd,
429                                            command, ou->path);
430     }
431
432   proxyauth = NULL;
433   if (u->proxy)
434     {
435       char *proxy_user, *proxy_passwd;
436       /* For normal username and password, URL components override
437          command-line/wgetrc parameters.  With proxy authentication,
438          it's the reverse, because proxy URLs are normally the
439          "permanent" ones, so command-line args should take
440          precedence.  */
441       if (opt.proxy_user && opt.proxy_passwd)
442         {
443           proxy_user = opt.proxy_user;
444           proxy_passwd = opt.proxy_passwd;
445         }
446       else
447         {
448           proxy_user = u->user;
449           proxy_passwd = u->passwd;
450         }
451       /* #### This is junky.  Can't the proxy request, say, `Digest'
452          authentication?  */
453       if (proxy_user && proxy_passwd)
454         proxyauth = basic_authentication_encode (proxy_user, proxy_passwd,
455                                                  "Proxy-Authorization");
456     }
457   remhost = ou->host;
458   remport = ou->port;
459
460   if (remport == 80)
461     {
462       host_port = NULL;
463       host_port_len = 0;
464     }
465   else
466     {
467       host_port = (char *)alloca (numdigit (remport) + 2);
468       host_port_len = sprintf (host_port, ":%d", remport);
469     }
470
471   /* Allocate the memory for the request.  */
472   request = (char *)alloca (strlen (command) + strlen (path)
473                             + strlen (useragent)
474                             + strlen (remhost) + host_port_len
475                             + strlen (HTTP_ACCEPT)
476                             + (referer ? strlen (referer) : 0)
477                             + (wwwauth ? strlen (wwwauth) : 0)
478                             + (proxyauth ? strlen (proxyauth) : 0)
479                             + (range ? strlen (range) : 0)
480                             + strlen (pragma_h)
481                             + (opt.user_header ? strlen (opt.user_header) : 0)
482                             + 64);
483   /* Construct the request.  */
484   sprintf (request, "\
485 %s %s HTTP/1.0\r\n\
486 User-Agent: %s\r\n\
487 Host: %s%s\r\n\
488 Accept: %s\r\n\
489 %s%s%s%s%s%s\r\n",
490            command, path, useragent, remhost,
491            host_port ? host_port : "",
492            HTTP_ACCEPT, referer ? referer : "",
493            wwwauth ? wwwauth : "", 
494            proxyauth ? proxyauth : "", 
495            range ? range : "",
496            pragma_h, 
497            opt.user_header ? opt.user_header : "");
498   DEBUGP (("---request begin---\n%s---request end---\n", request));
499    /* Free the temporary memory.  */
500   FREE_MAYBE (wwwauth);
501   FREE_MAYBE (proxyauth);
502
503   /* Send the request to server.  */
504   num_written = iwrite (sock, request, strlen (request));
505   if (num_written < 0)
506     {
507       logputs (LOG_VERBOSE, _("Failed writing HTTP request.\n"));
508       CLOSE (sock);
509       return WRITEFAILED;
510     }
511   logprintf (LOG_VERBOSE, _("%s request sent, awaiting response... "),
512              u->proxy ? "Proxy" : "HTTP");
513   contlen = contrange = -1;
514   type = NULL;
515   statcode = -1;
516   *dt &= ~RETROKF;
517
518   /* Before reading anything, initialize the rbuf.  */
519   rbuf_initialize (&rbuf, sock);
520
521   all_headers = NULL;
522   all_length = 0;
523   /* Header-fetching loop.  */
524   hcount = 0;
525   while (1)
526     {
527       char *hdr;
528       int status;
529
530       ++hcount;
531       /* Get the header.  */
532       status = header_get (&rbuf, &hdr,
533                            /* Disallow continuations for status line.  */
534                            (hcount == 1 ? HG_NO_CONTINUATIONS : HG_NONE));
535
536       /* Check for errors.  */
537       if (status == HG_EOF && *hdr)
538         {
539           /* This used to be an unconditional error, but that was
540              somewhat controversial, because of a large number of
541              broken CGI's that happily "forget" to send the second EOL
542              before closing the connection of a HEAD request.
543
544              So, the deal is to check whether the header is empty
545              (*hdr is zero if it is); if yes, it means that the
546              previous header was fully retrieved, and that -- most
547              probably -- the request is complete.  "...be liberal in
548              what you accept."  Oh boy.  */
549           logputs (LOG_VERBOSE, "\n");
550           logputs (LOG_NOTQUIET, _("End of file while parsing headers.\n"));
551           free (hdr);
552           FREE_MAYBE (type);
553           FREE_MAYBE (hs->newloc);
554           FREE_MAYBE (all_headers);
555           CLOSE (sock);
556           return HEOF;
557         }
558       else if (status == HG_ERROR)
559         {
560           logputs (LOG_VERBOSE, "\n");
561           logprintf (LOG_NOTQUIET, _("Read error (%s) in headers.\n"),
562                      strerror (errno));
563           free (hdr);
564           FREE_MAYBE (type);
565           FREE_MAYBE (hs->newloc);
566           FREE_MAYBE (all_headers);
567           CLOSE (sock);
568           return HERR;
569         }
570
571       /* If the headers are to be saved to a file later, save them to
572          memory now.  */
573       if (opt.save_headers)
574         {
575           int lh = strlen (hdr);
576           all_headers = (char *)xrealloc (all_headers, all_length + lh + 2);
577           memcpy (all_headers + all_length, hdr, lh);
578           all_length += lh;
579           all_headers[all_length++] = '\n';
580           all_headers[all_length] = '\0';
581         }
582
583       /* Print the header if requested.  */
584       if (opt.server_response && hcount != 1)
585         logprintf (LOG_VERBOSE, "\n%d %s", hcount, hdr);
586
587       /* Check for status line.  */
588       if (hcount == 1)
589         {
590           const char *error;
591           /* Parse the first line of server response.  */
592           statcode = parse_http_status_line (hdr, &error);
593           hs->statcode = statcode;
594           /* Store the descriptive response.  */
595           if (statcode == -1) /* malformed response */
596             {
597               /* A common reason for "malformed response" error is the
598                  case when no data was actually received.  Handle this
599                  special case.  */
600               if (!*hdr)
601                 hs->error = xstrdup (_("No data received"));
602               else
603                 hs->error = xstrdup (_("Malformed status line"));
604               free (hdr);
605               break;
606             }
607           else if (!*error)
608             hs->error = xstrdup (_("(no description)"));
609           else
610             hs->error = xstrdup (error);
611
612           if ((statcode != -1)
613 #ifdef DEBUG
614               && !opt.debug
615 #endif
616               )
617             logprintf (LOG_VERBOSE, "%d %s", statcode, error);
618
619           goto done_header;
620         }
621
622       /* Exit on empty header.  */
623       if (!*hdr)
624         {
625           free (hdr);
626           break;
627         }
628
629       /* Try getting content-length.  */
630       if (contlen == -1 && !opt.ignore_length)
631         if (header_process (hdr, "Content-Length", header_extract_number,
632                             &contlen))
633           goto done_header;
634       /* Try getting content-type.  */
635       if (!type)
636         if (header_process (hdr, "Content-Type", http_process_type, &type))
637           goto done_header;
638       /* Try getting location.  */
639       if (!hs->newloc)
640         if (header_process (hdr, "Location", header_strdup, &hs->newloc))
641           goto done_header;
642       /* Try getting last-modified.  */
643       if (!hs->remote_time)
644         if (header_process (hdr, "Last-Modified", header_strdup,
645                             &hs->remote_time))
646           goto done_header;
647       /* Try getting www-authentication.  */
648       if (!authenticate_h)
649         if (header_process (hdr, "WWW-Authenticate", header_strdup,
650                             &authenticate_h))
651           goto done_header;
652       /* Check for accept-ranges header.  If it contains the word
653          `none', disable the ranges.  */
654       if (*dt & ACCEPTRANGES)
655         {
656           int nonep;
657           if (header_process (hdr, "Accept-Ranges", http_process_none, &nonep))
658             {
659               if (nonep)
660                 *dt &= ~ACCEPTRANGES;
661               goto done_header;
662             }
663         }
664       /* Try getting content-range.  */
665       if (contrange == -1)
666         {
667           struct http_process_range_closure closure;
668           if (header_process (hdr, "Content-Range", http_process_range, &closure))
669             {
670               contrange = closure.first_byte_pos;
671               goto done_header;
672             }
673         }
674     done_header:
675       free (hdr);
676     }
677
678   logputs (LOG_VERBOSE, "\n");
679
680   if ((statcode == HTTP_STATUS_UNAUTHORIZED)
681       && authenticate_h)
682     {
683       /* Authorization is required.  */
684       FREE_MAYBE (type);
685       type = NULL;
686       FREEHSTAT (*hs);
687       CLOSE (sock);
688       if (auth_tried_already)
689         {
690           /* If we have tried it already, then there is not point
691              retrying it.  */
692           logputs (LOG_NOTQUIET, _("Authorization failed.\n"));
693           free (authenticate_h);
694           return AUTHFAILED;
695         }
696       else if (!known_authentication_scheme_p (authenticate_h))
697         {
698           free (authenticate_h);
699           logputs (LOG_NOTQUIET, _("Unknown authentication scheme.\n"));
700           return AUTHFAILED;
701         }
702       else
703         {
704           auth_tried_already = 1;
705           goto again;
706         }
707     }
708   /* We do not need this anymore.  */
709   if (authenticate_h)
710     {
711       free (authenticate_h);
712       authenticate_h = NULL;
713     }
714
715   /* 20x responses are counted among successful by default.  */
716   if (H_20X (statcode))
717     *dt |= RETROKF;
718
719   if (type && !strncasecmp (type, TEXTHTML_S, strlen (TEXTHTML_S)))
720     *dt |= TEXTHTML;
721   else
722     /* We don't assume text/html by default.  */
723     *dt &= ~TEXTHTML;
724
725   if (contrange == -1)
726     hs->restval = 0;
727   else if (contrange != hs->restval ||
728            (H_PARTIAL (statcode) && contrange == -1))
729     {
730       /* This means the whole request was somehow misunderstood by the
731          server.  Bail out.  */
732       FREE_MAYBE (type);
733       FREE_MAYBE (hs->newloc);
734       FREE_MAYBE (all_headers);
735       CLOSE (sock);
736       return RANGEERR;
737     }
738
739   if (hs->restval)
740     {
741       if (contlen != -1)
742         contlen += contrange;
743       else
744         contrange = -1;        /* If conent-length was not sent,
745                                   content-range will be ignored.  */
746     }
747   hs->contlen = contlen;
748
749   /* Return if redirected.  */
750   if (H_REDIRECTED (statcode) || statcode == HTTP_STATUS_MULTIPLE_CHOICES)
751     {
752       /* RFC2068 says that in case of the 300 (multiple choices)
753          response, the server can output a preferred URL through
754          `Location' header; otherwise, the request should be treated
755          like GET.  So, if the location is set, it will be a
756          redirection; otherwise, just proceed normally.  */
757       if (statcode == HTTP_STATUS_MULTIPLE_CHOICES && !hs->newloc)
758         *dt |= RETROKF;
759       else
760         {
761           logprintf (LOG_VERBOSE,
762                      _("Location: %s%s\n"),
763                      hs->newloc ? hs->newloc : _("unspecified"),
764                      hs->newloc ? _(" [following]") : "");
765           CLOSE (sock);
766           FREE_MAYBE (type);
767           FREE_MAYBE (all_headers);
768           return NEWLOCATION;
769         }
770     }
771   if (opt.verbose)
772     {
773       if ((*dt & RETROKF) && !opt.server_response)
774         {
775           /* No need to print this output if the body won't be
776              downloaded at all, or if the original server response is
777              printed.  */
778           logputs (LOG_VERBOSE, _("Length: "));
779           if (contlen != -1)
780             {
781               logputs (LOG_VERBOSE, legible (contlen));
782               if (contrange != -1)
783                 logprintf (LOG_VERBOSE, _(" (%s to go)"),
784                            legible (contlen - contrange));
785             }
786           else
787             logputs (LOG_VERBOSE,
788                      opt.ignore_length ? _("ignored") : _("unspecified"));
789           if (type)
790             logprintf (LOG_VERBOSE, " [%s]\n", type);
791           else
792             logputs (LOG_VERBOSE, "\n");
793         }
794     }
795   FREE_MAYBE (type);
796   type = NULL;                  /* We don't need it any more.  */
797
798   /* Return if we have no intention of further downloading.  */
799   if (!(*dt & RETROKF) || (*dt & HEAD_ONLY))
800     {
801       /* In case someone cares to look...  */
802       hs->len = 0L;
803       hs->res = 0;
804       FREE_MAYBE (type);
805       FREE_MAYBE (all_headers);
806       CLOSE (sock);
807       return RETRFINISHED;
808     }
809
810   /* Open the local file.  */
811   if (!opt.dfp)
812     {
813       mkalldirs (u->local);
814       if (opt.backups)
815         rotate_backups (u->local);
816       fp = fopen (u->local, hs->restval ? "ab" : "wb");
817       if (!fp)
818         {
819           logprintf (LOG_NOTQUIET, "%s: %s\n", u->local, strerror (errno));
820           CLOSE (sock);
821           FREE_MAYBE (all_headers);
822           return FOPENERR;
823         }
824     }
825   else                      /* opt.dfp */
826     fp = opt.dfp;
827
828   /* #### This confuses the code that checks for file size.  There
829      should be some overhead information.  */
830   if (opt.save_headers)
831     fwrite (all_headers, 1, all_length, fp);
832   reset_timer ();
833   /* Get the contents of the document.  */
834   hs->res = get_contents (sock, fp, &hs->len, hs->restval,
835                           (contlen != -1 ? contlen : 0),
836                           &rbuf);
837   hs->dltime = elapsed_time ();
838   {
839     /* Close or flush the file.  We have to be careful to check for
840        error here.  Checking the result of fwrite() is not enough --
841        errors could go unnoticed!  */
842     int flush_res;
843     if (!opt.dfp)
844       flush_res = fclose (fp);
845     else
846       flush_res = fflush (fp);
847     if (flush_res == EOF)
848       hs->res = -2;
849   }
850   FREE_MAYBE (all_headers);
851   CLOSE (sock);
852   if (hs->res == -2)
853     return FWRITEERR;
854   return RETRFINISHED;
855 }
856
857 /* The genuine HTTP loop!  This is the part where the retrieval is
858    retried, and retried, and retried, and...  */
859 uerr_t
860 http_loop (struct urlinfo *u, char **newloc, int *dt)
861 {
862   static int first_retrieval = 1;
863
864   int count;
865   int local_dot_orig_file_exists = FALSE;
866   int use_ts, got_head = 0;     /* time-stamping info */
867   char *tms, *suf, *locf, *tmrate;
868   uerr_t err;
869   time_t tml = -1, tmr = -1;    /* local and remote time-stamps */
870   long local_size = 0;          /* the size of the local file */
871   struct http_stat hstat;       /* HTTP status */
872   struct stat st;
873
874   *newloc = NULL;
875
876   /* Warn on (likely bogus) wildcard usage in HTTP.  Don't use
877      has_wildcards_p because it would also warn on `?', and we know that
878      shows up in CGI paths a *lot*.  */
879   if (strchr (u->url, '*'))
880     logputs (LOG_VERBOSE, _("Warning: wildcards not supported in HTTP.\n"));
881
882   /* Determine the local filename.  */
883   if (!u->local)
884     u->local = url_filename (u->proxy ? u->proxy : u);
885
886   if (!opt.output_document)
887     locf = u->local;
888   else
889     locf = opt.output_document;
890
891   if (opt.noclobber && file_exists_p (u->local))
892     {
893       /* If opt.noclobber is turned on and file already exists, do not
894          retrieve the file */
895       logprintf (LOG_VERBOSE, _("\
896 File `%s' already there, will not retrieve.\n"), u->local);
897       /* If the file is there, we suppose it's retrieved OK.  */
898       *dt |= RETROKF;
899
900       /* #### Bogusness alert.  */
901       /* If its suffix is "html" or (yuck!) "htm", we suppose it's
902          text/html, a harmless lie.  */
903       if (((suf = suffix (u->local)) != NULL)
904           && (!strcmp (suf, "html") || !strcmp (suf, "htm")))
905         *dt |= TEXTHTML;
906       free (suf);
907       /* Another harmless lie: */
908       return RETROK;
909     }
910
911   use_ts = 0;
912   if (opt.timestamping)
913     {
914       boolean  local_file_exists = FALSE;
915
916       if (opt.backup_converted)
917         /* If -K is specified, we'll act on the assumption that it was specified
918            last time these files were downloaded as well, and instead of just
919            comparing local file X against server file X, we'll compare local
920            file X.orig (if extant, else X) against server file X.  If -K
921            _wasn't_ specified last time, or the server contains files called
922            *.orig, -N will be back to not operating correctly with -k. */
923         {
924           size_t filename_len = strlen(u->local);
925           char*  filename_plus_orig_suffix = malloc(filename_len +
926                                                     sizeof(".orig"));
927
928           /* Would a single s[n]printf() call be faster? */
929           strcpy(filename_plus_orig_suffix, u->local);
930           strcpy(filename_plus_orig_suffix + filename_len, ".orig");
931
932           /* Try to stat() the .orig file. */
933           if (stat(filename_plus_orig_suffix, &st) == 0)
934             {
935               local_file_exists = TRUE;
936               local_dot_orig_file_exists = TRUE;
937             }
938
939           free(filename_plus_orig_suffix);
940         }      
941
942       if (!local_dot_orig_file_exists)
943         /* Couldn't stat() <file>.orig, so try to stat() <file>. */
944         if (stat (u->local, &st) == 0)
945           local_file_exists = TRUE;
946
947       if (local_file_exists)
948         /* There was a local file, so we'll check later to see if the version
949            the server has is the same version we already have, allowing us to
950            skip a download. */
951         {
952           use_ts = 1;
953           tml = st.st_mtime;
954           local_size = st.st_size;
955           got_head = 0;
956         }
957     }
958   /* Reset the counter.  */
959   count = 0;
960   *dt = 0 | ACCEPTRANGES;
961   /* THE loop */
962   do
963     {
964       /* Increment the pass counter.  */
965       ++count;
966       /* Wait before the retrieval (unless this is the very first
967          retrieval).
968          Check if we are retrying or not, wait accordingly - HEH */
969       if (!first_retrieval && (opt.wait || (count && opt.waitretry)))
970         {
971           if (count)
972             {
973               if (count<opt.waitretry)
974                 sleep(count);
975               else
976                 sleep(opt.waitretry);
977             }
978           else
979             sleep (opt.wait);
980         }
981       if (first_retrieval)
982         first_retrieval = 0;
983       /* Get the current time string.  */
984       tms = time_str (NULL);
985       /* Print fetch message, if opt.verbose.  */
986       if (opt.verbose)
987         {
988           char *hurl = str_url (u->proxy ? u->proxy : u, 1);
989           char tmp[15];
990           strcpy (tmp, "        ");
991           if (count > 1)
992             sprintf (tmp, _("(try:%2d)"), count);
993           logprintf (LOG_VERBOSE, "--%s--  %s\n  %s => `%s'\n",
994                      tms, hurl, tmp, locf);
995 #ifdef WINDOWS
996           ws_changetitle (hurl, 1);
997 #endif
998           free (hurl);
999         }
1000
1001       /* Default document type is empty.  However, if spider mode is
1002          on or time-stamping is employed, HEAD_ONLY commands is
1003          encoded within *dt.  */
1004       if (opt.spider || (use_ts && !got_head))
1005         *dt |= HEAD_ONLY;
1006       else
1007         *dt &= ~HEAD_ONLY;
1008       /* Assume no restarting.  */
1009       hstat.restval = 0L;
1010       /* Decide whether or not to restart.  */
1011       if (((count > 1 && (*dt & ACCEPTRANGES)) || opt.always_rest)
1012           && file_exists_p (u->local))
1013         if (stat (u->local, &st) == 0)
1014           hstat.restval = st.st_size;
1015       /* Decide whether to send the no-cache directive.  */
1016       if (u->proxy && (count > 1 || (opt.proxy_cache == 0)))
1017         *dt |= SEND_NOCACHE;
1018       else
1019         *dt &= ~SEND_NOCACHE;
1020
1021       /* Try fetching the document, or at least its head.  :-) */
1022       err = gethttp (u, &hstat, dt);
1023       /* Time?  */
1024       tms = time_str (NULL);
1025       /* Get the new location (with or without the redirection).  */
1026       if (hstat.newloc)
1027         *newloc = xstrdup (hstat.newloc);
1028       switch (err)
1029         {
1030         case HERR: case HEOF: case CONSOCKERR: case CONCLOSED:
1031         case CONERROR: case READERR: case WRITEFAILED:
1032         case RANGEERR:
1033           /* Non-fatal errors continue executing the loop, which will
1034              bring them to "while" statement at the end, to judge
1035              whether the number of tries was exceeded.  */
1036           FREEHSTAT (hstat);
1037           printwhat (count, opt.ntry);
1038           continue;
1039           break;
1040         case HOSTERR: case CONREFUSED: case PROXERR: case AUTHFAILED:
1041           /* Fatal errors just return from the function.  */
1042           FREEHSTAT (hstat);
1043           return err;
1044           break;
1045         case FWRITEERR: case FOPENERR:
1046           /* Another fatal error.  */
1047           logputs (LOG_VERBOSE, "\n");
1048           logprintf (LOG_NOTQUIET, _("Cannot write to `%s' (%s).\n"),
1049                      u->local, strerror (errno));
1050           FREEHSTAT (hstat);
1051           return err;
1052           break;
1053         case NEWLOCATION:
1054           /* Return the new location to the caller.  */
1055           if (!hstat.newloc)
1056             {
1057               logprintf (LOG_NOTQUIET,
1058                          _("ERROR: Redirection (%d) without location.\n"),
1059                          hstat.statcode);
1060               return WRONGCODE;
1061             }
1062           FREEHSTAT (hstat);
1063           return NEWLOCATION;
1064           break;
1065         case RETRFINISHED:
1066           /* Deal with you later.  */
1067           break;
1068         default:
1069           /* All possibilities should have been exhausted.  */
1070           abort ();
1071         }
1072       if (!(*dt & RETROKF))
1073         {
1074           if (!opt.verbose)
1075             {
1076               /* #### Ugly ugly ugly! */
1077               char *hurl = str_url (u->proxy ? u->proxy : u, 1);
1078               logprintf (LOG_NONVERBOSE, "%s:\n", hurl);
1079               free (hurl);
1080             }
1081           logprintf (LOG_NOTQUIET, _("%s ERROR %d: %s.\n"),
1082                      tms, hstat.statcode, hstat.error);
1083           logputs (LOG_VERBOSE, "\n");
1084           FREEHSTAT (hstat);
1085           return WRONGCODE;
1086         }
1087
1088       /* Did we get the time-stamp?  */
1089       if (!got_head)
1090         {
1091           if (opt.timestamping && !hstat.remote_time)
1092             {
1093               logputs (LOG_NOTQUIET, _("\
1094 Last-modified header missing -- time-stamps turned off.\n"));
1095             }
1096           else if (hstat.remote_time)
1097             {
1098               /* Convert the date-string into struct tm.  */
1099               tmr = http_atotm (hstat.remote_time);
1100               if (tmr == (time_t) (-1))
1101                 logputs (LOG_VERBOSE, _("\
1102 Last-modified header invalid -- time-stamp ignored.\n"));
1103             }
1104         }
1105
1106       /* The time-stamping section.  */
1107       if (use_ts)
1108         {
1109           got_head = 1;
1110           *dt &= ~HEAD_ONLY;
1111           use_ts = 0;           /* no more time-stamping */
1112           count = 0;            /* the retrieve count for HEAD is
1113                                    reset */
1114           if (hstat.remote_time && tmr != (time_t) (-1))
1115             {
1116               /* Now time-stamping can be used validly.  Time-stamping
1117                  means that if the sizes of the local and remote file
1118                  match, and local file is newer than the remote file,
1119                  it will not be retrieved.  Otherwise, the normal
1120                  download procedure is resumed.  */
1121               if (tml >= tmr &&
1122                   (hstat.contlen == -1 || local_size == hstat.contlen))
1123                 {
1124                   if (local_dot_orig_file_exists)
1125                     /* We can't collapse this down into just one logprintf()
1126                        call with a variable set to u->local or the .orig
1127                        filename because we have to malloc() space for the
1128                        latter, and because there are multiple returns above (a
1129                        coding style no-no by many measures, for reasons such as
1130                        this) we'd have to remember to free() the string at each
1131                        one to avoid a memory leak. */
1132                     logprintf (LOG_VERBOSE, _("\
1133 Server file no newer than local file `%s.orig' -- not retrieving.\n\n"),
1134                                u->local);
1135                   else
1136                     logprintf (LOG_VERBOSE, _("\
1137 Server file no newer than local file `%s' -- not retrieving.\n\n"), u->local);
1138                   FREEHSTAT (hstat);
1139                   return RETROK;
1140                 }
1141               else if (tml >= tmr)
1142                 logprintf (LOG_VERBOSE, _("\
1143 The sizes do not match (local %ld) -- retrieving.\n"), local_size);
1144               else
1145                 logputs (LOG_VERBOSE,
1146                          _("Remote file is newer, retrieving.\n"));
1147             }
1148           FREEHSTAT (hstat);
1149           continue;
1150         }
1151       if (!opt.dfp
1152           && (tmr != (time_t) (-1))
1153           && !opt.spider
1154           && ((hstat.len == hstat.contlen) ||
1155               ((hstat.res == 0) &&
1156                ((hstat.contlen == -1) ||
1157                 (hstat.len >= hstat.contlen && !opt.kill_longer)))))
1158         {
1159           touch (u->local, tmr);
1160         }
1161       /* End of time-stamping section.  */
1162
1163       if (opt.spider)
1164         {
1165           logprintf (LOG_NOTQUIET, "%d %s\n\n", hstat.statcode, hstat.error);
1166           return RETROK;
1167         }
1168
1169       /* It is now safe to free the remainder of hstat, since the
1170          strings within it will no longer be used.  */
1171       FREEHSTAT (hstat);
1172
1173       tmrate = rate (hstat.len - hstat.restval, hstat.dltime);
1174
1175       if (hstat.len == hstat.contlen)
1176         {
1177           if (*dt & RETROKF)
1178             {
1179               logprintf (LOG_VERBOSE,
1180                          _("%s (%s) - `%s' saved [%ld/%ld]\n\n"),
1181                          tms, tmrate, locf, hstat.len, hstat.contlen);
1182               logprintf (LOG_NONVERBOSE,
1183                          "%s URL:%s [%ld/%ld] -> \"%s\" [%d]\n",
1184                          tms, u->url, hstat.len, hstat.contlen, locf, count);
1185             }
1186           ++opt.numurls;
1187           opt.downloaded += hstat.len;
1188           downloaded_file(ADD_FILE, locf);
1189           return RETROK;
1190         }
1191       else if (hstat.res == 0) /* No read error */
1192         {
1193           if (hstat.contlen == -1)  /* We don't know how much we were supposed
1194                                        to get, so assume we succeeded. */ 
1195             {
1196               if (*dt & RETROKF)
1197                 {
1198                   logprintf (LOG_VERBOSE,
1199                              _("%s (%s) - `%s' saved [%ld]\n\n"),
1200                              tms, tmrate, locf, hstat.len);
1201                   logprintf (LOG_NONVERBOSE,
1202                              "%s URL:%s [%ld] -> \"%s\" [%d]\n",
1203                              tms, u->url, hstat.len, locf, count);
1204                 }
1205               ++opt.numurls;
1206               opt.downloaded += hstat.len;
1207               downloaded_file(ADD_FILE, locf);
1208               return RETROK;
1209             }
1210           else if (hstat.len < hstat.contlen) /* meaning we lost the
1211                                                  connection too soon */
1212             {
1213               logprintf (LOG_VERBOSE,
1214                          _("%s (%s) - Connection closed at byte %ld. "),
1215                          tms, tmrate, hstat.len);
1216               printwhat (count, opt.ntry);
1217               continue;
1218             }
1219           else if (!opt.kill_longer) /* meaning we got more than expected */
1220             {
1221               logprintf (LOG_VERBOSE,
1222                          _("%s (%s) - `%s' saved [%ld/%ld])\n\n"),
1223                          tms, tmrate, locf, hstat.len, hstat.contlen);
1224               logprintf (LOG_NONVERBOSE,
1225                          "%s URL:%s [%ld/%ld] -> \"%s\" [%d]\n",
1226                          tms, u->url, hstat.len, hstat.contlen, locf, count);
1227               ++opt.numurls;
1228               opt.downloaded += hstat.len;
1229               downloaded_file(ADD_FILE, locf);
1230               return RETROK;
1231             }
1232           else                  /* the same, but not accepted */
1233             {
1234               logprintf (LOG_VERBOSE,
1235                          _("%s (%s) - Connection closed at byte %ld/%ld. "),
1236                          tms, tmrate, hstat.len, hstat.contlen);
1237               printwhat (count, opt.ntry);
1238               continue;
1239             }
1240         }
1241       else                      /* now hstat.res can only be -1 */
1242         {
1243           if (hstat.contlen == -1)
1244             {
1245               logprintf (LOG_VERBOSE,
1246                          _("%s (%s) - Read error at byte %ld (%s)."),
1247                          tms, tmrate, hstat.len, strerror (errno));
1248               printwhat (count, opt.ntry);
1249               continue;
1250             }
1251           else                  /* hstat.res == -1 and contlen is given */
1252             {
1253               logprintf (LOG_VERBOSE,
1254                          _("%s (%s) - Read error at byte %ld/%ld (%s). "),
1255                          tms, tmrate, hstat.len, hstat.contlen,
1256                          strerror (errno));
1257               printwhat (count, opt.ntry);
1258               continue;
1259             }
1260         }
1261       /* not reached */
1262       break;
1263     }
1264   while (!opt.ntry || (count < opt.ntry));
1265   return TRYLIMEXC;
1266 }
1267 \f
1268 /* Converts struct tm to time_t, assuming the data in tm is UTC rather
1269    than local timezone (mktime assumes the latter).
1270
1271    Contributed by Roger Beeman <beeman@cisco.com>, with the help of
1272    Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO.  */
1273 static time_t
1274 mktime_from_utc (struct tm *t)
1275 {
1276   time_t tl, tb;
1277
1278   tl = mktime (t);
1279   if (tl == -1)
1280     return -1;
1281   tb = mktime (gmtime (&tl));
1282   return (tl <= tb ? (tl + (tl - tb)) : (tl - (tb - tl)));
1283 }
1284
1285 /* Check whether the result of strptime() indicates success.
1286    strptime() returns the pointer to how far it got to in the string.
1287    The processing has been successful if the string is at `GMT' or
1288    `+X', or at the end of the string.
1289
1290    In extended regexp parlance, the function returns 1 if P matches
1291    "^ *(GMT|[+-][0-9]|$)", 0 otherwise.  P being NULL (a valid result of
1292    strptime()) is considered a failure and 0 is returned.  */
1293 static int
1294 check_end (char *p)
1295 {
1296   if (!p)
1297     return 0;
1298   while (ISSPACE (*p))
1299     ++p;
1300   if (!*p
1301       || (p[0] == 'G' && p[1] == 'M' && p[2] == 'T')
1302       || ((p[0] == '+' || p[1] == '-') && ISDIGIT (p[1])))
1303     return 1;
1304   else
1305     return 0;
1306 }
1307
1308 /* Convert TIME_STRING time to time_t.  TIME_STRING can be in any of
1309    the three formats RFC2068 allows the HTTP servers to emit --
1310    RFC1123-date, RFC850-date or asctime-date.  Timezones are ignored,
1311    and should be GMT.
1312
1313    We use strptime() to recognize various dates, which makes it a
1314    little bit slacker than the RFC1123/RFC850/asctime (e.g. it always
1315    allows shortened dates and months, one-digit days, etc.).  It also
1316    allows more than one space anywhere where the specs require one SP.
1317    The routine should probably be even more forgiving (as recommended
1318    by RFC2068), but I do not have the time to write one.
1319
1320    Return the computed time_t representation, or -1 if all the
1321    schemes fail.
1322
1323    Needless to say, what we *really* need here is something like
1324    Marcus Hennecke's atotm(), which is forgiving, fast, to-the-point,
1325    and does not use strptime().  atotm() is to be found in the sources
1326    of `phttpd', a little-known HTTP server written by Peter Erikson.  */
1327 static time_t
1328 http_atotm (char *time_string)
1329 {
1330   struct tm t;
1331
1332   /* Roger Beeman says: "This function dynamically allocates struct tm
1333      t, but does no initialization.  The only field that actually
1334      needs initialization is tm_isdst, since the others will be set by
1335      strptime.  Since strptime does not set tm_isdst, it will return
1336      the data structure with whatever data was in tm_isdst to begin
1337      with.  For those of us in timezones where DST can occur, there
1338      can be a one hour shift depending on the previous contents of the
1339      data area where the data structure is allocated."  */
1340   t.tm_isdst = -1;
1341
1342   /* Note that under foreign locales Solaris strptime() fails to
1343      recognize English dates, which renders this function useless.  I
1344      assume that other non-GNU strptime's are plagued by the same
1345      disease.  We solve this by setting only LC_MESSAGES in
1346      i18n_initialize(), instead of LC_ALL.
1347
1348      Another solution could be to temporarily set locale to C, invoke
1349      strptime(), and restore it back.  This is slow and dirty,
1350      however, and locale support other than LC_MESSAGES can mess other
1351      things, so I rather chose to stick with just setting LC_MESSAGES.
1352
1353      Also note that none of this is necessary under GNU strptime(),
1354      because it recognizes both international and local dates.  */
1355
1356   /* NOTE: We don't use `%n' for white space, as OSF's strptime uses
1357      it to eat all white space up to (and including) a newline, and
1358      the function fails if there is no newline (!).
1359
1360      Let's hope all strptime() implementations use ` ' to skip *all*
1361      whitespace instead of just one (it works that way on all the
1362      systems I've tested it on).  */
1363
1364   /* RFC1123: Thu, 29 Jan 1998 22:12:57 */
1365   if (check_end (strptime (time_string, "%a, %d %b %Y %T", &t)))
1366     return mktime_from_utc (&t);
1367   /* RFC850:  Thu, 29-Jan-98 22:12:57 */
1368   if (check_end (strptime (time_string, "%a, %d-%b-%y %T", &t)))
1369     return mktime_from_utc (&t);
1370   /* asctime: Thu Jan 29 22:12:57 1998 */
1371   if (check_end (strptime (time_string, "%a %b %d %T %Y", &t)))
1372     return mktime_from_utc (&t);
1373   /* Failure.  */
1374   return -1;
1375 }
1376 \f
1377 /* Authorization support: We support two authorization schemes:
1378
1379    * `Basic' scheme, consisting of base64-ing USER:PASSWORD string;
1380
1381    * `Digest' scheme, added by Junio Hamano <junio@twinsun.com>,
1382    consisting of answering to the server's challenge with the proper
1383    MD5 digests.  */
1384
1385 /* How many bytes it will take to store LEN bytes in base64.  */
1386 #define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
1387
1388 /* Encode the string S of length LENGTH to base64 format and place it
1389    to STORE.  STORE will be 0-terminated, and must point to a writable
1390    buffer of at least 1+BASE64_LENGTH(length) bytes.  */
1391 static void
1392 base64_encode (const char *s, char *store, int length)
1393 {
1394   /* Conversion table.  */
1395   static char tbl[64] = {
1396     'A','B','C','D','E','F','G','H',
1397     'I','J','K','L','M','N','O','P',
1398     'Q','R','S','T','U','V','W','X',
1399     'Y','Z','a','b','c','d','e','f',
1400     'g','h','i','j','k','l','m','n',
1401     'o','p','q','r','s','t','u','v',
1402     'w','x','y','z','0','1','2','3',
1403     '4','5','6','7','8','9','+','/'
1404   };
1405   int i;
1406   unsigned char *p = (unsigned char *)store;
1407
1408   /* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
1409   for (i = 0; i < length; i += 3)
1410     {
1411       *p++ = tbl[s[0] >> 2];
1412       *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
1413       *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
1414       *p++ = tbl[s[2] & 0x3f];
1415       s += 3;
1416     }
1417   /* Pad the result if necessary...  */
1418   if (i == length + 1)
1419     *(p - 1) = '=';
1420   else if (i == length + 2)
1421     *(p - 1) = *(p - 2) = '=';
1422   /* ...and zero-terminate it.  */
1423   *p = '\0';
1424 }
1425
1426 /* Create the authentication header contents for the `Basic' scheme.
1427    This is done by encoding the string `USER:PASS' in base64 and
1428    prepending `HEADER: Basic ' to it.  */
1429 static char *
1430 basic_authentication_encode (const char *user, const char *passwd,
1431                              const char *header)
1432 {
1433   char *t1, *t2, *res;
1434   int len1 = strlen (user) + 1 + strlen (passwd);
1435   int len2 = BASE64_LENGTH (len1);
1436
1437   t1 = (char *)alloca (len1 + 1);
1438   sprintf (t1, "%s:%s", user, passwd);
1439   t2 = (char *)alloca (1 + len2);
1440   base64_encode (t1, t2, len1);
1441   res = (char *)malloc (len2 + 11 + strlen (header));
1442   sprintf (res, "%s: Basic %s\r\n", header, t2);
1443
1444   return res;
1445 }
1446
1447 #ifdef USE_DIGEST
1448 /* Parse HTTP `WWW-Authenticate:' header.  AU points to the beginning
1449    of a field in such a header.  If the field is the one specified by
1450    ATTR_NAME ("realm", "opaque", and "nonce" are used by the current
1451    digest authorization code), extract its value in the (char*)
1452    variable pointed by RET.  Returns negative on a malformed header,
1453    or number of bytes that have been parsed by this call.  */
1454 static int
1455 extract_header_attr (const char *au, const char *attr_name, char **ret)
1456 {
1457   const char *cp, *ep;
1458
1459   ep = cp = au;
1460
1461   if (strncmp (cp, attr_name, strlen (attr_name)) == 0)
1462     {
1463       cp += strlen (attr_name);
1464       if (!*cp)
1465         return -1;
1466       cp += skip_lws (cp);
1467       if (*cp != '=')
1468         return -1;
1469       if (!*++cp)
1470         return -1;
1471       cp += skip_lws (cp);
1472       if (*cp != '\"')
1473         return -1;
1474       if (!*++cp)
1475         return -1;
1476       for (ep = cp; *ep && *ep != '\"'; ep++)
1477         ;
1478       if (!*ep)
1479         return -1;
1480       FREE_MAYBE (*ret);
1481       *ret = strdupdelim (cp, ep);
1482       return ep - au + 1;
1483     }
1484   else
1485     return 0;
1486 }
1487
1488 /* Response value needs to be in lowercase, so we cannot use HEXD2ASC
1489    from url.h.  See RFC 2069 2.1.2 for the syntax of response-digest.  */
1490 #define HEXD2asc(x) (((x) < 10) ? ((x) + '0') : ((x) - 10 + 'a'))
1491
1492 /* Dump the hexadecimal representation of HASH to BUF.  HASH should be
1493    an array of 16 bytes containing the hash keys, and BUF should be a
1494    buffer of 33 writable characters (32 for hex digits plus one for
1495    zero termination).  */
1496 static void
1497 dump_hash (unsigned char *buf, const unsigned char *hash)
1498 {
1499   int i;
1500
1501   for (i = 0; i < MD5_HASHLEN; i++, hash++)
1502     {
1503       *buf++ = HEXD2asc (*hash >> 4);
1504       *buf++ = HEXD2asc (*hash & 0xf);
1505     }
1506   *buf = '\0';
1507 }
1508
1509 /* Take the line apart to find the challenge, and compose a digest
1510    authorization header.  See RFC2069 section 2.1.2.  */
1511 char *
1512 digest_authentication_encode (const char *au, const char *user,
1513                               const char *passwd, const char *method,
1514                               const char *path)
1515 {
1516   static char *realm, *opaque, *nonce;
1517   static struct {
1518     const char *name;
1519     char **variable;
1520   } options[] = {
1521     { "realm", &realm },
1522     { "opaque", &opaque },
1523     { "nonce", &nonce }
1524   };
1525   char *res;
1526
1527   realm = opaque = nonce = NULL;
1528
1529   au += 6;                      /* skip over `Digest' */
1530   while (*au)
1531     {
1532       int i;
1533
1534       au += skip_lws (au);
1535       for (i = 0; i < ARRAY_SIZE (options); i++)
1536         {
1537           int skip = extract_header_attr (au, options[i].name,
1538                                           options[i].variable);
1539           if (skip < 0)
1540             {
1541               FREE_MAYBE (realm);
1542               FREE_MAYBE (opaque);
1543               FREE_MAYBE (nonce);
1544               return NULL;
1545             }
1546           else if (skip)
1547             {
1548               au += skip;
1549               break;
1550             }
1551         }
1552       if (i == ARRAY_SIZE (options))
1553         {
1554           while (*au && *au != '=')
1555             au++;
1556           if (*au && *++au)
1557             {
1558               au += skip_lws (au);
1559               if (*au == '\"')
1560                 {
1561                   au++;
1562                   while (*au && *au != '\"')
1563                     au++;
1564                   if (*au)
1565                     au++;
1566                 }
1567             }
1568         }
1569       while (*au && *au != ',')
1570         au++;
1571       if (*au)
1572         au++;
1573     }
1574   if (!realm || !nonce || !user || !passwd || !path || !method)
1575     {
1576       FREE_MAYBE (realm);
1577       FREE_MAYBE (opaque);
1578       FREE_MAYBE (nonce);
1579       return NULL;
1580     }
1581
1582   /* Calculate the digest value.  */
1583   {
1584     struct md5_ctx ctx;
1585     unsigned char hash[MD5_HASHLEN];
1586     unsigned char a1buf[MD5_HASHLEN * 2 + 1], a2buf[MD5_HASHLEN * 2 + 1];
1587     unsigned char response_digest[MD5_HASHLEN * 2 + 1];
1588
1589     /* A1BUF = H(user ":" realm ":" password) */
1590     md5_init_ctx (&ctx);
1591     md5_process_bytes (user, strlen (user), &ctx);
1592     md5_process_bytes (":", 1, &ctx);
1593     md5_process_bytes (realm, strlen (realm), &ctx);
1594     md5_process_bytes (":", 1, &ctx);
1595     md5_process_bytes (passwd, strlen (passwd), &ctx);
1596     md5_finish_ctx (&ctx, hash);
1597     dump_hash (a1buf, hash);
1598
1599     /* A2BUF = H(method ":" path) */
1600     md5_init_ctx (&ctx);
1601     md5_process_bytes (method, strlen (method), &ctx);
1602     md5_process_bytes (":", 1, &ctx);
1603     md5_process_bytes (path, strlen (path), &ctx);
1604     md5_finish_ctx (&ctx, hash);
1605     dump_hash (a2buf, hash);
1606
1607     /* RESPONSE_DIGEST = H(A1BUF ":" nonce ":" A2BUF) */
1608     md5_init_ctx (&ctx);
1609     md5_process_bytes (a1buf, MD5_HASHLEN * 2, &ctx);
1610     md5_process_bytes (":", 1, &ctx);
1611     md5_process_bytes (nonce, strlen (nonce), &ctx);
1612     md5_process_bytes (":", 1, &ctx);
1613     md5_process_bytes (a2buf, MD5_HASHLEN * 2, &ctx);
1614     md5_finish_ctx (&ctx, hash);
1615     dump_hash (response_digest, hash);
1616
1617     res = (char*) xmalloc (strlen (user)
1618                            + strlen (user)
1619                            + strlen (realm)
1620                            + strlen (nonce)
1621                            + strlen (path)
1622                            + 2 * MD5_HASHLEN /*strlen (response_digest)*/
1623                            + (opaque ? strlen (opaque) : 0)
1624                            + 128);
1625     sprintf (res, "Authorization: Digest \
1626 username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
1627              user, realm, nonce, path, response_digest);
1628     if (opaque)
1629       {
1630         char *p = res + strlen (res);
1631         strcat (p, ", opaque=\"");
1632         strcat (p, opaque);
1633         strcat (p, "\"");
1634       }
1635     strcat (res, "\r\n");
1636   }
1637   return res;
1638 }
1639 #endif /* USE_DIGEST */
1640
1641
1642 #define HACK_O_MATIC(line, string_constant)                             \
1643   (!strncasecmp (line, string_constant, sizeof (string_constant) - 1)   \
1644    && (ISSPACE (line[sizeof (string_constant) - 1])                     \
1645        || !line[sizeof (string_constant) - 1]))
1646
1647 static int
1648 known_authentication_scheme_p (const char *au)
1649 {
1650   return HACK_O_MATIC (au, "Basic") || HACK_O_MATIC (au, "Digest");
1651 }
1652
1653 #undef HACK_O_MATIC
1654
1655 /* Create the HTTP authorization request header.  When the
1656    `WWW-Authenticate' response header is seen, according to the
1657    authorization scheme specified in that header (`Basic' and `Digest'
1658    are supported by the current implementation), produce an
1659    appropriate HTTP authorization request header.  */
1660 static char *
1661 create_authorization_line (const char *au, const char *user,
1662                            const char *passwd, const char *method,
1663                            const char *path)
1664 {
1665   char *wwwauth = NULL;
1666
1667   if (!strncasecmp (au, "Basic", 5))
1668     wwwauth = basic_authentication_encode (user, passwd, "Authorization");
1669 #ifdef USE_DIGEST
1670   else if (!strncasecmp (au, "Digest", 6))
1671     wwwauth = digest_authentication_encode (au, user, passwd, method, path);
1672 #endif /* USE_DIGEST */
1673   return wwwauth;
1674 }