]> git.mxchange.org Git - simgear.git/commitdiff
HTTP engine tweaks for SVN support.
authorJames Turner <zakalawe@mac.com>
Sun, 9 Jun 2013 18:16:46 +0000 (19:16 +0100)
committerJames Turner <zakalawe@mac.com>
Sun, 9 Jun 2013 18:19:02 +0000 (19:19 +0100)
simgear/io/HTTPClient.cxx
simgear/io/HTTPClient.hxx
simgear/io/HTTPRequest.cxx
simgear/io/HTTPRequest.hxx
simgear/io/sg_netChannel.cxx
simgear/io/sg_netChannel.hxx

index 5e32d2cb8a32263e459a675d5bea0575dccfda92..ba68a94a4b0f60947cee8a47f6ff3c949b8e54d7 100644 (file)
@@ -53,6 +53,8 @@ const int GZIP_HEADER_FNAME = 1 << 3;
 const int GZIP_HEADER_COMMENT = 1 << 4;
 const int GZIP_HEADER_CRC = 1 << 1;
   
+typedef std::list<Request_ptr> RequestList;
+  
 class Connection : public NetChat
 {
 public:
@@ -117,13 +119,27 @@ public:
     virtual void 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 
         // socket again
             state =  STATE_CLOSED;
             responseComplete();
         } 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;
         }
       
@@ -186,6 +202,7 @@ public:
       }
      
       Request_ptr r = queuedRequests.front();
+      r->requestStart();
       requestBodyBytesToSend = r->requestBodyLength();
           
       stringstream headerData;
@@ -229,6 +246,7 @@ public:
       
       bool ok = push(headerData.str().c_str());
       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
           // drain down before trying to start any more requests.
           return;
@@ -236,8 +254,7 @@ public:
       
       while (requestBodyBytesToSend > 0) {
         char buf[4096];
-        int len = 4096;
-        r->getBodyData(buf, len);
+        int len = r->getBodyData(buf, 4096);
         if (len > 0) {
           requestBodyBytesToSend -= len;
           if (!bufferSend(buf, len)) {
@@ -245,13 +262,16 @@ public:
             state = STATE_SOCKET_ERROR;
             return;
           }
+      //    SG_LOG(SG_IO, SG_INFO, "sent body:\n" << string(buf, len) << "\n%%%%%%%%%");
         } 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;
         }
       }
       
-      //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
       queuedRequests.pop_front();
       sentRequests.push_back(r);
@@ -308,7 +328,7 @@ public:
         if (result == Z_OK || result == Z_STREAM_END) {
             // nothing to do
         } else {
-          SG_LOG(SG_IO, SG_WARN, "got Zlib error:" << result);
+          SG_LOG(SG_IO, SG_WARN, "HTTP: got Zlib error:" << result);
           return;
         }
             
@@ -607,7 +627,7 @@ private:
     
     void responseComplete()
     {
-      //std::cout << "responseComplete:" << activeRequest->url() << std::endl;
+     //   SG_LOG(SG_IO, SG_INFO, "*** responseComplete:" << activeRequest->url());
         activeRequest->responseComplete();
         client->requestFinished(this);
       
@@ -666,8 +686,8 @@ private:
     unsigned char* zlibOutputBuffer;
     bool contentGZip, contentDeflate;
   
-    std::list<Request_ptr> queuedRequests;
-    std::list<Request_ptr> sentRequests;
+    RequestList queuedRequests;
+    RequestList sentRequests;
 };
 
 Client::Client()
@@ -677,7 +697,7 @@ Client::Client()
 
 void Client::update(int waitTimeout)
 {
-    NetChannel::poll(waitTimeout);
+    _poller.poll(waitTimeout);
         
     ConnectionDict::iterator it = _connections.begin();
     for (; it != _connections.end(); ) {
@@ -715,6 +735,7 @@ void Client::makeRequest(const Request_ptr& r)
     if (_connections.find(connectionId) == _connections.end()) {
         Connection* con = new Connection(this);
         con->setServer(host, port);
+        _poller.addChannel(con);
         _connections[connectionId] = con;
     }
     
index f200b9f44c9f11aed2c96734141018f269078776..f1bdf0d63efd18997a827c2e30523b602acb6a9c 100644 (file)
@@ -4,6 +4,7 @@
 #include <map>
 
 #include <simgear/io/HTTPRequest.hxx>
+#include <simgear/io/sg_netChannel.hxx>
 
 namespace simgear
 {
@@ -49,6 +50,7 @@ private:
     std::string _proxy;
     int _proxyPort;
     std::string _proxyAuth;
+    NetChannelPoller _poller;
     
 // connections by host
     typedef std::map<std::string, Connection*> ConnectionDict;
index ce706957b6f45469b4213b9f2c6244f462830fc9..23018d9c4a8a0500dafec404f6f2245e0da0894e 100644 (file)
@@ -48,6 +48,11 @@ 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
@@ -232,10 +237,9 @@ std::string Request::requestBodyType() const
     return "text/plain";
 }
   
-void Request::getBodyData(char*, int& count) const
+int Request::getBodyData(char*, int maxCount) const
 {
-  count = 0;
-  return;
+  return 0;
 }
 
 } // of namespace HTTP
index 0c6e2685c6f1df956d95d1bf2388600b27c5ea8c..c3fe525b63698e12d8f92767d913f0edf454c5c5 100644 (file)
@@ -52,10 +52,10 @@ public:
     
     /**
      * 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. 
      */
-    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
@@ -86,6 +86,7 @@ public:
 protected:
     Request(const std::string& url, const std::string method = "GET");
 
+    virtual void requestStart();
     virtual void responseStart(const std::string& r);
     virtual void responseHeader(const std::string& key, const std::string& value);
     virtual void responseHeadersComplete();
index 817650ac482b04c5da9b835d3809e15530f65e8d..be8299f7658e735ed5c69f86df7679953379b9b5 100644 (file)
@@ -41,8 +41,6 @@
 
 namespace simgear  {
 
-static NetChannel* channels = 0 ;
-
 NetChannel::NetChannel ()
 {
   closed = true ;
@@ -51,31 +49,14 @@ NetChannel::NetChannel ()
   accepting = false ;
   write_blocked = false ;
   should_delete = false ;
-
-  next_channel = channels ;
-  channels = this ;
+  poller = NULL;
 }
   
 NetChannel::~NetChannel ()
 {
   close();
-
-  NetChannel* prev = NULL ;
-
-  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 ;
+  if (poller) {
+      poller->removeChannel(this);
   }
 }
   
@@ -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) {
   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
index 6cadc1f308cc148219233a296e8120d985b37eef..bf28a730e2da55b0c172cb72bb006036e4962877 100644 (file)
 #define SG_NET_CHANNEL_H
 
 #include <simgear/io/raw_socket.hxx>
+
 #include <string>
+#include <vector>
 
 namespace simgear
 {
 
+class NetChannelPoller;
+    
 class NetChannel : public Socket
 {
   bool closed, connected, accepting, write_blocked, should_delete, resolving_host ;
-  NetChannel* next_channel ;
   std::string host;
   int port;
   
-  friend bool netPoll (unsigned int timeout);
-
+    friend class NetChannelPoller;
+    NetChannelPoller* poller;
 public:
 
   NetChannel () ;
@@ -109,9 +112,19 @@ public:
   virtual void handleWrite (void);
   virtual void handleAccept (void);
   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