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 * 28f62e5228SDag-Erling Smørgrav * $Id: http.c,v 1.3 1998/07/11 21:29:08 des Exp $ 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> 644ca1ab94SDag-Erling Smørgrav #include <sys/errno.h> 654ca1ab94SDag-Erling Smørgrav #include <sys/socket.h> 664ca1ab94SDag-Erling Smørgrav #include <sys/types.h> 674ca1ab94SDag-Erling Smørgrav 684ca1ab94SDag-Erling Smørgrav #include <netinet/in.h> 694ca1ab94SDag-Erling Smørgrav 704ca1ab94SDag-Erling Smørgrav #include <err.h> 714ca1ab94SDag-Erling Smørgrav #include <ctype.h> 724ca1ab94SDag-Erling Smørgrav #include <netdb.h> 73f62e5228SDag-Erling Smørgrav #include <stdarg.h> 744ca1ab94SDag-Erling Smørgrav #include <stdio.h> 754ca1ab94SDag-Erling Smørgrav #include <stdlib.h> 764ca1ab94SDag-Erling Smørgrav #include <string.h> 774ca1ab94SDag-Erling Smørgrav #include <unistd.h> 784ca1ab94SDag-Erling Smørgrav 794ca1ab94SDag-Erling Smørgrav #include "fetch.h" 804ca1ab94SDag-Erling Smørgrav #include "httperr.c" 814ca1ab94SDag-Erling Smørgrav 824ca1ab94SDag-Erling Smørgrav #ifndef NDEBUG 834ca1ab94SDag-Erling Smørgrav #define DEBUG(x) do x; while (0) 844ca1ab94SDag-Erling Smørgrav #else 854ca1ab94SDag-Erling Smørgrav #define DEBUG(x) do { } while (0) 864ca1ab94SDag-Erling Smørgrav #endif 874ca1ab94SDag-Erling Smørgrav 884ca1ab94SDag-Erling Smørgrav extern char *__progname; 894ca1ab94SDag-Erling Smørgrav 904ca1ab94SDag-Erling Smørgrav #define ENDL "\r\n" 914ca1ab94SDag-Erling Smørgrav 924ca1ab94SDag-Erling Smørgrav struct cookie 934ca1ab94SDag-Erling Smørgrav { 944ca1ab94SDag-Erling Smørgrav FILE *real_f; 954ca1ab94SDag-Erling Smørgrav #define ENC_NONE 0 964ca1ab94SDag-Erling Smørgrav #define ENC_CHUNKED 1 974ca1ab94SDag-Erling Smørgrav int encoding; /* 1 = chunked, 0 = none */ 984ca1ab94SDag-Erling Smørgrav #define HTTPCTYPELEN 59 994ca1ab94SDag-Erling Smørgrav char content_type[HTTPCTYPELEN+1]; 1004ca1ab94SDag-Erling Smørgrav char *buf; 1014ca1ab94SDag-Erling Smørgrav int b_cur, eof; 1024ca1ab94SDag-Erling Smørgrav unsigned b_len, chunksize; 1034ca1ab94SDag-Erling Smørgrav }; 1044ca1ab94SDag-Erling Smørgrav 105f62e5228SDag-Erling Smørgrav /* 106f62e5228SDag-Erling Smørgrav * Look up error code 107f62e5228SDag-Erling Smørgrav */ 1088e3986eaSDag-Erling Smørgrav static const char * 1098e3986eaSDag-Erling Smørgrav _http_errstring(int e) 1104ca1ab94SDag-Erling Smørgrav { 1118e3986eaSDag-Erling Smørgrav struct httperr *p = _http_errlist; 1124ca1ab94SDag-Erling Smørgrav 1138e3986eaSDag-Erling Smørgrav while ((p->num != -1) && (p->num != e)) 1148e3986eaSDag-Erling Smørgrav p++; 1154ca1ab94SDag-Erling Smørgrav 1168e3986eaSDag-Erling Smørgrav return p->string; 1174ca1ab94SDag-Erling Smørgrav } 1184ca1ab94SDag-Erling Smørgrav 119f62e5228SDag-Erling Smørgrav /* 120f62e5228SDag-Erling Smørgrav * Send a formatted line; optionally echo to terminal 121f62e5228SDag-Erling Smørgrav */ 122f62e5228SDag-Erling Smørgrav static int 123f62e5228SDag-Erling Smørgrav _http_cmd(FILE *f, char *fmt, ...) 124f62e5228SDag-Erling Smørgrav { 125f62e5228SDag-Erling Smørgrav va_list ap; 126f62e5228SDag-Erling Smørgrav 127f62e5228SDag-Erling Smørgrav va_start(ap, fmt); 128f62e5228SDag-Erling Smørgrav vfprintf(f, fmt, ap); 129f62e5228SDag-Erling Smørgrav #ifndef NDEBUG 130f62e5228SDag-Erling Smørgrav fprintf(stderr, "\033[1m>>> "); 131f62e5228SDag-Erling Smørgrav vfprintf(stderr, fmt, ap); 132f62e5228SDag-Erling Smørgrav fprintf(stderr, "\033[m"); 133f62e5228SDag-Erling Smørgrav #endif 134f62e5228SDag-Erling Smørgrav va_end(ap); 135f62e5228SDag-Erling Smørgrav 136f62e5228SDag-Erling Smørgrav return 0; /* XXX */ 137f62e5228SDag-Erling Smørgrav } 138f62e5228SDag-Erling Smørgrav 139f62e5228SDag-Erling Smørgrav /* 140f62e5228SDag-Erling Smørgrav * Fill the input buffer, do chunk decoding on the fly 141f62e5228SDag-Erling Smørgrav */ 1424ca1ab94SDag-Erling Smørgrav static char * 1434ca1ab94SDag-Erling Smørgrav _http_fillbuf(struct cookie *c) 1444ca1ab94SDag-Erling Smørgrav { 1454ca1ab94SDag-Erling Smørgrav char *ln; 1464ca1ab94SDag-Erling Smørgrav unsigned int len; 1474ca1ab94SDag-Erling Smørgrav 1484ca1ab94SDag-Erling Smørgrav if (c->eof) 1494ca1ab94SDag-Erling Smørgrav return NULL; 1504ca1ab94SDag-Erling Smørgrav 1514ca1ab94SDag-Erling Smørgrav if (c->encoding == ENC_NONE) { 1524ca1ab94SDag-Erling Smørgrav c->buf = fgetln(c->real_f, &(c->b_len)); 1534ca1ab94SDag-Erling Smørgrav c->b_cur = 0; 1544ca1ab94SDag-Erling Smørgrav } else if (c->encoding == ENC_CHUNKED) { 1554ca1ab94SDag-Erling Smørgrav if (c->chunksize == 0) { 1564ca1ab94SDag-Erling Smørgrav ln = fgetln(c->real_f, &len); 1574ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, "\033[1m_http_fillbuf(): new chunk: " 1584ca1ab94SDag-Erling Smørgrav "%*.*s\033[m\n", (int)len-2, (int)len-2, ln)); 1594ca1ab94SDag-Erling Smørgrav sscanf(ln, "%x", &(c->chunksize)); 1604ca1ab94SDag-Erling Smørgrav if (!c->chunksize) { 1614ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, "\033[1m_http_fillbuf(): " 1624ca1ab94SDag-Erling Smørgrav "end of last chunk\033[m\n")); 1634ca1ab94SDag-Erling Smørgrav c->eof = 1; 1644ca1ab94SDag-Erling Smørgrav return NULL; 1654ca1ab94SDag-Erling Smørgrav } 1664ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, "\033[1m_http_fillbuf(): " 1674ca1ab94SDag-Erling Smørgrav "new chunk: %X\033[m\n", c->chunksize)); 1684ca1ab94SDag-Erling Smørgrav } 1694ca1ab94SDag-Erling Smørgrav c->buf = fgetln(c->real_f, &(c->b_len)); 1704ca1ab94SDag-Erling Smørgrav if (c->b_len > c->chunksize) 1714ca1ab94SDag-Erling Smørgrav c->b_len = c->chunksize; 1724ca1ab94SDag-Erling Smørgrav c->chunksize -= c->b_len; 1734ca1ab94SDag-Erling Smørgrav c->b_cur = 0; 1744ca1ab94SDag-Erling Smørgrav } 1754ca1ab94SDag-Erling Smørgrav else return NULL; /* unknown encoding */ 1764ca1ab94SDag-Erling Smørgrav return c->buf; 1774ca1ab94SDag-Erling Smørgrav } 1784ca1ab94SDag-Erling Smørgrav 179f62e5228SDag-Erling Smørgrav /* 180f62e5228SDag-Erling Smørgrav * Read function 181f62e5228SDag-Erling Smørgrav */ 1824ca1ab94SDag-Erling Smørgrav static int 1834ca1ab94SDag-Erling Smørgrav _http_readfn(struct cookie *c, char *buf, int len) 1844ca1ab94SDag-Erling Smørgrav { 1854ca1ab94SDag-Erling Smørgrav int l, pos = 0; 1864ca1ab94SDag-Erling Smørgrav while (len) { 1874ca1ab94SDag-Erling Smørgrav /* empty buffer */ 1884ca1ab94SDag-Erling Smørgrav if (!c->buf || (c->b_cur == c->b_len)) 1894ca1ab94SDag-Erling Smørgrav if (!_http_fillbuf(c)) 1904ca1ab94SDag-Erling Smørgrav break; 1914ca1ab94SDag-Erling Smørgrav 1924ca1ab94SDag-Erling Smørgrav l = c->b_len - c->b_cur; 1934ca1ab94SDag-Erling Smørgrav if (len < l) l = len; 1944ca1ab94SDag-Erling Smørgrav memcpy(buf + pos, c->buf + c->b_cur, l); 1954ca1ab94SDag-Erling Smørgrav c->b_cur += l; 1964ca1ab94SDag-Erling Smørgrav pos += l; 1974ca1ab94SDag-Erling Smørgrav len -= l; 1984ca1ab94SDag-Erling Smørgrav } 1994ca1ab94SDag-Erling Smørgrav 2004ca1ab94SDag-Erling Smørgrav if (ferror(c->real_f)) 2014ca1ab94SDag-Erling Smørgrav return -1; 2024ca1ab94SDag-Erling Smørgrav else return pos; 2034ca1ab94SDag-Erling Smørgrav } 2044ca1ab94SDag-Erling Smørgrav 205f62e5228SDag-Erling Smørgrav /* 206f62e5228SDag-Erling Smørgrav * Write function 207f62e5228SDag-Erling Smørgrav */ 2084ca1ab94SDag-Erling Smørgrav static int 2094ca1ab94SDag-Erling Smørgrav _http_writefn(struct cookie *c, const char *buf, int len) 2104ca1ab94SDag-Erling Smørgrav { 2114ca1ab94SDag-Erling Smørgrav size_t r = fwrite(buf, 1, (size_t)len, c->real_f); 2124ca1ab94SDag-Erling Smørgrav return r ? r : -1; 2134ca1ab94SDag-Erling Smørgrav } 2144ca1ab94SDag-Erling Smørgrav 215f62e5228SDag-Erling Smørgrav /* 216f62e5228SDag-Erling Smørgrav * Close function 217f62e5228SDag-Erling Smørgrav */ 2184ca1ab94SDag-Erling Smørgrav static int 2194ca1ab94SDag-Erling Smørgrav _http_closefn(struct cookie *c) 2204ca1ab94SDag-Erling Smørgrav { 2214ca1ab94SDag-Erling Smørgrav int r = fclose(c->real_f); 2224ca1ab94SDag-Erling Smørgrav free(c); 2234ca1ab94SDag-Erling Smørgrav return (r == EOF) ? -1 : 0; 2244ca1ab94SDag-Erling Smørgrav } 2254ca1ab94SDag-Erling Smørgrav 226f62e5228SDag-Erling Smørgrav /* 227f62e5228SDag-Erling Smørgrav * Extract content type from cookie 228f62e5228SDag-Erling Smørgrav */ 2294ca1ab94SDag-Erling Smørgrav char * 2304ca1ab94SDag-Erling Smørgrav fetchContentType(FILE *f) 2314ca1ab94SDag-Erling Smørgrav { 2324ca1ab94SDag-Erling Smørgrav /* 2334ca1ab94SDag-Erling Smørgrav * We have no way of making sure this really *is* one of our cookies, 2344ca1ab94SDag-Erling Smørgrav * so just check for a null pointer and hope for the best. 2354ca1ab94SDag-Erling Smørgrav */ 2364ca1ab94SDag-Erling Smørgrav return f->_cookie ? (((struct cookie *)f->_cookie)->content_type) : NULL; 2374ca1ab94SDag-Erling Smørgrav } 2384ca1ab94SDag-Erling Smørgrav 239f62e5228SDag-Erling Smørgrav /* 240f62e5228SDag-Erling Smørgrav * Base64 encoding 241f62e5228SDag-Erling Smørgrav */ 242f62e5228SDag-Erling Smørgrav int 243f62e5228SDag-Erling Smørgrav _http_base64(char *dst, char *src, int l) 244f62e5228SDag-Erling Smørgrav { 245f62e5228SDag-Erling Smørgrav static const char base64[] = 246f62e5228SDag-Erling Smørgrav "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 247f62e5228SDag-Erling Smørgrav "abcdefghijklmnopqrstuvwxyz" 248f62e5228SDag-Erling Smørgrav "0123456789+/"; 249f62e5228SDag-Erling Smørgrav int t, r = 0; 250f62e5228SDag-Erling Smørgrav 251f62e5228SDag-Erling Smørgrav while (l >= 3) { 252f62e5228SDag-Erling Smørgrav t = (src[0] << 16) | (src[1] << 8) | src[2]; 253f62e5228SDag-Erling Smørgrav dst[0] = base64[(t >> 18) & 0x3f]; 254f62e5228SDag-Erling Smørgrav dst[1] = base64[(t >> 12) & 0x3f]; 255f62e5228SDag-Erling Smørgrav dst[2] = base64[(t >> 6) & 0x3f]; 256f62e5228SDag-Erling Smørgrav dst[3] = base64[(t >> 0) & 0x3f]; 257f62e5228SDag-Erling Smørgrav src += 3; l -= 3; 258f62e5228SDag-Erling Smørgrav dst += 4; r += 4; 259f62e5228SDag-Erling Smørgrav } 260f62e5228SDag-Erling Smørgrav 261f62e5228SDag-Erling Smørgrav switch (l) { 262f62e5228SDag-Erling Smørgrav case 2: 263f62e5228SDag-Erling Smørgrav t = (src[0] << 16) | (src[1] << 8); 264f62e5228SDag-Erling Smørgrav dst[0] = base64[(t >> 18) & 0x3f]; 265f62e5228SDag-Erling Smørgrav dst[1] = base64[(t >> 12) & 0x3f]; 266f62e5228SDag-Erling Smørgrav dst[2] = base64[(t >> 6) & 0x3f]; 267f62e5228SDag-Erling Smørgrav dst[3] = '='; 268f62e5228SDag-Erling Smørgrav dst += 4; 269f62e5228SDag-Erling Smørgrav r += 4; 270f62e5228SDag-Erling Smørgrav break; 271f62e5228SDag-Erling Smørgrav case 1: 272f62e5228SDag-Erling Smørgrav t = src[0] << 16; 273f62e5228SDag-Erling Smørgrav dst[0] = base64[(t >> 18) & 0x3f]; 274f62e5228SDag-Erling Smørgrav dst[1] = base64[(t >> 12) & 0x3f]; 275f62e5228SDag-Erling Smørgrav dst[2] = dst[3] = '='; 276f62e5228SDag-Erling Smørgrav dst += 4; 277f62e5228SDag-Erling Smørgrav r += 4; 278f62e5228SDag-Erling Smørgrav break; 279f62e5228SDag-Erling Smørgrav case 0: 280f62e5228SDag-Erling Smørgrav break; 281f62e5228SDag-Erling Smørgrav } 282f62e5228SDag-Erling Smørgrav 283f62e5228SDag-Erling Smørgrav *dst = 0; 284f62e5228SDag-Erling Smørgrav return r; 285f62e5228SDag-Erling Smørgrav } 286f62e5228SDag-Erling Smørgrav 287f62e5228SDag-Erling Smørgrav /* 288f62e5228SDag-Erling Smørgrav * Encode username and password 289f62e5228SDag-Erling Smørgrav */ 290f62e5228SDag-Erling Smørgrav char * 291f62e5228SDag-Erling Smørgrav _http_auth(char *usr, char *pwd) 292f62e5228SDag-Erling Smørgrav { 293f62e5228SDag-Erling Smørgrav int len, lu, lp; 294f62e5228SDag-Erling Smørgrav char *str, *s; 295f62e5228SDag-Erling Smørgrav 296f62e5228SDag-Erling Smørgrav lu = strlen(usr); 297f62e5228SDag-Erling Smørgrav lp = strlen(pwd); 298f62e5228SDag-Erling Smørgrav 299f62e5228SDag-Erling Smørgrav len = (lu * 4 + 2) / 3 /* user name, round up */ 300f62e5228SDag-Erling Smørgrav + 1 /* colon */ 301f62e5228SDag-Erling Smørgrav + (lp * 4 + 2) / 3 /* password, round up */ 302f62e5228SDag-Erling Smørgrav + 1; /* null */ 303f62e5228SDag-Erling Smørgrav 304f62e5228SDag-Erling Smørgrav if ((s = str = (char *)malloc(len)) == NULL) 305f62e5228SDag-Erling Smørgrav return NULL; 306f62e5228SDag-Erling Smørgrav 307f62e5228SDag-Erling Smørgrav s += _http_base64(s, usr, lu); 308f62e5228SDag-Erling Smørgrav *s++ = ':'; 309f62e5228SDag-Erling Smørgrav s += _http_base64(s, pwd, lp); 310f62e5228SDag-Erling Smørgrav *s = 0; 311f62e5228SDag-Erling Smørgrav 312f62e5228SDag-Erling Smørgrav return str; 313f62e5228SDag-Erling Smørgrav } 314f62e5228SDag-Erling Smørgrav 315f62e5228SDag-Erling Smørgrav /* 316f62e5228SDag-Erling Smørgrav * retrieve a file by HTTP 317f62e5228SDag-Erling Smørgrav */ 3184ca1ab94SDag-Erling Smørgrav FILE * 3194ca1ab94SDag-Erling Smørgrav fetchGetHTTP(url_t *URL, char *flags) 3204ca1ab94SDag-Erling Smørgrav { 3218e3986eaSDag-Erling Smørgrav int sd = -1, err, i, enc = ENC_NONE; 3224ca1ab94SDag-Erling Smørgrav struct cookie *c; 3234ca1ab94SDag-Erling Smørgrav char *ln, *p, *q; 3244ca1ab94SDag-Erling Smørgrav FILE *f, *cf; 3254ca1ab94SDag-Erling Smørgrav size_t len; 3264ca1ab94SDag-Erling Smørgrav 3274ca1ab94SDag-Erling Smørgrav /* allocate cookie */ 3284ca1ab94SDag-Erling Smørgrav if ((c = calloc(1, sizeof(struct cookie))) == NULL) 3294ca1ab94SDag-Erling Smørgrav return NULL; 3304ca1ab94SDag-Erling Smørgrav 3314ca1ab94SDag-Erling Smørgrav /* check port */ 3324ca1ab94SDag-Erling Smørgrav if (!URL->port) 3334ca1ab94SDag-Erling Smørgrav URL->port = 80; /* default HTTP port */ 3344ca1ab94SDag-Erling Smørgrav 3354ca1ab94SDag-Erling Smørgrav /* attempt to connect to proxy server */ 3364ca1ab94SDag-Erling Smørgrav if (getenv("HTTP_PROXY")) { 3374ca1ab94SDag-Erling Smørgrav char *px, host[MAXHOSTNAMELEN]; 3384ca1ab94SDag-Erling Smørgrav int port = 3128; /* XXX I think 3128 is default... check? */ 3394ca1ab94SDag-Erling Smørgrav size_t len; 3404ca1ab94SDag-Erling Smørgrav 3414ca1ab94SDag-Erling Smørgrav /* measure length */ 3424ca1ab94SDag-Erling Smørgrav px = getenv("HTTP_PROXY"); 3434ca1ab94SDag-Erling Smørgrav len = strcspn(px, ":"); 3444ca1ab94SDag-Erling Smørgrav 3454ca1ab94SDag-Erling Smørgrav /* get port (atoi is a little too tolerant perhaps?) */ 3464ca1ab94SDag-Erling Smørgrav if (px[len] == ':') 3474ca1ab94SDag-Erling Smørgrav port = atoi(px+len+1); 3484ca1ab94SDag-Erling Smørgrav 3494ca1ab94SDag-Erling Smørgrav /* get host name */ 3504ca1ab94SDag-Erling Smørgrav if (len >= MAXHOSTNAMELEN) 3514ca1ab94SDag-Erling Smørgrav len = MAXHOSTNAMELEN - 1; 3524ca1ab94SDag-Erling Smørgrav strncpy(host, px, len); 3534ca1ab94SDag-Erling Smørgrav host[len] = 0; 3544ca1ab94SDag-Erling Smørgrav 3554ca1ab94SDag-Erling Smørgrav /* connect */ 3568e3986eaSDag-Erling Smørgrav sd = fetchConnect(host, port); 3574ca1ab94SDag-Erling Smørgrav } 3584ca1ab94SDag-Erling Smørgrav 3594ca1ab94SDag-Erling Smørgrav /* if no proxy is configured or could be contacted, try direct */ 3608e3986eaSDag-Erling Smørgrav if (sd < 0) { 3618e3986eaSDag-Erling Smørgrav if ((sd = fetchConnect(URL->host, URL->port)) < 0) 3624ca1ab94SDag-Erling Smørgrav goto ouch; 3634ca1ab94SDag-Erling Smørgrav } 3644ca1ab94SDag-Erling Smørgrav 3654ca1ab94SDag-Erling Smørgrav /* reopen as stream */ 3668e3986eaSDag-Erling Smørgrav if ((f = fdopen(sd, "r+")) == NULL) 3674ca1ab94SDag-Erling Smørgrav goto ouch; 3684ca1ab94SDag-Erling Smørgrav c->real_f = f; 3694ca1ab94SDag-Erling Smørgrav 3704ca1ab94SDag-Erling Smørgrav /* send request (proxies require absolute form, so use that) */ 371f62e5228SDag-Erling Smørgrav _http_cmd(f, "GET http://%s:%d%s HTTP/1.1" ENDL, 3724ca1ab94SDag-Erling Smørgrav URL->host, URL->port, URL->doc); 3734ca1ab94SDag-Erling Smørgrav 3744ca1ab94SDag-Erling Smørgrav /* start sending headers away */ 3754ca1ab94SDag-Erling Smørgrav if (URL->user[0] || URL->pwd[0]) { 376f62e5228SDag-Erling Smørgrav char *auth_str = _http_auth(URL->user, URL->pwd); 377f62e5228SDag-Erling Smørgrav if (!auth_str) 378f62e5228SDag-Erling Smørgrav goto fouch; 379f62e5228SDag-Erling Smørgrav _http_cmd(f, "Authorization: Basic %s" ENDL, auth_str); 380f62e5228SDag-Erling Smørgrav free(auth_str); 3814ca1ab94SDag-Erling Smørgrav } 382f62e5228SDag-Erling Smørgrav _http_cmd(f, "Host: %s:%d" ENDL, URL->host, URL->port); 383f62e5228SDag-Erling Smørgrav _http_cmd(f, "User-Agent: %s " _LIBFETCH_VER ENDL, __progname); 384f62e5228SDag-Erling Smørgrav _http_cmd(f, "Connection: close" ENDL ENDL); 3854ca1ab94SDag-Erling Smørgrav 3864ca1ab94SDag-Erling Smørgrav /* get response */ 3874ca1ab94SDag-Erling Smørgrav if ((ln = fgetln(f, &len)) == NULL) 3884ca1ab94SDag-Erling Smørgrav goto fouch; 3894ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, "response: [\033[1m%*.*s\033[m]\n", 3904ca1ab94SDag-Erling Smørgrav (int)len-2, (int)len-2, ln)); 3914ca1ab94SDag-Erling Smørgrav 3924ca1ab94SDag-Erling Smørgrav /* we can't use strchr() and friends since ln isn't NUL-terminated */ 3934ca1ab94SDag-Erling Smørgrav p = ln; 3944ca1ab94SDag-Erling Smørgrav while ((p < ln + len) && !isspace(*p)) 3954ca1ab94SDag-Erling Smørgrav p++; 3964ca1ab94SDag-Erling Smørgrav while ((p < ln + len) && !isdigit(*p)) 3974ca1ab94SDag-Erling Smørgrav p++; 3984ca1ab94SDag-Erling Smørgrav if (!isdigit(*p)) 3994ca1ab94SDag-Erling Smørgrav goto fouch; 4004ca1ab94SDag-Erling Smørgrav err = atoi(p); 4014ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, "code: [\033[1m%d\033[m]\n", err)); 4024ca1ab94SDag-Erling Smørgrav 4034ca1ab94SDag-Erling Smørgrav /* add code to handle redirects later */ 4048e3986eaSDag-Erling Smørgrav if (err != 200) { 4058e3986eaSDag-Erling Smørgrav fetchLastErrCode = err; 4068e3986eaSDag-Erling Smørgrav fetchLastErrText = _http_errstring(err); 4074ca1ab94SDag-Erling Smørgrav goto fouch; 4088e3986eaSDag-Erling Smørgrav } 4094ca1ab94SDag-Erling Smørgrav 4104ca1ab94SDag-Erling Smørgrav /* browse through header */ 4114ca1ab94SDag-Erling Smørgrav while (1) { 4124ca1ab94SDag-Erling Smørgrav if ((ln = fgetln(f, &len)) == NULL) 4134ca1ab94SDag-Erling Smørgrav goto fouch; 4144ca1ab94SDag-Erling Smørgrav if ((ln[0] == '\r') || (ln[0] == '\n')) 4154ca1ab94SDag-Erling Smørgrav break; 4164ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, "header: [\033[1m%*.*s\033[m]\n", 4174ca1ab94SDag-Erling Smørgrav (int)len-2, (int)len-2, ln)); 4184ca1ab94SDag-Erling Smørgrav #define XFERENC "Transfer-Encoding:" 4194ca1ab94SDag-Erling Smørgrav if (strncasecmp(ln, XFERENC, sizeof(XFERENC)-1) == 0) { 4204ca1ab94SDag-Erling Smørgrav p = ln + sizeof(XFERENC) - 1; 4214ca1ab94SDag-Erling Smørgrav while ((p < ln + len) && isspace(*p)) 4224ca1ab94SDag-Erling Smørgrav p++; 4234ca1ab94SDag-Erling Smørgrav for (q = p; (q < ln + len) && !isspace(*q); q++) 4244ca1ab94SDag-Erling Smørgrav /* VOID */ ; 4254ca1ab94SDag-Erling Smørgrav *q = 0; 4264ca1ab94SDag-Erling Smørgrav if (strcasecmp(p, "chunked") == 0) 4274ca1ab94SDag-Erling Smørgrav enc = ENC_CHUNKED; 4284ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, "xferenc: [\033[1m%s\033[m]\n", p)); 4294ca1ab94SDag-Erling Smørgrav #undef XFERENC 4304ca1ab94SDag-Erling Smørgrav #define CONTTYPE "Content-Type:" 4314ca1ab94SDag-Erling Smørgrav } else if (strncasecmp(ln, CONTTYPE, sizeof(CONTTYPE)-1) == 0) { 4324ca1ab94SDag-Erling Smørgrav p = ln + sizeof(CONTTYPE) - 1; 4334ca1ab94SDag-Erling Smørgrav while ((p < ln + len) && isspace(*p)) 4344ca1ab94SDag-Erling Smørgrav p++; 4354ca1ab94SDag-Erling Smørgrav for (i = 0; p < ln + len; p++) 4364ca1ab94SDag-Erling Smørgrav if (i < HTTPCTYPELEN) 4374ca1ab94SDag-Erling Smørgrav c->content_type[i++] = *p; 4384ca1ab94SDag-Erling Smørgrav do c->content_type[i--] = 0; while (isspace(c->content_type[i])); 4394ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, "conttype: [\033[1m%s\033[m]\n", 4404ca1ab94SDag-Erling Smørgrav c->content_type)); 4414ca1ab94SDag-Erling Smørgrav #undef CONTTYPE 4424ca1ab94SDag-Erling Smørgrav } 4434ca1ab94SDag-Erling Smørgrav } 4444ca1ab94SDag-Erling Smørgrav 4454ca1ab94SDag-Erling Smørgrav /* only body remains */ 4464ca1ab94SDag-Erling Smørgrav c->encoding = enc; 4474ca1ab94SDag-Erling Smørgrav cf = funopen(c, 4484ca1ab94SDag-Erling Smørgrav (int (*)(void *, char *, int))_http_readfn, 4494ca1ab94SDag-Erling Smørgrav (int (*)(void *, const char *, int))_http_writefn, 4504ca1ab94SDag-Erling Smørgrav (fpos_t (*)(void *, fpos_t, int))NULL, 4514ca1ab94SDag-Erling Smørgrav (int (*)(void *))_http_closefn); 4524ca1ab94SDag-Erling Smørgrav if (cf == NULL) 4534ca1ab94SDag-Erling Smørgrav goto fouch; 4544ca1ab94SDag-Erling Smørgrav return cf; 4554ca1ab94SDag-Erling Smørgrav 4564ca1ab94SDag-Erling Smørgrav ouch: 4578e3986eaSDag-Erling Smørgrav if (sd >= 0) 4588e3986eaSDag-Erling Smørgrav close(sd); 4594ca1ab94SDag-Erling Smørgrav free(c); 4604ca1ab94SDag-Erling Smørgrav return NULL; 4614ca1ab94SDag-Erling Smørgrav fouch: 4624ca1ab94SDag-Erling Smørgrav fclose(f); 4634ca1ab94SDag-Erling Smørgrav free(c); 4644ca1ab94SDag-Erling Smørgrav return NULL; 4654ca1ab94SDag-Erling Smørgrav } 4664ca1ab94SDag-Erling Smørgrav 4674ca1ab94SDag-Erling Smørgrav FILE * 4684ca1ab94SDag-Erling Smørgrav fetchPutHTTP(url_t *URL, char *flags) 4694ca1ab94SDag-Erling Smørgrav { 4704ca1ab94SDag-Erling Smørgrav warnx("fetchPutHTTP(): not implemented"); 4714ca1ab94SDag-Erling Smørgrav return NULL; 4724ca1ab94SDag-Erling Smørgrav } 473