Exemple #1
0
        public void FCGIApp_LargeRequest()
        {
            var app = new FCGIApplication();

            var expectedLength = 128317;

            app.OnRequestReceived += (sender, request) =>
            {
                var responseBody = new byte[expectedLength];
                request.WriteResponse(responseBody);
                request.Close();
            };

            // Connect to the app, impoersonating a webserver
            var inputStream = new MemoryStream();
            inputStream.Capacity = 4096;
            var outputStream = new MemoryStream();
            outputStream.Capacity = 4096 + expectedLength;

            // Send a request to it and make sure it responds to requests.

            var requestId = 5172;

            var beginRequestContent = new byte[]
            {
                0x00, // role byte 1
                (byte)Constants.FCGI_RESPONDER, // role byte 2
                Constants.FCGI_KEEP_CONN, // flags
                0x00, 0x00, 0x00, 0x00, 0x00 // reserved bytes
            };

            var beginRequest = new Record
            {
                Type = Record.RecordType.BeginRequest,
                RequestId = requestId,
                ContentLength = beginRequestContent.Length,
                ContentData = beginRequestContent
            };

            beginRequest.WriteToStream(inputStream);

            // Empty stdin indicates that the request is fully transmitted
            var stdinRequest = new Record
            {
                Type = Record.RecordType.Stdin,
                RequestId = requestId,
                ContentLength = 0,
                ContentData = new byte[0]
            };

            stdinRequest.WriteToStream(inputStream);

            inputStream.Seek(0, SeekOrigin.Begin);

            app.ProcessStream(inputStream, outputStream);

            outputStream.Seek(0, SeekOrigin.Begin);

            // Now the app should respond with a large response, splitted into 64KB stdout records

            var response = Record.ReadRecord(outputStream);

            Assert.AreEqual(65535, response.ContentLength);

            var totalLength = 0;

            while (response.ContentLength > 0)
            {
                Assert.AreEqual(Record.RecordType.Stdout, response.Type);
                Assert.AreEqual(requestId, response.RequestId);

                totalLength += response.ContentLength;

                response = Record.ReadRecord(outputStream);
            }

            Assert.AreEqual(expectedLength, totalLength);

            // Then, an empty stdout record should indicate the end of the response body
            Assert.AreEqual(Record.RecordType.Stdout, response.Type);
            Assert.AreEqual(requestId, response.RequestId);
            Assert.AreEqual(0, response.ContentLength);

            // And finally, a EndRequest record should close the request.
            response = Record.ReadRecord(outputStream);
            Assert.AreEqual(Record.RecordType.EndRequest, response.Type);
            Assert.AreEqual(requestId, response.RequestId);
        }
Exemple #2
0
        public void FCGIApp_Connections()
        {
            // Create an app that actually listens on the loopback interface
            var app = new FCGIApplication();
            app.Timeout = 100;

            try
            {
                app.Listen(new IPEndPoint(IPAddress.Loopback, 21511));
                Request receivedRequest = null;
                app.OnRequestReceived += (sender, request) => {
                    receivedRequest = request;
                    request.WriteResponseASCII("Hello Server!");
                    request.Close();
                };

                app.Process();

                var serverSocket = new Socket(SocketType.Stream, ProtocolType.Tcp);
                var asyncResult = serverSocket.BeginConnect(new IPEndPoint(IPAddress.Loopback, 21511), (r) => { }, null);

                while(!asyncResult.IsCompleted)
                    app.Process();

                serverSocket.EndConnect(asyncResult);

                var serverStream = new NetworkStream(serverSocket);

                // Now send a request to the app and make sure it is received correctly.

                var requestId = 5172;

                var beginRequestContent = new byte[]
                {
                    0x00, // role byte 1
                    (byte)Constants.FCGI_RESPONDER, // role byte 2
                    0x00, // flags
                    0x00, 0x00, 0x00, 0x00, 0x00 // reserved bytes
                };

                var beginRequest = new Record
                {
                    Type = Record.RecordType.BeginRequest,
                    RequestId = requestId,
                    ContentLength = beginRequestContent.Length,
                    ContentData = beginRequestContent
                };

                beginRequest.WriteToStream(serverStream);

                var stdinRequest = new Record
                {
                    Type = Record.RecordType.Stdin,
                    RequestId = requestId,
                    ContentLength = 0,
                    ContentData = new byte[0]
                };

                stdinRequest.WriteToStream(serverStream);

                serverStream.Flush();

                // Make the app digest everything
                while(receivedRequest == null)
                {
                    app.Process();
                }
                    

                // Do we have the correct request?
                Assert.AreEqual(requestId, receivedRequest.RequestId);

                // And did the response work?
                var responseRecord = Record.ReadRecord(serverStream);
                Assert.AreEqual(Record.RecordType.Stdout, responseRecord.Type);
                Assert.AreEqual("Hello Server!", Encoding.ASCII.GetString(responseRecord.ContentData));

                // Change the timeout while still connected
                app.Timeout = 100;

                app.StopListening();
                Assert.IsFalse(app.Connected);

            }
            // If the port is already in use, an execution can be thrown.
            // Report the test as inconclusive then.
            catch(SocketException e)
            {
                Assert.Inconclusive("SocketException: " + e.Message);
            }
        }
Exemple #3
0
        public void FCGIApp_GetValues()
        {
            var app = new FCGIApplication();

            // Connect to the app, impoersonating a webserver
            var inputStream = new MemoryStream();
            inputStream.Capacity = 4096;
            var outputStream = new MemoryStream();
            outputStream.Capacity = 4096;

            // Send a GetValues record
            var getValues = new Record
            {
                Type = Record.RecordType.GetValues,
                RequestId = 0,
                ContentLength = 0,
            };

            getValues.WriteToStream(inputStream);
            inputStream.Seek(0, SeekOrigin.Begin);
            app.ProcessStream(inputStream, outputStream);
            outputStream.Seek(0, SeekOrigin.Begin);

            // Now the app should respond with a GetValuesResult
            var response = Record.ReadRecord(outputStream);

            Assert.AreEqual(Record.RecordType.GetValuesResult, response.Type);
            Assert.AreEqual(0, response.RequestId);

            var responseValues = response.GetNameValuePairs();

            // Response should include these three values
            Assert.Contains("FCGI_MAX_CONNS", responseValues.Keys);
            Assert.Contains("FCGI_MAX_REQS", responseValues.Keys);
            Assert.Contains("FCGI_MPXS_CONNS", responseValues.Keys);

            // No other values should be included
            Assert.AreEqual(3, responseValues.Count);

            int responseMaxConns, responseMaxReqs, responseMultiplexing;

            // Make sure the returned values look plausible
            var sMaxConns = Encoding.ASCII.GetString(responseValues["FCGI_MAX_CONNS"]);
            var sMaxReqs = Encoding.ASCII.GetString(responseValues["FCGI_MAX_REQS"]);
            var sMultiplexing = Encoding.ASCII.GetString(responseValues["FCGI_MPXS_CONNS"]);

            Assert.IsTrue(int.TryParse(sMaxConns, out responseMaxConns));
            Assert.IsTrue(int.TryParse(sMaxReqs, out responseMaxReqs));
            Assert.IsTrue(int.TryParse(sMultiplexing, out responseMultiplexing));

            Assert.GreaterOrEqual(responseMaxConns, 0);
            Assert.GreaterOrEqual(responseMaxReqs, 0);
            Assert.GreaterOrEqual(responseMultiplexing, 0);
            Assert.LessOrEqual(responseMultiplexing, 1);
        }
Exemple #4
0
        public void FCGIApp_Request()
        {
            var app = new FCGIApplication();

            app.OnRequestReceived += (sender, request) =>
            {
                request.WriteResponseASCII("Hello!");
                request.Close();
            };

            // Connect to the app, impoersonating a webserver
            var streamServerToApp = new MemoryStream();
            streamServerToApp.Capacity = 4096;
            var streamAppToServer = new MemoryStream();
            streamAppToServer.Capacity = 4096;

            // Send a request to it and make sure it responds to requests.

            var requestId = 5172;

            var beginRequestContent = new byte[]
            {
                0x00, // role byte 1
                (byte)Constants.FCGI_RESPONDER, // role byte 2
                Constants.FCGI_KEEP_CONN, // flags
                0x00, 0x00, 0x00, 0x00, 0x00 // reserved bytes
            };

            var beginRequest = new Record
            {
                Type = Record.RecordType.BeginRequest,
                RequestId = requestId,
                ContentLength = beginRequestContent.Length,
                ContentData = beginRequestContent
            };

            beginRequest.WriteToStream(streamServerToApp);

            // Empty stdin indicates that the request is fully transmitted
            var stdinRequest = new Record
            {
                Type = Record.RecordType.Stdin,
                RequestId = requestId,
                ContentLength = 0,
                ContentData = new byte[0]
            };

            stdinRequest.WriteToStream(streamServerToApp);

            streamServerToApp.Seek(0, SeekOrigin.Begin);

            app.ProcessStream(streamServerToApp, streamAppToServer);;

            streamAppToServer.Seek(0, SeekOrigin.Begin);

            // Now the app should respond with 'Hello!'

            var response = Record.ReadRecord(streamAppToServer);

            var expectedBytes = Encoding.ASCII.GetBytes("Hello!");

            Assert.AreEqual(Record.RecordType.Stdout, response.Type);
            Assert.AreEqual(requestId, response.RequestId);
            Assert.AreEqual(expectedBytes.Length, response.ContentLength);
            Assert.AreEqual(expectedBytes, response.ContentData);

            // Then, an empty stdout record should indicate the end of the response body
            response = Record.ReadRecord(streamAppToServer);
            Assert.AreEqual(Record.RecordType.Stdout, response.Type);
            Assert.AreEqual(requestId, response.RequestId);
            Assert.AreEqual(0, response.ContentLength);

            // And finally, a EndRequest record should close the request.
            response = Record.ReadRecord(streamAppToServer);
            Assert.AreEqual(Record.RecordType.EndRequest, response.Type);
            Assert.AreEqual(requestId, response.RequestId);
        }
Exemple #5
0
        public void FCGIApp_Params()
        {
            var app = new FCGIApplication();

            Request receivedRequest = null;

            app.OnRequestReceived += (sender, request) =>
            {
                receivedRequest = request;
            };

            // Connect to the app, impoersonating a webserver
            var streamServerToApp = new MemoryStream();
            streamServerToApp.Capacity = 4096;
            var streamAppToServer = new MemoryStream();
            streamAppToServer.Capacity = 4096;

            // Send a request to it and make sure it responds to requests.

            var requestId = 5172;

            var beginRequestContent = new byte[]
            {
                            0x00, // role byte 1
                            (byte)Constants.FCGI_RESPONDER, // role byte 2
                            Constants.FCGI_KEEP_CONN, // flags
                            0x00, 0x00, 0x00, 0x00, 0x00 // reserved bytes
            };

            var beginRequest = new Record
            {
                Type = Record.RecordType.BeginRequest,
                RequestId = requestId,
                ContentLength = beginRequestContent.Length,
                ContentData = beginRequestContent
            };

            beginRequest.WriteToStream(streamServerToApp);

            var paramDict = new Dictionary<string, byte[]>
            {
                {"SOME_NAME", Encoding.UTF8.GetBytes("SOME_KEY") },
                {"SOME_OTHER_NAME", Encoding.UTF8.GetBytes("SOME_KEY") },
                //{"ONE_MEGABYTE_OF_ZEROS", new byte[1024 * 1024] },
                {"EMPTY_VALUE", new byte[0] },
                {"1", Encoding.UTF8.GetBytes("☕☳üß - \n \r\n .,;(){}%$!") },
                {"2", Encoding.UTF8.GetBytes("") },
                {"3", Encoding.UTF8.GetBytes(" ") },
                {"4", Encoding.UTF8.GetBytes("\n") },
                {"5", Encoding.UTF8.GetBytes(";") },
            };

            var paramsRequest = new Record
            {
                Type = Record.RecordType.Params,
                RequestId = requestId
            };

            paramsRequest.SetNameValuePairs(paramDict);
            paramsRequest.WriteToStream(streamServerToApp);

            // Empty params record indicates that the parameters are fully transmitted
            var paramsCloseRequest = new Record
            {
                Type = Record.RecordType.Params,
                RequestId = requestId,
                ContentLength = 0,
                ContentData = new byte[0]
            };
            paramsCloseRequest.WriteToStream(streamServerToApp);


            // Empty stdin indicates that the request is fully transmitted
            var stdinRequest = new Record
            {
                Type = Record.RecordType.Stdin,
                RequestId = requestId,
                ContentLength = 0,
                ContentData = new byte[0]
            };

            stdinRequest.WriteToStream(streamServerToApp);

            streamServerToApp.Seek(0, SeekOrigin.Begin);

            app.ProcessStream(streamServerToApp, streamAppToServer);

            // Now the app should have received the request. Make sure the Parameters correctly decoded
            Assert.IsNotNull(receivedRequest);
            Assert.AreEqual(paramDict.Count, receivedRequest.Parameters.Count);

            foreach (var entry in paramDict)
            {
                Assert.Contains(entry.Key, receivedRequest.Parameters.Keys);
                Assert.AreEqual(entry.Value, receivedRequest.Parameters[entry.Key]);
            }
        }
Exemple #6
0
        public void Records_BrokenRecords()
        {
            // Create some broken records and make sure the right things happen
            Record result;

            // An empty stream should simply result in a null record
            var emptyStream = new MemoryStream(new byte[0]);
            result = Record.ReadRecord(emptyStream);
            Assert.IsNull(result);

            // A wrong version number bytes should throw a InvalidDataException
            var wrongVersion = new MemoryStream(new byte[1] { Constants.FCGI_VERSION_1 + 1 });
            Assert.Throws(typeof(InvalidDataException), () => { Record.ReadRecord(wrongVersion); });


            // So should a bunch of zeroes
            var zeroes = new MemoryStream(new byte[4] { 0, 0, 0, 0 });
            Assert.Throws(typeof(InvalidDataException), () => { Record.ReadRecord(zeroes); });

            // And a correct version number with an incomplete header
            var incomplete = new MemoryStream(new byte[4] { Constants.FCGI_VERSION_1, 0, 0, 0 });
            Assert.Throws(typeof(InvalidDataException), () => { Record.ReadRecord(incomplete); });


            // Writing should fail for content above 64KB
            var tooLong = new Record
            {
                Version = Constants.FCGI_VERSION_1,
                Type = Record.RecordType.Stderr,
                RequestId = 123,
                ContentLength = 127000,
                ContentData = new byte[127000]
            };
            Assert.Throws(typeof(InvalidOperationException), () => { tooLong.WriteToStream(new MemoryStream()); });
        }