fetch.c revision 37573
1/*- 2 * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $Id: fetch.c,v 1.1.1.1 1998/07/09 16:52:42 des Exp $ 29 */ 30 31#include <sys/param.h> 32#include <sys/types.h> 33#include <sys/socket.h> 34#include <netinet/in.h> 35 36#include <ctype.h> 37#include <netdb.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <string.h> 41#include <unistd.h> 42 43#include "fetch.h" 44 45#ifndef NDEBUG 46#define DEBUG(x) do x; while (0) 47#else 48#define DEBUG(x) do { } while (0) 49#endif 50 51int fetchLastErrCode; 52const char *fetchLastErrText; 53 54/* get URL */ 55FILE * 56fetchGetURL(char *URL, char *flags) 57{ 58 url_t *u; 59 FILE *f; 60 61 /* parse URL */ 62 if ((u = fetchParseURL(URL)) == NULL) 63 return NULL; 64 65 /* select appropriate function */ 66 if (strcasecmp(u->scheme, "file") == 0) 67 f = fetchGetFile(u, flags); 68 else if (strcasecmp(u->scheme, "http") == 0) 69 f = fetchGetHTTP(u, flags); 70 else if (strcasecmp(u->scheme, "ftp") == 0) 71 f = fetchGetFTP(u, flags); 72 else f = NULL; 73 74 fetchFreeURL(u); 75 return f; 76} 77 78 79/* put URL */ 80FILE * 81fetchPutURL(char *URL, char *flags) 82{ 83 url_t *u; 84 FILE *f; 85 86 /* parse URL */ 87 if ((u = fetchParseURL(URL)) == NULL) 88 return NULL; 89 90 /* select appropriate function */ 91 if (strcasecmp(u->scheme, "file") == 0) 92 f = fetchPutFile(u, flags); 93 else if (strcasecmp(u->scheme, "http") == 0) 94 f = fetchPutHTTP(u, flags); 95 else if (strcasecmp(u->scheme, "ftp") == 0) 96 f = fetchPutFTP(u, flags); 97 else f = NULL; 98 99 fetchFreeURL(u); 100 return f; 101} 102 103/* 104 * Split an URL into components. URL syntax is: 105 * method:[//[user[:pwd]@]host[:port]]/[document] 106 * This almost, but not quite, RFC1738 URL syntax. 107 */ 108url_t * 109fetchParseURL(char *URL) 110{ 111 char *p, *q; 112 url_t *u; 113 int i; 114 115 /* allocate url_t */ 116 if ((u = calloc(1, sizeof(url_t))) == NULL) 117 return NULL; 118 119 /* scheme name */ 120 for (i = 0; *URL && (*URL != ':'); URL++) 121 if (i < URL_SCHEMELEN) 122 u->scheme[i++] = *URL; 123 if (!URL[0] || (URL[1] != '/')) 124 goto ouch; 125 else URL++; 126 if (URL[1] != '/') { 127 p = URL; 128 goto nohost; 129 } 130 else URL += 2; 131 132 p = strpbrk(URL, "/@"); 133 if (*p == '@') { 134 /* username */ 135 for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++) 136 if (i < URL_USERLEN) 137 u->user[i++] = *q; 138 139 /* password */ 140 if (*q == ':') 141 for (q++, i = 0; (*q != ':') && (*q != '@'); q++) 142 if (i < URL_PWDLEN) 143 u->pwd[i++] = *q; 144 145 p++; 146 } else p = URL; 147 148 /* hostname */ 149 for (i = 0; *p && (*p != '/') && (*p != ':'); p++) 150 if (i < MAXHOSTNAMELEN) 151 u->host[i++] = *p; 152 153 /* port */ 154 if (*p == ':') { 155 for (q = ++p; *q && (*q != '/'); q++) 156 if (isdigit(*q)) 157 u->port = u->port * 10 + (*q - '0'); 158 else return 0; /* invalid port */ 159 while (*p && (*p != '/')) 160 p++; 161 } 162 163nohost: 164 /* document */ 165 if (*p) 166 u->doc = strdup(p); 167 u->doc = strdup(*p ? p : "/"); 168 if (!u->doc) 169 goto ouch; 170 171 DEBUG(fprintf(stderr, 172 "scheme: [\033[1m%s\033[m]\n" 173 "user: [\033[1m%s\033[m]\n" 174 "password: [\033[1m%s\033[m]\n" 175 "host: [\033[1m%s\033[m]\n" 176 "port: [\033[1m%d\033[m]\n" 177 "document: [\033[1m%s\033[m]\n", 178 u->scheme, u->user, u->pwd, 179 u->host, u->port, u->doc)); 180 181 return u; 182 183ouch: 184 free(u); 185 return NULL; 186} 187 188void 189fetchFreeURL(url_t *u) 190{ 191 if (u) { 192 if (u->doc) 193 free(u->doc); 194 free(u); 195 } 196} 197 198int 199fetchConnect(char *host, int port) 200{ 201 struct sockaddr_in sin; 202 struct hostent *he; 203 int sd; 204 205 /* look up host name */ 206 if ((he = gethostbyname(host)) == NULL) 207 return -1; 208 209 /* set up socket address structure */ 210 bzero(&sin, sizeof(sin)); 211 bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); 212 sin.sin_family = he->h_addrtype; 213 sin.sin_port = htons(port); 214 215 /* try to connect */ 216 if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) < 0) 217 return -1; 218 if (connect(sd, (struct sockaddr *)&sin, sizeof sin) < 0) { 219 close(sd); 220 return -1; 221 } 222 223 return sd; 224} 225