#include "HTTPRequest.hxx" #include #include #include using std::string; using std::map; namespace simgear { namespace HTTP { extern const int DEFAULT_HTTP_PORT; Request::Request(const string& url, const string method) : _method(method), _url(url), _responseVersion(HTTP_VERSION_UNKNOWN), _responseStatus(0), _responseLength(0), _receivedBodyBytes(0), _willClose(false) { } Request::~Request() { } void Request::setUrl(const string& url) { _url = url; } string_list Request::requestHeaders() const { string_list r; return r; } string Request::header(const std::string& name) const { return string(); } void Request::requestStart() { } void Request::responseStart(const string& r) { 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") != string::npos); } _responseHeaders[key] = value; } void Request::responseHeadersComplete() { // no op } void Request::processBodyBytes(const char* s, int n) { _receivedBodyBytes += n; gotBodyData(s, n); } void Request::gotBodyData(const char* s, int n) { } void Request::responseComplete() { } string Request::scheme() const { int firstColon = url().find(":"); if (firstColon > 0) { return url().substr(0, firstColon); } return ""; // couldn't parse scheme } string Request::path() const { string u(url()); int schemeEnd = u.find("://"); if (schemeEnd < 0) { return ""; // couldn't parse scheme } int hostEnd = u.find('/', schemeEnd + 3); if (hostEnd < 0) { // couldn't parse host, or URL looks like 'http://foo.com' (no trailing '/') // fixup to root resource path: '/' return "/"; } int query = u.find('?', hostEnd + 1); if (query < 0) { // all remainder of URL is path return u.substr(hostEnd); } return u.substr(hostEnd, query - hostEnd); } string Request::query() const { string u(url()); int query = u.find('?'); if (query < 0) { return ""; //no query string found } return u.substr(query); //includes question mark } 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("://"); if (schemeEnd < 0) { return ""; // couldn't parse scheme } int hostEnd = u.find('/', schemeEnd + 3); if (hostEnd < 0) { // all remainder of URL is host return u.substr(schemeEnd + 3); } return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3)); } void Request::setResponseLength(unsigned int l) { _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 _responseLength; } void Request::setFailure(int code, const std::string& reason) { _responseStatus = code; _responseReason = reason; failed(); } void Request::failed() { SG_LOG(SG_IO, SG_INFO, "request failed:" << url() << " : " << responseCode() << "/" << responseReason()); } 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); } int Request::requestBodyLength() const { return -1; } std::string Request::requestBodyType() const { return "text/plain"; } int Request::getBodyData(char*, int maxCount) const { return 0; } } // of namespace HTTP } // of namespace simgear