~ubuntu-branches/ubuntu/karmic/m2crypto/karmic

« back to all changes in this revision

Viewing changes to M2Crypto/httpslib.py

  • Committer: Bazaar Package Importer
  • Author(s): Dima Barsky
  • Date: 2007-10-13 02:21:26 UTC
  • mto: (1.1.3 upstream) (2.2.2 lenny)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20071013022126-mh2i44h1ajngwq1q
ImportĀ upstreamĀ versionĀ 0.18.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""M2Crypto support for Python 1.5.2 and Python 2.x's httplib. 
 
1
"""M2Crypto support for Python's httplib. 
2
2
 
3
3
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved."""
4
4
 
5
5
import string, sys
 
6
import socket
 
7
import urllib
 
8
import base64
 
9
 
6
10
from httplib import *
7
11
from httplib import HTTPS_PORT # This is not imported with just '*'
8
12
import SSL
16
20
    default_port = HTTPS_PORT
17
21
 
18
22
    def __init__(self, host, port=None, strict=None, **ssl):
 
23
        self.session = None
19
24
        keys = ssl.keys()
20
25
        try: 
21
26
            keys.remove('key_file')
33
38
            raise IllegalKeywordArgument()
34
39
        try:
35
40
            self.ssl_ctx = ssl['ssl_context']
36
 
            assert isinstance(self.ssl_ctx, SSL.Context)
 
41
            assert isinstance(self.ssl_ctx, SSL.Context), self.ssl_ctx
37
42
        except KeyError:
38
43
            self.ssl_ctx = SSL.Context('sslv23')
39
44
        HTTPConnection.__init__(self, host, port, strict)
40
45
 
41
46
    def connect(self):
42
47
        self.sock = SSL.Connection(self.ssl_ctx)
 
48
        if self.session:
 
49
            self.sock.set_session(self.session)
43
50
        self.sock.connect((self.host, self.port))
44
51
 
45
52
    def close(self):
58
65
        # XXX but I've not investigated if the above conditions
59
66
        # XXX remain.
60
67
        pass
 
68
    
 
69
    def get_session(self):
 
70
        return self.sock.get_session()
61
71
 
 
72
    def set_session(self, session):
 
73
        self.session = session
 
74
        
62
75
 
63
76
class HTTPS(HTTP):
64
77
    
72
85
            self.ssl_ctx = SSL.Context('sslv23')
73
86
        assert isinstance(self._conn, HTTPSConnection)
74
87
        self._conn.ssl_ctx = self.ssl_ctx
 
88
 
 
89
 
 
90
class ProxyHTTPSConnection(HTTPSConnection):
 
91
 
 
92
    """
 
93
    An HTTPS Connection that uses a proxy and the CONNECT request.
 
94
 
 
95
    When the connection is initiated, CONNECT is first sent to the proxy (along
 
96
    with authorization headers, if supplied). If successful, an SSL connection
 
97
    will be established over the socket through the proxy and to the target
 
98
    host.
 
99
 
 
100
    Finally, the actual request is sent over the SSL connection tunneling
 
101
    through the proxy.
 
102
    """
 
103
 
 
104
    _ports = {'http' : 80, 'https' : 443}
 
105
    _AUTH_HEADER = "Proxy-Authorization"
 
106
 
 
107
    def __init__(self, host, port=None, strict=None, username=None,
 
108
        password=None, **ssl):
 
109
        """
 
110
        Create the ProxyHTTPSConnection object.
 
111
 
 
112
        host and port are the hostname and port number of the proxy server.
 
113
        """
 
114
        HTTPSConnection.__init__(self, host, port, strict, **ssl)
 
115
 
 
116
        self._username = username
 
117
        self._password = password
 
118
        self._proxy_auth = None
 
119
 
 
120
    def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0):
 
121
        #putrequest is called before connect, so can interpret url and get
 
122
        #real host/port to be used to make CONNECT request to proxy
 
123
        proto, rest = urllib.splittype(url)
 
124
        if proto is None:
 
125
            raise ValueError, "unknown URL type: %s" % url
 
126
        #get host
 
127
        host, rest = urllib.splithost(rest)
 
128
        #try to get port
 
129
        host, port = urllib.splitport(host)
 
130
        #if port is not defined try to get from proto
 
131
        if port is None:
 
132
            try:
 
133
                port = self._ports[proto]
 
134
            except KeyError:
 
135
                raise ValueError, "unknown protocol for: %s" % url
 
136
        self._real_host = host
 
137
        self._real_port = port
 
138
        HTTPSConnection.putrequest(self, method, url, skip_host, skip_accept_encoding)
 
139
 
 
140
    def putheader(self, header, value):
 
141
        # Store the auth header if passed in.
 
142
        if header.lower() == self._AUTH_HEADER.lower():
 
143
            self._proxy_auth = value
 
144
        else:
 
145
            HTTPSConnection.putheader(self, header, value)
 
146
 
 
147
    def endheaders(self):
 
148
        # We've recieved all of hte headers. Use the supplied username
 
149
        # and password for authorization, possibly overriding the authstring
 
150
        # supplied in the headers.
 
151
        if not self._proxy_auth:
 
152
            self._proxy_auth = self._encode_auth()
 
153
 
 
154
        HTTPSConnection.endheaders(self)
 
155
 
 
156
    def connect(self):
 
157
        HTTPConnection.connect(self)
 
158
 
 
159
        #send proxy CONNECT request
 
160
        self.sock.sendall(self._get_connect_msg())
 
161
        response = HTTPResponse(self.sock)
 
162
        response.begin()
 
163
        
 
164
        code = response.status
 
165
        if code != 200:
 
166
            #proxy returned and error, abort connection, and raise exception
 
167
            self.close()
 
168
            raise socket.error, "Proxy connection failed: %d" % code
 
169
       
 
170
        self._start_ssl()
 
171
 
 
172
    def _get_connect_msg(self):
 
173
        """ Return an HTTP CONNECT request to send to the proxy. """
 
174
        msg = "CONNECT %s:%d HTTP/1.1\r\n" % (self._real_host, self._real_port)
 
175
        if self._proxy_auth:
 
176
            msg = msg + "%s: %s\r\n" % (self._AUTH_HEADER, self._proxy_auth) 
 
177
        msg = msg + "\r\n"
 
178
        return msg
 
179
 
 
180
    def _start_ssl(self):
 
181
        """ Make this connection's socket SSL-aware. """
 
182
        self.sock = SSL.Connection(self.ssl_ctx, self.sock)
 
183
        self.sock.setup_ssl()
 
184
        self.sock.set_connect_state()
 
185
        self.sock.connect_ssl()
 
186
 
 
187
    def _encode_auth(self):
 
188
        """ Encode the username and password for use in the auth header. """
 
189
        if not (self._username and self._password):
 
190
            return None
 
191
        # Authenticated proxy
 
192
        userpass = "%s:%s" % (self._username, self._password)
 
193
        enc_userpass = base64.encodestring(userpass).replace("\n", "")
 
194
        return "Basic %s" % enc_userpass