This is an automated email from the ASF dual-hosted git repository.

kgiusti pushed a commit to branch dev-protocol-adaptors-2
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git


The following commit(s) were added to refs/heads/dev-protocol-adaptors-2 by 
this push:
     new aace44e  DISPATCH-1845: cleanup input buffers on server disconnect
aace44e is described below

commit aace44ea34fb3e9b91b619adb81a68913846af9c
Author: Kenneth Giusti <kgiu...@apache.org>
AuthorDate: Wed Nov 18 15:28:58 2020 -0500

    DISPATCH-1845: cleanup input buffers on server disconnect
---
 src/adaptors/http1/http1_codec.c    | 33 ++++++++-----
 tests/system_tests_http1_adaptor.py | 96 +++++++++++++++++++++++++++++++++++++
 2 files changed, 117 insertions(+), 12 deletions(-)

diff --git a/src/adaptors/http1/http1_codec.c b/src/adaptors/http1/http1_codec.c
index b9558b4..7c817a3 100644
--- a/src/adaptors/http1/http1_codec.c
+++ b/src/adaptors/http1/http1_codec.c
@@ -245,20 +245,29 @@ h1_codec_connection_t 
*h1_codec_connection(h1_codec_config_t *config, void *cont
 //
 void h1_codec_connection_closed(h1_codec_connection_t *conn)
 {
-    if (conn) {
-        if (conn->config.type == HTTP1_CONN_SERVER) {
-            struct decoder_t *decoder = &conn->decoder;
-            h1_codec_request_state_t *hrs = decoder->hrs;
-            if (hrs && hrs->request_complete) {
-                decoder_reset(decoder);
-                if (!hrs->response_complete) {
-                    hrs->response_complete = true;
-                    conn->config.rx_done(hrs);
-                }
-                conn->config.request_complete(hrs, false);
-                h1_codec_request_state_free(hrs);
+    if (conn && conn->config.type == HTTP1_CONN_SERVER) {
+
+        // is decoding a response in progress
+        struct decoder_t *decoder = &conn->decoder;
+        h1_codec_request_state_t *hrs = decoder->hrs;
+        if (hrs && hrs->request_complete) {
+            // the corresponding request msg is complete
+            if (!hrs->response_complete) {
+                hrs->response_complete = true;
+                conn->config.rx_done(hrs);
             }
+            conn->config.request_complete(hrs, false);
+            decoder_reset(decoder);
+            h1_codec_request_state_free(hrs);
+            if (hrs == conn->encoder.hrs)
+                encoder_reset(&conn->encoder);
         }
+
+        // since the underlying connection is gone discard all remaining
+        // incoming data
+        decoder_reset(decoder);
+        qd_buffer_list_free_buffers(&conn->decoder.incoming);
+        decoder->read_ptr = NULL_I_PTR;
     }
 }
 
diff --git a/tests/system_tests_http1_adaptor.py 
b/tests/system_tests_http1_adaptor.py
index f630050..4744229 100644
--- a/tests/system_tests_http1_adaptor.py
+++ b/tests/system_tests_http1_adaptor.py
@@ -1290,5 +1290,101 @@ class Http1AdaptorEdge2EdgeTest(TestCase):
         self.assertEqual(1, client.count)
 
 
+class FakeHttpServerBase(object):
+    def __init__(self, host='', port=80):
+        super(FakeHttpServerBase, self).__init__()
+        self.host = host
+        self.port = port
+        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.socket.settimeout(TIMEOUT)
+        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        self.socket.bind((host, port))
+        self.socket.listen(1)
+        self.conn, self.addr = self.socket.accept()
+
+        self.do_connect()
+        while True:
+            data = self.conn.recv(1024)
+            if not data: break
+            self.do_data(data)
+        self.do_closed()
+        self.conn.close()
+        self.socket.close()
+
+    def do_connect(self):
+        pass
+
+    def do_data(self, data):
+        pass
+
+    def do_closed(self):
+        pass
+
+
+class Http1AdaptorBadEndpointsTest(TestCase):
+    """
+    Subject the router to mis-behaving HTTP endpoints.
+    """
+    @classmethod
+    def setUpClass(cls):
+        """
+        Single router configuration with one HTTPListener and one
+        HTTPConnector.
+        """
+        super(Http1AdaptorBadEndpointsTest, cls).setUpClass()
+
+        cls.http_server_port = cls.tester.get_port()
+        cls.http_listener_port = cls.tester.get_port()
+
+        config = [
+            ('router', {'mode': 'standalone',
+                        'id': 'TestBadEnpoints',
+                        'allowUnsettledMulticast': 'yes'}),
+            ('listener', {'role': 'normal',
+                          'port': cls.tester.get_port()}),
+            ('httpConnector', {'port': cls.http_server_port,
+                               'protocolVersion': 'HTTP1',
+                               'address': 'testServer'}),
+            ('httpListener', {'port': cls.http_listener_port,
+                              'protocolVersion': 'HTTP1',
+                              'address': 'testServer'}),
+            ('address', {'prefix': 'closest',   'distribution': 'closest'}),
+            ('address', {'prefix': 'multicast', 'distribution': 'multicast'}),
+        ]
+        config = Qdrouterd.Config(config)
+        cls.INT_A = cls.tester.qdrouterd("TestBadEndpoints", config, wait=True)
+        cls.INT_A.listener = cls.INT_A.addresses[0]
+
+    def test_01_unsolicited_response(self):
+        """
+        Create a server that sends an immediate Request Timeout response
+        without first waiting for a request to arrive.
+        """
+        class UnsolicitedResponse(FakeHttpServerBase):
+            def __init__(self, host, port):
+                self.request_sent = False
+                super(UnsolicitedResponse, self).__init__(host, port)
+
+            def do_connect(self):
+                self.conn.sendall(b'HTTP/1.1 408 Request Timeout\r\n'
+                                  + b'Content-Length: 10\r\n'
+                                  + b'\r\n'
+                                  + b'Bad Server')
+                self.request_sent = True
+
+        count, error = http1_ping(self.http_server_port,
+                                  self.http_listener_port)
+        self.assertIsNone(error)
+        self.assertEqual(1, count)
+
+        server = UnsolicitedResponse('', self.http_server_port)
+        self.assertTrue(server.request_sent)
+
+        count, error = http1_ping(self.http_server_port,
+                                  self.http_listener_port)
+        self.assertIsNone(error)
+        self.assertEqual(1, count)
+
+
 if __name__ == '__main__':
     unittest.main(main_module())


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org
For additional commands, e-mail: commits-h...@qpid.apache.org

Reply via email to