wvurl.cc

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 Thu Jan 24 16:50:57 2008 for WvStreams by  doxygen 1.5.4