Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling self.cont() in RESPMOD handler causes Broken Piper error #24

Open
ichramm opened this issue May 8, 2017 · 3 comments
Open

Calling self.cont() in RESPMOD handler causes Broken Piper error #24

ichramm opened this issue May 8, 2017 · 3 comments

Comments

@ichramm
Copy link

ichramm commented May 8, 2017

I am testing the icap server using the example respmod_copy.py and Squid 3.5.25.

The only change I made was to put a call to self.cont() before copying the response body into the temporary file: like this:

    def example_RESPMOD(self):
        self.set_icap_response(200)

        self.set_enc_status(b' '.join(self.enc_res_status))
        for h in self.enc_res_headers:
            for v in self.enc_res_headers[h]:
                self.set_enc_header(h, v)

        if not self.has_body:
            self.send_headers(False)
            return

        self.cont() ### <-- Send 100 Continue ###

        # Read everything from the response to a temporary file
        # This file can be placed onto a tmpfs filesystem for more performance
        with tempfile.NamedTemporaryFile(prefix='pyicap.', suffix='.tmp') as upstream:
            self.read_into(upstream)
            if self.preview and not self.ieof:
                self.cont()
                self.read_into(upstream)
            upstream.seek(0)

            # And write it to downstream
            content = upstream.read()
            self.write_chunk(content)

From the OPTIONS message I understand Squid should send only the response headers to the ICAP Server:

self.set_icap_header(b'Preview', b'0')
self.set_icap_header(b'Transfer-Preview', b'*')
self.set_icap_header(b'Transfer-Ignore', b'jpg,jpeg,gif,png,swf,flv')
self.set_icap_header(b'Transfer-Complete', b'')

So, the behavior I expect is the following:

  • Squid send the response headers (Threasfer-Preview=* and Preview=0)
  • The ICAP Server send the 100 Continue
  • Squid send the response body
  • The ICAP Server writes to the temporary file and everything does as planned

Nevertheless, the ICAP Server doesn't perform es expected and it fails writing the response:

$ python examples/respmod_copy.py 
127.0.0.1 - - [08/b'May'/2017 16:15:24] "b'OPTIONS icap://127.0.0.1:1344/resp ICAP/1.0'" b'200' b'-'
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 36906)
Traceback (most recent call last):
  File "/usr/lib/python3.6/socketserver.py", line 639, in process_request_thread
    self.finish_request(request, client_address)
  File "/usr/lib/python3.6/socketserver.py", line 361, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/lib/python3.6/socketserver.py", line 696, in __init__
    self.handle()
  File "/usr/lib/python3.6/site-packages/pyicap.py", line 443, in handle
    self.handle_one_request()
  File "/usr/lib/python3.6/site-packages/pyicap.py", line 493, in handle_one_request
    method()
  File "examples/respmod_copy.py", line 67, in resp_RESPMOD
    self.write_chunk(content)
  File "/usr/lib/python3.6/site-packages/pyicap.py", line 213, in write_chunk
    self.wfile.write(l + b'\r\n' + data + b'\r\n')
  File "/usr/lib/python3.6/socketserver.py", line 775, in write
    self._sock.sendall(b)
ConnectionResetError: [Errno 104] Connection reset by peer
----------------------------------------

The error messages indicates that, for some reason, Squid closed the connection.

The only message I get from Squid is this one:

1494271928.277      0 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ICAP_OPT/200 258 OPTIONS icap://127.0.0.1:1344/resp - -/127.0.0.1 -
1494271928.278      1 wilderkrieger.localdomain ICAP_ERR_OTHER/100 50 RESPMOD icap://127.0.0.1:1344/resp - -/127.0.0.1 

And there is where I get lost, Squid is configured with ICAP Preview and Persistent Connections enabled. Perhaps Squid is failed due to the 100 continue?

Any help would be greatly appreciated.

Thanks!

Juan

@ichramm
Copy link
Author

ichramm commented May 9, 2017

I found that self.cont() should not be called before reading because the only way to check for the ieof tag is by reading the request body.

The problem arises when the response is larger than the size of the Preview. In that case, the following code is executed:

if self.preview and not self.ieof:
    self.cont()
    self.read_into(upstream)

And then the icap server failes as explained above. It fails because Squid already sent the whole body but the ieof tag was not present. By reading the code of the function readchunk in pyicap.py I noticed that it also sets the variable self.bob.

It is safe to check also for that variable before calling self.cont()?

@uovobw
Copy link

uovobw commented May 17, 2017

@ichramm i am trying to get this to work too, using the test server in examples/respmod_copy.py. did you make any progress?

@aes3219563
Copy link

See no_adaptation_required() in pyicap.py. Under the case that icap client does not allow 204, it copies everything to the client. This part works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants