def handshake(self, conn, env): peer_id = env['HTTP_X_MIFCHO_ID'] res_status = 200 # Regular connection res_status_msg = 'OK' res_headers = [ ('X-Mifcho-Id', self.cm.identifier) ] # "Reversed" connection reverse = env.get('HTTP_UPGRADE') == 'mifcho-reverse/0.1' if reverse: res_status = 101 res_status_msg = 'Switching Protocol' res_headers.append(('Upgrade', env['HTTP_UPGRADE'])) try: # Inform peer messages.send_response( conn, res_status, res_status_msg, 'HTTP/1.1', res_headers ) except: logging.error('Failed sending response to "handshake".') raise if reverse: # Store for later use (tunnel requests) self.cm.add_peer(PeerInfo(peer_id, conn))
def work(self, env): conn = env['mifcho.conn'] opened_sockets = [] for bo in self.cm.opened: try: opened_sockets.append({'sockname': bo.getsockname(), 'peername':bo.getpeername()}) except: opened_sockets.append({'sockname': 'Not connected', 'peername':'Not connected'}) serializable_perf = { 'peers': [repr(peer) for peer in self.cm.peers], 'bound_sockets': [{'sockname': bs.getsockname()} for bs in self.cm.bound], 'opened_sockets': opened_sockets, 'perf_log': [x for x in self.cm.performance_collector.log()] } try: res_body = json.dumps(serializable_perf) res_headers = [('Content-Length', len(res_body)), ('Content-Type', 'text/html'), ('Access-Control-Allow-Origin', '*')] messages.send_response(conn, 200, 'OK', 'HTTP/1.1', res_headers) conn.sendall(res_body) self.cm.teardown(conn) except: logging.debug('Something went wrong', exc_info=3)
def tunnel(self, conn, env): logging.debug('TUNNEL') if 'HTTP_X_MIFCHO_TUNNEL_ID' in env: # We requested the tunnel logging.debug('We requested the tunnel...') tunnel = self.cm.tunnels[env['HTTP_X_MIFCHO_TUNNEL_ID']] tunnel.peer_connection = conn messages.send_response(conn, code = 101, message = 'Switching Protocols', headers = [ ('X-Mifcho-Id', env['mifcho.id']) ] ) tunnel.event.set() else: # We did not request the tunnel so this is an indirect tunnel carrier. logging.debug('We did not request it...') ep_address = ( env['HTTP_X_MIFCHO_TUNNEL_ENDPOINTHOST'], int(headers['X_MIFCHO_TUNNEL_ENDPOINTPORT']) ) ep_conn = self.cm.connect(ep_address) if conn and ep_conn: logging.debug('Successfully contacted endpoint...') tunnel = Tunnel.fromconnections(conn, ep_conn) tunnel.id = str(uuid.uuid4()) self.cm.add_tunnel(tunnel) messages.send_response(conn, code = 101, message = 'Switching Protocols', headers = [ ('X-Mifcho-Id', self.cm.identifier) ] ) pipe = Piper(self.cm, conn, ep_conn, 4096, sink_recovery=(ep_address, None)) pipe.start() self.cm.pipes.append(pipe) else: logging.error('Failed connecting to endpoint [%s].' % repr(address)) self.cm.teardown(conn)
def start_response(status, response_headers, exc_info=None): status = status headers_sent = response_headers messages.send_response( conn, int(status.split(' ')[0]), message =status.split(' ')[1], version ='HTTP/1.1', headers = response_headers ) return write
def same_origin_sec(self, conn): # Doing options res_headers = [ ('Server', '%s/%s' % (self.server_name, self.server_ver)), ('Access-Control-Allow-Origin', ','.join(self.ac_origins)), ('Access-Control-Allow-Methods', ','.join(self.ac_methods)), ('Access-Control-Allow-Headers', ','.join(self.ac_headers)), ('Access-Control-Max-Age', repr(self.ac_max_age)), ('Content-Length', '0'), ('Connection', 'Keep-Alive') ] messages.send_response(conn, 200, 'OK', self.http_ver, res_headers)
def _ws_handshake(self, env): conn = env['mifcho.conn'] headers = [ ('Upgrade', 'WebSocket'), ('Connection', 'Upgrade'), ('Sec-WebSocket-Origin', env['HTTP_ORIGIN']), ('Sec-WebSocket-Protocol', 'sample'), ('Sec-WebSocket-Location', 'ws://%s%s' % (env['HTTP_HOST'], env['PATH_INFO'])), ] key1 = env['HTTP_SEC_WEBSOCKET_KEY1'] key2 = env['HTTP_SEC_WEBSOCKET_KEY2'], key3 = conn.recv(8) server_key = websocket.keys_to_md5(key1, key2, key3) messages.send_response( conn, 101, 'Web Socket Protocol Handshake', 'HTTP/1.1', headers ) conn.send(server_key) # Grab connection parameters ep_stuff = None peer_id = None req_path = env['PATH_INFO'].split('/') if len(req_path) == 4: # Directly ep_stuff = (_, _, ep_host, ep_port) = req_path elif len(req_path) == 5: # Via Peer ep_stuff = (_, _, ep_host, ep_port, peer_id) = req_path else: logging.error('Invalid path! %s' % repr(data)) if ep_stuff: ep_address = (ep_host, int(ep_port)) # Initiate endpoint connection vnc_conn = self.cm.connect(ep_address, peer_id) sink_recovery = (ep_address, peer_id) return (conn, vnc_conn, sink_recovery)
def work(self, env): conn = env['mifcho.conn'] path = self.path_prefix + os.sep + "/".join(env['PATH_INFO'].split('?')[0].split('/')[2:]) status = 404 status_msg = 'File Not Found' res_body = '404 - File Not Found' content_type = ('Content-Type', 'text/plain') if os.path.exists(path): status = 200 status_msg = 'OK' if os.path.isdir(path): res_body = pprint.pformat(os.listdir(path)) else: fd = open(path) res_body = fd.read() fd.close() content_type = ('Content-Type', mimetypes.guess_type(path)[0]) res_headers = [ ('Content-Length', len(res_body)), content_type, ('Access-Control-Allow-Origin', '*') ] messages.send_response( conn, status, status_msg, 'HTTP/1.1', res_headers ) if res_body: conn.sendall(res_body) try: conn.close() except: logging.debug('Something went wrong when trying to close socket.', exc_info=3)
def work(self, env): conn = env['mifcho.conn'] i = 0; try: if env['REQUEST_METHOD'] == 'GET' and string.find(env['PATH_INFO'], 'create') > -1: ep_stuff = None prefix = '' method = '' rid = 0 wait = 50 ep_host = '' ep_port = 0 peer_id = None req_path = env['PATH_INFO'].split('/') if len(req_path) == 7: # Directly ep_stuff = ( _, prefix, method, rid, wait, ep_host, ep_port ) = req_path elif len(req_path) == 8: # Via Peer ep_stuff = ( _, prefix, method, rid, wait, ep_host, ep_port, peer_id ) = req_path else: logging.error('Invalid path! %s' % repr(data)) rid = int(rid) wait = int(wait) ep_address = (ep_host, int(ep_port)) # Assume failure, overwritten on successful connect sid = '' ep_status = 404 ep_status_msg = 'Connection Denied.' # Try and connect to end-point try: vnc_conn = self.cm.connect(ep_address, peer_id) if not vnc_conn: logging.error('Could not connect to endpoint!') sid = "%d" % uuid.uuid1().int ep_status = 200 ep_status_msg = 'OK' pipe = HobsVncPiper(self.cm, None, vnc_conn, sink_recovery=(ep_address, peer_id)) HobsHandler.hobs_sessions[sid] = {'rid': rid, 'wait': wait, 'pipe':pipe} pipe.start() except: logging.error('Error when connecting to end-point host %s' % repr(ep_address), exc_info=3) headers = [ ('Content-Length', len(sid)), ('Access-Control-Allow-Origin', '*') ] messages.send_response(conn, ep_status, ep_status_msg, 'HTTP/1.1', headers) conn.sendall(sid) # Receive data that should be forwarded elif env['REQUEST_METHOD'] == 'POST' and string.find(env['PATH_INFO'], 'session') > -1: hobs = HobsHandler._HOBS_SESSION_SEND.search(env['PATH_INFO']) sid = hobs.group(1) rid = int(hobs.group(2)) session = HobsHandler.hobs_sessions[sid] if (session['rid']+1) == rid: session['rid'] = rid else: logging.error('Incorrect RID, %d, %d.' % (rid, session['rid'])) req_txt = '' if len(env['wsgi.input']) > 0: #stuff it into the piper session['pipe'].hobs_in_queue.put(env['wsgi.input']) headers = [ ('Content-Length', '0'), ('Access-Control-Allow-Origin', '*') ] messages.send_response(conn, 200, 'OK', 'HTTP/1.1', headers) # GET, hang on to this until we have something to send... elif env['REQUEST_METHOD'] == 'GET' and string.find(env['PATH_INFO'], 'session') > -1: hobs = HobsHandler._HOBS_SESSION_RECV.search(env['PATH_INFO']) sid = hobs.group(1) data = [] q = HobsHandler.hobs_sessions[sid]['pipe'].hobs_out_queue # Grab data until buffer is empty block = False timeout = 0 while self.running: # This is so far the best strategy... but it seems way too inefficient... severe latency issues.. try: # Get from piper queue data.append(q.get(block, timeout)) # NOTE: This blocking halt delays the exit of mifcho q.task_done() if len(data) > 0 and block: # Data arrived while blocking, timeout is "reset" block = False timeout = 0 except Queue.Empty: if len(data)>0: # Buffer has been sucked dry break elif block: # No data and we have already blocked and timed out break else: # No data so block until data is available or timeout exceeds block = True timeout = 30 buf = base64.b64encode(''.join(data)) headers = [ ('Content-Length', str(len(buf))), ('Content-Type', 'text/plain'), ('Access-Control-Allow-Origin', '*') ] messages.send_response(conn, 200, 'OK', 'HTTP/1.1', headers) conn.sendall(buf) else: logging.error('Unsupported HOBS request! %s.' % (repr(req_uri))) except: logging.error('Something went terribly wrong in the Hobs-handling...', exc_info=3) i += 1 self.cm.teardown(conn)