7 #include <boost/algorithm/string/case_conv.hpp>
9 #include "HTTPClient.hxx"
10 #include "HTTPRequest.hxx"
12 #include <simgear/io/sg_netChat.hxx>
13 #include <simgear/misc/strutils.hxx>
14 #include <simgear/timing/timestamp.hxx>
20 using std::stringstream;
22 using namespace simgear;
24 const char* BODY1 = "The quick brown fox jumps over a lazy dog.";
26 const unsigned int body2Size = 8 * 1024;
27 char body2[body2Size];
29 #define COMPARE(a, b) \
31 cerr << "failed:" << #a << " != " << #b << endl; \
32 cerr << "\tgot:" << a << endl; \
38 cerr << "failed:" << #a << endl; \
42 class TestRequest : public HTTP::Request
48 TestRequest(const std::string& url) :
56 virtual void responseHeadersComplete()
60 virtual void responseComplete()
65 virtual void gotBodyData(const char* s, int n)
67 bodyData += string(s, n);
71 class TestServerChannel : public NetChat
84 setTerminator("\r\n");
87 virtual void collectIncomingData(const char* s, int n)
89 buffer += string(s, n);
92 virtual void foundTerminator(void)
94 if (state == STATE_IDLE) {
95 state = STATE_HEADERS;
96 string_list line = strutils::split(buffer, NULL, 3);
97 if (line.size() < 4) {
98 cerr << "malformed request:" << buffer << endl;
104 httpVersion = line[2];
106 requestHeaders.clear();
108 } else if (state == STATE_HEADERS) {
109 string s = strutils::simplify(buffer);
112 receivedRequestHeaders();
116 int colonPos = buffer.find(':');
118 cerr << "malformed HTTP response header:" << buffer << endl;
123 string key = strutils::simplify(buffer.substr(0, colonPos));
124 string lkey = boost::to_lower_copy(key);
125 string value = strutils::strip(buffer.substr(colonPos + 1));
126 requestHeaders[lkey] = value;
128 } else if (state == STATE_REQUEST_BODY) {
133 void receivedRequestHeaders()
136 if (path == "/test1") {
137 string contentStr(BODY1);
139 d << "HTTP1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
140 d << "Content-Length:" << contentStr.size() << "\r\n";
141 d << "\r\n"; // final CRLF to terminate the headers
143 push(d.str().c_str());
144 } else if (path == "/test2") {
146 } else if (path == "http://www.google.com/test2") {
148 if (requestHeaders["host"] != "www.google.com") {
149 sendErrorResponse(400);
152 if (requestHeaders["proxy-authorization"] != string()) {
153 sendErrorResponse(401); // shouldn't supply auth
157 } else if (path == "http://www.google.com/test3") {
159 if (requestHeaders["host"] != "www.google.com") {
160 sendErrorResponse(400);
163 if (requestHeaders["proxy-authorization"] != "ABCDEF") {
164 sendErrorResponse(401); // forbidden
169 sendErrorResponse(404);
176 d << "HTTP1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
177 d << "Content-Length:" << body2Size << "\r\n";
178 d << "\r\n"; // final CRLF to terminate the headers
179 push(d.str().c_str());
180 bufferSend(body2, body2Size);
183 void sendErrorResponse(int code)
185 cerr << "sending error " << code << " for " << path << endl;
186 stringstream headerData;
187 headerData << "HTTP1.1 " << code << " " << reasonForCode(code) << "\r\n";
188 headerData << "\r\n"; // final CRLF to terminate the headers
189 push(headerData.str().c_str());
192 string reasonForCode(int code)
195 case 200: return "OK";
196 case 404: return "not found";
197 default: return "unknown code";
207 std::map<string, string> requestHeaders;
210 class TestServer : public NetChannel
216 bind(NULL, 2000); // localhost, any port
220 virtual ~TestServer()
224 virtual bool writable (void) { return false ; }
226 virtual void handleAccept (void)
228 simgear::IPAddress addr ;
229 int handle = accept ( &addr ) ;
231 TestServerChannel* chan = new TestServerChannel();
232 chan->setHandle(handle);
236 void waitForComplete(TestRequest* tr)
238 SGTimeStamp start(SGTimeStamp::now());
239 while (start.elapsedMSec() < 1000) {
240 NetChannel::poll(10);
246 cerr << "timed out" << endl;
249 int main(int argc, char* argv[])
256 TestRequest* tr1 = new TestRequest("http://localhost.woo.zar:2000/test1?foo=bar");
257 COMPARE(tr1->scheme(), "http");
258 COMPARE(tr1->hostAndPort(), "localhost.woo.zar:2000");
259 COMPARE(tr1->host(), "localhost.woo.zar");
260 COMPARE(tr1->port(), 2000);
261 COMPARE(tr1->path(), "/test1");
263 TestRequest* tr2 = new TestRequest("http://192.168.1.1/test1/dir/thing/file.png");
264 COMPARE(tr2->scheme(), "http");
265 COMPARE(tr2->hostAndPort(), "192.168.1.1");
266 COMPARE(tr2->host(), "192.168.1.1");
267 COMPARE(tr2->port(), 80);
268 COMPARE(tr2->path(), "/test1/dir/thing/file.png");
272 TestRequest* tr = new TestRequest("http://localhost:2000/test1");
273 HTTP::Request_ptr own(tr);
277 COMPARE(tr->responseCode(), 200);
278 COMPARE(tr->responseReason(), string("OK"));
279 COMPARE(tr->contentLength(), strlen(BODY1));
280 COMPARE(tr->bodyData, string(BODY1));
283 // larger get request
284 for (unsigned int i=0; i<body2Size; ++i) {
285 body2[i] = (i << 4) | (i >> 2);
289 TestRequest* tr = new TestRequest("http://localhost:2000/test2");
290 HTTP::Request_ptr own(tr);
293 COMPARE(tr->responseCode(), 200);
294 COMPARE(tr->contentLength(), body2Size);
295 COMPARE(tr->bodyData, string(body2, body2Size));
300 TestRequest* tr = new TestRequest("http://localhost:2000/not-found");
301 HTTP::Request_ptr own(tr);
304 COMPARE(tr->responseCode(), 404);
305 COMPARE(tr->responseReason(), string("not found"));
306 COMPARE(tr->contentLength(), 0);
311 cl.setProxy("localhost:2000");
312 TestRequest* tr = new TestRequest("http://www.google.com/test2");
313 HTTP::Request_ptr own(tr);
316 COMPARE(tr->responseCode(), 200);
317 COMPARE(tr->contentLength(), body2Size);
318 COMPARE(tr->bodyData, string(body2, body2Size));
322 cl.setProxy("localhost:2000", "ABCDEF");
323 TestRequest* tr = new TestRequest("http://www.google.com/test3");
324 HTTP::Request_ptr own(tr);
327 COMPARE(tr->responseCode(), 200);
328 COMPARE(tr->contentLength(), body2Size);
329 COMPARE(tr->bodyData, string(body2, body2Size));
332 cout << "all tests passed ok" << endl;