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.3 1998/07/11 21:29:07 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 51 int fetchLastErrCode; 52 const char *fetchLastErrText; 53 54 FILE * 55 fetchGet(url_t *URL, char *flags) 56 { 57 if (strcasecmp(URL->scheme, "file") == 0) 58 return fetchGetFile(URL, flags); 59 else if (strcasecmp(URL->scheme, "http") == 0) 60 return fetchGetHTTP(URL, flags); 61 else if (strcasecmp(URL->scheme, "ftp") == 0) 62 return fetchGetFTP(URL, flags); 63 else return NULL; 64 65 } 66 67 FILE * 68 fetchPut(url_t *URL, char *flags) 69 { 70 if (strcasecmp(URL->scheme, "file") == 0) 71 return fetchPutFile(URL, flags); 72 else if (strcasecmp(URL->scheme, "http") == 0) 73 return fetchPutHTTP(URL, flags); 74 else if (strcasecmp(URL->scheme, "ftp") == 0) 75 return fetchPutFTP(URL, flags); 76 else return NULL; 77 } 78 79 /* get URL */ 80 FILE * 81 fetchGetURL(char *URL, char *flags) 82 { 83 url_t *u; 84 FILE *f; 85 86 if ((u = fetchParseURL(URL)) == NULL) 87 return NULL; 88 89 f = fetchGet(u, flags); 90 91 fetchFreeURL(u); 92 return f; 93 } 94 95 96 /* put URL */ 97 FILE * 98 fetchPutURL(char *URL, char *flags) 99 { 100 url_t *u; 101 FILE *f; 102 103 if ((u = fetchParseURL(URL)) == NULL) 104 return NULL; 105 106 f = fetchPut(u, flags); 107 108 fetchFreeURL(u); 109 return f; 110 } 111 112 /* 113 * Split an URL into components. URL syntax is: 114 * method:[//[user[:pwd]@]host[:port]]/[document] 115 * This almost, but not quite, RFC1738 URL syntax. 116 */ 117 url_t * 118 fetchParseURL(char *URL) 119 { 120 char *p, *q; 121 url_t *u; 122 int i; 123 124 /* allocate url_t */ 125 if ((u = calloc(1, sizeof(url_t))) == NULL) 126 return NULL; 127 128 /* scheme name */ 129 for (i = 0; *URL && (*URL != ':'); URL++) 130 if (i < URL_SCHEMELEN) 131 u->scheme[i++] = *URL; 132 if (!URL[0] || (URL[1] != '/')) 133 goto ouch; 134 else URL++; 135 if (URL[1] != '/') { 136 p = URL; 137 goto nohost; 138 } 139 else URL += 2; 140 141 p = strpbrk(URL, "/@"); 142 if (*p == '@') { 143 /* username */ 144 for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++) 145 if (i < URL_USERLEN) 146 u->user[i++] = *q; 147 148 /* password */ 149 if (*q == ':') 150 for (q++, i = 0; (*q != ':') && (*q != '@'); q++) 151 if (i < URL_PWDLEN) 152 u->pwd[i++] = *q; 153 154 p++; 155 } else p = URL; 156 157 /* hostname */ 158 for (i = 0; *p && (*p != '/') && (*p != ':'); p++) 159 if (i < MAXHOSTNAMELEN) 160 u->host[i++] = *p; 161 162 /* port */ 163 if (*p == ':') { 164 for (q = ++p; *q && (*q != '/'); q++) 165 if (isdigit(*q)) 166 u->port = u->port * 10 + (*q - '0'); 167 else return 0; /* invalid port */ 168 while (*p && (*p != '/')) 169 p++; 170 } 171 172 nohost: 173 /* document */ 174 if (*p) 175 u->doc = strdup(p); 176 u->doc = strdup(*p ? p : "/"); 177 if (!u->doc) 178 goto ouch; 179 180 DEBUG(fprintf(stderr, 181 "scheme: [\033[1m%s\033[m]\n" 182 "user: [\033[1m%s\033[m]\n" 183 "password: [\033[1m%s\033[m]\n" 184 "host: [\033[1m%s\033[m]\n" 185 "port: [\033[1m%d\033[m]\n" 186 "document: [\033[1m%s\033[m]\n", 187 u->scheme, u->user, u->pwd, 188 u->host, u->port, u->doc)); 189 190 return u; 191 192 ouch: 193 free(u); 194 return NULL; 195 } 196 197 void 198 fetchFreeURL(url_t *u) 199 { 200 if (u) { 201 if (u->doc) 202 free(u->doc); 203 free(u); 204 } 205 } 206 207 int 208 fetchConnect(char *host, int port) 209 { 210 struct sockaddr_in sin; 211 struct hostent *he; 212 int sd; 213 214 #ifndef NDEBUG 215 fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port); 216 #endif 217 218 /* look up host name */ 219 if ((he = gethostbyname(host)) == NULL) 220 return -1; 221 222 /* set up socket address structure */ 223 bzero(&sin, sizeof(sin)); 224 bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); 225 sin.sin_family = he->h_addrtype; 226 sin.sin_port = htons(port); 227 228 /* try to connect */ 229 if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1) 230 return -1; 231 if (connect(sd, (struct sockaddr *)&sin, sizeof sin) == -1) { 232 close(sd); 233 return -1; 234 } 235 236 return sd; 237 } 238