wvhttp.cc

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 "wvsslstream.h"
00010 #include "strutils.h"
00011 #include <assert.h>
00012 
00013 
00014 
00015 WvHTTPStream::WvHTTPStream(const WvURL &_url)
00016         : WvStreamClone(NULL), headers(7), client_headers(7),
00017           url(_url)
00018 {
00019     state = Resolving;
00020     num_received = 0;
00021     tcp = NULL;
00022     ssl = NULL;
00023     
00024     // we need this: if the URL tried to dns-resolve before, but failed,
00025     // this might make isok() true again if the name has turned up.
00026     url.resolve();
00027 }
00028 
00029 
00030 bool WvHTTPStream::isok() const
00031 {
00032     if (cloned)
00033         return WvStreamClone::isok();
00034     else
00035         return url.isok();
00036 }
00037 
00038 
00039 int WvHTTPStream::geterr() const
00040 {
00041     if (cloned)
00042         return WvStreamClone::geterr();
00043     else
00044         return -1;
00045 }
00046 
00047 
00048 WvString WvHTTPStream::errstr() const
00049 {
00050     if (cloned)
00051         return WvStreamClone::errstr();
00052     else if (!url.isok())
00053         return url.errstr();
00054     else
00055         return "Unknown error! (no stream yet)";
00056 }
00057 
00058 
00059 bool WvHTTPStream::pre_select(SelectInfo &si)
00060 {
00061     if (!isok()) return false;
00062     
00063     switch (state)
00064     {
00065     case Resolving:
00066         if (!url.isok())
00067             seterr("Invalid URL");
00068         else if (url.resolve())
00069         {
00070             state = Connecting;
00071             tcp = new WvTCPConn(url.getaddr());
00072             if (url.getproto() == "https")
00073             {
00074                 ssl = new WvSSLStream(tcp, NULL, 0);
00075                 conn = ssl;
00076                 setclone(ssl);
00077             }
00078             else
00079             {
00080                 conn = tcp;
00081                 setclone(tcp);
00082             }
00083         }
00084         return false;
00085 
00086     case Connecting:
00087         conn->select(0, false, true, false);
00088         if (!tcp->isconnected())
00089             return false;
00090         if (conn->geterr())
00091             return false;
00092 
00093         // otherwise, we just finished connecting:  start transfer.
00094         state = ReadHeader1;
00095         delay_output(true);
00096         print("GET %s HTTP/1.0\r\n", url.getfile());
00097         print("Host: %s:%s\r\n", url.gethost(), url.getport());
00098         {
00099             WvHTTPHeaderDict::Iter i(client_headers);
00100             for (i.rewind(); i.next(); )
00101             {
00102                 print("%s: %s\r\n", i().name, i().value);
00103             }
00104         }
00105         print("\r\n");
00106         delay_output(false);
00107         
00108         // FALL THROUGH!
00109         
00110     default:
00111         return WvStreamClone::isok()
00112             && WvStreamClone::pre_select(si);
00113     }
00114 }
00115 
00116 
00117 size_t WvHTTPStream::uread(void *buf, size_t count)
00118 {
00119     char *line;
00120     int retval;
00121     size_t len;
00122     
00123     switch (state)
00124     {
00125     case Resolving:
00126     case Connecting:
00127         break;
00128         
00129     case ReadHeader1:
00130         line = trim_string(conn->getline());
00131         if (line) // got response code line
00132         {
00133             if (strncmp(line, "HTTP/", 5))
00134             {
00135                 seterr("Invalid HTTP response");
00136                 return 0;
00137             }
00138             
00139             retval = atoi(trim_string(line+9));
00140             
00141             if (retval / 100 != 2)
00142             {
00143                 seterr(WvString("HTTP error: %s", trim_string(line+9)));
00144                 return 0;
00145             }
00146                 
00147             state = ReadHeader;
00148         }
00149         break;
00150         
00151     case ReadHeader:
00152         line = trim_string(conn->getline());
00153         if (line)
00154         {
00155             if (!line[0])
00156                 state = ReadData;       // header is done
00157             else
00158             {
00159                 char *cptr = strchr(line, ':');
00160                 if (!cptr)
00161                     headers.add(new WvHTTPHeader(line, ""), true);
00162                 else
00163                 {
00164                     *cptr++ = 0;
00165                     line = trim_string(line);
00166                     cptr = trim_string(cptr);
00167                     headers.add(new WvHTTPHeader(line, cptr), true);
00168                 }
00169             }
00170         }
00171         break;
00172         
00173     case ReadData:
00174         len = conn->read(buf, count);
00175         num_received += len;
00176         return len;
00177         
00178     case Done:
00179         break;
00180     }
00181     
00182     return 0;
00183 }

Generated on Mon Feb 5 10:54:29 2007 for WvStreams by  doxygen 1.5.1