X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fio%2FHTTPRequest.cxx;h=6b06785ad00bf57d79fb12e77b971a9475362138;hb=72bb9f4d5d6d861902a5779381e4ebe977db1df1;hp=e3980ca10af3608209ca1e62b324374e0f47a28e;hpb=7076c9a0ff82a27cbee3f5a9a512b11adc4abd97;p=simgear.git diff --git a/simgear/io/HTTPRequest.cxx b/simgear/io/HTTPRequest.cxx index e3980ca1..6b06785a 100644 --- a/simgear/io/HTTPRequest.cxx +++ b/simgear/io/HTTPRequest.cxx @@ -1,9 +1,27 @@ +// Copyright (C) 2011 James Turner +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + #include "HTTPRequest.hxx" #include #include #include #include +#include namespace simgear { @@ -14,6 +32,7 @@ extern const int DEFAULT_HTTP_PORT; //------------------------------------------------------------------------------ Request::Request(const std::string& url, const std::string method): + _client(0), _method(method), _url(url), _responseVersion(HTTP_VERSION_UNKNOWN), @@ -21,7 +40,8 @@ Request::Request(const std::string& url, const std::string method): _responseLength(0), _receivedBodyBytes(0), _ready_state(UNSENT), - _willClose(false) + _willClose(false), + _connectionCloseHeader(false) { } @@ -38,7 +58,7 @@ Request* Request::done(const Callback& cb) if( _ready_state == DONE ) cb(this); else - _cb_done = cb; + _cb_done.push_back(cb); return this; } @@ -49,7 +69,7 @@ Request* Request::fail(const Callback& cb) if( _ready_state == FAILED ) cb(this); else - _cb_fail = cb; + _cb_fail.push_back(cb); return this; } @@ -60,7 +80,7 @@ Request* Request::always(const Callback& cb) if( isComplete() ) cb(this); else - _cb_always = cb; + _cb_always.push_back(cb); return this; } @@ -115,21 +135,28 @@ void Request::responseStart(const std::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; + throw sg_io_exception("bad HTTP response:" + r); } - + _responseVersion = decodeHTTPVersion(parts[0]); _responseStatus = strutils::to_int(parts[1]); _responseReason = parts[2]; + + setReadyState(STATUS_RECEIVED); } //------------------------------------------------------------------------------ void Request::responseHeader(const std::string& key, const std::string& value) { - if( key == "connection" ) - _willClose = (value.find("close") != std::string::npos); + if( key == "connection" ) { + _connectionCloseHeader = (value.find("close") != std::string::npos); + // track willClose seperately because other conditions (abort, for + // example) can also set it + _willClose = _connectionCloseHeader; + } else if (key == "content-length") { + int sz = strutils::to_int(value); + setResponseLength(sz); + } _responseHeaders[key] = value; } @@ -191,7 +218,7 @@ std::string Request::scheme() const if (firstColon > 0) { return url().substr(0, firstColon); } - + return ""; // couldn't parse scheme } @@ -203,20 +230,20 @@ std::string Request::path() const 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 "/"; +// 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); } @@ -228,7 +255,7 @@ std::string Request::query() const if (query < 0) { return ""; //no query string found } - + return u.substr(query); //includes question mark } @@ -273,6 +300,16 @@ std::string Request::hostAndPort() const return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3)); } +//------------------------------------------------------------------------------ +std::string Request::responseMime() const +{ + std::string content_type = _responseHeaders.get("content-type"); + if( content_type.empty() ) + return "application/octet-stream"; + + return content_type.substr(0, content_type.find(';')); +} + //------------------------------------------------------------------------------ void Request::setResponseLength(unsigned int l) { @@ -293,9 +330,12 @@ unsigned int Request::responseLength() const //------------------------------------------------------------------------------ void Request::setFailure(int code, const std::string& reason) { + SG_LOG(SG_IO, SG_WARN, "HTTP request: set failure:" << code << " reason " << reason); _responseStatus = code; _responseReason = reason; - setReadyState(FAILED); + + if( !isComplete() ) + setReadyState(FAILED); } //------------------------------------------------------------------------------ @@ -310,45 +350,39 @@ void Request::setReadyState(ReadyState state) onDone(); onAlways(); - if( _cb_done ) - _cb_done(this); + _cb_done(this); } else if( state == FAILED ) { onFail(); onAlways(); - if( _cb_fail ) - _cb_fail(this); + _cb_fail(this); } else return; - if( _cb_always ) - _cb_always(this); + _cb_always(this); } //------------------------------------------------------------------------------ -void Request::abort() +bool Request::closeAfterComplete() const { - abort("Request aborted."); + // for non HTTP/1.1 connections, assume server closes + return _willClose || (_responseVersion != HTTP_1_1); } -//---------------------------------------------------------------------------- -void Request::abort(const std::string& reason) -{ - if( isComplete() ) - return; +//------------------------------------------------------------------------------ - setFailure(-1, reason); - _willClose = true; +void Request::setCloseAfterComplete() +{ + _willClose = true; } //------------------------------------------------------------------------------ -bool Request::closeAfterComplete() const +bool Request::serverSupportsPipelining() const { - // for non HTTP/1.1 connections, assume server closes - return _willClose || (_responseVersion != HTTP_1_1); + return (_responseVersion == HTTP_1_1) && !_connectionCloseHeader; } //------------------------------------------------------------------------------