Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wvurl.cc

Go to the documentation of this file.
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * WvUrl is a simple URL-parsing class with built-in (though still somewhat 00006 * inconvenient) DNS resolution. 00007 * 00008 * See wvurl.h. 00009 */ 00010 #include "wvurl.h" 00011 #include "strutils.h" 00012 00013 // A static list of the default ports for each protocol. 00014 struct DefaultPort 00015 { 00016 char *proto; 00017 int port; 00018 bool uses_slashes; 00019 }; 00020 00021 // The protocols must be arranged from longest to shortest because they're 00022 // compared with strncmp, so "https://" will also match http. 00023 static DefaultPort portmap[] = { 00024 { "exchangeits", 7070, false }, 00025 { "exchangeit", 6969, false }, 00026 { "https", 443, true }, 00027 { "http", 80, true }, 00028 { "sip", 5060, false }, 00029 { "ftp", 21, true }, 00030 { NULL, 0 } 00031 }; 00032 00033 // Look up the protocol and return the default port. 00034 static int get_default_port(WvString proto) 00035 { 00036 DefaultPort *p = portmap; 00037 for (p = portmap; p->proto != NULL; p++) 00038 { 00039 if (strncmp(p->proto, proto, strlen(p->proto)) == 0) 00040 return p->port; 00041 } 00042 return -1; 00043 } 00044 00045 // Look up the protocol and decide whether it uses slashes (http) or not (sip) 00046 // A check of rfc2396 shows that the URI standard actually distinguishes 00047 // these: 'hierarchical' vs. 'opaque'. 00048 static bool protocol_uses_slashes(WvString proto) 00049 { 00050 DefaultPort *p = portmap; 00051 for (p = portmap; p->proto != NULL; p++) 00052 { 00053 if (strncmp(p->proto, proto, strlen(p->proto)) == 0) 00054 return p->uses_slashes; 00055 } 00056 return false; 00057 } 00058 00059 // Split up the URL into a hostname, a port, and the rest of it. 00060 WvUrl::WvUrl(WvStringParm url) : err("No error") 00061 { 00062 WvString work(url); 00063 char *cptr, *wptr = work.edit(); 00064 00065 port = 0; // error condition by default 00066 addr = NULL; 00067 resolving = true; 00068 00069 // deal with extra whitespace. 00070 wptr = trim_string(wptr); 00071 cptr = wptr + strcspn(wptr, " \t\r\n"); 00072 *cptr = 0; 00073 00074 // if it's not one of these easy prefixes, give up. Our URL parser is 00075 // pretty dumb. 00076 if (get_default_port(wptr) < 0) 00077 { 00078 err = "WvUrl cannot handle the given protocol."; 00079 return; 00080 } 00081 00082 cptr = strchr(wptr, ':'); 00083 if (!cptr) 00084 { 00085 err = "No colon after the protocol."; 00086 return; 00087 } 00088 *cptr = 0; 00089 proto = wptr; 00090 00091 bool use_slashes = protocol_uses_slashes(proto); 00092 wptr = cptr + (use_slashes ? 3 : 1); 00093 00094 cptr = strchr(wptr, '@'); 00095 if (!cptr) // no user given 00096 { 00097 user = ""; 00098 password = ""; 00099 } 00100 else 00101 { 00102 *cptr = 0; 00103 char *cptr2 = strchr(wptr, ':'); 00104 if (cptr2 && (*(cptr2+1) != 0)) 00105 { 00106 *cptr2 = 0; 00107 password = cptr2 + 1; 00108 } 00109 else 00110 password = ""; 00111 user = wptr; 00112 wptr = cptr + 1; 00113 } 00114 00115 cptr = strchr(wptr, '/'); 00116 if (!cptr) // no path given 00117 file = use_slashes ? "/" : ""; 00118 else 00119 { 00120 file = cptr; 00121 *cptr = 0; 00122 } 00123 00124 cptr = strchr(wptr, ':'); 00125 if (!cptr) 00126 port = get_default_port(proto); 00127 else 00128 { 00129 port = atoi(cptr+1); 00130 *cptr = 0; 00131 } 00132 00133 hostname = wptr; 00134 00135 resolve(); 00136 } 00137 00138 00139 WvUrl::WvUrl(const WvUrl &url) : err("No error") 00140 { 00141 addr = NULL; 00142 resolving = true; 00143 00144 proto = url.proto; 00145 user = url.user; 00146 password = url.password; 00147 hostname = url.hostname; 00148 file = url.file; 00149 port = url.port; 00150 00151 resolve(); 00152 } 00153 00154 00155 WvUrl::~WvUrl() 00156 { 00157 if (addr) delete addr; 00158 } 00159 00160 00161 bool WvUrl::resolve() 00162 { 00163 const WvIPAddr *ip; 00164 int numaddrs; 00165 00166 numaddrs = dns.findaddr(0, hostname, &ip); 00167 if (!numaddrs) // error condition 00168 { 00169 err = WvString("Host '%s' could not be found.", hostname); 00170 resolving = false; 00171 return false; 00172 } 00173 else if (numaddrs < 0) // still waiting 00174 { 00175 resolving = true; 00176 return false; 00177 } 00178 else // got at least one address 00179 { 00180 resolving = false; 00181 if (addr) delete addr; 00182 addr = new WvIPPortAddr(*ip, port); 00183 return true; 00184 } 00185 } 00186 00187 00188 // Print out the URL, using the port name (if it's not 80), and either the 00189 // hostname (if we know it) or the address (if we know that instead.) 00190 WvUrl::operator WvString () const 00191 { 00192 if (!isok()) 00193 return WvString("(Invalid URL: %s)", err); 00194 00195 WvString protostr; 00196 if (protocol_uses_slashes(proto)) 00197 protostr = WvString("%s://", proto); 00198 else 00199 protostr = WvString("%s:", proto); 00200 WvString userstr(""); 00201 if (user && user.len() != 0) 00202 { 00203 userstr = WvString("%s", user); 00204 if (password && password.len() != 0) 00205 userstr.append(WvString(":%s@", password)); 00206 else 00207 userstr.append("@"); 00208 } 00209 WvString portstr(""); 00210 if (port && port != get_default_port(proto)) 00211 portstr = WvString(":%s", port); 00212 if (hostname) 00213 return WvString("%s%s%s%s%s", protostr, userstr, hostname, portstr, file); 00214 else if (addr) 00215 return WvString("%s%s%s%s%s", protostr, userstr, *addr, portstr, file); 00216 else 00217 { 00218 assert(0); 00219 return WvString("(Invalid URL)"); 00220 } 00221 } 00222 00223

Generated on Tue Oct 5 01:09:21 2004 for WvStreams by doxygen 1.3.7