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 // couldn't parse host, or URL looks like 'http://foo.com' (no trailing '/')
117 // fixup to root resource path: '/'
121 int query = u.find('?', hostEnd + 1);
123 // all remainder of URL is path
124 return u.substr(hostEnd);
127 return u.substr(hostEnd, query - hostEnd);
131 string Request::query() const
134 int query = u.find('?');
136 return ""; //no query string found
139 return u.substr(query); //includes question mark
144 string Request::host() const
146 string hp(hostAndPort());
147 int colonPos = hp.find(':');
149 return hp.substr(0, colonPos); // trim off the colon and port
151 return hp; // no port specifier
155 unsigned short Request::port() const
157 string hp(hostAndPort());
158 int colonPos = hp.find(':');
160 return (unsigned short) strutils::to_int(hp.substr(colonPos + 1));
162 return DEFAULT_HTTP_PORT;
166 string Request::hostAndPort() const
169 int schemeEnd = u.find("://");
171 return ""; // couldn't parse scheme
174 int hostEnd = u.find('/', schemeEnd + 3);
175 if (hostEnd < 0) { // all remainder of URL is host
176 return u.substr(schemeEnd + 3);
179 return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3));
182 void Request::setResponseLength(unsigned int l)
187 unsigned int Request::responseLength() const
189 // if the server didn't supply a content length, use the number
190 // of bytes we actually received (so far)
191 if ((_responseLength == 0) && (_receivedBodyBytes > 0)) {
192 return _receivedBodyBytes;
195 return _responseLength;
198 void Request::setFailure(int code, const std::string& reason)
200 _responseStatus = code;
201 _responseReason = reason;
205 void Request::failed()
207 // no-op in base class
208 SG_LOG(SG_IO, SG_INFO, "request failed:" << url());
211 Request::HTTPVersion Request::decodeVersion(const string& v)
213 if (v == "HTTP/1.1") return HTTP_1_1;
214 if (v == "HTTP/1.0") return HTTP_1_0;
215 if (strutils::starts_with(v, "HTTP/0.")) return HTTP_0_x;
216 return HTTP_VERSION_UNKNOWN;
219 bool Request::closeAfterComplete() const
221 // for non HTTP/1.1 connections, assume server closes
222 return _willClose || (_responseVersion != HTTP_1_1);
225 int Request::requestBodyLength() const
230 std::string Request::requestBodyType() const
235 void Request::getBodyData(char*, int& count) const
241 } // of namespace HTTP
243 } // of namespace simgear