"Fossies" - the Fresh Open Source Software Archive

Member "links-1.03/http.c" (20 Nov 2011, 18577 Bytes) of archive /linux/www/links-1.03.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "http.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8_vs_1.03.

    1 #include "links.h"
    2 
    3 struct http_connection_info {
    4     int bl_flags;
    5     int http10;
    6     int close;
    7     off_t length;
    8     int version;
    9     int chunk_remaining;
   10 };
   11 
   12 unsigned char *parse_http_header(unsigned char *head, unsigned char *item, unsigned char **ptr)
   13 {
   14     unsigned char *i, *f, *g, *h;
   15     if (!head) return NULL;
   16     h = NULL;
   17     for (f = head; *f; f++) {
   18         if (*f != 10) continue;
   19         f++;
   20         for (i = item; *i && *f; i++, f++)
   21             if (upcase(*i) != upcase(*f)) goto cont;
   22         if (!*f) break;
   23         if (f[0] == ':') {
   24             while (f[1] == ' ') f++;
   25             for (g = ++f; *g >= ' '; g++) ;
   26             while (g > f && g[-1] == ' ') g--;
   27             if (h) mem_free(h);
   28             h = mem_alloc(g - f + 1);
   29             memcpy(h, f, g - f);
   30             h[g - f] = 0;
   31             if (ptr) {
   32                 *ptr = f;
   33                 break;
   34             }
   35             return h;
   36         }
   37         cont:;
   38         f--;
   39     }
   40     return h;
   41 }
   42 
   43 unsigned char *parse_header_param(unsigned char *x, unsigned char *e)
   44 {
   45     unsigned char u;
   46     size_t le = strlen(e);
   47     int lp;
   48     unsigned char *y = x;
   49     a:
   50     if (!(y = strchr(y, ';'))) return NULL;
   51     while (*y && (*y == ';' || *y <= ' ')) y++;
   52     if (strlen(y) < le) return NULL;
   53     if (casecmp(y, e, le)) goto a;
   54     y += le;
   55     while (*y && (*y <= ' ' || *y == '=')) y++;
   56     u = ';';
   57     if (*y == '\'' || *y == '"') u = *y++;
   58     lp = 0;
   59     while (y[lp] >= ' ' && y[lp] != u) {
   60         lp++;
   61         if (lp == MAXINT) overalloc();
   62     }
   63     return memacpy(y, lp);
   64 }
   65 
   66 /*
   67  Parse string param="value", return value as new string
   68  or NULL if any error.
   69 */
   70 unsigned char *get_param(unsigned char *e, unsigned char *name)
   71 {
   72     unsigned char *n, *start;
   73     int i = 0;
   74 again:  
   75     while (*e && upcase(*e++) != upcase(*name));
   76     if (!*e) return NULL;
   77     n = name + 1;
   78     while (*n && upcase(*e) == upcase(*n)) e++, n++;
   79     if (*n) goto again;
   80     while (WHITECHAR(*e)) e++;
   81     if (*e++ != '=') return NULL;
   82     while (WHITECHAR(*e)) e++;
   83 
   84     start = e;
   85     if (!U(*e)) while (*e && !WHITECHAR(*e)) e++;
   86     else {
   87         char uu = *e++;
   88         start++;
   89         while (*e != uu) {
   90             if (!*e) return NULL;
   91             e++;
   92         }
   93     }
   94     
   95     while (start < e && *start == ' ') start++;
   96     while (start < e && *(e - 1) == ' ') e--;
   97     if (start == e) return NULL;
   98     
   99     n = mem_alloc(e - start + 1);
  100     while (start < e) {
  101         if (*start < ' ') n[i] = '.';
  102         else n[i] = *start;
  103         i++; start++;
  104     }
  105     n[i] = 0;
  106     return n;
  107 }
  108 
  109 static int get_http_code(unsigned char *head, int *code, int *version)
  110 {
  111     while (head[0] == ' ') head++;
  112     if (upcase(head[0]) != 'H' || upcase(head[1]) != 'T' || upcase(head[2]) != 'T' ||
  113         upcase(head[3]) != 'P') return -1;
  114     if (head[4] == '/' && head[5] >= '0' && head[5] <= '9'
  115      && head[6] == '.' && head[7] >= '0' && head[7] <= '9' && head[8] <= ' ') {
  116         *version = (head[5] - '0') * 10 + head[7] - '0';
  117     } else *version = 0;
  118     for (head += 4; *head > ' '; head++) ;
  119     if (*head++ != ' ') return -1;
  120     if (head[0] < '1' || head [0] > '9' || head[1] < '0' || head[1] > '9' ||
  121         head[2] < '0' || head [2] > '9') return -1;
  122     *code = (head[0]-'0')*100 + (head[1]-'0')*10 + head[2]-'0';
  123     return 0;
  124 }
  125 
  126 struct {
  127     unsigned char *name;
  128     int bugs;
  129 } buggy_servers[] = {
  130     { "mod_czech/3.1.0", BL_HTTP10 },
  131     { "Purveyor", BL_HTTP10 },
  132     { "Netscape-Enterprise", BL_HTTP10 | BL_NO_ACCEPT_LANGUAGE },
  133     { "Apache Coyote", BL_HTTP10 },
  134     { "lighttpd", BL_HTTP10 },
  135     { "FORPSI", BL_NO_RANGE },
  136     { "Sausalito", BL_HTTP10 },
  137     { NULL, 0 }
  138 };
  139 
  140 int check_http_server_bugs(unsigned char *url, struct http_connection_info *info, unsigned char *head)
  141 {
  142     unsigned char *server;
  143     int i, bugs;
  144     if (!http_bugs.allow_blacklist || info->http10) return 0;
  145     if (!(server = parse_http_header(head, "Server", NULL))) return 0;
  146     bugs = 0;
  147     for (i = 0; buggy_servers[i].name; i++) if (strstr(server, buggy_servers[i].name)) bugs |= buggy_servers[i].bugs;
  148     mem_free(server);
  149     if (bugs && (server = get_host_name(url))) {
  150         add_blacklist_entry(server, bugs);
  151         mem_free(server);
  152         return bugs & ~BL_NO_RANGE;
  153     }
  154     return 0;   
  155 }
  156 
  157 void http_end_request(struct connection *c, int notrunc)
  158 {
  159     if (c->state == S_OK) {
  160         if (c->cache) {
  161             if (!notrunc) truncate_entry(c->cache, c->from, 1);
  162             c->cache->incomplete = 0;
  163         }
  164     }
  165     if (c->info && !((struct http_connection_info *)c->info)->close 
  166 #ifdef HAVE_SSL
  167     && (!c->ssl) /* We won't keep alive ssl connections */
  168 #endif
  169     && (!http_bugs.bug_post_no_keepalive || !strchr(c->url, POST_CHAR))) {
  170         add_keepalive_socket(c, HTTP_KEEPALIVE_TIMEOUT);
  171     } else abort_connection(c);
  172 }
  173 
  174 void http_send_header(struct connection *);
  175 
  176 void http_func(struct connection *c)
  177 {
  178     /*setcstate(c, S_CONN);*/
  179     /*set_timeout(c);*/
  180     if (get_keepalive_socket(c)) {
  181         int p;
  182         if ((p = get_port(c->url)) == -1) {
  183             setcstate(c, S_INTERNAL);
  184             abort_connection(c);
  185             return;
  186         }
  187         make_connection(c, p, &c->sock1, http_send_header);
  188     } else http_send_header(c);
  189 }
  190 
  191 void proxy_func(struct connection *c)
  192 {
  193     http_func(c);
  194 }
  195 
  196 void http_get_header(struct connection *);
  197 
  198 void http_send_header(struct connection *c)
  199 {
  200     static unsigned char *accept_charset = NULL;
  201     struct http_connection_info *info;
  202     int http10 = http_bugs.http10;
  203     struct cache_entry *e = NULL;
  204     unsigned char *hdr;
  205     unsigned char *h, *u, *uu, *sp;
  206     int l = 0;
  207     int la;
  208     unsigned char *post;
  209     unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url);
  210     set_timeout(c);
  211     info = mem_alloc(sizeof(struct http_connection_info));
  212     memset(info, 0, sizeof(struct http_connection_info));
  213     c->info = info;
  214     if ((h = get_host_name(host))) {
  215         info->bl_flags = get_blacklist_flags(h);
  216         mem_free(h);
  217     }
  218     if (info->bl_flags & BL_HTTP10) http10 = 1;
  219     info->http10 = http10;
  220     post = strchr(c->url, POST_CHAR);
  221     if (post) post++;
  222     hdr = init_str();
  223     if (!post) add_to_str(&hdr, &l, "GET ");
  224     else {
  225         add_to_str(&hdr, &l, "POST ");
  226         c->unrestartable = 2;
  227     }
  228     if (upcase(c->url[0]) != 'P') add_to_str(&hdr, &l, "/");
  229     if (!(u = get_url_data(c->url))) {
  230         mem_free(hdr);
  231         setcstate(c, S_BAD_URL);
  232         http_end_request(c, 0);
  233         return;
  234     }
  235     if (post && post < u) {
  236         mem_free(hdr);
  237         setcstate(c, S_BAD_URL);
  238         http_end_request(c, 0);
  239         return;
  240     }
  241     if (!post) uu = stracpy(u);
  242     else uu = memacpy(u, post - u - 1);
  243     a:
  244     for (sp = uu; *sp; sp++) if (*sp <= ' ') {
  245         unsigned char *nu = mem_alloc(strlen(uu) + 3);
  246         memcpy(nu, uu, sp - uu);
  247         sprintf(nu + (sp - uu), "%%%02X", (int)*sp);
  248         strcat(nu, sp + 1);
  249         mem_free(uu);
  250         uu = nu;
  251         goto a;
  252     }
  253     add_to_str(&hdr, &l, uu);
  254     mem_free(uu);
  255     if (!http10) add_to_str(&hdr, &l, " HTTP/1.1\r\n");
  256     else add_to_str(&hdr, &l, " HTTP/1.0\r\n");
  257     if ((h = get_host_name(host))) {
  258         add_to_str(&hdr, &l, "Host: ");
  259         add_to_str(&hdr, &l, h);
  260         mem_free(h);
  261         if ((h = get_port_str(host))) {
  262             add_to_str(&hdr, &l, ":");
  263             add_to_str(&hdr, &l, h);
  264             mem_free(h);
  265         }
  266         add_to_str(&hdr, &l, "\r\n");
  267     }
  268     add_to_str(&hdr, &l, "User-Agent: Links (" VERSION_STRING "; ");
  269     add_to_str(&hdr, &l, system_name);
  270     add_to_str(&hdr, &l, "; ");
  271     if (!list_empty(terminals)) {
  272         add_to_str(&hdr, &l, "text");
  273     } else {
  274         add_to_str(&hdr, &l, "dump");
  275     }
  276     add_to_str(&hdr, &l, ")\r\n");
  277     add_to_str(&hdr, &l, "Accept: */*\r\n");
  278     if (!(accept_charset)) {
  279         int i;
  280         unsigned char *cs, *ac;
  281         int aclen = 0;
  282         ac = init_str();
  283         for (i = 0; (cs = get_cp_mime_name(i)); i++) {
  284             if (aclen) add_to_str(&ac, &aclen, ", ");
  285             else add_to_str(&ac, &aclen, "Accept-Charset: ");
  286             add_to_str(&ac, &aclen, cs);
  287         }
  288         if (aclen) add_to_str(&ac, &aclen, "\r\n");
  289         if ((accept_charset = malloc(strlen(ac) + 1))) strcpy(accept_charset, ac);
  290         else accept_charset = "";
  291         mem_free(ac);
  292     }
  293     if (!(info->bl_flags & BL_NO_CHARSET) && !http_bugs.no_accept_charset) add_to_str(&hdr, &l, accept_charset);
  294     if (!(info->bl_flags & BL_NO_ACCEPT_LANGUAGE)) {
  295         add_to_str(&hdr, &l, "Accept-Language: ");
  296         la = l;
  297         add_to_str(&hdr, &l, _(TEXT_(T__ACCEPT_LANGUAGE), NULL));
  298         add_to_str(&hdr, &l, ", ");
  299         if (!strstr(hdr + la, "en,") && !strstr(hdr + la, "en;")) add_to_str(&hdr, &l, "en;q=0.2, ");
  300         add_to_str(&hdr, &l, "*;q=0.1\r\n");
  301     }
  302     if (!http10) {
  303         if (upcase(c->url[0]) != 'P') add_to_str(&hdr, &l, "Connection: ");
  304         else add_to_str(&hdr, &l, "Proxy-Connection: ");
  305         if (!post || !http_bugs.bug_post_no_keepalive) add_to_str(&hdr, &l, "Keep-Alive\r\n");
  306         else add_to_str(&hdr, &l, "close\r\n");
  307     }
  308     if ((e = c->cache)) {
  309         int code, vers;
  310         if (get_http_code(e->head, &code, &vers) || code >= 400) goto skip_ifmod_and_range;
  311         if (!e->incomplete && e->head && c->no_cache <= NC_IF_MOD &&
  312             e->last_modified) {
  313             add_to_str(&hdr, &l, "If-Modified-Since: ");
  314             add_to_str(&hdr, &l, e->last_modified);
  315             add_to_str(&hdr, &l, "\r\n");
  316         }
  317     }
  318     if (c->from && (c->est_length == -1 || c->from < c->est_length) && c->no_cache < NC_IF_MOD && !(info->bl_flags & BL_NO_RANGE)) {
  319         add_to_str(&hdr, &l, "Range: bytes=");
  320         add_num_to_str(&hdr, &l, c->from);
  321         add_to_str(&hdr, &l, "-\r\n");
  322     }
  323     skip_ifmod_and_range:
  324     if (c->no_cache >= NC_PR_NO_CACHE) add_to_str(&hdr, &l, "Pragma: no-cache\r\nCache-Control: no-cache\r\n");
  325     if (post) {
  326         unsigned char *pd = strchr(post, '\n');
  327         if (pd) {
  328             add_to_str(&hdr, &l, "Content-Type: ");
  329             add_bytes_to_str(&hdr, &l, post, pd - post);
  330             add_to_str(&hdr, &l, "\r\n");
  331             post = pd + 1;
  332         }
  333         add_to_str(&hdr, &l, "Content-Length: ");
  334         add_num_to_str(&hdr, &l, strlen(post) / 2);
  335         add_to_str(&hdr, &l, "\r\n");
  336     }
  337     send_cookies(&hdr, &l, host);
  338     add_to_str(&hdr, &l, "\r\n");
  339     if (post) {
  340         while (post[0] && post[1]) {
  341             int h1, h2;
  342             h1 = post[0] <= '9' ? post[0] - '0' : post[0] >= 'A' ? upcase(post[0]) - 'A' + 10 : 0;
  343             if (h1 < 0 || h1 >= 16) h1 = 0;
  344             h2 = post[1] <= '9' ? post[1] - '0' : post[1] >= 'A' ? upcase(post[1]) - 'A' + 10 : 0;
  345             if (h2 < 0 || h2 >= 16) h2 = 0;
  346             add_chr_to_str(&hdr, &l, h1 * 16 + h2);
  347             post += 2;
  348         }
  349     }
  350     write_to_socket(c, c->sock1, hdr, l, http_get_header);
  351     mem_free(hdr);
  352     setcstate(c, S_SENT);
  353 }
  354 
  355 int is_line_in_buffer(struct read_buffer *rb)
  356 {
  357     int l;
  358     for (l = 0; l < rb->len; l++) {
  359         if (rb->data[l] == 10) return l + 1;
  360         if (l < rb->len - 1 && rb->data[l] == 13 && rb->data[l + 1] == 10) return l + 2;
  361         if (l == rb->len - 1 && rb->data[l] == 13) return 0;
  362         if (rb->data[l] < ' ') return -1;
  363     }
  364     return 0;
  365 }
  366 
  367 void read_http_data(struct connection *c, struct read_buffer *rb)
  368 {
  369     struct http_connection_info *info = c->info;
  370     set_timeout(c);
  371     if (rb->close == 2) {
  372         setcstate(c, S_OK);
  373         http_end_request(c, 0);
  374         return;
  375     }
  376     if (info->length != -2) {
  377         int l = rb->len;
  378         if (info->length >= 0 && info->length < l) l = info->length;
  379         if ((off_t)(0UL + c->from + l) < 0) {
  380             setcstate(c, S_LARGE_FILE);
  381             abort_connection(c);
  382             return;
  383         }
  384         c->received += l;
  385         if (add_fragment(c->cache, c->from, rb->data, l) == 1) c->tries = 0;
  386         if (info->length >= 0) info->length -= l;
  387         c->from += l;
  388         kill_buffer_data(rb, l);
  389         if (!info->length && !rb->close) {
  390             setcstate(c, S_OK);
  391             http_end_request(c, 0);
  392             return;
  393         }
  394     } else {
  395         next_chunk:
  396         if (info->chunk_remaining == -2) {
  397             int l;
  398             if ((l = is_line_in_buffer(rb))) {
  399                 if (l == -1) {
  400                     setcstate(c, S_HTTP_ERROR);
  401                     abort_connection(c);
  402                     return;
  403                 }
  404                 kill_buffer_data(rb, l);
  405                 if (l <= 2) {
  406                     setcstate(c, S_OK);
  407                     http_end_request(c, 0);
  408                     return;
  409                 }
  410                 goto next_chunk;
  411             }
  412         } else if (info->chunk_remaining == -1) {
  413             int l;
  414             if ((l = is_line_in_buffer(rb))) {
  415                 unsigned char *de;
  416                 long n = 0; /* warning, go away */
  417                 if (l != -1) n = strtol(rb->data, (char **)(void *)&de, 16);
  418                 if (l == -1 || n < 0 || n >= MAXINT || de == rb->data) {
  419                     setcstate(c, S_HTTP_ERROR);
  420                     abort_connection(c);
  421                     return;
  422                 }
  423                 kill_buffer_data(rb, l);
  424                 if (!(info->chunk_remaining = n)) info->chunk_remaining = -2;
  425                 goto next_chunk;
  426             }
  427         } else {
  428             int l = info->chunk_remaining;
  429             if (l > rb->len) l = rb->len;
  430             if ((off_t)(0UL + c->from + l) < 0) {
  431                 setcstate(c, S_LARGE_FILE);
  432                 abort_connection(c);
  433                 return;
  434             }
  435             c->received += l;
  436             if (add_fragment(c->cache, c->from, rb->data, l) == 1) c->tries = 0;
  437             info->chunk_remaining -= l;
  438             c->from += l;
  439             kill_buffer_data(rb, l);
  440             if (!info->chunk_remaining && rb->len >= 1) {
  441                 if (rb->data[0] == 10) kill_buffer_data(rb, 1);
  442                 else {
  443                     if (rb->data[0] != 13 || (rb->len >= 2 && rb->data[1] != 10)) {
  444                         setcstate(c, S_HTTP_ERROR);
  445                         abort_connection(c);
  446                         return;
  447                     }
  448                     if (rb->len < 2) goto read_more;
  449                     kill_buffer_data(rb, 2);
  450                 }
  451                 info->chunk_remaining = -1;
  452                 goto next_chunk;
  453             }
  454         }
  455                 
  456     }
  457     read_more:
  458     read_from_socket(c, c->sock1, rb, read_http_data);
  459     setcstate(c, S_TRANS);
  460 }
  461 
  462 int get_header(struct read_buffer *rb)
  463 {
  464     int i;
  465     for (i = 0; i < rb->len; i++) {
  466         unsigned char a = rb->data[i];
  467         if (/*a < ' ' && a != 10 && a != 13*/!a) return -1;
  468         if (i < rb->len - 1 && a == 10 && rb->data[i + 1] == 10) return i + 2;
  469         if (i < rb->len - 3 && a == 13) {
  470             if (rb->data[i + 1] != 10) return -1;
  471             if (rb->data[i + 2] == 13) {
  472                 if (rb->data[i + 3] != 10) return -1;
  473                 return i + 4;
  474             }
  475         }
  476     }
  477     return 0;
  478 }
  479 
  480 void http_got_header(struct connection *c, struct read_buffer *rb)
  481 {
  482     off_t cf;
  483     int state = c->state != S_PROC ? S_GETH : S_PROC;
  484     unsigned char *head;
  485     unsigned char *cookie, *ch;
  486     int a, h, version;
  487     unsigned char *d;
  488     struct cache_entry *e;
  489     struct http_connection_info *info;
  490     unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url);
  491     set_timeout(c);
  492     info = c->info;
  493     if (rb->close == 2) {
  494         unsigned char *h;
  495         if (!c->tries && (h = get_host_name(host))) {
  496             if (info->bl_flags & BL_NO_CHARSET) {
  497                 del_blacklist_entry(h, BL_NO_CHARSET);
  498             } else {
  499                 add_blacklist_entry(h, BL_NO_CHARSET);
  500                 c->tries = -1;
  501             }
  502             mem_free(h);
  503         }
  504         setcstate(c, S_CANT_READ);
  505         retry_connection(c);
  506         return;
  507     }
  508     rb->close = 0;
  509     again:
  510     if ((a = get_header(rb)) == -1) {
  511         setcstate(c, S_HTTP_ERROR);
  512         abort_connection(c);
  513         return;
  514     }
  515     if (!a) {
  516         read_from_socket(c, c->sock1, rb, http_got_header);
  517         setcstate(c, state);
  518         return;
  519     }
  520     if (get_http_code(rb->data, &h, &version) || h == 101) {
  521         setcstate(c, S_HTTP_ERROR);
  522         abort_connection(c);
  523         return;
  524     }
  525     head = mem_alloc(a + 1);
  526     memcpy(head, rb->data, a); head[a] = 0;
  527     if (check_http_server_bugs(host, c->info, head) && is_connection_restartable(c)) {
  528         mem_free(head);
  529         setcstate(c, S_RESTART);
  530         retry_connection(c);
  531         return;
  532     }
  533     ch = head;
  534     while ((cookie = parse_http_header(ch, "Set-Cookie", &ch))) {
  535         unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url);
  536         set_cookie(NULL, host, cookie);
  537         mem_free(cookie);
  538     }
  539     if (h == 100) {
  540         mem_free(head);
  541         state = S_PROC;
  542         kill_buffer_data(rb, a);
  543         goto again;
  544     }
  545     if (h < 200) {
  546         mem_free(head);
  547         setcstate(c, S_HTTP_ERROR);
  548         abort_connection(c);
  549         return;
  550     }
  551     if (h == 304) {
  552         mem_free(head);
  553         setcstate(c, S_OK);
  554         http_end_request(c, 1);
  555         return;
  556     }
  557     if (h == 204) {
  558         mem_free(head);
  559         setcstate(c, S_HTTP_204);
  560         http_end_request(c, 0);
  561         return;
  562     }
  563     if (!c->cache) {
  564         if (get_cache_entry(c->url, &c->cache)) {
  565             mem_free(head);
  566             setcstate(c, S_OUT_OF_MEM);
  567             abort_connection(c);
  568             return;
  569         }
  570         c->cache->refcount--;
  571     }
  572     e = c->cache;
  573     if (e->head) mem_free(e->head);
  574     e->head = head;
  575 #ifdef HAVE_SSL
  576     if (c->ssl) {
  577         int l = 0;
  578         if (e->ssl_info) mem_free(e->ssl_info);
  579         e->ssl_info = init_str();
  580         add_num_to_str(&e->ssl_info, &l, SSL_get_cipher_bits(c->ssl, NULL));
  581         add_to_str(&e->ssl_info, &l, "-bit ");
  582         add_to_str(&e->ssl_info, &l, SSL_get_cipher_version(c->ssl));
  583         add_to_str(&e->ssl_info, &l, " ");
  584         add_to_str(&e->ssl_info, &l, (unsigned  char *)SSL_get_cipher_name(c->ssl));
  585     }
  586 #endif
  587     if (e->redirect) mem_free(e->redirect), e->redirect = NULL;
  588     if (h == 301 || h == 302 || h == 303 || h == 307) {
  589         if ((d = parse_http_header(e->head, "Location", NULL))) {
  590             if (e->redirect) mem_free(e->redirect);
  591             e->redirect = d;
  592             e->redirect_get = h == 303;
  593         }
  594     }
  595     kill_buffer_data(rb, a);
  596     info->close = 0;
  597     info->length = -1;
  598     info->version = version;
  599     if ((d = parse_http_header(e->head, "Connection", NULL)) || (d = parse_http_header(e->head, "Proxy-Connection", NULL))) {
  600         if (!strcasecmp(d, "close")) info->close = 1;
  601         mem_free(d);
  602     } else if (version < 11) info->close = 1;
  603     cf = c->from;
  604     c->from = 0;
  605     if ((d = parse_http_header(e->head, "Content-Range", NULL))) {
  606         if (strlen(d) > 6) {
  607             d[5] = 0;
  608             if (!(strcasecmp(d, "bytes")) && d[6] >= '0' && d[6] <= '9') {
  609 #if defined(HAVE_STRTOLL)
  610                 long long f = strtoll(d + 6, NULL, 10);
  611 #elif defined(HAVE_STRTOQ)
  612                 longlong f = strtoq(d + 6, NULL, 10);
  613 #else
  614                 long f = strtol(d + 6, NULL, 10);
  615                 if (f == MAXLONG) f = -1;
  616 #endif
  617                 if (f >= 0 && (off_t)f >= 0 && (off_t)f == f) c->from = f;
  618             }
  619         }
  620         mem_free(d);
  621     } else if (h == 206) {
  622 /* Hmm ... some servers send 206 partial but don't send Content-Range */
  623         c->from = cf;
  624     }
  625     if (cf && !c->from && !c->unrestartable) c->unrestartable = 1;
  626     if (c->from > cf || c->from < 0) {
  627         setcstate(c, S_HTTP_ERROR);
  628         abort_connection(c);
  629         return;
  630     }
  631     if ((d = parse_http_header(e->head, "Content-Length", NULL))) {
  632         unsigned char *ep;
  633 #if defined(HAVE_STRTOLL)
  634         long long l = strtoll(d, (char **)(void *)&ep, 10);
  635 #elif defined(HAVE_STRTOQ)
  636         longlong l = strtoq(d, (char **)(void *)&ep, 10);
  637 #else
  638         long l = strtol(d, (char **)(void *)&ep, 10);
  639         if (l == MAXLONG) l = -1;
  640 #endif
  641         if (!*ep && l >= 0 && (off_t)l >= 0 && (off_t)l == l) {
  642             if (!info->close || version >= 11) info->length = l;
  643             if (c->from + l >= 0) c->est_length = c->from + l;
  644         }
  645         mem_free(d);
  646     }
  647     if ((d = parse_http_header(e->head, "Accept-Ranges", NULL))) {
  648         if (!strcasecmp(d, "none") && !c->unrestartable) c->unrestartable = 1;
  649         mem_free(d);
  650     } else {
  651         if (!c->unrestartable && !c->from) c->unrestartable = 1;
  652     }
  653     if (info->bl_flags & BL_NO_RANGE && !c->unrestartable) c->unrestartable = 1;
  654     if ((d = parse_http_header(e->head, "Transfer-Encoding", NULL))) {
  655         if (!strcasecmp(d, "chunked")) {
  656             info->length = -2;
  657             info->chunk_remaining = -1;
  658         }
  659         mem_free(d);
  660     }
  661     if (!info->close && info->length == -1) info->close = 1;
  662     if ((d = parse_http_header(e->head, "Last-Modified", NULL))) {
  663         if (e->last_modified && strcasecmp(e->last_modified, d)) {
  664             delete_entry_content(e);
  665             if (c->from) {
  666                 c->from = 0;
  667                 mem_free(d);
  668                 setcstate(c, S_MODIFIED);
  669                 retry_connection(c);
  670                 return;
  671             }
  672         }
  673         if (!e->last_modified) e->last_modified = d;
  674         else mem_free(d);
  675     }
  676     if (!e->last_modified && (d = parse_http_header(e->head, "Date", NULL)))
  677         e->last_modified = d;
  678     if (info->length == -1 || (version < 11 && info->close)) rb->close = 1;
  679     read_http_data(c, rb);
  680 }
  681 
  682 void http_get_header(struct connection *c)
  683 {
  684     struct read_buffer *rb;
  685     set_timeout(c);
  686     if (!(rb = alloc_read_buffer(c))) return;
  687     rb->close = 1;
  688     read_from_socket(c, c->sock1, rb, http_got_header);
  689 }