Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

# urllib3/connection.py 

# Copyright 2008-2013 Andrey Petrov and contributors (see CONTRIBUTORS.txt) 

# 

# This module is part of urllib3 and is released under 

# the MIT License: http://www.opensource.org/licenses/mit-license.php 

 

import sys 

import socket 

from socket import timeout as SocketTimeout 

 

try: # Python 3 

    from http.client import HTTPConnection as _HTTPConnection, HTTPException 

except ImportError: 

    from httplib import HTTPConnection as _HTTPConnection, HTTPException 

 

class DummyConnection(object): 

    "Used to detect a failed ConnectionCls import." 

    pass 

 

try: # Compiled with SSL? 

    ssl = None 

    HTTPSConnection = DummyConnection 

 

    class BaseSSLError(BaseException): 

        pass 

 

    try: # Python 3 

        from http.client import HTTPSConnection as _HTTPSConnection 

    except ImportError: 

        from httplib import HTTPSConnection as _HTTPSConnection 

 

    import ssl 

    BaseSSLError = ssl.SSLError 

 

except (ImportError, AttributeError): # Platform-specific: No SSL. 

    pass 

 

from .exceptions import ( 

    ConnectTimeoutError, 

) 

from .packages.ssl_match_hostname import match_hostname 

from .packages import six 

from .util import ( 

    assert_fingerprint, 

    resolve_cert_reqs, 

    resolve_ssl_version, 

    ssl_wrap_socket, 

) 

 

 

port_by_scheme = { 

    'http': 80, 

    'https': 443, 

} 

 

 

class HTTPConnection(_HTTPConnection, object): 

    """ 

    Based on httplib.HTTPConnection but provides an extra constructor 

    backwards-compatibility layer between older and newer Pythons. 

    """ 

 

    default_port = port_by_scheme['http'] 

 

    # By default, disable Nagle's Algorithm. 

    tcp_nodelay = 1 

 

    def __init__(self, *args, **kw): 

        if six.PY3:  # Python 3 

            kw.pop('strict', None) 

        if sys.version_info < (2, 7):  # Python 2.6 and older 

            kw.pop('source_address', None) 

 

        # Pre-set source_address in case we have an older Python like 2.6. 

        self.source_address = kw.get('source_address') 

 

        # Superclass also sets self.source_address in Python 2.7+. 

        _HTTPConnection.__init__(self, *args, **kw) 

 

    def _new_conn(self): 

        """ Establish a socket connection and set nodelay settings on it. 

 

        :return: a new socket connection 

        """ 

        extra_args = [] 

        if self.source_address:  # Python 2.7+ 

            extra_args.append(self.source_address) 

 

        conn = socket.create_connection( 

            (self.host, self.port), self.timeout, *extra_args) 

        conn.setsockopt( 

            socket.IPPROTO_TCP, socket.TCP_NODELAY, self.tcp_nodelay) 

 

        return conn 

 

    def _prepare_conn(self, conn): 

        self.sock = conn 

        # the _tunnel_host attribute was added in python 2.6.3 (via 

        # http://hg.python.org/cpython/rev/0f57b30a152f) so pythons 2.6(0-2) do 

        # not have them. 

        if getattr(self, '_tunnel_host', None): 

            # TODO: Fix tunnel so it doesn't depend on self.sock state. 

            self._tunnel() 

 

    def connect(self): 

        conn = self._new_conn() 

        self._prepare_conn(conn) 

 

 

class HTTPSConnection(HTTPConnection): 

    default_port = port_by_scheme['https'] 

 

    def __init__(self, host, port=None, key_file=None, cert_file=None, 

                 strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, **kw): 

 

        HTTPConnection.__init__(self, host, port, strict=strict, 

                                timeout=timeout, **kw) 

 

        self.key_file = key_file 

        self.cert_file = cert_file 

 

        # Required property for Google AppEngine 1.9.0 which otherwise causes 

        # HTTPS requests to go out as HTTP. (See Issue #356) 

        self._protocol = 'https' 

 

    def connect(self): 

        conn = self._new_conn() 

        self._prepare_conn(conn) 

        self.sock = ssl.wrap_socket(conn, self.key_file, self.cert_file) 

 

 

class VerifiedHTTPSConnection(HTTPSConnection): 

    """ 

    Based on httplib.HTTPSConnection but wraps the socket with 

    SSL certification. 

    """ 

    cert_reqs = None 

    ca_certs = None 

    ssl_version = None 

    conn_kw = {} 

 

    def set_cert(self, key_file=None, cert_file=None, 

                 cert_reqs=None, ca_certs=None, 

                 assert_hostname=None, assert_fingerprint=None): 

 

        self.key_file = key_file 

        self.cert_file = cert_file 

        self.cert_reqs = cert_reqs 

        self.ca_certs = ca_certs 

        self.assert_hostname = assert_hostname 

        self.assert_fingerprint = assert_fingerprint 

 

    def connect(self): 

        # Add certificate verification 

 

        try: 

            sock = socket.create_connection( 

                address=(self.host, self.port), timeout=self.timeout, 

                **self.conn_kw) 

        except SocketTimeout: 

            raise ConnectTimeoutError( 

                self, "Connection to %s timed out. (connect timeout=%s)" % 

                (self.host, self.timeout)) 

 

        sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 

                        self.tcp_nodelay) 

 

        resolved_cert_reqs = resolve_cert_reqs(self.cert_reqs) 

        resolved_ssl_version = resolve_ssl_version(self.ssl_version) 

 

        hostname = self.host 

        if getattr(self, '_tunnel_host', None): 

            # _tunnel_host was added in Python 2.6.3 

            # (See: http://hg.python.org/cpython/rev/0f57b30a152f) 

 

            self.sock = sock 

            # Calls self._set_hostport(), so self.host is 

            # self._tunnel_host below. 

            self._tunnel() 

 

            # Override the host with the one we're requesting data from. 

            hostname = self._tunnel_host 

 

        # Wrap socket using verification with the root certs in 

        # trusted_root_certs 

        self.sock = ssl_wrap_socket(sock, self.key_file, self.cert_file, 

                                    cert_reqs=resolved_cert_reqs, 

                                    ca_certs=self.ca_certs, 

                                    server_hostname=hostname, 

                                    ssl_version=resolved_ssl_version) 

 

        if resolved_cert_reqs != ssl.CERT_NONE: 

            if self.assert_fingerprint: 

                assert_fingerprint(self.sock.getpeercert(binary_form=True), 

                                   self.assert_fingerprint) 

            elif self.assert_hostname is not False: 

                match_hostname(self.sock.getpeercert(), 

                               self.assert_hostname or hostname) 

 

 

if ssl: 

    # Make a copy for testing. 

    UnverifiedHTTPSConnection = HTTPSConnection 

    HTTPSConnection = VerifiedHTTPSConnection