Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

wvhttp.cc

Go to the documentation of this file.
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * WvHTTPStream connects to an HTTP server and allows the requested file
00006  * to be retrieved using the usual WvStream-style calls.
00007  */
00008 #include "wvhttp.h"
00009 #include "strutils.h"
00010 #include <assert.h>
00011 
00012 
00014 
00015 
00016 // Split up the URL into a hostname, a port, and the rest of it.
00017 WvURL::WvURL(const WvString &url) : err("No error")
00018 {
00019     WvString work(url);
00020     char *cptr, *wptr = work.edit();
00021     
00022     port = 0; // error condition by default
00023     addr = NULL;
00024     resolving = true;
00025     
00026     if (strncmp(wptr, "http://", 7)) // NOT equal
00027     {
00028         err = "WvURL can only handle HTTP URLs.";
00029         return;
00030     }
00031     wptr += 7;
00032     
00033     hostname = wptr;
00034     hostname.unique();
00035     
00036     cptr = strchr(wptr, '/');
00037     if (!cptr) // no path given
00038         file = "/";
00039     else
00040     {
00041         file = cptr;
00042         file.unique();
00043         *cptr = 0;
00044     }
00045     
00046     cptr = strchr(wptr, ':');
00047     if (!cptr)
00048         port = 80;
00049     else
00050     {
00051         port = atoi(cptr+1);
00052         *cptr = 0;
00053     }
00054 
00055     hostname = wptr;
00056     hostname.unique();
00057     
00058     resolve();
00059 }
00060 
00061 
00062 WvURL::~WvURL()
00063 {
00064     if (addr) delete addr;
00065 }
00066 
00067 
00068 bool WvURL::resolve()
00069 {
00070     const WvIPAddr *ip;
00071     int numaddrs;
00072     
00073     numaddrs = dns.findaddr(0, hostname, &ip);
00074     if (!numaddrs) // error condition
00075     {
00076         err = WvString("Host %s could not be found.", hostname);
00077         resolving = false;
00078         return false;
00079     }
00080     else if (numaddrs < 0) // still waiting
00081     {
00082         resolving = true;
00083         return false;
00084     }
00085     else // got at least one address
00086     {
00087         resolving = false;
00088         if (addr) delete addr;
00089         addr = new WvIPPortAddr(*ip, port);
00090         return true;
00091     }
00092 }
00093 
00094 
00095 // Print out the URL, using the port name (if it's not 80), and either the 
00096 // hostname (if we know it) or the address (if we know that instead.)
00097 WvURL::operator WvString () const
00098 {
00099     if (!isok())
00100         return WvString("(Invalid URL: %s)", err);
00101     
00102     WvString portstr("");
00103     if (port && port != 80)
00104         portstr = WvString(":%s", port);
00105     if (hostname)
00106         return WvString("http://%s%s%s", hostname, portstr, file);
00107     else if (addr)
00108         return WvString("http://%s%s%s", *addr, portstr, file);
00109     else
00110     {
00111         assert(0);
00112         return WvString("(Invalid URL)");
00113     }
00114 }
00115 
00116 
00117 
00119 
00120 
00121 
00122 WvHTTPStream::WvHTTPStream(WvURL &_url)
00123         : WvStreamClone((WvStream **)&http), headers(7), client_headers(7),
00124           url(_url)
00125 {
00126     state = Resolving;
00127     http = NULL;
00128     num_received = 0;
00129     
00130     // we need this: if the URL tried to dns-resolve before, but failed,
00131     // this might make isok() true again if the name has turned up.
00132     url.resolve();
00133 }
00134 
00135 
00136 WvHTTPStream::~WvHTTPStream()
00137 {
00138     if (http) delete http;
00139 }
00140 
00141 
00142 bool WvHTTPStream::isok() const
00143 {
00144     if (http)
00145         return WvStreamClone::isok();
00146     else
00147         return url.isok();
00148 }
00149 
00150 
00151 int WvHTTPStream::geterr() const
00152 {
00153     if (http)
00154         return WvStreamClone::geterr();
00155     else
00156         return -1;
00157 }
00158 
00159 
00160 const char *WvHTTPStream::errstr() const
00161 {
00162     if (http)
00163         return WvStreamClone::errstr();
00164     else if (!url.isok())
00165         return url.errstr();
00166     else
00167         return "Unknown error!";
00168 }
00169 
00170 
00171 bool WvHTTPStream::pre_select(SelectInfo &si)
00172 {
00173     if (!isok()) return false;
00174     
00175     switch (state)
00176     {
00177     case Resolving:
00178         if (!url.isok())
00179             seterr("Invalid URL");
00180         else if (url.resolve())
00181         {
00182             state = Connecting;
00183             http = new WvTCPConn(url.getaddr());
00184         }
00185         return false;
00186 
00187     case Connecting:
00188         http->select(0, false, true, false);
00189         if (!http->isconnected())
00190             return false;
00191         if (http->geterr())
00192             return false;
00193 
00194         // otherwise, we just finished connecting:  start transfer.
00195         state = ReadHeader1;
00196         print("GET %s HTTP/1.0\n", url.getfile());
00197         {
00198             WvHTTPHeaderDict::Iter i(client_headers);
00199             for (i.rewind(); i.next(); )
00200             {
00201                 print("%s: %s\n", i().name, i().value);
00202             }
00203         }
00204         print("\n");
00205         
00206         // FALL THROUGH!
00207         
00208     default:
00209         return WvStreamClone::isok()
00210             && WvStreamClone::pre_select(si);
00211     }
00212 }
00213 
00214 
00215 size_t WvHTTPStream::uread(void *buf, size_t count)
00216 {
00217     char *line;
00218     int retval;
00219     size_t len;
00220     
00221     switch (state)
00222     {
00223     case Resolving:
00224     case Connecting:
00225         break;
00226         
00227     case ReadHeader1:
00228         line = http->getline(0);
00229         line = trim_string(line);
00230         if (line) // got response code line
00231         {
00232             if (strncmp(line, "HTTP/", 5))
00233             {
00234                 seterr("Invalid HTTP response");
00235                 return 0;
00236             }
00237             
00238             retval = atoi(trim_string(line+9));
00239             
00240             if (retval / 100 != 2)
00241             {
00242                 seterr(WvString("HTTP error: %s", trim_string(line+9)));
00243                 return 0;
00244             }
00245                 
00246             state = ReadHeader;
00247         }
00248         break;
00249         
00250     case ReadHeader:
00251         line = http->getline(0);
00252         if (line)
00253         {
00254             line = trim_string(line);
00255             if (!line[0])
00256                 state = ReadData;       // header is done
00257             else
00258             {
00259                 char *cptr = strchr(line, ':');
00260                 if (!cptr)
00261                     headers.add(new WvHTTPHeader(line, ""), true);
00262                 else
00263                 {
00264                     *cptr++ = 0;
00265                     line = trim_string(line);
00266                     cptr = trim_string(cptr);
00267                     headers.add(new WvHTTPHeader(line, cptr), true);
00268                 }
00269             }
00270         }
00271         break;
00272         
00273     case ReadData:
00274         len = http->read(buf, count);
00275         num_received += len;
00276         return len;
00277         
00278     case Done:
00279         break;
00280     }
00281     
00282     return 0;
00283 }

Generated on Fri Apr 5 15:16:52 2002 for WvStreams by doxygen1.2.15