| 655 | |
| 656 | @asyncio.coroutine |
| 657 | def _create_connection(self, req): |
| 658 | proxy_req = ClientRequest( |
| 659 | hdrs.METH_GET, self._proxy, |
| 660 | headers={hdrs.HOST: req.host}, |
| 661 | auth=self._proxy_auth, |
| 662 | loop=self._loop) |
| 663 | try: |
| 664 | transport, proto = yield from super()._create_connection(proxy_req) |
| 665 | except OSError as exc: |
| 666 | raise ProxyConnectionError(*exc.args) from exc |
| 667 | |
| 668 | if not req.ssl: |
| 669 | req.path = '{scheme}://{host}{path}'.format(scheme=req.scheme, |
| 670 | host=req.netloc, |
| 671 | path=req.path) |
| 672 | if hdrs.AUTHORIZATION in proxy_req.headers: |
| 673 | auth = proxy_req.headers[hdrs.AUTHORIZATION] |
| 674 | del proxy_req.headers[hdrs.AUTHORIZATION] |
| 675 | if not req.ssl: |
| 676 | req.headers[hdrs.PROXY_AUTHORIZATION] = auth |
| 677 | else: |
| 678 | proxy_req.headers[hdrs.PROXY_AUTHORIZATION] = auth |
| 679 | |
| 680 | if req.ssl: |
| 681 | # For HTTPS requests over HTTP proxy |
| 682 | # we must notify proxy to tunnel connection |
| 683 | # so we send CONNECT command: |
| 684 | # CONNECT www.python.org:443 HTTP/1.1 |
| 685 | # Host: www.python.org |
| 686 | # |
| 687 | # next we must do TLS handshake and so on |
| 688 | # to do this we must wrap raw socket into secure one |
| 689 | # asyncio handles this perfectly |
| 690 | proxy_req.method = hdrs.METH_CONNECT |
| 691 | proxy_req.path = '{}:{}'.format(req.host, req.port) |
| 692 | key = (req.host, req.port, req.ssl) |
| 693 | conn = Connection(self, key, proxy_req, |
| 694 | transport, proto, self._loop) |
| 695 | self._acquired[key].add(conn._transport) |
| 696 | proxy_resp = proxy_req.send(conn.writer, conn.reader) |
| 697 | try: |
| 698 | resp = yield from proxy_resp.start(conn, True) |
| 699 | except: |
| 700 | proxy_resp.close() |
| 701 | conn.close() |
| 702 | raise |
| 703 | else: |
| 704 | conn.detach() |
| 705 | if resp.status != 200: |
| 706 | raise HttpProxyError(code=resp.status, message=resp.reason) |
| 707 | rawsock = transport.get_extra_info('socket', default=None) |
| 708 | if rawsock is None: |
| 709 | raise RuntimeError( |
| 710 | "Transport does not expose socket instance") |
| 711 | transport.pause_reading() |
| 712 | transport, proto = yield from self._loop.create_connection( |
| 713 | self._factory, ssl=self.ssl_context, sock=rawsock, |
| 714 | server_hostname=req.host) |