]> git.mxchange.org Git - simgear.git/blobdiff - simgear/io/HTTPRequest.cxx
Ensure individual log-level setting works.
[simgear.git] / simgear / io / HTTPRequest.cxx
index e38f7aae101383456204ff6fe497a56f575c27d5..ce706957b6f45469b4213b9f2c6244f462830fc9 100644 (file)
@@ -7,21 +7,22 @@
 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)
 {
     
 }
@@ -31,6 +32,11 @@ Request::~Request()
     
 }
 
+void Request::setUrl(const string& url)
+{
+    _url = url;
+}
+
 string_list Request::requestHeaders() const
 {
     string_list r;
@@ -44,14 +50,25 @@ string Request::header(const std::string& name) const
 
 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") != string::npos);
+    }
+    
     _responseHeaders[key] = value;
 }
 
@@ -60,6 +77,12 @@ 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)
 {
 
@@ -89,8 +112,10 @@ string Request::path() const
     }
     
     int hostEnd = u.find('/', schemeEnd + 3);
-    if (hostEnd < 0) { 
-        return ""; // couldn't parse host
+    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);
@@ -102,7 +127,43 @@ string Request::path() const
     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("://");
@@ -118,14 +179,63 @@ string Request::host() const
     return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3));
 }
 
-int Request::contentLength() const
+void Request::setResponseLength(unsigned int l)
+{
+    _responseLength = l;
+}
+
+unsigned int Request::responseLength() const
 {
-    HeaderDict::const_iterator it = _responseHeaders.find("content-length");
-    if (it == _responseHeaders.end()) {
-        return 0;
+// 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
+    SG_LOG(SG_IO, SG_INFO, "request failed:" << url());
+}
+
+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";
+}
+  
+void Request::getBodyData(char*, int& count) const
+{
+  count = 0;
+  return;
 }
 
 } // of namespace HTTP