Example #1
0
    async def set_url_and_addr(self):
        """
            将url和 浏览器客户端的网络地址 设置到queue中
            :return:
            """
        socket_info = self.conn.getpeername()
        browser_addr = socket_info[0] + ':' + str(socket_info[1])

        # 使用 communicate_identify 在消息队列(Queue, redis..)中进行交换数据
        self.communicate_identify = self.__generate_identify(browser_addr)
        # 初始化消息队列
        GLOBAL_CACHE.init_http_commu_queue_map(self.communicate_identify)

        self.control_http_queue = GLOBAL_CACHE.HTTP_COMMU_QUEUE_MAP[
            self.communicate_identify]['control_http_queue']
        self.control_proxy_queue = GLOBAL_CACHE.HTTP_COMMU_QUEUE_MAP[
            self.communicate_identify]['control_proxy_queue']

        url_and_addr = {
            'url': self.url,
            'addr': browser_addr,
            'communicate_identify': self.communicate_identify
        }
        queue = GLOBAL_CACHE.PROXY_URL_ADDR_LIST[self.client_id]
        logger.debug(queue)
        await queue.put(url_and_addr)
Example #2
0
    def auth_process(self, request):
        """
        process auth
        :param request:
        :return: (err_code, msg, binary response data)
        """
        user = request['Payload'].get('User')
        pwd = request['Payload'].get('Password')
        version = request['Payload'].get('Version')
        mm_version = request['Payload'].get('MmVersion')
        os_type = request['Payload'].get('OS')
        arch = request['Payload'].get('Arch')

        err, msg, client_id = NgrokController.auth(user, pwd, version,
                                                   mm_version, os_type, arch)
        logger.debug('auth process: err[%d], msg[%s], client_id[%s]', err, msg,
                     client_id)

        if err != ERR_SUCCESS:
            resp = generate_auth_resp(error=msg)
        else:
            self.client_id = client_id
            GLOBAL_CACHE.add_client_id(client_id)

            # 准备接收 req_proxy 的命令
            asyncio.ensure_future(self.waiting_send_req_proxy(),
                                  loop=self.loop)

            resp = generate_auth_resp(client_id=client_id)

        return err, msg, resp
Example #3
0
    async def __write_handler(self):
        """
            处理写回调。
            :return:
            """
        if len(self.resp_list) == 0 and self.writing_resp is None:
            return

        try:

            if self.writing_resp is None:
                self.writing_resp = self.resp_list[0]
                self.resp_list = self.resp_list[1:]

            sent_bytes = self.conn.send(self.writing_resp)
            if sent_bytes < len(self.writing_resp):
                self.writing_resp = self.writing_resp[sent_bytes:]
            else:
                self.writing_resp = None
                self.loop.remove_writer(self.fd)
                self.loop.add_reader(self.fd, self.read_handler)

        except ssl.SSLWantReadError as ex:
            logger.debug("SSLWantReadError")
        except Exception as ex:
            logger.exception("Exception in write_handler:", exc_info=ex)
            asyncio.ensure_future(self.process_error(), loop=self.loop)
Example #4
0
    def _on_handshake(self, conn):
        """
        SSL handshake function, copy from asyncio.selector_events.
        :param conn: client connection socket
        :return:
        """
        try:
            conn.do_handshake()
        except ssl.SSLWantReadError:
            self.loop.add_reader(conn.fileno(), self._on_handshake, conn)
            return
        except ssl.SSLWantWriteError:
            self.loop.add_writer(conn.fileno(), self._on_handshake, conn)
            return
        except BaseException as exc:

            logger.warning("%r: SSL handshake failed", self, exc_info=True)
            self.loop.remove_reader(conn.fileno())
            self.loop.remove_writer(conn.fileno())
            conn.close()
            if isinstance(exc, Exception):
                return
            else:
                raise

        self.loop.remove_reader(conn.fileno())
        self.loop.remove_writer(conn.fileno())
        logger.debug("ssl handshake finish")

        handler = self.handler_cls(conn, self.loop)
        self.loop.add_reader(handler.fd, handler.read_handler)
Example #5
0
    async def __read_handler(self):
        """
            处理read回调
            :return:
            """
        try:
            data = self.conn.recv(DEFAULT_BUF_SIZE)
        except ssl.SSLWantReadError:
            return

        if not data:
            asyncio.ensure_future(self.process_error(), loop=self.loop)
        else:
            headers = get_http_headers(data.decode('utf-8'))

            if 'HOST' in headers:
                url = self.protocol + '://' + headers['HOST']

                if url in GLOBAL_CACHE.HOSTS:
                    self.binary_data = data
                    self.url = url

                    logger.debug("Http request for url[%s]", url)

                    self.client_id = GLOBAL_CACHE.HOSTS[url]['client_id']

                    await self.set_url_and_addr()

                    # TODO: 用协程在这里让 NgrokHandler 中的 socket 发送一个ReqProxy命令到客户端,并等待一个proxy连接上。尽可能使用异步的方式
                    queue = GLOBAL_CACHE.SEND_REQ_PROXY_LIST[self.client_id]
                    asyncio.ensure_future(queue.put('send'), loop=self.loop)

                    # 添加处理proxy意外断开的处理事件
                    asyncio.ensure_future(self.close_by_ngrok(),
                                          loop=self.loop)

                    # 将接收到的http 请求内容 插入消息队列中
                    await self.insert_data_to_http_req_queue()

                    asyncio.ensure_future(self.write_resp_to_browser(),
                                          loop=self.loop)
                else:
                    logger.debug(
                        "Http request for url[%s], no such url, return 404",
                        url)

                    # Can not find the tunnel
                    # Return 404 to browser
                    self.send_404(headers['HOST'])
            else:
                # No 'HOST' in http headers
                self.send_404('without host in header')
Example #6
0
 async def handle_connect(self):
     conn, address = await self.loop.sock_accept(self.__socket)
     conn.setblocking(0)
     if self.is_ssl:
         conn = self.context.wrap_socket(conn,
                                         server_side=True,
                                         do_handshake_on_connect=False,
                                         server_hostname=self.hostname)
         logger.debug("start ssl handshake")
         self._on_handshake(conn)
     else:
         handler = self.handler_cls(conn, self.loop)
         self.loop.add_reader(handler.fd, handler.read_handler)
Example #7
0
    async def start(self):

        logger.debug("start to run")

        if self.running:
            return

        if not self.initialized:
            self.initialize()

        self.running = True

        while self.running:
            await self.handle_connect()
Example #8
0
    async def __read_handler(self):
        """
        协程,真正处理read回调。
        :return:
        """
        try:
            data = self.conn.recv(DEFAULT_BUF_SIZE)
        except ssl.SSLWantReadError:
            return

        if not data:
            asyncio.ensure_future(self.process_error(), loop=self.loop)
        else:

            if self.is_proxy is True:
                # 如果是Proxy连接,将数据直接传给http handler
                await self.insert_data_to_http_resp_queue(data)
            else:

                request_size = tolen(data[:8])

                if request_size > len(data[8:]):
                    # 请求没接收全,继续接受

                    self.binary_data = bytearray(data)

                    # 移除旧的read回调
                    self.loop.remove_reader(self.fd)
                    # 因为请求未接受完, 使用继续接收的read回调
                    self.loop.add_reader(self.fd, self.continue_read_handler)
                elif request_size == len(data[8:]):
                    # 请求接受全

                    request_data = data[8:]
                    logger.debug("receive control request: %s", request_data)

                    await self.process_request(request_data)

                    self.loop.remove_reader(self.fd)
                else:

                    request_data = data[8:request_size + 8]

                    await self.process_request(request_data)

                    # 有TCP粘包
                    self.binary_data = bytearray(data[request_size + 8:])
Example #9
0
    async def __continue_read_handler(self):
        """
        处理read回调。用来处理请求过大没有一次接收完的。
        :return:
        """
        try:
            data = self.conn.recv(DEFAULT_BUF_SIZE)

        except ssl.SSLWantReadError as ex:
            logger.debug("SSLWantReadError")
            return

        if not data:
            self.loop.remove_reader(self.conn.fileno())
            self.conn.close()
        else:
            request_size = tolen(self.binary_data[:8])
            try:
                self.binary_data.extend(data)
            except Exception as ex:
                logger.exception("test:", exc_info=ex)
            if request_size > len(self.binary_data[8:]):
                # 请求没接收全,继续接受
                pass
            elif request_size < len(self.binary_data[8:]):
                # 请求的大小,小于收到的大小,有TCP粘包

                # 获取本次请求
                request_data = self.binary_data[8:8 + request_size]

                logger.debug("receive control request: %s", request_data)

                await self.process_request(request_data)

                # 移除已处理请求的数据
                self.binary_data = self.binary_data[8 + request_size:]

                # 移除继续读的read回调
                self.loop.remove_reader(self.fd)
            else:
                # 请求接受全
                request_data = self.binary_data[8:]
                logger.debug("receive control request: %s", request_data)

                await self.process_request(request_data)

                self.binary_data = None

                # 移除继续读的read回调
                self.loop.remove_reader(self.fd)