File: connect.py

package info (click to toggle)
utopia-documents 2.4.4-2
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 30,560 kB
  • ctags: 24,084
  • sloc: cpp: 179,735; ansic: 16,208; python: 13,446; xml: 1,937; sh: 1,918; ruby: 1,594; makefile: 527; sql: 6
file content (175 lines) | stat: -rw-r--r-- 5,743 bytes parent folder | download
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
#!/usr/bin/env python2.6
# encoding: utf-8
##############################################################################
##############################################################################
##############################################################################
###
### connect.py
###
### This is for doing CONNECT to remote servers using urllib2.
###
##############################################################################
##############################################################################
##############################################################################

import socket
import select

from coda_network import urllib2
from coda_network import httplib

# Slight specialisation of HTTPSConnection to not do anything else apart from
# the connect to the remote server.
class HTTPSConnectConnection(httplib.HTTPSConnection):
    """
    This class performs a CONNECT to allow daisy chaining sockets.
    """

    def request(self, method, url, body=None, headers={}):
        """Send a complete request to the server."""
        if self._tunnel_host:
            self.connect_response = self._tunnel(self._tunnel_host, self._tunnel_port, self._tunnel_headers)
        # Because we want the vanilla socket then we don't perform any more
        # communication.

# Slight specialisation of HTTPSHandler to return the socket in the response
# structure so we can perform the CONNECT operations correctly.
class HTTPSConnectHandler(urllib2.HTTPSHandler):
    """
    Perform the connect.
    NOTE: Do it this way so we reuse the maximum amount of code so we can
    get the correct behaviour when punching thorugh proxies.
    """

    http_class = HTTPSConnectConnection

    def __init__(self, debuglevel=0, cert=None):
        urllib2.HTTPSHandler.__init__(self, debuglevel=debuglevel)
        self.cert = cert

    def create_response(self, h, r, full_url):
        # Pick apart the HTTPResponse object to get the addinfourl
        # object initialized properly.

        # Wrap the HTTPResponse object in socket's file object adapter
        # for Windows.  That adapter calls recv(), so delegate recv()
        # to read().  This weird wrapping allows the returned object to
        # have readline() and readlines() methods.

        # XXX It might be better to extract the read buffering code
        # out of socket._fileobject() and into a base class.

        r.recv = r.read
        fp = socket._fileobject(r, close=True)

        resp = urllib2.addinfourl(fp, r.msg, full_url)
        resp.code = r.status
        resp.msg = r.reason
        # We expose the socket for CONNECT.
        resp.connect_sock = h.sock
        return resp


###########################################################################
#
def build_connect_opener(cert=None, proxy_handlers=None, auth_handlers=None):
    """Builds the list of opener objects required for the specific type of request."""
    handlers = [HTTPSConnectHandler(cert=cert)]

    if proxy_handlers:
        handlers.extend(proxy_handlers)

    if auth_handlers:
        handlers.extend(auth_handlers)

    return urllib2.build_opener(*handlers)
#
###########################################################################


###########################################################################
#
def create_connect_handle(host, proxy_handlers, auth_handlers=None, cert=None, timeout_sec=None):
    """
    Wraps handle connect creation.
    """
    url_req = urllib2.Request(host)

    url_opener = build_connect_opener(cert, proxy_handlers, auth_handlers)

    if timeout_sec:
        return url_opener.open(url_req, timeout=timeout_sec)

    return url_opener.open(url_req)
#
###########################################################################


###########################################################################
#
def socket_read_write(soc, connection, max_idling=20, socket_timeout=20, chunk_size=8192):
    """Handle the socket communication."""
    iw = [soc, connection]
    ow = []
    count = 0
    while 1:
        count += 1
        (ins, outs, errs) = select.select(iw, ow, iw, socket_timeout)
        if errs:
            break

        if ins:
            for i in ins:
                if i is soc:
                    out = connection
                else:
                    out = soc
                data = i.recv(chunk_size)
                if data:
                    out.send(data)
                    count = 0

        else:
            # SOCKET: no data after socket_timeout? kill it
            break

        if count == max_idling:
            break
#
###########################################################################


###########################################################################
#
def do_connect_chain(host, port, proxy_handlers, auth_handlers, connection, outputfile, protocol_version):
    scheme = 'http'
    if port == 443:
        scheme = 'https'

    sock = None
    handle = None
    try:
        if proxy_handlers:
            handle = create_connect_handle('%s://%s:%d' % (scheme, host, port), proxy_handlers, auth_handlers)
            sock = handle.connect_sock
        else:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((host, port))

        outputfile.write("%s 200 Connection established\r\n" % protocol_version)
        outputfile.write("Proxy-agent: %s\r\n" % "blah")
        outputfile.write("\r\n")

        socket_read_write(sock, connection, 100)

    finally:
        if sock:
            sock.close()

        if handle:
            handle.close()

        if connection:
            connection.close()
#
###########################################################################