00001
00002
00003
00004
00005
00006
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
00025
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
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
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)
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;
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 }