HTTP engine tweaks for SVN support.
This commit is contained in:
+32
-11
@@ -53,6 +53,8 @@ const int GZIP_HEADER_FNAME = 1 << 3;
|
|||||||
const int GZIP_HEADER_COMMENT = 1 << 4;
|
const int GZIP_HEADER_COMMENT = 1 << 4;
|
||||||
const int GZIP_HEADER_CRC = 1 << 1;
|
const int GZIP_HEADER_CRC = 1 << 1;
|
||||||
|
|
||||||
|
typedef std::list<Request_ptr> RequestList;
|
||||||
|
|
||||||
class Connection : public NetChat
|
class Connection : public NetChat
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -117,13 +119,27 @@ public:
|
|||||||
virtual void handleClose()
|
virtual void handleClose()
|
||||||
{
|
{
|
||||||
NetChat::handleClose();
|
NetChat::handleClose();
|
||||||
|
|
||||||
if ((state == STATE_GETTING_BODY) && activeRequest) {
|
// closing of the connection from the server side when getting the body,
|
||||||
|
bool canCloseState = (state == STATE_GETTING_BODY);
|
||||||
|
if (canCloseState && activeRequest) {
|
||||||
// force state here, so responseComplete can avoid closing the
|
// force state here, so responseComplete can avoid closing the
|
||||||
// socket again
|
// socket again
|
||||||
state = STATE_CLOSED;
|
state = STATE_CLOSED;
|
||||||
responseComplete();
|
responseComplete();
|
||||||
} else {
|
} else {
|
||||||
|
if (activeRequest) {
|
||||||
|
activeRequest->setFailure(500, "server closed connection");
|
||||||
|
// remove the failed request from sentRequests, so it does
|
||||||
|
// not get restored
|
||||||
|
RequestList::iterator it = std::find(sentRequests.begin(),
|
||||||
|
sentRequests.end(), activeRequest);
|
||||||
|
if (it != sentRequests.end()) {
|
||||||
|
sentRequests.erase(it);
|
||||||
|
}
|
||||||
|
activeRequest = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
state = STATE_CLOSED;
|
state = STATE_CLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,6 +202,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Request_ptr r = queuedRequests.front();
|
Request_ptr r = queuedRequests.front();
|
||||||
|
r->requestStart();
|
||||||
requestBodyBytesToSend = r->requestBodyLength();
|
requestBodyBytesToSend = r->requestBodyLength();
|
||||||
|
|
||||||
stringstream headerData;
|
stringstream headerData;
|
||||||
@@ -229,6 +246,7 @@ public:
|
|||||||
|
|
||||||
bool ok = push(headerData.str().c_str());
|
bool ok = push(headerData.str().c_str());
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
|
SG_LOG(SG_IO, SG_WARN, "HTTPClient: over-stuffed the socket");
|
||||||
// we've over-stuffed the socket, give up for now, let things
|
// we've over-stuffed the socket, give up for now, let things
|
||||||
// drain down before trying to start any more requests.
|
// drain down before trying to start any more requests.
|
||||||
return;
|
return;
|
||||||
@@ -236,8 +254,7 @@ public:
|
|||||||
|
|
||||||
while (requestBodyBytesToSend > 0) {
|
while (requestBodyBytesToSend > 0) {
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
int len = 4096;
|
int len = r->getBodyData(buf, 4096);
|
||||||
r->getBodyData(buf, len);
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
requestBodyBytesToSend -= len;
|
requestBodyBytesToSend -= len;
|
||||||
if (!bufferSend(buf, len)) {
|
if (!bufferSend(buf, len)) {
|
||||||
@@ -245,13 +262,16 @@ public:
|
|||||||
state = STATE_SOCKET_ERROR;
|
state = STATE_SOCKET_ERROR;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// SG_LOG(SG_IO, SG_INFO, "sent body:\n" << string(buf, len) << "\n%%%%%%%%%");
|
||||||
} else {
|
} else {
|
||||||
SG_LOG(SG_IO, SG_WARN, "asynchronous request body generation is unsupported");
|
SG_LOG(SG_IO, SG_WARN, "HTTP asynchronous request body generation is unsupported");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//std::cout << "did send request:" << r->url() << std::endl;
|
SG_LOG(SG_IO, SG_DEBUG, "did start request:" << r->url() <<
|
||||||
|
"\n\t @ " << reinterpret_cast<void*>(r.ptr()) <<
|
||||||
|
"\n\t on connection " << this);
|
||||||
// successfully sent, remove from queue, and maybe send the next
|
// successfully sent, remove from queue, and maybe send the next
|
||||||
queuedRequests.pop_front();
|
queuedRequests.pop_front();
|
||||||
sentRequests.push_back(r);
|
sentRequests.push_back(r);
|
||||||
@@ -308,7 +328,7 @@ public:
|
|||||||
if (result == Z_OK || result == Z_STREAM_END) {
|
if (result == Z_OK || result == Z_STREAM_END) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
} else {
|
} else {
|
||||||
SG_LOG(SG_IO, SG_WARN, "got Zlib error:" << result);
|
SG_LOG(SG_IO, SG_WARN, "HTTP: got Zlib error:" << result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,7 +627,7 @@ private:
|
|||||||
|
|
||||||
void responseComplete()
|
void responseComplete()
|
||||||
{
|
{
|
||||||
//std::cout << "responseComplete:" << activeRequest->url() << std::endl;
|
// SG_LOG(SG_IO, SG_INFO, "*** responseComplete:" << activeRequest->url());
|
||||||
activeRequest->responseComplete();
|
activeRequest->responseComplete();
|
||||||
client->requestFinished(this);
|
client->requestFinished(this);
|
||||||
|
|
||||||
@@ -666,8 +686,8 @@ private:
|
|||||||
unsigned char* zlibOutputBuffer;
|
unsigned char* zlibOutputBuffer;
|
||||||
bool contentGZip, contentDeflate;
|
bool contentGZip, contentDeflate;
|
||||||
|
|
||||||
std::list<Request_ptr> queuedRequests;
|
RequestList queuedRequests;
|
||||||
std::list<Request_ptr> sentRequests;
|
RequestList sentRequests;
|
||||||
};
|
};
|
||||||
|
|
||||||
Client::Client()
|
Client::Client()
|
||||||
@@ -677,7 +697,7 @@ Client::Client()
|
|||||||
|
|
||||||
void Client::update(int waitTimeout)
|
void Client::update(int waitTimeout)
|
||||||
{
|
{
|
||||||
NetChannel::poll(waitTimeout);
|
_poller.poll(waitTimeout);
|
||||||
|
|
||||||
ConnectionDict::iterator it = _connections.begin();
|
ConnectionDict::iterator it = _connections.begin();
|
||||||
for (; it != _connections.end(); ) {
|
for (; it != _connections.end(); ) {
|
||||||
@@ -715,6 +735,7 @@ void Client::makeRequest(const Request_ptr& r)
|
|||||||
if (_connections.find(connectionId) == _connections.end()) {
|
if (_connections.find(connectionId) == _connections.end()) {
|
||||||
Connection* con = new Connection(this);
|
Connection* con = new Connection(this);
|
||||||
con->setServer(host, port);
|
con->setServer(host, port);
|
||||||
|
_poller.addChannel(con);
|
||||||
_connections[connectionId] = con;
|
_connections[connectionId] = con;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <simgear/io/HTTPRequest.hxx>
|
#include <simgear/io/HTTPRequest.hxx>
|
||||||
|
#include <simgear/io/sg_netChannel.hxx>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
@@ -49,6 +50,7 @@ private:
|
|||||||
std::string _proxy;
|
std::string _proxy;
|
||||||
int _proxyPort;
|
int _proxyPort;
|
||||||
std::string _proxyAuth;
|
std::string _proxyAuth;
|
||||||
|
NetChannelPoller _poller;
|
||||||
|
|
||||||
// connections by host
|
// connections by host
|
||||||
typedef std::map<std::string, Connection*> ConnectionDict;
|
typedef std::map<std::string, Connection*> ConnectionDict;
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ string Request::header(const std::string& name) const
|
|||||||
return string();
|
return string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Request::requestStart()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void Request::responseStart(const string& r)
|
void Request::responseStart(const string& r)
|
||||||
{
|
{
|
||||||
const int maxSplit = 2; // HTTP/1.1 nnn reason-string
|
const int maxSplit = 2; // HTTP/1.1 nnn reason-string
|
||||||
@@ -232,10 +237,9 @@ std::string Request::requestBodyType() const
|
|||||||
return "text/plain";
|
return "text/plain";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Request::getBodyData(char*, int& count) const
|
int Request::getBodyData(char*, int maxCount) const
|
||||||
{
|
{
|
||||||
count = 0;
|
return 0;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // of namespace HTTP
|
} // of namespace HTTP
|
||||||
|
|||||||
@@ -52,10 +52,10 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the body data bytes. Will be passed the maximum body bytes
|
* Retrieve the body data bytes. Will be passed the maximum body bytes
|
||||||
* to return in the buffer, and should update count with the actual number
|
* to return in the buffer, and must return the actual number
|
||||||
* of bytes written.
|
* of bytes written.
|
||||||
*/
|
*/
|
||||||
virtual void getBodyData(char* s, int& count) const;
|
virtual int getBodyData(char* s, int count) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* retrieve the request body content type. Default is text/plain
|
* retrieve the request body content type. Default is text/plain
|
||||||
@@ -86,6 +86,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
Request(const std::string& url, const std::string method = "GET");
|
Request(const std::string& url, const std::string method = "GET");
|
||||||
|
|
||||||
|
virtual void requestStart();
|
||||||
virtual void responseStart(const std::string& r);
|
virtual void responseStart(const std::string& r);
|
||||||
virtual void responseHeader(const std::string& key, const std::string& value);
|
virtual void responseHeader(const std::string& key, const std::string& value);
|
||||||
virtual void responseHeadersComplete();
|
virtual void responseHeadersComplete();
|
||||||
|
|||||||
+111
-105
@@ -41,8 +41,6 @@
|
|||||||
|
|
||||||
namespace simgear {
|
namespace simgear {
|
||||||
|
|
||||||
static NetChannel* channels = 0 ;
|
|
||||||
|
|
||||||
NetChannel::NetChannel ()
|
NetChannel::NetChannel ()
|
||||||
{
|
{
|
||||||
closed = true ;
|
closed = true ;
|
||||||
@@ -51,31 +49,14 @@ NetChannel::NetChannel ()
|
|||||||
accepting = false ;
|
accepting = false ;
|
||||||
write_blocked = false ;
|
write_blocked = false ;
|
||||||
should_delete = false ;
|
should_delete = false ;
|
||||||
|
poller = NULL;
|
||||||
next_channel = channels ;
|
|
||||||
channels = this ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NetChannel::~NetChannel ()
|
NetChannel::~NetChannel ()
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
|
if (poller) {
|
||||||
NetChannel* prev = NULL ;
|
poller->removeChannel(this);
|
||||||
|
|
||||||
for ( NetChannel* ch = channels; ch != NULL;
|
|
||||||
ch = ch -> next_channel )
|
|
||||||
{
|
|
||||||
if (ch == this)
|
|
||||||
{
|
|
||||||
ch = ch -> next_channel ;
|
|
||||||
if ( prev != NULL )
|
|
||||||
prev -> next_channel = ch ;
|
|
||||||
else
|
|
||||||
channels = ch ;
|
|
||||||
next_channel = 0 ;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prev = ch ;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,89 +213,6 @@ NetChannel::handleResolve()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
NetChannel::poll (unsigned int timeout)
|
|
||||||
{
|
|
||||||
if (!channels)
|
|
||||||
return false ;
|
|
||||||
|
|
||||||
enum { MAX_SOCKETS = 256 } ;
|
|
||||||
Socket* reads [ MAX_SOCKETS+1 ] ;
|
|
||||||
Socket* writes [ MAX_SOCKETS+1 ] ;
|
|
||||||
Socket* deletes [ MAX_SOCKETS+1 ] ;
|
|
||||||
int nreads = 0 ;
|
|
||||||
int nwrites = 0 ;
|
|
||||||
int ndeletes = 0 ;
|
|
||||||
int nopen = 0 ;
|
|
||||||
NetChannel* ch;
|
|
||||||
for ( ch = channels; ch != NULL; ch = ch -> next_channel )
|
|
||||||
{
|
|
||||||
if ( ch -> should_delete )
|
|
||||||
{
|
|
||||||
assert(ndeletes<MAX_SOCKETS);
|
|
||||||
deletes[ndeletes++] = ch ;
|
|
||||||
}
|
|
||||||
else if ( ! ch -> closed )
|
|
||||||
{
|
|
||||||
if (ch -> resolving_host )
|
|
||||||
{
|
|
||||||
ch -> handleResolve();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nopen++ ;
|
|
||||||
if (ch -> readable()) {
|
|
||||||
assert(nreads<MAX_SOCKETS);
|
|
||||||
reads[nreads++] = ch ;
|
|
||||||
}
|
|
||||||
if (ch -> writable()) {
|
|
||||||
assert(nwrites<MAX_SOCKETS);
|
|
||||||
writes[nwrites++] = ch ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reads[nreads] = NULL ;
|
|
||||||
writes[nwrites] = NULL ;
|
|
||||||
deletes[ndeletes] = NULL ;
|
|
||||||
|
|
||||||
int i ;
|
|
||||||
for ( i=0; deletes[i]; i++ )
|
|
||||||
{
|
|
||||||
ch = (NetChannel*)deletes[i];
|
|
||||||
delete ch ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nopen)
|
|
||||||
return false ;
|
|
||||||
if (!nreads && !nwrites)
|
|
||||||
return true ; //hmmm- should we shutdown?
|
|
||||||
|
|
||||||
Socket::select (reads, writes, timeout) ;
|
|
||||||
|
|
||||||
for ( i=0; reads[i]; i++ )
|
|
||||||
{
|
|
||||||
ch = (NetChannel*)reads[i];
|
|
||||||
if ( ! ch -> closed )
|
|
||||||
ch -> handleReadEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( i=0; writes[i]; i++ )
|
|
||||||
{
|
|
||||||
ch = (NetChannel*)writes[i];
|
|
||||||
if ( ! ch -> closed )
|
|
||||||
ch -> handleWriteEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true ;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
NetChannel::loop (unsigned int timeout)
|
|
||||||
{
|
|
||||||
while ( poll (timeout) ) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void NetChannel::handleRead (void) {
|
void NetChannel::handleRead (void) {
|
||||||
SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled read");
|
SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled read");
|
||||||
}
|
}
|
||||||
@@ -336,4 +234,112 @@ void NetChannel::handleError (int error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NetChannelPoller::addChannel(NetChannel* channel)
|
||||||
|
{
|
||||||
|
assert(channel);
|
||||||
|
assert(channel->poller == NULL);
|
||||||
|
|
||||||
|
channel->poller = this;
|
||||||
|
channels.push_back(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NetChannelPoller::removeChannel(NetChannel* channel)
|
||||||
|
{
|
||||||
|
assert(channel);
|
||||||
|
assert(channel->poller == this);
|
||||||
|
channel->poller = NULL;
|
||||||
|
|
||||||
|
ChannelList::iterator it = channels.begin();
|
||||||
|
for (; it != channels.end(); ++it) {
|
||||||
|
if (*it == channel) {
|
||||||
|
channels.erase(it);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NetChannelPoller::poll(unsigned int timeout)
|
||||||
|
{
|
||||||
|
if (channels.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { MAX_SOCKETS = 256 } ;
|
||||||
|
Socket* reads [ MAX_SOCKETS+1 ] ;
|
||||||
|
Socket* writes [ MAX_SOCKETS+1 ] ;
|
||||||
|
int nreads = 0 ;
|
||||||
|
int nwrites = 0 ;
|
||||||
|
int nopen = 0 ;
|
||||||
|
NetChannel* ch;
|
||||||
|
|
||||||
|
ChannelList::iterator it = channels.begin();
|
||||||
|
while( it != channels.end() )
|
||||||
|
{
|
||||||
|
NetChannel* ch = *it;
|
||||||
|
if ( ch -> should_delete )
|
||||||
|
{
|
||||||
|
delete ch;
|
||||||
|
it = channels.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
++it; // we've copied the pointer into ch
|
||||||
|
if ( ch->closed ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch -> resolving_host )
|
||||||
|
{
|
||||||
|
ch -> handleResolve();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nopen++ ;
|
||||||
|
if (ch -> readable()) {
|
||||||
|
assert(nreads<MAX_SOCKETS);
|
||||||
|
reads[nreads++] = ch ;
|
||||||
|
}
|
||||||
|
if (ch -> writable()) {
|
||||||
|
assert(nwrites<MAX_SOCKETS);
|
||||||
|
writes[nwrites++] = ch ;
|
||||||
|
}
|
||||||
|
} // of array-filling pass
|
||||||
|
|
||||||
|
reads[nreads] = NULL ;
|
||||||
|
writes[nwrites] = NULL ;
|
||||||
|
|
||||||
|
if (!nopen)
|
||||||
|
return false ;
|
||||||
|
if (!nreads && !nwrites)
|
||||||
|
return true ; //hmmm- should we shutdown?
|
||||||
|
|
||||||
|
Socket::select (reads, writes, timeout) ;
|
||||||
|
|
||||||
|
for ( int i=0; reads[i]; i++ )
|
||||||
|
{
|
||||||
|
ch = (NetChannel*)reads[i];
|
||||||
|
if ( ! ch -> closed )
|
||||||
|
ch -> handleReadEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i=0; writes[i]; i++ )
|
||||||
|
{
|
||||||
|
ch = (NetChannel*)writes[i];
|
||||||
|
if ( ! ch -> closed )
|
||||||
|
ch -> handleWriteEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NetChannelPoller::loop (unsigned int timeout)
|
||||||
|
{
|
||||||
|
while ( poll (timeout) ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // of namespace simgear
|
} // of namespace simgear
|
||||||
|
|||||||
@@ -54,20 +54,23 @@
|
|||||||
#define SG_NET_CHANNEL_H
|
#define SG_NET_CHANNEL_H
|
||||||
|
|
||||||
#include <simgear/io/raw_socket.hxx>
|
#include <simgear/io/raw_socket.hxx>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class NetChannelPoller;
|
||||||
|
|
||||||
class NetChannel : public Socket
|
class NetChannel : public Socket
|
||||||
{
|
{
|
||||||
bool closed, connected, accepting, write_blocked, should_delete, resolving_host ;
|
bool closed, connected, accepting, write_blocked, should_delete, resolving_host ;
|
||||||
NetChannel* next_channel ;
|
|
||||||
std::string host;
|
std::string host;
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
friend bool netPoll (unsigned int timeout);
|
friend class NetChannelPoller;
|
||||||
|
NetChannelPoller* poller;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NetChannel () ;
|
NetChannel () ;
|
||||||
@@ -109,9 +112,19 @@ public:
|
|||||||
virtual void handleWrite (void);
|
virtual void handleWrite (void);
|
||||||
virtual void handleAccept (void);
|
virtual void handleAccept (void);
|
||||||
virtual void handleError (int error);
|
virtual void handleError (int error);
|
||||||
|
|
||||||
static bool poll (unsigned int timeout = 0 ) ;
|
};
|
||||||
static void loop (unsigned int timeout = 0 ) ;
|
|
||||||
|
class NetChannelPoller
|
||||||
|
{
|
||||||
|
typedef std::vector<NetChannel*> ChannelList;
|
||||||
|
ChannelList channels;
|
||||||
|
public:
|
||||||
|
void addChannel(NetChannel* channel);
|
||||||
|
void removeChannel(NetChannel* channel);
|
||||||
|
|
||||||
|
bool poll(unsigned int timeout = 0);
|
||||||
|
void loop(unsigned int timeout = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // of namespace simgear
|
} // of namespace simgear
|
||||||
|
|||||||
Reference in New Issue
Block a user