1 #include "HTTPRequest.hxx"
3 #include <simgear/misc/strutils.hxx>
4 #include <simgear/compiler.h>
5 #include <simgear/debug/logstream.hxx>
16 extern const int DEFAULT_HTTP_PORT;
18 Request::Request(const string& url, const string method) :
21 _responseVersion(HTTP_VERSION_UNKNOWN),
24 _receivedBodyBytes(0),
35 void Request::setUrl(const string& url)
40 string_list Request::requestHeaders() const
46 string Request::header(const std::string& name) const
51 void Request::requestStart()
56 void Request::responseStart(const string& r)
58 const int maxSplit = 2; // HTTP/1.1 nnn reason-string
59 string_list parts = strutils::split(r, NULL, maxSplit);
60 if (parts.size() != 3) {
61 SG_LOG(SG_IO, SG_WARN, "HTTP::Request: malformed response start:" << r);
62 setFailure(400, "malformed HTTP response header");
66 _responseVersion = decodeVersion(parts[0]);
67 _responseStatus = strutils::to_int(parts[1]);
68 _responseReason = parts[2];
71 void Request::responseHeader(const string& key, const string& value)
73 if (key == "connection") {
74 _willClose = (value.find("close") != string::npos);
77 _responseHeaders[key] = value;
80 void Request::responseHeadersComplete()
85 void Request::processBodyBytes(const char* s, int n)
87 _receivedBodyBytes += n;
91 void Request::gotBodyData(const char* s, int n)
96 void Request::responseComplete()
101 string Request::scheme() const
103 int firstColon = url().find(":");
104 if (firstColon > 0) {
105 return url().substr(0, firstColon);
108 return ""; // couldn't parse scheme
111 string Request::path() const
114 int schemeEnd = u.find("://");
116 return ""; // couldn't parse scheme
119 int hostEnd = u.find('/', schemeEnd + 3);
121 // couldn't parse host, or URL looks like 'http://foo.com' (no trailing '/')
122 // fixup to root resource path: '/'
126 int query = u.find('?', hostEnd + 1);
128 // all remainder of URL is path
129 return u.substr(hostEnd);
132 return u.substr(hostEnd, query - hostEnd);
136 string Request::query() const
139 int query = u.find('?');
141 return ""; //no query string found
144 return u.substr(query); //includes question mark
149 string Request::host() const
151 string hp(hostAndPort());
152 int colonPos = hp.find(':');
154 return hp.substr(0, colonPos); // trim off the colon and port
156 return hp; // no port specifier
160 unsigned short Request::port() const
162 string hp(hostAndPort());
163 int colonPos = hp.find(':');
165 return (unsigned short) strutils::to_int(hp.substr(colonPos + 1));
167 return DEFAULT_HTTP_PORT;
171 string Request::hostAndPort() const
174 int schemeEnd = u.find("://");
176 return ""; // couldn't parse scheme
179 int hostEnd = u.find('/', schemeEnd + 3);
180 if (hostEnd < 0) { // all remainder of URL is host
181 return u.substr(schemeEnd + 3);
184 return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3));
187 void Request::setResponseLength(unsigned int l)
192 unsigned int Request::responseLength() const
194 // if the server didn't supply a content length, use the number
195 // of bytes we actually received (so far)
196 if ((_responseLength == 0) && (_receivedBodyBytes > 0)) {
197 return _receivedBodyBytes;
200 return _responseLength;
203 void Request::setFailure(int code, const std::string& reason)
205 _responseStatus = code;
206 _responseReason = reason;
210 void Request::failed()
212 SG_LOG(SG_IO, SG_INFO, "request failed:" << url() << " : "
213 << responseCode() << "/" << responseReason());
216 Request::HTTPVersion Request::decodeVersion(const string& v)
218 if (v == "HTTP/1.1") return HTTP_1_1;
219 if (v == "HTTP/1.0") return HTTP_1_0;
220 if (strutils::starts_with(v, "HTTP/0.")) return HTTP_0_x;
221 return HTTP_VERSION_UNKNOWN;
224 bool Request::closeAfterComplete() const
226 // for non HTTP/1.1 connections, assume server closes
227 return _willClose || (_responseVersion != HTTP_1_1);
230 int Request::requestBodyLength() const
235 std::string Request::requestBodyType() const
240 int Request::getBodyData(char*, int maxCount) const
245 } // of namespace HTTP
247 } // of namespace simgear