Пример #1
0
 /// <summary>
 /// Creates a new request. Usually, you don't need to call this.
 /// </summary>
 /// <remarks> Records are created by <see cref="FCGIApplication"/> when a new request has been received.</remarks>
 public Request(int requestId, Stream responseStream, FCGIApplication app = null, bool keepAlive = false)
 {
     this.RequestId = requestId;
     ResponseStream = responseStream;
     ParamStream    = new MemoryStream();
     ManagingApp    = app;
     KeepAlive      = keepAlive;
 }
Пример #2
0
 /// <summary>
 /// Creates a new request. Usually, you don't need to call this.
 /// </summary>
 /// <remarks> Records are created by <see cref="FCGIApplication"/> when a new request has been received.</remarks>
 public Request(int requestId, Stream responseStream, FCGIApplication app = null, string body = "", bool keepAlive = false)
 {
     this.RequestId = requestId;
     ResponseStream = responseStream;
     ParamStream = new MemoryStream();
     ManagingApp = app;
     Body = body;
     KeepAlive = keepAlive;
 }
Пример #3
0
        static void Main(string[] args)
        {
            // Create a new FCGIApplication, will accept FastCGI requests
            var app = new FCGIApplication();

            // Handle requests by responding with a 'Hello World' message
            app.OnRequestReceived += (sender, request) =>
            {
                request.WriteResponseASCII("HTTP/1.1 200 OK\nContent-Type:text/html\n\nHello World!");
                request.Close();
            };

            // Start listening on port 19000
            app.Run(19000);
        }
Пример #4
0
        public void Nginx_SingleRequest()
        {
            AssertNginxInPath();

            var nginx = StartNginx("ServerConfigs/NginxBasicConfig.conf");
            var expectedResult = "Hello World!";

            var app = new FCGIApplication();
            app.OnRequestReceived += (sender, request) =>
            {
                request.WriteResponseASCII("HTTP/1.1 200 OK\nContent-Type:text/html\n\n" + expectedResult);
                request.Close();
            };

            var appThread = new Thread(() => {
                app.Run(19000);
            });

            appThread.Start();

            var result = GetHttp("http://localhost:8182");

            app.Stop();
            StopNginx(nginx);

            Assert.AreEqual(expectedResult, result);
        }
Пример #5
0
        public void Nginx_ManyRequests_Keepalive()
        {
            AssertNginxInPath();

            var nginx = StartNginx("ServerConfigs/NginxKeepalive.conf");
            var expectedResult = "Hello World!";

            var app = new FCGIApplication();
            app.OnRequestReceived += (sender, request) =>
            {
                request.WriteResponseASCII("HTTP/1.1 200 OK\nContent-Type:text/html\n\n" + expectedResult);
                request.Close();
            };

            var appThread = new Thread(() => {
                app.Run(19000);
            });

            appThread.Start();

            Task<string>[] results = new Task<string>[1000];

            for (int i = 0; i < results.Length; i++)
            {
                results[i] = GetHttpAsync("http://localhost:8182");
                Thread.Sleep(1);
            }

            for (int i = 0; i < results.Length; i++)
            {
                results[i].Wait(20000);
                var result = results[i].Result;
                Assert.AreEqual(expectedResult, result);
            }

            StopNginx(nginx);
            app.Stop();
            appThread.Join(500);
        }
Пример #6
0
 public FastCGIBackend(int port)
 {
     _port = port;
     _fcgiApplication = new FCGIApplication();
     _fcgiApplication.OnRequestReceived += FcgiApplicationOnOnRequestReceived;
 }
Пример #7
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);
        }
Пример #8
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);
            }
        }
Пример #9
0
        public void FCGIApp_DisconnectedOperations()
        {
            // Create a new FCGIApplication without opening a connection
            // and make sure everything can be called without any problems
            var app = new FCGIApplication();

            Assert.IsFalse(app.Process());
            Assert.IsFalse(app.ProcessStream(new MemoryStream(), new MemoryStream()));
            Assert.IsFalse(app.ProcessSingleRecord(new MemoryStream(), new MemoryStream()));
            Assert.IsFalse(app.Connected);

            app.StopListening();
        }
Пример #10
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);
        }
Пример #11
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);
        }
Пример #12
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]);
            }
        }