summaryrefslogtreecommitdiff
path: root/tests/open_socket_cb_test.py
blob: b2ddbebd0be5231e6c2614b76488c895852f9564 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4:et

from . import localhost
import socket
import pycurl
import unittest

from . import appmanager
from . import util

setup_module, teardown_module = appmanager.setup(('app', 8380))

socket_open_called_ipv4 = False
socket_open_called_ipv6 = False
socket_open_called_unix = False
socket_open_address = None

def socket_open_ipv4(purpose, curl_address):
    family, socktype, protocol, address = curl_address
    global socket_open_called_ipv4
    global socket_open_address
    socket_open_called_ipv4 = True
    socket_open_address = address

    s = socket.socket(family, socktype, protocol)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
    return s

def socket_open_ipv6(purpose, curl_address):
    family, socktype, protocol, address = curl_address
    global socket_open_called_ipv6
    global socket_open_address
    socket_open_called_ipv6 = True
    socket_open_address = address

    s = socket.socket(family, socktype, protocol)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
    return s

def socket_open_unix(purpose, curl_address):
    family, socktype, protocol, address = curl_address
    global socket_open_called_unix
    global socket_open_address
    socket_open_called_unix = True
    socket_open_address = address

    sockets = socket.socketpair()
    sockets[0].close()
    return sockets[1]

def socket_open_bad(purpose, curl_address):
    return pycurl.SOCKET_BAD

class OpenSocketCbTest(unittest.TestCase):
    def setUp(self):
        self.curl = util.DefaultCurl()

    def tearDown(self):
        self.curl.close()

    # This is failing too much on appveyor
    @util.only_unix
    def test_socket_open(self):
        self.curl.setopt(pycurl.OPENSOCKETFUNCTION, socket_open_ipv4)
        self.curl.setopt(self.curl.URL, 'http://%s:8380/success' % localhost)
        sio = util.BytesIO()
        self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
        self.curl.perform()

        assert socket_open_called_ipv4
        self.assertEqual(("127.0.0.1", 8380), socket_open_address)
        self.assertEqual('success', sio.getvalue().decode())

    @util.only_ipv6
    def test_socket_open_ipv6(self):
        self.curl.setopt(pycurl.OPENSOCKETFUNCTION, socket_open_ipv6)
        self.curl.setopt(self.curl.URL, 'http://[::1]:8380/success')
        sio = util.BytesIO()
        self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
        try:
            # perform fails because we do not listen on ::1
            self.curl.perform()
        except pycurl.error:
            pass

        assert socket_open_called_ipv6

        assert len(socket_open_address) == 4
        assert socket_open_address[0] == '::1'
        assert socket_open_address[1] == 8380
        assert type(socket_open_address[2]) == int
        assert type(socket_open_address[3]) == int

    @util.min_libcurl(7, 40, 0)
    @util.only_unix
    def test_socket_open_unix(self):
        self.curl.setopt(pycurl.OPENSOCKETFUNCTION, socket_open_unix)
        self.curl.setopt(self.curl.URL, 'http://%s:8380/success' % localhost)
        self.curl.setopt(self.curl.UNIX_SOCKET_PATH, '/tmp/pycurl-test-path.sock')
        sio = util.BytesIO()
        self.curl.setopt(pycurl.WRITEFUNCTION, sio.write)
        try:
            # perform fails because we return a socket that is
            # not attached to anything
            self.curl.perform()
        except pycurl.error:
            pass

        assert socket_open_called_unix
        if util.py3:
            assert isinstance(socket_open_address, bytes)
            self.assertEqual(b'/tmp/pycurl-test-path.sock', socket_open_address)
        else:
            assert isinstance(socket_open_address, str)
            self.assertEqual('/tmp/pycurl-test-path.sock', socket_open_address)

    def test_socket_open_none(self):
        self.curl.setopt(pycurl.OPENSOCKETFUNCTION, None)

    def test_unset_socket_open(self):
        self.curl.unsetopt(pycurl.OPENSOCKETFUNCTION)

    def test_socket_bad(self):
        self.assertEqual(-1, pycurl.SOCKET_BAD)

    def test_socket_open_bad(self):
        self.curl.setopt(pycurl.OPENSOCKETFUNCTION, socket_open_bad)
        self.curl.setopt(self.curl.URL, 'http://%s:8380/success' % localhost)
        try:
            self.curl.perform()
        except pycurl.error as e:
            # libcurl 7.38.0 for some reason fails with a timeout
            # (and spends 5 minutes on this test)
            if pycurl.version_info()[1].split('.') == ['7', '38', '0']:
                self.assertEqual(pycurl.E_OPERATION_TIMEDOUT, e.args[0])
            else:
                self.assertEqual(pycurl.E_COULDNT_CONNECT, e.args[0])
        else:
            self.fail('Should have raised')