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::responseStart(const string& r)
53 const int maxSplit = 2; // HTTP/1.1 nnn reason-string
54 string_list parts = strutils::split(r, NULL, maxSplit);
55 if (parts.size() != 3) {
56 SG_LOG(SG_IO, SG_WARN, "HTTP::Request: malformed response start:" << r);
57 setFailure(400, "malformed HTTP response header");
61 _responseVersion = decodeVersion(parts[0]);
62 _responseStatus = strutils::to_int(parts[1]);
63 _responseReason = parts[2];
66 void Request::responseHeader(const string& key, const string& value)
68 if (key == "connection") {
69 _willClose = (value.find("close") != string::npos);
72 _responseHeaders[key] = value;
75 void Request::responseHeadersComplete()
80 void Request::processBodyBytes(const char* s, int n)
82 _receivedBodyBytes += n;
86 void Request::gotBodyData(const char* s, int n)
91 void Request::responseComplete()
96 string Request::scheme() const
98 int firstColon = url().find(":");
100 return url().substr(0, firstColon);
103 return ""; // couldn't parse scheme
106 string Request::path() const
109 int schemeEnd = u.find("://");
111 return ""; // couldn't parse scheme
114 int hostEnd = u.find('/', schemeEnd + 3);
116 return ""; // couldn't parse host
119 int query = u.find('?', hostEnd + 1);
121 // all remainder of URL is path
122 return u.substr(hostEnd);
125 return u.substr(hostEnd, query - hostEnd);
129 string Request::query() const
132 int query = u.find('?');
134 return ""; //no query string found
137 return u.substr(query); //includes question mark
142 string Request::host() const
144 string hp(hostAndPort());
145 int colonPos = hp.find(':');
147 return hp.substr(0, colonPos); // trim off the colon and port
149 return hp; // no port specifier
153 unsigned short Request::port() const
155 string hp(hostAndPort());
156 int colonPos = hp.find(':');
158 return (unsigned short) strutils::to_int(hp.substr(colonPos + 1));
160 return DEFAULT_HTTP_PORT;
164 string Request::hostAndPort() const
167 int schemeEnd = u.find("://");
169 return ""; // couldn't parse scheme
172 int hostEnd = u.find('/', schemeEnd + 3);
173 if (hostEnd < 0) { // all remainder of URL is host
174 return u.substr(schemeEnd + 3);
177 return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3));
180 void Request::setResponseLength(unsigned int l)
185 unsigned int Request::responseLength() const
187 // if the server didn't supply a content length, use the number
188 // of bytes we actually received (so far)
189 if ((_responseLength == 0) && (_receivedBodyBytes > 0)) {
190 return _receivedBodyBytes;
193 return _responseLength;
196 void Request::setFailure(int code, const std::string& reason)
198 _responseStatus = code;
199 _responseReason = reason;
203 void Request::failed()
205 // no-op in base class
208 Request::HTTPVersion Request::decodeVersion(const string& v)
210 if (v == "HTTP/1.1") return HTTP_1_1;
211 if (v == "HTTP/1.0") return HTTP_1_0;
212 if (strutils::starts_with(v, "HTTP/0.")) return HTTP_0_x;
213 return HTTP_VERSION_UNKNOWN;
216 bool Request::closeAfterComplete() const
218 // for non HTTP/1.1 connections, assume server closes
219 return _willClose || (_responseVersion != HTTP_1_1);
222 } // of namespace HTTP
224 } // of namespace simgear