using std::string;
using std::map;
-#include <iostream>
-
-using std::cout;
-using std::cerr;
-using std::endl;
-
namespace simgear
{
namespace HTTP
{
+extern const int DEFAULT_HTTP_PORT;
+
Request::Request(const string& url, const string method) :
_method(method),
- _url(url)
+ _url(url),
+ _responseVersion(HTTP_VERSION_UNKNOWN),
+ _responseStatus(0),
+ _responseLength(0),
+ _receivedBodyBytes(0),
+ _willClose(false)
{
}
}
+void Request::setUrl(const string& url)
+{
+ _url = url;
+}
+
string_list Request::requestHeaders() const
{
string_list r;
void Request::responseStart(const string& r)
{
- const int maxSplit = 2; // HTTP/1.1 nnn status code
+ const int maxSplit = 2; // HTTP/1.1 nnn reason-string
string_list parts = strutils::split(r, NULL, maxSplit);
+ if (parts.size() != 3) {
+ SG_LOG(SG_IO, SG_WARN, "HTTP::Request: malformed response start:" << r);
+ setFailure(400, "malformed HTTP response header");
+ return;
+ }
+
+ _responseVersion = decodeVersion(parts[0]);
_responseStatus = strutils::to_int(parts[1]);
_responseReason = parts[2];
}
void Request::responseHeader(const string& key, const string& value)
{
+ if (key == "connection") {
+ _willClose = (value.find("close") >= 0);
+ }
+
_responseHeaders[key] = value;
}
// no op
}
+void Request::processBodyBytes(const char* s, int n)
+{
+ _receivedBodyBytes += n;
+ gotBodyData(s, n);
+}
+
void Request::gotBodyData(const char* s, int n)
{
}
string Request::host() const
+{
+ string hp(hostAndPort());
+ int colonPos = hp.find(':');
+ if (colonPos >= 0) {
+ return hp.substr(0, colonPos); // trim off the colon and port
+ } else {
+ return hp; // no port specifier
+ }
+}
+
+unsigned short Request::port() const
+{
+ string hp(hostAndPort());
+ int colonPos = hp.find(':');
+ if (colonPos >= 0) {
+ return (unsigned short) strutils::to_int(hp.substr(colonPos + 1));
+ } else {
+ return DEFAULT_HTTP_PORT;
+ }
+}
+
+string Request::hostAndPort() const
{
string u(url());
int schemeEnd = u.find("://");
return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3));
}
-int Request::contentLength() const
+void Request::setResponseLength(unsigned int l)
{
- HeaderDict::const_iterator it = _responseHeaders.find("content-length");
- if (it == _responseHeaders.end()) {
- return 0;
+ _responseLength = l;
+}
+
+unsigned int Request::responseLength() const
+{
+// if the server didn't supply a content length, use the number
+// of bytes we actually received (so far)
+ if ((_responseLength == 0) && (_receivedBodyBytes > 0)) {
+ return _receivedBodyBytes;
}
- return strutils::to_int(it->second);
+ return _responseLength;
+}
+
+void Request::setFailure(int code, const std::string& reason)
+{
+ _responseStatus = code;
+ _responseReason = reason;
+ failed();
+}
+
+void Request::failed()
+{
+ // no-op in base class
+}
+
+Request::HTTPVersion Request::decodeVersion(const string& v)
+{
+ if (v == "HTTP/1.1") return HTTP_1_1;
+ if (v == "HTTP/1.0") return HTTP_1_0;
+ if (strutils::starts_with(v, "HTTP/0.")) return HTTP_0_x;
+ return HTTP_VERSION_UNKNOWN;
+}
+
+bool Request::closeAfterComplete() const
+{
+// for non HTTP/1.1 connections, assume server closes
+ return _willClose || (_responseVersion != HTTP_1_1);
}
} // of namespace HTTP