1 #include "HTTPClient.hxx"
7 #include <boost/foreach.hpp>
8 #include <boost/algorithm/string/case_conv.hpp>
10 #include <simgear/io/sg_netChat.hxx>
11 #include <simgear/misc/strutils.hxx>
12 #include <simgear/compiler.h>
13 #include <simgear/debug/logstream.hxx>
14 #include <simgear/version.h>
17 using std::stringstream;
33 class Connection : public NetChat
36 Connection(Client* pr) :
40 setTerminator("\r\n");
43 void connectToHost(const string& host)
47 int colonPos = host.find(':');
49 string h = host.substr(0, colonPos);
50 int port = strutils::to_int(host.substr(colonPos + 1));
51 connect(h.c_str(), port);
53 connect(host.c_str(), 80 /* default port */);
57 void queueRequest(const Request_ptr& r)
62 queuedRequests.push_back(r);
66 void startRequest(const Request_ptr& r)
72 stringstream headerData;
73 string path = r->path();
74 if (!client->proxyHost().empty()) {
75 path = "http://" + r->host() + path;
79 headerData << r->method() << " " << path << " HTTP/1.1 " << client->userAgent() << "\r\n";
80 headerData << "Host: " << r->host() << "\r\n";
81 headerData << "X-Time: " << requestTime << "\r\n";
83 if (!client->proxyAuth().empty()) {
84 headerData << "Proxy-Authorization: " << client->proxyAuth() << "\r\n";
87 BOOST_FOREACH(string h, r->requestHeaders()) {
88 headerData << h << ": " << r->header(h) << "\r\n";
91 headerData << "\r\n"; // final CRLF to terminate the headers
93 // TODO - add request body support for PUT, etc operations
95 push(headerData.str().c_str());
96 cout << "sent request" << endl;
99 virtual void collectIncomingData(const char* s, int n)
101 if (state == STATE_GETTING_BODY) {
102 activeRequest->gotBodyData(s, n);
104 buffer += string(s, n);
108 virtual void foundTerminator(void)
112 activeRequest->responseStart(buffer);
113 state = STATE_GETTING_HEADERS;
117 case STATE_GETTING_HEADERS:
122 case STATE_GETTING_BODY:
125 setTerminator("\r\n");
127 if (!queuedRequests.empty()) {
128 Request_ptr next = queuedRequests.front();
129 queuedRequests.pop_front();
140 string h = strutils::simplify(buffer);
141 if (h.empty()) { // blank line terminates headers
144 if (bodyTransferSize > 0) {
145 state = STATE_GETTING_BODY;
146 cout << "getting body:" << bodyTransferSize << endl;
147 setByteCount(bodyTransferSize);
150 state = STATE_IDLE; // no response body, we're done
155 int colonPos = buffer.find(':');
157 SG_LOG(SG_IO, SG_WARN, "malformed HTTP response header:" << h);
161 string key = strutils::simplify(buffer.substr(0, colonPos));
162 string lkey = boost::to_lower_copy(key);
163 string value = strutils::strip(buffer.substr(colonPos + 1));
165 if (lkey == "content-length" && (bodyTransferSize <= 0)) {
166 bodyTransferSize = strutils::to_int(value);
167 } else if (lkey == "transfer-length") {
168 bodyTransferSize = strutils::to_int(value);
171 activeRequest->responseHeader(lkey, value);
174 void headersComplete()
176 activeRequest->responseHeadersComplete();
179 void responseComplete()
181 activeRequest->responseComplete();
182 client->requestFinished(this);
183 activeRequest = NULL;
186 enum ConnectionState {
188 STATE_GETTING_HEADERS,
193 Request_ptr activeRequest;
194 ConnectionState state;
196 int bodyTransferSize;
198 std::list<Request_ptr> queuedRequests;
203 setUserAgent("SimGear-" SG_STRINGIZE(SIMGEAR_VERSION));
206 void Client::makeRequest(const Request_ptr& r)
208 string host = r->host();
209 if (!_proxy.empty()) {
213 if (_connections.find(host) == _connections.end()) {
214 Connection* con = new Connection(this);
215 con->connectToHost(host);
216 _connections[host] = con;
219 _connections[host]->queueRequest(r);
222 void Client::requestFinished(Connection* con)
227 void Client::setUserAgent(const string& ua)
232 void Client::setProxy(const string& proxy, const string& auth)
238 } // of namespace HTTP
240 } // of namespace simgear