Https memory leak on Windows CE

+1 vote
asked Dec 13, 2017 by yuretz (180 points)

We have a problem with the latest realease of Rebex Https library (R6.1), because it seems to leak memory. To reproduce the issue I used the following program.

namespace cehttpstest
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Net;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading;
    using Rebex;
    using Rebex.Net;

    class Program
    {
        static void Main(string[] args)
        {

            HttpRequestCreator creator = new HttpRequestCreator();

            creator.Settings.SslAllowedSuites = TlsCipherSuite.RSA_WITH_AES_128_CBC_SHA256 |
                                                TlsCipherSuite.RSA_WITH_AES_128_CBC_SHA;
            creator.Settings.SslAcceptAllCertificates = true;
            creator.Register();

            while (true)
            {
                MemoryStatus status;
                SendRequest(null);
                GlobalMemoryStatusCE(out status);
                Console.WriteLine("{0}", status);
                Thread.Sleep(10000);
            }
        }




        private static void SendRequest(object state)
        {

            Console.Write("Sending request... ");
            HttpRequest request = (HttpRequest)WebRequest.Create("https://httpbin.org/post");
            try
            {

                byte[] data = Encoding.UTF8.GetBytes(string.Format(@"
                    {{
                        ""ticks"":{0},
                        ""foo"":""bar""
                    }}", Environment.TickCount));
                request.Method = "POST";
                request.Accept = "*/*";
                request.ContentType = "application/json";
                request.ContentLength = data.Length;

                Stream requestStream = request.GetRequestStream();
                requestStream.Write(data, 0, data.Length);
                requestStream.Close();

                using (var response = (HttpResponse)request.GetResponse())
                {

                    Console.WriteLine("{0} (Length {1})", response.StatusCode, GetResponseString(response).Length);

                }
            }
            catch (SystemException ex)
            {
                request.Abort();
                Console.WriteLine("{0}: {1}", ex.GetType().Name, ex.Message);
            }

        }

        private static string GetResponseString(HttpResponse response)
        {
            StringBuilder sb = new StringBuilder(4096);

            byte[] buf = new byte[8192];

            using (var stream = response.GetResponseStream())
            {
                int count;

                do
                {
                    count = stream.Read(buf, 0, buf.Length);

                    if (count != 0)
                    {
                        // look for a UTF8 header
                        string result;
                        if ((buf[0] == 0xEF) && (buf[1] == 0xBB) && (buf[2] == 0xBF))
                        {
                            result = Encoding.UTF8.GetString(buf, 3, count - 3);
                        }
                        else
                        {
                            result = Encoding.UTF8.GetString(buf, 0, count);
                        }
                        sb.Append(result);
                    }
                } while (count > 0);

                response.Close();
            }

            return sb.ToString();
        }

        [Serializable]
        private struct MemoryStatus
        {
            internal uint dwLength;
            public int MemoryLoad;
            public int TotalPhysical;
            public int AvailablePhysical;
            public int TotalPageFile;
            public int AvailablePageFile;
            public int TotalVirtual;
            public int AvailableVirtual;

            public override string ToString()
            {
                return string.Format
                    ("Load: {0,3} TotalPhys: {1,10} AvailPhys: {2,10} TotalVirt: {3,10} AvailVirt: {4,10}",
                    MemoryLoad, TotalPhysical, AvailablePhysical, TotalVirtual, AvailableVirtual);
            }
        }

        [DllImport("coredll", EntryPoint = "GlobalMemoryStatus", SetLastError = false)]
        private static extern void GlobalMemoryStatusCE(out MemoryStatus msce);
    }
}

On my device (ARM9 with 64MB, running Windows CE 6.0 with .NET CF3.5) it eats up all the available free memory in around 40 minutes.
Downgrading the library to R5 seems to solve the issue.

Could you please help us with this problem?
Thanks in advance!

2 Answers

0 votes
answered Dec 13, 2017 by Lukas Pokorny (94,310 points)
edited Jan 15 by Lukas Pokorny

Many thanks for your excellent error report! We were able to reproduce this issue and will start looking into it immediately. I will keep you updated.

Update: This has been fixed in Rebex HTTPS 2017 R6.2.

commented Dec 14, 2017 by yuretz (180 points)
Nice, thank you!
commented Dec 15, 2017 by Lukas Pokorny (94,310 points)
I have sent a link to the latest hotfix to your e-mail address. Please give it a try (with HttpSessionCacheEnabled = true) and let us know whether it solves the issue.
commented Dec 19, 2017 by yuretz (180 points)
Thank you for the hotfix build. I've tested it both with my example code and with the actual application and it seems to solve the issue! Thanks a lot!
0 votes
answered Dec 14, 2017 by stepantalalayev (3,940 points)

Hello,

could you try to disable HTTP session cache? It could be done the following way:

creator.Settings.HttpSessionCacheEnabled = false;

Please provide us feedback if it works for you. It will help us in further processing of this issue.

commented Dec 15, 2017 by yuretz (180 points)
Hello,
Thank you. Turning off session cache seems to help. I've left the device running overnight and the memory usage remains stable. But I was wondering how will the performance of the system be affected when it's running with the session cache turned off? What does this option actually do?
commented Dec 15, 2017 by Lukas Pokorny (94,310 points)
Hello, thanks for confirming this! This was not actually supposed to be a solution - we just needed to make sure we have in fact identified the issue.
The option disables caching and reusing of HTTP sessions (those with Keep-Alive enabled), which means each request has to establish a new connection. This is slower than reusing existing HTTP sessions for further requests.
commented Dec 19, 2017 by Lukas Pokorny (94,310 points)
Thanks for testing! We will publish a new release shortly that solves this issue. And once again, thanks for bringing this to our attention.
commented Jan 8 by Ajay (150 points)
Hi Lukas,

Does "Rebex HTTPS for .NET - Release 2017 R6.2 released 2017-12-22" included fix for this issue?
...