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)
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
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)
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)
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')
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)
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()
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:])
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)