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);
128 string Request::host() const
130 string hp(hostAndPort());
131 int colonPos = hp.find(':');
133 return hp.substr(0, colonPos); // trim off the colon and port
135 return hp; // no port specifier
139 unsigned short Request::port() const
141 string hp(hostAndPort());
142 int colonPos = hp.find(':');
144 return (unsigned short) strutils::to_int(hp.substr(colonPos + 1));
146 return DEFAULT_HTTP_PORT;
150 string Request::hostAndPort() const
153 int schemeEnd = u.find("://");
155 return ""; // couldn't parse scheme
158 int hostEnd = u.find('/', schemeEnd + 3);
159 if (hostEnd < 0) { // all remainder of URL is host
160 return u.substr(schemeEnd + 3);
163 return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3));
166 void Request::setResponseLength(unsigned int l)
171 unsigned int Request::responseLength() const
173 // if the server didn't supply a content length, use the number
174 // of bytes we actually received (so far)
175 if ((_responseLength == 0) && (_receivedBodyBytes > 0)) {
176 return _receivedBodyBytes;
179 return _responseLength;
182 void Request::setFailure(int code, const std::string& reason)
184 _responseStatus = code;
185 _responseReason = reason;
189 void Request::failed()
191 // no-op in base class
194 Request::HTTPVersion Request::decodeVersion(const string& v)
196 if (v == "HTTP/1.1") return HTTP_1_1;
197 if (v == "HTTP/1.0") return HTTP_1_0;
198 if (strutils::starts_with(v, "HTTP/0.")) return HTTP_0_x;
199 return HTTP_VERSION_UNKNOWN;
202 bool Request::closeAfterComplete() const
204 // for non HTTP/1.1 connections, assume server closes
205 return _willClose || (_responseVersion != HTTP_1_1);
208 } // of namespace HTTP
210 } // of namespace simgear