14ca1ab94SDag-Erling Smørgrav /*- 24ca1ab94SDag-Erling Smørgrav * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav 34ca1ab94SDag-Erling Smørgrav * All rights reserved. 44ca1ab94SDag-Erling Smørgrav * 54ca1ab94SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 64ca1ab94SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 74ca1ab94SDag-Erling Smørgrav * are met: 84ca1ab94SDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 94ca1ab94SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer 104ca1ab94SDag-Erling Smørgrav * in this position and unchanged. 114ca1ab94SDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 124ca1ab94SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 134ca1ab94SDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 144ca1ab94SDag-Erling Smørgrav * 3. The name of the author may not be used to endorse or promote products 154ca1ab94SDag-Erling Smørgrav * derived from this software without specific prior written permission 164ca1ab94SDag-Erling Smørgrav * 174ca1ab94SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 184ca1ab94SDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 194ca1ab94SDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 204ca1ab94SDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 214ca1ab94SDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 224ca1ab94SDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 234ca1ab94SDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 244ca1ab94SDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 254ca1ab94SDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 264ca1ab94SDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274ca1ab94SDag-Erling Smørgrav * 287f3dea24SPeter Wemm * $FreeBSD$ 294ca1ab94SDag-Erling Smørgrav */ 304ca1ab94SDag-Erling Smørgrav 31f62e5228SDag-Erling Smørgrav /* 32f62e5228SDag-Erling Smørgrav * The base64 code in this file is based on code from MIT fetch, which 33f62e5228SDag-Erling Smørgrav * has the following copyright and license: 34f62e5228SDag-Erling Smørgrav * 35f62e5228SDag-Erling Smørgrav *- 36f62e5228SDag-Erling Smørgrav * Copyright 1997 Massachusetts Institute of Technology 37f62e5228SDag-Erling Smørgrav * 38f62e5228SDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software and 39f62e5228SDag-Erling Smørgrav * its documentation for any purpose and without fee is hereby 40f62e5228SDag-Erling Smørgrav * granted, provided that both the above copyright notice and this 41f62e5228SDag-Erling Smørgrav * permission notice appear in all copies, that both the above 42f62e5228SDag-Erling Smørgrav * copyright notice and this permission notice appear in all 43f62e5228SDag-Erling Smørgrav * supporting documentation, and that the name of M.I.T. not be used 44f62e5228SDag-Erling Smørgrav * in advertising or publicity pertaining to distribution of the 45f62e5228SDag-Erling Smørgrav * software without specific, written prior permission. M.I.T. makes 46f62e5228SDag-Erling Smørgrav * no representations about the suitability of this software for any 47f62e5228SDag-Erling Smørgrav * purpose. It is provided "as is" without express or implied 48f62e5228SDag-Erling Smørgrav * warranty. 49f62e5228SDag-Erling Smørgrav * 50f62e5228SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 51f62e5228SDag-Erling Smørgrav * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 52f62e5228SDag-Erling Smørgrav * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 53f62e5228SDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 54f62e5228SDag-Erling Smørgrav * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 55f62e5228SDag-Erling Smørgrav * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 56f62e5228SDag-Erling Smørgrav * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 57f62e5228SDag-Erling Smørgrav * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 58f62e5228SDag-Erling Smørgrav * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 59f62e5228SDag-Erling Smørgrav * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 60f62e5228SDag-Erling Smørgrav * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61f62e5228SDag-Erling Smørgrav * SUCH DAMAGE. */ 62f62e5228SDag-Erling Smørgrav 634ca1ab94SDag-Erling Smørgrav #include <sys/param.h> 6428c645cfSHajimu UMEMOTO #include <sys/socket.h> 654ca1ab94SDag-Erling Smørgrav 664ca1ab94SDag-Erling Smørgrav #include <err.h> 674ca1ab94SDag-Erling Smørgrav #include <ctype.h> 6860245e42SDag-Erling Smørgrav #include <locale.h> 69e6182307SDag-Erling Smørgrav #include <netdb.h> 70f62e5228SDag-Erling Smørgrav #include <stdarg.h> 714ca1ab94SDag-Erling Smørgrav #include <stdio.h> 724ca1ab94SDag-Erling Smørgrav #include <stdlib.h> 734ca1ab94SDag-Erling Smørgrav #include <string.h> 7460245e42SDag-Erling Smørgrav #include <time.h> 754ca1ab94SDag-Erling Smørgrav #include <unistd.h> 764ca1ab94SDag-Erling Smørgrav 774ca1ab94SDag-Erling Smørgrav #include "fetch.h" 78842a95ccSDag-Erling Smørgrav #include "common.h" 790fba3a00SDag-Erling Smørgrav #include "httperr.h" 804ca1ab94SDag-Erling Smørgrav 814ca1ab94SDag-Erling Smørgrav extern char *__progname; 824ca1ab94SDag-Erling Smørgrav 834ca1ab94SDag-Erling Smørgrav #define ENDL "\r\n" 844ca1ab94SDag-Erling Smørgrav 853d2a8471SDag-Erling Smørgrav #define HTTP_OK 200 863d2a8471SDag-Erling Smørgrav #define HTTP_PARTIAL 206 87*6f9febf9SDag-Erling Smørgrav #define HTTP_MOVED 302 883d2a8471SDag-Erling Smørgrav 894ca1ab94SDag-Erling Smørgrav struct cookie 904ca1ab94SDag-Erling Smørgrav { 914ca1ab94SDag-Erling Smørgrav FILE *real_f; 924ca1ab94SDag-Erling Smørgrav #define ENC_NONE 0 934ca1ab94SDag-Erling Smørgrav #define ENC_CHUNKED 1 944ca1ab94SDag-Erling Smørgrav int encoding; /* 1 = chunked, 0 = none */ 954ca1ab94SDag-Erling Smørgrav #define HTTPCTYPELEN 59 964ca1ab94SDag-Erling Smørgrav char content_type[HTTPCTYPELEN+1]; 974ca1ab94SDag-Erling Smørgrav char *buf; 984ca1ab94SDag-Erling Smørgrav int b_cur, eof; 994ca1ab94SDag-Erling Smørgrav unsigned b_len, chunksize; 1004ca1ab94SDag-Erling Smørgrav }; 1014ca1ab94SDag-Erling Smørgrav 102f62e5228SDag-Erling Smørgrav /* 103f62e5228SDag-Erling Smørgrav * Send a formatted line; optionally echo to terminal 104f62e5228SDag-Erling Smørgrav */ 105f62e5228SDag-Erling Smørgrav static int 106f62e5228SDag-Erling Smørgrav _http_cmd(FILE *f, char *fmt, ...) 107f62e5228SDag-Erling Smørgrav { 108f62e5228SDag-Erling Smørgrav va_list ap; 109f62e5228SDag-Erling Smørgrav 110f62e5228SDag-Erling Smørgrav va_start(ap, fmt); 111f62e5228SDag-Erling Smørgrav vfprintf(f, fmt, ap); 112f62e5228SDag-Erling Smørgrav #ifndef NDEBUG 113f62e5228SDag-Erling Smørgrav fprintf(stderr, "\033[1m>>> "); 114f62e5228SDag-Erling Smørgrav vfprintf(stderr, fmt, ap); 115f62e5228SDag-Erling Smørgrav fprintf(stderr, "\033[m"); 116f62e5228SDag-Erling Smørgrav #endif 117f62e5228SDag-Erling Smørgrav va_end(ap); 118f62e5228SDag-Erling Smørgrav 119f62e5228SDag-Erling Smørgrav return 0; /* XXX */ 120f62e5228SDag-Erling Smørgrav } 121f62e5228SDag-Erling Smørgrav 122f62e5228SDag-Erling Smørgrav /* 123f62e5228SDag-Erling Smørgrav * Fill the input buffer, do chunk decoding on the fly 124f62e5228SDag-Erling Smørgrav */ 1254ca1ab94SDag-Erling Smørgrav static char * 1264ca1ab94SDag-Erling Smørgrav _http_fillbuf(struct cookie *c) 1274ca1ab94SDag-Erling Smørgrav { 1284ca1ab94SDag-Erling Smørgrav char *ln; 1294ca1ab94SDag-Erling Smørgrav unsigned int len; 1304ca1ab94SDag-Erling Smørgrav 1314ca1ab94SDag-Erling Smørgrav if (c->eof) 1324ca1ab94SDag-Erling Smørgrav return NULL; 1334ca1ab94SDag-Erling Smørgrav 1344ca1ab94SDag-Erling Smørgrav if (c->encoding == ENC_NONE) { 1354ca1ab94SDag-Erling Smørgrav c->buf = fgetln(c->real_f, &(c->b_len)); 1364ca1ab94SDag-Erling Smørgrav c->b_cur = 0; 1374ca1ab94SDag-Erling Smørgrav } else if (c->encoding == ENC_CHUNKED) { 1384ca1ab94SDag-Erling Smørgrav if (c->chunksize == 0) { 1394ca1ab94SDag-Erling Smørgrav ln = fgetln(c->real_f, &len); 1406efb30c8SDag-Erling Smørgrav if (len <= 2) 1416efb30c8SDag-Erling Smørgrav return NULL; 1424ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, "\033[1m_http_fillbuf(): new chunk: " 1434ca1ab94SDag-Erling Smørgrav "%*.*s\033[m\n", (int)len-2, (int)len-2, ln)); 1444ca1ab94SDag-Erling Smørgrav sscanf(ln, "%x", &(c->chunksize)); 1454ca1ab94SDag-Erling Smørgrav if (!c->chunksize) { 1464ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, "\033[1m_http_fillbuf(): " 1474ca1ab94SDag-Erling Smørgrav "end of last chunk\033[m\n")); 1484ca1ab94SDag-Erling Smørgrav c->eof = 1; 1494ca1ab94SDag-Erling Smørgrav return NULL; 1504ca1ab94SDag-Erling Smørgrav } 1514ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, "\033[1m_http_fillbuf(): " 1524ca1ab94SDag-Erling Smørgrav "new chunk: %X\033[m\n", c->chunksize)); 1534ca1ab94SDag-Erling Smørgrav } 1544ca1ab94SDag-Erling Smørgrav c->buf = fgetln(c->real_f, &(c->b_len)); 1554ca1ab94SDag-Erling Smørgrav if (c->b_len > c->chunksize) 1564ca1ab94SDag-Erling Smørgrav c->b_len = c->chunksize; 1574ca1ab94SDag-Erling Smørgrav c->chunksize -= c->b_len; 1584ca1ab94SDag-Erling Smørgrav c->b_cur = 0; 1594ca1ab94SDag-Erling Smørgrav } 1604ca1ab94SDag-Erling Smørgrav else return NULL; /* unknown encoding */ 1614ca1ab94SDag-Erling Smørgrav return c->buf; 1624ca1ab94SDag-Erling Smørgrav } 1634ca1ab94SDag-Erling Smørgrav 164f62e5228SDag-Erling Smørgrav /* 165f62e5228SDag-Erling Smørgrav * Read function 166f62e5228SDag-Erling Smørgrav */ 1674ca1ab94SDag-Erling Smørgrav static int 1684ca1ab94SDag-Erling Smørgrav _http_readfn(struct cookie *c, char *buf, int len) 1694ca1ab94SDag-Erling Smørgrav { 1704ca1ab94SDag-Erling Smørgrav int l, pos = 0; 1714ca1ab94SDag-Erling Smørgrav while (len) { 1724ca1ab94SDag-Erling Smørgrav /* empty buffer */ 1734ca1ab94SDag-Erling Smørgrav if (!c->buf || (c->b_cur == c->b_len)) 1744ca1ab94SDag-Erling Smørgrav if (!_http_fillbuf(c)) 1754ca1ab94SDag-Erling Smørgrav break; 1764ca1ab94SDag-Erling Smørgrav 1774ca1ab94SDag-Erling Smørgrav l = c->b_len - c->b_cur; 1784ca1ab94SDag-Erling Smørgrav if (len < l) l = len; 1794ca1ab94SDag-Erling Smørgrav memcpy(buf + pos, c->buf + c->b_cur, l); 1804ca1ab94SDag-Erling Smørgrav c->b_cur += l; 1814ca1ab94SDag-Erling Smørgrav pos += l; 1824ca1ab94SDag-Erling Smørgrav len -= l; 1834ca1ab94SDag-Erling Smørgrav } 1844ca1ab94SDag-Erling Smørgrav 1854ca1ab94SDag-Erling Smørgrav if (ferror(c->real_f)) 1864ca1ab94SDag-Erling Smørgrav return -1; 1874ca1ab94SDag-Erling Smørgrav else return pos; 1884ca1ab94SDag-Erling Smørgrav } 1894ca1ab94SDag-Erling Smørgrav 190f62e5228SDag-Erling Smørgrav /* 191f62e5228SDag-Erling Smørgrav * Write function 192f62e5228SDag-Erling Smørgrav */ 1934ca1ab94SDag-Erling Smørgrav static int 1944ca1ab94SDag-Erling Smørgrav _http_writefn(struct cookie *c, const char *buf, int len) 1954ca1ab94SDag-Erling Smørgrav { 1964ca1ab94SDag-Erling Smørgrav size_t r = fwrite(buf, 1, (size_t)len, c->real_f); 1974ca1ab94SDag-Erling Smørgrav return r ? r : -1; 1984ca1ab94SDag-Erling Smørgrav } 1994ca1ab94SDag-Erling Smørgrav 200f62e5228SDag-Erling Smørgrav /* 201f62e5228SDag-Erling Smørgrav * Close function 202f62e5228SDag-Erling Smørgrav */ 2034ca1ab94SDag-Erling Smørgrav static int 2044ca1ab94SDag-Erling Smørgrav _http_closefn(struct cookie *c) 2054ca1ab94SDag-Erling Smørgrav { 2064ca1ab94SDag-Erling Smørgrav int r = fclose(c->real_f); 2074ca1ab94SDag-Erling Smørgrav free(c); 2084ca1ab94SDag-Erling Smørgrav return (r == EOF) ? -1 : 0; 2094ca1ab94SDag-Erling Smørgrav } 2104ca1ab94SDag-Erling Smørgrav 211f62e5228SDag-Erling Smørgrav /* 212f62e5228SDag-Erling Smørgrav * Extract content type from cookie 213f62e5228SDag-Erling Smørgrav */ 2144ca1ab94SDag-Erling Smørgrav char * 2154ca1ab94SDag-Erling Smørgrav fetchContentType(FILE *f) 2164ca1ab94SDag-Erling Smørgrav { 2174ca1ab94SDag-Erling Smørgrav /* 2184ca1ab94SDag-Erling Smørgrav * We have no way of making sure this really *is* one of our cookies, 2194ca1ab94SDag-Erling Smørgrav * so just check for a null pointer and hope for the best. 2204ca1ab94SDag-Erling Smørgrav */ 2214ca1ab94SDag-Erling Smørgrav return f->_cookie ? (((struct cookie *)f->_cookie)->content_type) : NULL; 2224ca1ab94SDag-Erling Smørgrav } 2234ca1ab94SDag-Erling Smørgrav 224f62e5228SDag-Erling Smørgrav /* 225f62e5228SDag-Erling Smørgrav * Base64 encoding 226f62e5228SDag-Erling Smørgrav */ 227f62e5228SDag-Erling Smørgrav int 228f62e5228SDag-Erling Smørgrav _http_base64(char *dst, char *src, int l) 229f62e5228SDag-Erling Smørgrav { 230f62e5228SDag-Erling Smørgrav static const char base64[] = 231f62e5228SDag-Erling Smørgrav "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 232f62e5228SDag-Erling Smørgrav "abcdefghijklmnopqrstuvwxyz" 233f62e5228SDag-Erling Smørgrav "0123456789+/"; 234f62e5228SDag-Erling Smørgrav int t, r = 0; 235f62e5228SDag-Erling Smørgrav 236f62e5228SDag-Erling Smørgrav while (l >= 3) { 237f62e5228SDag-Erling Smørgrav t = (src[0] << 16) | (src[1] << 8) | src[2]; 238f62e5228SDag-Erling Smørgrav dst[0] = base64[(t >> 18) & 0x3f]; 239f62e5228SDag-Erling Smørgrav dst[1] = base64[(t >> 12) & 0x3f]; 240f62e5228SDag-Erling Smørgrav dst[2] = base64[(t >> 6) & 0x3f]; 241f62e5228SDag-Erling Smørgrav dst[3] = base64[(t >> 0) & 0x3f]; 242f62e5228SDag-Erling Smørgrav src += 3; l -= 3; 243f62e5228SDag-Erling Smørgrav dst += 4; r += 4; 244f62e5228SDag-Erling Smørgrav } 245f62e5228SDag-Erling Smørgrav 246f62e5228SDag-Erling Smørgrav switch (l) { 247f62e5228SDag-Erling Smørgrav case 2: 248f62e5228SDag-Erling Smørgrav t = (src[0] << 16) | (src[1] << 8); 249f62e5228SDag-Erling Smørgrav dst[0] = base64[(t >> 18) & 0x3f]; 250f62e5228SDag-Erling Smørgrav dst[1] = base64[(t >> 12) & 0x3f]; 251f62e5228SDag-Erling Smørgrav dst[2] = base64[(t >> 6) & 0x3f]; 252f62e5228SDag-Erling Smørgrav dst[3] = '='; 253f62e5228SDag-Erling Smørgrav dst += 4; 254f62e5228SDag-Erling Smørgrav r += 4; 255f62e5228SDag-Erling Smørgrav break; 256f62e5228SDag-Erling Smørgrav case 1: 257f62e5228SDag-Erling Smørgrav t = src[0] << 16; 258f62e5228SDag-Erling Smørgrav dst[0] = base64[(t >> 18) & 0x3f]; 259f62e5228SDag-Erling Smørgrav dst[1] = base64[(t >> 12) & 0x3f]; 260f62e5228SDag-Erling Smørgrav dst[2] = dst[3] = '='; 261f62e5228SDag-Erling Smørgrav dst += 4; 262f62e5228SDag-Erling Smørgrav r += 4; 263f62e5228SDag-Erling Smørgrav break; 264f62e5228SDag-Erling Smørgrav case 0: 265f62e5228SDag-Erling Smørgrav break; 266f62e5228SDag-Erling Smørgrav } 267f62e5228SDag-Erling Smørgrav 268f62e5228SDag-Erling Smørgrav *dst = 0; 269f62e5228SDag-Erling Smørgrav return r; 270f62e5228SDag-Erling Smørgrav } 271f62e5228SDag-Erling Smørgrav 272f62e5228SDag-Erling Smørgrav /* 273f62e5228SDag-Erling Smørgrav * Encode username and password 274f62e5228SDag-Erling Smørgrav */ 275f62e5228SDag-Erling Smørgrav char * 276f62e5228SDag-Erling Smørgrav _http_auth(char *usr, char *pwd) 277f62e5228SDag-Erling Smørgrav { 278f62e5228SDag-Erling Smørgrav int len, lu, lp; 279f62e5228SDag-Erling Smørgrav char *str, *s; 280f62e5228SDag-Erling Smørgrav 281f62e5228SDag-Erling Smørgrav lu = strlen(usr); 282f62e5228SDag-Erling Smørgrav lp = strlen(pwd); 283f62e5228SDag-Erling Smørgrav 284f62e5228SDag-Erling Smørgrav len = (lu * 4 + 2) / 3 /* user name, round up */ 285f62e5228SDag-Erling Smørgrav + 1 /* colon */ 286f62e5228SDag-Erling Smørgrav + (lp * 4 + 2) / 3 /* password, round up */ 287f62e5228SDag-Erling Smørgrav + 1; /* null */ 288f62e5228SDag-Erling Smørgrav 289f62e5228SDag-Erling Smørgrav if ((s = str = (char *)malloc(len)) == NULL) 290f62e5228SDag-Erling Smørgrav return NULL; 291f62e5228SDag-Erling Smørgrav 292f62e5228SDag-Erling Smørgrav s += _http_base64(s, usr, lu); 293f62e5228SDag-Erling Smørgrav *s++ = ':'; 294f62e5228SDag-Erling Smørgrav s += _http_base64(s, pwd, lp); 295f62e5228SDag-Erling Smørgrav *s = 0; 296f62e5228SDag-Erling Smørgrav 297f62e5228SDag-Erling Smørgrav return str; 298f62e5228SDag-Erling Smørgrav } 299f62e5228SDag-Erling Smørgrav 300f62e5228SDag-Erling Smørgrav /* 30160245e42SDag-Erling Smørgrav * Connect to server or proxy 302f62e5228SDag-Erling Smørgrav */ 3034ca1ab94SDag-Erling Smørgrav FILE * 30460245e42SDag-Erling Smørgrav _http_connect(struct url *URL, char *flags) 3054ca1ab94SDag-Erling Smørgrav { 30660245e42SDag-Erling Smørgrav int direct, sd = -1, verbose; 30728c645cfSHajimu UMEMOTO #ifdef INET6 30828c645cfSHajimu UMEMOTO int af = AF_UNSPEC; 30928c645cfSHajimu UMEMOTO #else 31028c645cfSHajimu UMEMOTO int af = AF_INET; 31128c645cfSHajimu UMEMOTO #endif 3124ca1ab94SDag-Erling Smørgrav size_t len; 31360245e42SDag-Erling Smørgrav char *px; 31460245e42SDag-Erling Smørgrav FILE *f; 3154ca1ab94SDag-Erling Smørgrav 316f5f109a0SDag-Erling Smørgrav direct = (flags && strchr(flags, 'd')); 317f5f109a0SDag-Erling Smørgrav verbose = (flags && strchr(flags, 'v')); 31828c645cfSHajimu UMEMOTO if ((flags && strchr(flags, '4'))) 31928c645cfSHajimu UMEMOTO af = AF_INET; 32028c645cfSHajimu UMEMOTO else if ((flags && strchr(flags, '6'))) 32128c645cfSHajimu UMEMOTO af = AF_INET6; 3220fba3a00SDag-Erling Smørgrav 3234ca1ab94SDag-Erling Smørgrav /* check port */ 324e6182307SDag-Erling Smørgrav if (!URL->port) { 325e6182307SDag-Erling Smørgrav struct servent *se; 326e6182307SDag-Erling Smørgrav 327c97925adSHajimu UMEMOTO if (strcasecmp(URL->scheme, "ftp") == 0) 328c97925adSHajimu UMEMOTO if ((se = getservbyname("ftp", "tcp")) != NULL) 329c97925adSHajimu UMEMOTO URL->port = ntohs(se->s_port); 330c97925adSHajimu UMEMOTO else 331c97925adSHajimu UMEMOTO URL->port = 21; 332c97925adSHajimu UMEMOTO else 333e6182307SDag-Erling Smørgrav if ((se = getservbyname("http", "tcp")) != NULL) 334e6182307SDag-Erling Smørgrav URL->port = ntohs(se->s_port); 335e6182307SDag-Erling Smørgrav else 336e6182307SDag-Erling Smørgrav URL->port = 80; 337e6182307SDag-Erling Smørgrav } 3384ca1ab94SDag-Erling Smørgrav 3394ca1ab94SDag-Erling Smørgrav /* attempt to connect to proxy server */ 340f5f109a0SDag-Erling Smørgrav if (!direct && (px = getenv("HTTP_PROXY")) != NULL) { 3413b7a6740SDag-Erling Smørgrav char host[MAXHOSTNAMELEN]; 342e6182307SDag-Erling Smørgrav int port = 0; 3434ca1ab94SDag-Erling Smørgrav 3444ca1ab94SDag-Erling Smørgrav /* measure length */ 34528c645cfSHajimu UMEMOTO #ifdef INET6 34628c645cfSHajimu UMEMOTO if (px[0] != '[' || 34728c645cfSHajimu UMEMOTO (len = strcspn(px, "]")) >= strlen(px) || 34828c645cfSHajimu UMEMOTO (px[++len] != '\0' && px[len] != ':')) 34928c645cfSHajimu UMEMOTO #endif 3504ca1ab94SDag-Erling Smørgrav len = strcspn(px, ":"); 3514ca1ab94SDag-Erling Smørgrav 352f5f109a0SDag-Erling Smørgrav /* get port (XXX atoi is a little too tolerant perhaps?) */ 353e6182307SDag-Erling Smørgrav if (px[len] == ':') { 354e6182307SDag-Erling Smørgrav if (strspn(px+len+1, "0123456789") != strlen(px+len+1) 355e6182307SDag-Erling Smørgrav || strlen(px+len+1) > 5) { 356e6182307SDag-Erling Smørgrav /* XXX we should emit some kind of warning */ 357e6182307SDag-Erling Smørgrav } 3584ca1ab94SDag-Erling Smørgrav port = atoi(px+len+1); 359e6182307SDag-Erling Smørgrav if (port < 1 || port > 65535) { 360e6182307SDag-Erling Smørgrav /* XXX we should emit some kind of warning */ 361e6182307SDag-Erling Smørgrav } 362e6182307SDag-Erling Smørgrav } 363e6182307SDag-Erling Smørgrav if (!port) { 364e6182307SDag-Erling Smørgrav #if 0 365e6182307SDag-Erling Smørgrav /* 366e6182307SDag-Erling Smørgrav * commented out, since there is currently no service name 367e6182307SDag-Erling Smørgrav * for HTTP proxies 368e6182307SDag-Erling Smørgrav */ 369e6182307SDag-Erling Smørgrav struct servent *se; 370e6182307SDag-Erling Smørgrav 371e6182307SDag-Erling Smørgrav if ((se = getservbyname("xxxx", "tcp")) != NULL) 372e6182307SDag-Erling Smørgrav port = ntohs(se->s_port); 373e6182307SDag-Erling Smørgrav else 374e6182307SDag-Erling Smørgrav #endif 375e6182307SDag-Erling Smørgrav port = 3128; 376e6182307SDag-Erling Smørgrav } 3774ca1ab94SDag-Erling Smørgrav 3784ca1ab94SDag-Erling Smørgrav /* get host name */ 37928c645cfSHajimu UMEMOTO #ifdef INET6 38028c645cfSHajimu UMEMOTO if (len > 1 && px[0] == '[' && px[len - 1] == ']') { 38128c645cfSHajimu UMEMOTO px++; 38228c645cfSHajimu UMEMOTO len -= 2; 38328c645cfSHajimu UMEMOTO } 38428c645cfSHajimu UMEMOTO #endif 3854ca1ab94SDag-Erling Smørgrav if (len >= MAXHOSTNAMELEN) 3864ca1ab94SDag-Erling Smørgrav len = MAXHOSTNAMELEN - 1; 3874ca1ab94SDag-Erling Smørgrav strncpy(host, px, len); 3884ca1ab94SDag-Erling Smørgrav host[len] = 0; 3894ca1ab94SDag-Erling Smørgrav 3904ca1ab94SDag-Erling Smørgrav /* connect */ 39128c645cfSHajimu UMEMOTO sd = _fetch_connect(host, port, af, verbose); 3924ca1ab94SDag-Erling Smørgrav } 3934ca1ab94SDag-Erling Smørgrav 3944ca1ab94SDag-Erling Smørgrav /* if no proxy is configured or could be contacted, try direct */ 395ecc91352SDag-Erling Smørgrav if (sd == -1) { 396c97925adSHajimu UMEMOTO if (strcasecmp(URL->scheme, "ftp") == 0) 397c97925adSHajimu UMEMOTO goto ouch; 39828c645cfSHajimu UMEMOTO if ((sd = _fetch_connect(URL->host, URL->port, af, verbose)) == -1) 3994ca1ab94SDag-Erling Smørgrav goto ouch; 4004ca1ab94SDag-Erling Smørgrav } 4014ca1ab94SDag-Erling Smørgrav 4024ca1ab94SDag-Erling Smørgrav /* reopen as stream */ 4038e3986eaSDag-Erling Smørgrav if ((f = fdopen(sd, "r+")) == NULL) 4044ca1ab94SDag-Erling Smørgrav goto ouch; 40560245e42SDag-Erling Smørgrav 40660245e42SDag-Erling Smørgrav return f; 40760245e42SDag-Erling Smørgrav 40860245e42SDag-Erling Smørgrav ouch: 40960245e42SDag-Erling Smørgrav if (sd >= 0) 41060245e42SDag-Erling Smørgrav close(sd); 41160245e42SDag-Erling Smørgrav _http_seterr(999); /* XXX do this properly RSN */ 41260245e42SDag-Erling Smørgrav return NULL; 41360245e42SDag-Erling Smørgrav } 41460245e42SDag-Erling Smørgrav 41560245e42SDag-Erling Smørgrav /* 416*6f9febf9SDag-Erling Smørgrav * Check a header line 417*6f9febf9SDag-Erling Smørgrav */ 418*6f9febf9SDag-Erling Smørgrav char * 419*6f9febf9SDag-Erling Smørgrav _http_match(char *str, char *hdr) 420*6f9febf9SDag-Erling Smørgrav { 421*6f9febf9SDag-Erling Smørgrav while (*str && *hdr && tolower(*str++) == tolower(*hdr++)) 422*6f9febf9SDag-Erling Smørgrav /* nothing */; 423*6f9febf9SDag-Erling Smørgrav if (*str || *hdr != ':') 424*6f9febf9SDag-Erling Smørgrav return NULL; 425*6f9febf9SDag-Erling Smørgrav while (*hdr && isspace(*++hdr)) 426*6f9febf9SDag-Erling Smørgrav /* nothing */; 427*6f9febf9SDag-Erling Smørgrav return hdr; 428*6f9febf9SDag-Erling Smørgrav } 429*6f9febf9SDag-Erling Smørgrav 430*6f9febf9SDag-Erling Smørgrav /* 43160245e42SDag-Erling Smørgrav * Send a HEAD or GET request 43260245e42SDag-Erling Smørgrav */ 43360245e42SDag-Erling Smørgrav int 43460245e42SDag-Erling Smørgrav _http_request(FILE *f, char *op, struct url *URL, char *flags) 43560245e42SDag-Erling Smørgrav { 43660245e42SDag-Erling Smørgrav int e, verbose; 43760245e42SDag-Erling Smørgrav char *ln, *p; 43860245e42SDag-Erling Smørgrav size_t len; 43928c645cfSHajimu UMEMOTO char *host; 44028c645cfSHajimu UMEMOTO #ifdef INET6 44128c645cfSHajimu UMEMOTO char hbuf[MAXHOSTNAMELEN + 1]; 44228c645cfSHajimu UMEMOTO #endif 44360245e42SDag-Erling Smørgrav 44460245e42SDag-Erling Smørgrav verbose = (flags && strchr(flags, 'v')); 4454ca1ab94SDag-Erling Smørgrav 44628c645cfSHajimu UMEMOTO host = URL->host; 44728c645cfSHajimu UMEMOTO #ifdef INET6 44828c645cfSHajimu UMEMOTO if (strchr(URL->host, ':')) { 44928c645cfSHajimu UMEMOTO snprintf(hbuf, sizeof(hbuf), "[%s]", URL->host); 45028c645cfSHajimu UMEMOTO host = hbuf; 45128c645cfSHajimu UMEMOTO } 45228c645cfSHajimu UMEMOTO #endif 45328c645cfSHajimu UMEMOTO 4544ca1ab94SDag-Erling Smørgrav /* send request (proxies require absolute form, so use that) */ 4550fba3a00SDag-Erling Smørgrav if (verbose) 456c97925adSHajimu UMEMOTO _fetch_info("requesting %s://%s:%d%s", 45728c645cfSHajimu UMEMOTO URL->scheme, host, URL->port, URL->doc); 45860245e42SDag-Erling Smørgrav _http_cmd(f, "%s %s://%s:%d%s HTTP/1.1" ENDL, 45928c645cfSHajimu UMEMOTO op, URL->scheme, host, URL->port, URL->doc); 4604ca1ab94SDag-Erling Smørgrav 4614ca1ab94SDag-Erling Smørgrav /* start sending headers away */ 4624ca1ab94SDag-Erling Smørgrav if (URL->user[0] || URL->pwd[0]) { 463f62e5228SDag-Erling Smørgrav char *auth_str = _http_auth(URL->user, URL->pwd); 464f62e5228SDag-Erling Smørgrav if (!auth_str) 46560245e42SDag-Erling Smørgrav return 999; /* XXX wrong */ 466f62e5228SDag-Erling Smørgrav _http_cmd(f, "Authorization: Basic %s" ENDL, auth_str); 467f62e5228SDag-Erling Smørgrav free(auth_str); 4684ca1ab94SDag-Erling Smørgrav } 46928c645cfSHajimu UMEMOTO _http_cmd(f, "Host: %s:%d" ENDL, host, URL->port); 470f62e5228SDag-Erling Smørgrav _http_cmd(f, "User-Agent: %s " _LIBFETCH_VER ENDL, __progname); 4713d2a8471SDag-Erling Smørgrav if (URL->offset) 4723d2a8471SDag-Erling Smørgrav _http_cmd(f, "Range: bytes=%lld-" ENDL, URL->offset); 473f62e5228SDag-Erling Smørgrav _http_cmd(f, "Connection: close" ENDL ENDL); 4744ca1ab94SDag-Erling Smørgrav 4754ca1ab94SDag-Erling Smørgrav /* get response */ 4764ca1ab94SDag-Erling Smørgrav if ((ln = fgetln(f, &len)) == NULL) 47760245e42SDag-Erling Smørgrav return 999; 4784ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, "response: [\033[1m%*.*s\033[m]\n", 4794ca1ab94SDag-Erling Smørgrav (int)len-2, (int)len-2, ln)); 4804ca1ab94SDag-Erling Smørgrav 4814ca1ab94SDag-Erling Smørgrav /* we can't use strchr() and friends since ln isn't NUL-terminated */ 4824ca1ab94SDag-Erling Smørgrav p = ln; 4834ca1ab94SDag-Erling Smørgrav while ((p < ln + len) && !isspace(*p)) 4844ca1ab94SDag-Erling Smørgrav p++; 4854ca1ab94SDag-Erling Smørgrav while ((p < ln + len) && !isdigit(*p)) 4864ca1ab94SDag-Erling Smørgrav p++; 4874ca1ab94SDag-Erling Smørgrav if (!isdigit(*p)) 48860245e42SDag-Erling Smørgrav return 999; 48960245e42SDag-Erling Smørgrav 4903b7a6740SDag-Erling Smørgrav e = atoi(p); 4913b7a6740SDag-Erling Smørgrav DEBUG(fprintf(stderr, "code: [\033[1m%d\033[m]\n", e)); 49260245e42SDag-Erling Smørgrav return e; 49360245e42SDag-Erling Smørgrav } 49460245e42SDag-Erling Smørgrav 49560245e42SDag-Erling Smørgrav /* 49660245e42SDag-Erling Smørgrav * Retrieve a file by HTTP 49760245e42SDag-Erling Smørgrav */ 49860245e42SDag-Erling Smørgrav FILE * 49960245e42SDag-Erling Smørgrav fetchGetHTTP(struct url *URL, char *flags) 50060245e42SDag-Erling Smørgrav { 501*6f9febf9SDag-Erling Smørgrav int e, enc = ENC_NONE, i, noredirect; 50260245e42SDag-Erling Smørgrav struct cookie *c; 50360245e42SDag-Erling Smørgrav char *ln, *p, *q; 50460245e42SDag-Erling Smørgrav FILE *f, *cf; 50560245e42SDag-Erling Smørgrav size_t len; 50660245e42SDag-Erling Smørgrav off_t pos = 0; 50760245e42SDag-Erling Smørgrav 508*6f9febf9SDag-Erling Smørgrav noredirect = (flags && strchr(flags, 'A')); 509*6f9febf9SDag-Erling Smørgrav 51060245e42SDag-Erling Smørgrav /* allocate cookie */ 51160245e42SDag-Erling Smørgrav if ((c = calloc(1, sizeof *c)) == NULL) 51260245e42SDag-Erling Smørgrav return NULL; 51360245e42SDag-Erling Smørgrav 51460245e42SDag-Erling Smørgrav /* connect */ 51560245e42SDag-Erling Smørgrav if ((f = _http_connect(URL, flags)) == NULL) { 51660245e42SDag-Erling Smørgrav free(c); 51760245e42SDag-Erling Smørgrav return NULL; 51860245e42SDag-Erling Smørgrav } 51960245e42SDag-Erling Smørgrav c->real_f = f; 52060245e42SDag-Erling Smørgrav 52160245e42SDag-Erling Smørgrav e = _http_request(f, "GET", URL, flags); 522*6f9febf9SDag-Erling Smørgrav if (e != (URL->offset ? HTTP_PARTIAL : HTTP_OK) 523*6f9febf9SDag-Erling Smørgrav && (e != HTTP_MOVED || noredirect)) { 5243b7a6740SDag-Erling Smørgrav _http_seterr(e); 5254ca1ab94SDag-Erling Smørgrav goto fouch; 5268e3986eaSDag-Erling Smørgrav } 5274ca1ab94SDag-Erling Smørgrav 5284ca1ab94SDag-Erling Smørgrav /* browse through header */ 5294ca1ab94SDag-Erling Smørgrav while (1) { 5304ca1ab94SDag-Erling Smørgrav if ((ln = fgetln(f, &len)) == NULL) 5314ca1ab94SDag-Erling Smørgrav goto fouch; 5324ca1ab94SDag-Erling Smørgrav if ((ln[0] == '\r') || (ln[0] == '\n')) 5334ca1ab94SDag-Erling Smørgrav break; 53460245e42SDag-Erling Smørgrav while (isspace(ln[len-1])) 53560245e42SDag-Erling Smørgrav --len; 53660245e42SDag-Erling Smørgrav ln[len] = '\0'; /* XXX */ 53760245e42SDag-Erling Smørgrav DEBUG(fprintf(stderr, "header: [\033[1m%s\033[m]\n", ln)); 538*6f9febf9SDag-Erling Smørgrav if ((p = _http_match("Location", ln)) != NULL) { 539*6f9febf9SDag-Erling Smørgrav struct url *url; 540*6f9febf9SDag-Erling Smørgrav 541*6f9febf9SDag-Erling Smørgrav for (q = p; *q && !isspace(*q); q++) 542*6f9febf9SDag-Erling Smørgrav /* VOID */ ; 543*6f9febf9SDag-Erling Smørgrav *q = 0; 544*6f9febf9SDag-Erling Smørgrav if ((url = fetchParseURL(p)) == NULL) 545*6f9febf9SDag-Erling Smørgrav goto fouch; 546*6f9febf9SDag-Erling Smørgrav url->offset = URL->offset; 547*6f9febf9SDag-Erling Smørgrav url->length = URL->length; 548*6f9febf9SDag-Erling Smørgrav DEBUG(fprintf(stderr, "location: [\033[1m%s\033[m]\n", p)); 549*6f9febf9SDag-Erling Smørgrav cf = fetchGetHTTP(url, flags); 550*6f9febf9SDag-Erling Smørgrav fetchFreeURL(url); 551*6f9febf9SDag-Erling Smørgrav fclose(f); 552*6f9febf9SDag-Erling Smørgrav return cf; 553*6f9febf9SDag-Erling Smørgrav } else if ((p = _http_match("Transfer-Encoding", ln)) != NULL) { 55460245e42SDag-Erling Smørgrav for (q = p; *q && !isspace(*q); q++) 5554ca1ab94SDag-Erling Smørgrav /* VOID */ ; 5564ca1ab94SDag-Erling Smørgrav *q = 0; 5574ca1ab94SDag-Erling Smørgrav if (strcasecmp(p, "chunked") == 0) 5584ca1ab94SDag-Erling Smørgrav enc = ENC_CHUNKED; 55960245e42SDag-Erling Smørgrav DEBUG(fprintf(stderr, "transfer encoding: [\033[1m%s\033[m]\n", p)); 56060245e42SDag-Erling Smørgrav } else if ((p = _http_match("Content-Type", ln)) != NULL) { 56160245e42SDag-Erling Smørgrav for (i = 0; *p && i < HTTPCTYPELEN; p++, i++) 56260245e42SDag-Erling Smørgrav c->content_type[i] = *p; 5634ca1ab94SDag-Erling Smørgrav do c->content_type[i--] = 0; while (isspace(c->content_type[i])); 56460245e42SDag-Erling Smørgrav DEBUG(fprintf(stderr, "content type: [\033[1m%s\033[m]\n", 5654ca1ab94SDag-Erling Smørgrav c->content_type)); 56660245e42SDag-Erling Smørgrav } else if ((p = _http_match("Content-Range", ln)) != NULL) { 56760245e42SDag-Erling Smørgrav if (strncasecmp(p, "bytes ", 6) != 0) 5683d2a8471SDag-Erling Smørgrav goto fouch; 56960245e42SDag-Erling Smørgrav p += 6; 57060245e42SDag-Erling Smørgrav while (*p && isdigit(*p)) 5713d2a8471SDag-Erling Smørgrav pos = pos * 10 + (*p++ - '0'); 5723d2a8471SDag-Erling Smørgrav /* XXX wouldn't hurt to be slightly more paranoid here */ 57360245e42SDag-Erling Smørgrav DEBUG(fprintf(stderr, "content range: [\033[1m%lld-\033[m]\n", pos)); 5743d2a8471SDag-Erling Smørgrav if (pos > URL->offset) 5753d2a8471SDag-Erling Smørgrav goto fouch; 5764ca1ab94SDag-Erling Smørgrav } 5774ca1ab94SDag-Erling Smørgrav } 5784ca1ab94SDag-Erling Smørgrav 5794ca1ab94SDag-Erling Smørgrav /* only body remains */ 5804ca1ab94SDag-Erling Smørgrav c->encoding = enc; 5814ca1ab94SDag-Erling Smørgrav cf = funopen(c, 5824ca1ab94SDag-Erling Smørgrav (int (*)(void *, char *, int))_http_readfn, 5834ca1ab94SDag-Erling Smørgrav (int (*)(void *, const char *, int))_http_writefn, 5844ca1ab94SDag-Erling Smørgrav (fpos_t (*)(void *, fpos_t, int))NULL, 5854ca1ab94SDag-Erling Smørgrav (int (*)(void *))_http_closefn); 5864ca1ab94SDag-Erling Smørgrav if (cf == NULL) 5874ca1ab94SDag-Erling Smørgrav goto fouch; 588e6182307SDag-Erling Smørgrav 5893d2a8471SDag-Erling Smørgrav while (pos < URL->offset) 5903d2a8471SDag-Erling Smørgrav if (fgetc(cf) == EOF) 5913d2a8471SDag-Erling Smørgrav goto cfouch; 5923d2a8471SDag-Erling Smørgrav 5934ca1ab94SDag-Erling Smørgrav return cf; 5944ca1ab94SDag-Erling Smørgrav 5954ca1ab94SDag-Erling Smørgrav fouch: 5964ca1ab94SDag-Erling Smørgrav fclose(f); 5974ca1ab94SDag-Erling Smørgrav free(c); 5980fba3a00SDag-Erling Smørgrav _http_seterr(999); /* XXX do this properly RSN */ 5994ca1ab94SDag-Erling Smørgrav return NULL; 6003d2a8471SDag-Erling Smørgrav cfouch: 6013d2a8471SDag-Erling Smørgrav fclose(cf); 6023d2a8471SDag-Erling Smørgrav _http_seterr(999); /* XXX do this properly RSN */ 6033d2a8471SDag-Erling Smørgrav return NULL; 6044ca1ab94SDag-Erling Smørgrav } 6054ca1ab94SDag-Erling Smørgrav 6064ca1ab94SDag-Erling Smørgrav FILE * 607d8acd8dcSDag-Erling Smørgrav fetchPutHTTP(struct url *URL, char *flags) 6084ca1ab94SDag-Erling Smørgrav { 6094ca1ab94SDag-Erling Smørgrav warnx("fetchPutHTTP(): not implemented"); 6104ca1ab94SDag-Erling Smørgrav return NULL; 6114ca1ab94SDag-Erling Smørgrav } 612d8acd8dcSDag-Erling Smørgrav 613d8acd8dcSDag-Erling Smørgrav /* 614d8acd8dcSDag-Erling Smørgrav * Get an HTTP document's metadata 615d8acd8dcSDag-Erling Smørgrav */ 616d8acd8dcSDag-Erling Smørgrav int 61760245e42SDag-Erling Smørgrav fetchStatHTTP(struct url *URL, struct url_stat *us, char *flags) 618d8acd8dcSDag-Erling Smørgrav { 619*6f9febf9SDag-Erling Smørgrav int e, noredirect; 62060245e42SDag-Erling Smørgrav size_t len; 621*6f9febf9SDag-Erling Smørgrav char *ln, *p, *q; 62260245e42SDag-Erling Smørgrav FILE *f; 62360245e42SDag-Erling Smørgrav 624*6f9febf9SDag-Erling Smørgrav noredirect = (flags && strchr(flags, 'A')); 625*6f9febf9SDag-Erling Smørgrav 626f8f4130bSDag-Erling Smørgrav us->size = -1; 627f8f4130bSDag-Erling Smørgrav us->atime = us->mtime = 0; 62860245e42SDag-Erling Smørgrav 62960245e42SDag-Erling Smørgrav /* connect */ 63060245e42SDag-Erling Smørgrav if ((f = _http_connect(URL, flags)) == NULL) 63160245e42SDag-Erling Smørgrav return -1; 63260245e42SDag-Erling Smørgrav 633*6f9febf9SDag-Erling Smørgrav e = _http_request(f, "HEAD", URL, flags); 634*6f9febf9SDag-Erling Smørgrav if (e != HTTP_OK && (e != HTTP_MOVED || noredirect)) { 63560245e42SDag-Erling Smørgrav _http_seterr(e); 63660245e42SDag-Erling Smørgrav goto ouch; 63760245e42SDag-Erling Smørgrav } 63860245e42SDag-Erling Smørgrav 63960245e42SDag-Erling Smørgrav while (1) { 64060245e42SDag-Erling Smørgrav if ((ln = fgetln(f, &len)) == NULL) 64160245e42SDag-Erling Smørgrav goto fouch; 64260245e42SDag-Erling Smørgrav if ((ln[0] == '\r') || (ln[0] == '\n')) 64360245e42SDag-Erling Smørgrav break; 64460245e42SDag-Erling Smørgrav while (isspace(ln[len-1])) 64560245e42SDag-Erling Smørgrav --len; 64660245e42SDag-Erling Smørgrav ln[len] = '\0'; /* XXX */ 64760245e42SDag-Erling Smørgrav DEBUG(fprintf(stderr, "header: [\033[1m%s\033[m]\n", ln)); 648*6f9febf9SDag-Erling Smørgrav if ((p = _http_match("Location", ln)) != NULL) { 649*6f9febf9SDag-Erling Smørgrav struct url *url; 650*6f9febf9SDag-Erling Smørgrav 651*6f9febf9SDag-Erling Smørgrav for (q = p; *q && !isspace(*q); q++) 652*6f9febf9SDag-Erling Smørgrav /* VOID */ ; 653*6f9febf9SDag-Erling Smørgrav *q = 0; 654*6f9febf9SDag-Erling Smørgrav if ((url = fetchParseURL(p)) == NULL) 655*6f9febf9SDag-Erling Smørgrav goto ouch; 656*6f9febf9SDag-Erling Smørgrav url->offset = URL->offset; 657*6f9febf9SDag-Erling Smørgrav url->length = URL->length; 658*6f9febf9SDag-Erling Smørgrav DEBUG(fprintf(stderr, "location: [\033[1m%s\033[m]\n", p)); 659*6f9febf9SDag-Erling Smørgrav e = fetchStatHTTP(url, us, flags); 660*6f9febf9SDag-Erling Smørgrav fetchFreeURL(url); 661*6f9febf9SDag-Erling Smørgrav fclose(f); 662*6f9febf9SDag-Erling Smørgrav return e; 663*6f9febf9SDag-Erling Smørgrav } else if ((p = _http_match("Last-Modified", ln)) != NULL) { 66460245e42SDag-Erling Smørgrav struct tm tm; 66560245e42SDag-Erling Smørgrav char locale[64]; 66660245e42SDag-Erling Smørgrav 66760245e42SDag-Erling Smørgrav strncpy(locale, setlocale(LC_TIME, NULL), sizeof locale); 66860245e42SDag-Erling Smørgrav setlocale(LC_TIME, "C"); 66960245e42SDag-Erling Smørgrav strptime(p, "%a, %d %b %Y %H:%M:%S GMT", &tm); 67060245e42SDag-Erling Smørgrav /* XXX should add support for date-2 and date-3 */ 67160245e42SDag-Erling Smørgrav setlocale(LC_TIME, locale); 67260245e42SDag-Erling Smørgrav us->atime = us->mtime = timegm(&tm); 67360245e42SDag-Erling Smørgrav DEBUG(fprintf(stderr, "last modified: [\033[1m%04d-%02d-%02d " 67460245e42SDag-Erling Smørgrav "%02d:%02d:%02d\033[m]\n", 67560245e42SDag-Erling Smørgrav tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 67660245e42SDag-Erling Smørgrav tm.tm_hour, tm.tm_min, tm.tm_sec)); 67760245e42SDag-Erling Smørgrav } else if ((p = _http_match("Content-Length", ln)) != NULL) { 67860245e42SDag-Erling Smørgrav us->size = 0; 67960245e42SDag-Erling Smørgrav while (*p && isdigit(*p)) 68060245e42SDag-Erling Smørgrav us->size = us->size * 10 + (*p++ - '0'); 68160245e42SDag-Erling Smørgrav DEBUG(fprintf(stderr, "content length: [\033[1m%lld\033[m]\n", us->size)); 68260245e42SDag-Erling Smørgrav } 68360245e42SDag-Erling Smørgrav } 68460245e42SDag-Erling Smørgrav 685f8f4130bSDag-Erling Smørgrav fclose(f); 68660245e42SDag-Erling Smørgrav return 0; 68760245e42SDag-Erling Smørgrav ouch: 68860245e42SDag-Erling Smørgrav _http_seterr(999); /* XXX do this properly RSN */ 68960245e42SDag-Erling Smørgrav fouch: 69060245e42SDag-Erling Smørgrav fclose(f); 691d8acd8dcSDag-Erling Smørgrav return -1; 692d8acd8dcSDag-Erling Smørgrav } 693ce71b736SDag-Erling Smørgrav 694ce71b736SDag-Erling Smørgrav /* 695ce71b736SDag-Erling Smørgrav * List a directory 696ce71b736SDag-Erling Smørgrav */ 697ce71b736SDag-Erling Smørgrav struct url_ent * 698ce71b736SDag-Erling Smørgrav fetchListHTTP(struct url *url, char *flags) 699ce71b736SDag-Erling Smørgrav { 700ce71b736SDag-Erling Smørgrav warnx("fetchListHTTP(): not implemented"); 701ce71b736SDag-Erling Smørgrav return NULL; 702ce71b736SDag-Erling Smørgrav } 703