00001
00002
00003
00004
00005
00006
00007
00008 #include "wvhttp.h"
00009 #include "strutils.h"
00010 #include <assert.h>
00011
00012
00014
00015
00016
00017 WvURL::WvURL(const WvString &url) : err("No error")
00018 {
00019 WvString work(url);
00020 char *cptr, *wptr = work.edit();
00021
00022 port = 0;
00023 addr = NULL;
00024 resolving = true;
00025
00026 if (strncmp(wptr, "http://", 7))
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)
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)
00075 {
00076 err = WvString("Host %s could not be found.", hostname);
00077 resolving = false;
00078 return false;
00079 }
00080 else if (numaddrs < 0)
00081 {
00082 resolving = true;
00083 return false;
00084 }
00085 else
00086 {
00087 resolving = false;
00088 if (addr) delete addr;
00089 addr = new WvIPPortAddr(*ip, port);
00090 return true;
00091 }
00092 }
00093
00094
00095
00096
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
00131
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
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
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)
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;
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 }