<div dir="ltr"><div dir="ltr">Hi Eliezer!<br><br><br>> What version of Squid are you using?<br><br>I have reproduced the leak on squid versions: 4.8, 5.0.4, git master 38da9c24e.<br>In production deployment we use squid 4.x<br><br><br>> Can you provide a setup example for re-production?<br><br>Blow are the steps to reproduce the problem on the CentOS 7 system.<br><br>Test icap server is based on Example3 from <a href="https://github.com/Peoplecantfly/icapserver/blob/master/TUTORIAL.md">https://github.com/Peoplecantfly/icapserver/blob/master/TUTORIAL.md</a><br>The only difference is that implementations of example_REQMOD and example_RESPMOD methods are swapped.<br><br>1. Put the following code to file server.py:<br># vvvvvvvvvvvvvvvv<br># vvv cut here vvv<br># vvvvvvvvvvvvvvvv<br>import time<br>import threading<br><br>from icapserver import *<br><br>class ExampleICAPHandler(BaseICAPRequestHandler):<br><br>    def example_OPTIONS(self):<br>        self.set_icap_response(200)<br>        self.set_icap_header('Methods', 'RESPMOD, REQMOD')<br>        self.set_icap_header('Service',<br>            'ICAP Server' + ' ' + self._server_version)<br>        self.set_icap_header('Options-TTL', '3600')<br>        self.set_icap_header('Preview', '0')<br>        self.send_headers(False)<br><br>    def example_RESPMOD(self):<br>        self.no_adaptation_required()<br><br>    def example_REQMOD(self):<br>        if self.has_body:<br>            while True:<br>                if self.read_chunk() == '':<br>                    break<br>        self.set_icap_response(200)<br>        self.set_enc_status('HTTP/1.1 451 Unavailable For Legal Reasons')<br>        self.send_headers(False)<br><br>class ExampleICAPServer():<br><br>    def __init__(self, addr='', port=13440):<br>        self.addr = addr<br>        self.port = port<br><br>    def start(self):<br>        self.server = ICAPServer((self.addr, self.port), ExampleICAPHandler)<br>        self.thread = threading.Thread(target=self.server.serve_forever)<br>        self.thread.start()<br>        return True<br><br>    def stop(self):<br>        self.server.shutdown()<br>        self.server.server_close()<br>        self.thread.join(2)<br>        return True<br><br><br>try:<br>    server = ExampleICAPServer()<br>    server.start()<br>    print 'Use Control-C to exit'<br>    while True:<br>        time.sleep(1)<br>except KeyboardInterrupt:<br>    server.stop()<br>    print "Finished"<br># ^^^^^^^^^^^^^^^^<br># ^^^ cut here ^^^<br># ^^^^^^^^^^^^^^^^<br><br>2. Prepare environment for test icap server:<br>        # yum install -y python2-virtualenv<br>   # virtualenv-2 icapserver<br>     # source icapserver/bin/activate<br>      # pip install icapserver<br><br>3. Run the test icap server:<br>      # source icapserver/bin/activate<br>      # python server.py &<br><br>4. Install squid version 4 or above (built with --enable-icap-client).<br><br>5. Rewrite /etc/squid/squid.conf:<br>       cache deny all<br>        cache_mem 0<br>   shutdown_lifetime 5 seconds<br>   http_port 3128<br>        acl localnet src 127.0.0.1<br>    http_access deny !localnet<br>    http_access allow all<br> icap_enable on<br>        icap_service example_req reqmod_precache icap://<a href="http://127.0.0.1:13440/example">127.0.0.1:13440/example</a><br>    adaptation_access example_req allow all<br>       icap_service_failure_limit -1<br><br>6. Apply squid configuration changes:<br>        # systemctl restart squid<br><br>7. Initiate http request:<br>        # curl -q -x <a href="http://127.0.0.1:3128">http://127.0.0.1:3128</a> <a href="https://example.com">https://example.com</a><br><br>8. Output of curl should look like:<br>       curl: (56) Received HTTP code 451 from proxy after CONNECT<br><br>9. Leaked descriptor is in a CLOSE-WAIT state:<br>  # ss -natpo | grep CLOSE-WAIT<br><br><br>> If you can supply couple(2-3 or more) ICAP connections pcap I can try to see what happens in the connection level.<br><br>Pcap file with 3 connections attached.<br><br><br>> >From my experience there is much differences between holding the ICAP session open or closed after once request.<br>> The reason for this is that like HTTP/1.0 ICAP is a “blocking”(don’t remember the exact word, Alex might remember).<br>> There for if the proxy has 800 requests per seconds it’s better for the setup to open new connection per request to match the load.<br>> It will const memory and CPU in the short term but in the long term the clients requests will bock less and..<br>> It will probably consume less then the ICAP connections memory leak.<br><br>Leak happens both with and without the load.<br>Http client connections do leak, but ICAP connections do not.<br></div><div dir="ltr"><br></div><div dir="ltr"><br>> There for if the proxy has 800 requests per seconds it’s better for the setup to open new connection per request to match the load.<br><br>Production ICAP server reports "Max-Connections: 5000" in response to ICAP OPTIONS request.<br>Is in sufficient? If not, what should ICAP server do, and what should be done squid (and in squid.conf), to achieve the "open new connection per request" behaviour?<br><br><br>Thanks!<br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Dec 11, 2020 at 12:11 AM Eliezer Croitor <<a href="mailto:ngtech1ltd@gmail.com">ngtech1ltd@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;" lang="EN-US"><div class="gmail-m_-5196980829575998466WordSection1"><p class="MsoNormal">Hey Alexey,<u></u><u></u></p><p class="MsoNormal"><u></u> <u></u></p><p class="MsoNormal">What version of Squid are you using?<u></u><u></u></p><p class="MsoNormal">Can you provide a setup example for re-production?<u></u><u></u></p><p class="MsoNormal">I can write the relevant ICAP service however I am missing pcap file to understand the ICAP sessions.<u></u><u></u></p><p class="MsoNormal">If you can supply couple(2-3 or more) ICAP connections pcap I can try to see what happens in the connection level.<u></u><u></u></p><p class="MsoNormal"><u></u> <u></u></p><p class="MsoNormal">From my experience there is much differences between holding the ICAP session open or closed after once request.<u></u><u></u></p><p class="MsoNormal">The reason for this is that like HTTP/1.0 ICAP is a “blocking”(don’t remember the exact word, Alex might remember).<u></u><u></u></p><p class="MsoNormal">There for if the proxy has 800 requests per seconds it’s better for the setup to open new connection per request to match the load.<u></u><u></u></p><p class="MsoNormal">It will const memory and CPU in the short term but in the long term the clients requests will bock less and..<u></u><u></u></p><p class="MsoNormal">It will probably consume less then the ICAP connections memory leak.<u></u><u></u></p><p class="MsoNormal"><u></u> <u></u></p><p class="MsoNormal">Waiting,<u></u><u></u></p><p class="MsoNormal">Eliezer<u></u><u></u></p><p class="MsoNormal"><u></u> <u></u></p><p class="MsoNormal">----<u></u><u></u></p><p class="MsoNormal">Eliezer Croitoru<u></u><u></u></p><p class="MsoNormal">Tech Support<u></u><u></u></p><p class="MsoNormal">Mobile: +972-5-28704261<u></u><u></u></p><p class="MsoNormal">Email: <a href="mailto:ngtech1ltd@gmail.com" target="_blank">ngtech1ltd@gmail.com</a><u></u><u></u></p><p class="MsoNormal"><u></u> <u></u></p><div style="border-color:rgb(225,225,225) currentcolor currentcolor;border-style:solid none none;border-width:1pt medium medium;padding:3pt 0in 0in"><p class="MsoNormal"><b>From:</b> squid-dev <<a href="mailto:squid-dev-bounces@lists.squid-cache.org" target="_blank">squid-dev-bounces@lists.squid-cache.org</a>> <b>On Behalf Of </b>Alexey Sergin<br><b>Sent:</b> Thursday, December 10, 2020 10:33 PM<br><b>To:</b> <a href="mailto:squid-dev@lists.squid-cache.org" target="_blank">squid-dev@lists.squid-cache.org</a><br><b>Subject:</b> [squid-dev] File descriptor leak at ICAP reqmod rewrites of CONNECT requests<u></u><u></u></p></div><p class="MsoNormal"><u></u> <u></u></p><div><p class="MsoNormal">Hello Squid Developers.<br><br>I'm a software engineer.<br><br>My team uses Squid with an ICAP server. We have noticed that Squid leaks file descriptor and memory when (reqmod) ICAP server replies with http "403 Forbidden" on http CONNECT request.<br><br>Here is a step-by-step description of the problematic scenario:<br>- An http client connects to Squid and sends CONNECT request (for example, "curl -q -x <a href="http://127.0.0.1:3128" target="_blank">http://127.0.0.1:3128</a> <a href="https://example.com" target="_blank">https://example.com</a>");<br>- Squid sends CONNECT request to the (reqmod) ICAP server;<br>- ICAP server sends back a "403 Forbidden" http response;<br>- Squid sends "403 Forbidden" http response to the http client (in the example above, curl reports "Received HTTP code 403 from proxy after CONNECT");<br>- Squid writes to cache.log a message like "kick abandoning <....>";<br>- Squid does not close the file descriptor used for http client connection.<br><br>Those file descriptors and associated memory do pile up. For instance, after 200.000 forbidden requests squid (built from git master) has ~200.000 open descriptors and consumes ~4 Gb RAM. On production deployment with 1000+ users it takes less than a day for Squid to eat out all available RAM.<br><br>It seems that the same problem was previously reported here: <a href="http://www.squid-cache.org/mail-archive/squid-users/201301/0096.html" target="_blank">http://www.squid-cache.org/mail-archive/squid-users/201301/0096.html</a><br><br>Message "kick abandoning <....>" comes from ConnStateData::kick() in client_side.cc. Closing clientConnection right after "debugs(<....>abandoning<....>)" fixes the leak.<br><br>Is it ok to always close() clientConnection when "abandoning" thing happens? Are there any known scenarios where this close() would be inappropriate?<br><br>Could you please give me some advice on a better/proper fix, if close() at "abandoning" time is wrong?<u></u><u></u></p></div></div></div></blockquote></div></div>