def do_GET(self, headers_only=False): ''' GET request handler ''' logger = logging.getLogger('do_GET') self.reqtime = time.time() self.connected = True # Set HTTP protocol version if self.request_version == 'HTTP/1.1': self.protocol_version = 'HTTP/1.1' # Don't wait videodestroydelay if error happened self.errorhappened = True # Connected client IP address self.clientip = self.headers['X-Forwarded-For'] \ if self.headers.has_key('X-Forwarded-For') else self.request.getpeername()[0] if AceConfig.firewall: # If firewall enabled self.clientinrange = any(map(lambda i: ipaddr.IPAddress(self.clientip) \ in ipaddr.IPNetwork(i), AceConfig.firewallnetranges)) if (AceConfig.firewallblacklistmode and self.clientinrange) or \ (not AceConfig.firewallblacklistmode and not self.clientinrange): logger.info('Dropping connection from ' + self.clientip + ' due to ' + \ 'firewall rules') self.dieWithError(403) # 403 Forbidden return logger.info("Accepted connection from " + self.clientip + " path " + requests.utils.unquote(self.path).decode('UTF-8')) logger.debug("Headers:\n" + str(self.headers)) try: self.splittedpath = self.path.split('/') self.reqtype = self.splittedpath[1].lower() # If first parameter is 'pid','torrent', 'infohash'.... etc or it should be handled # by plugin if not (self.reqtype in ('pid', 'torrent', 'infohash', 'url', 'raw', 'efile') or self.reqtype in AceStuff.pluginshandlers): self.dieWithError(400) # 400 Bad Request return except IndexError: self.dieWithError(400) # 400 Bad Request return # Handle request with plugin handler if self.reqtype in AceStuff.pluginshandlers: try: AceStuff.pluginshandlers.get(self.reqtype).handle( self, headers_only) except Exception as e: logger.error('Plugin exception: ' + repr(e)) logger.error(traceback.format_exc()) self.dieWithError() finally: self.closeConnection() return self.handleRequest(headers_only)
def do_GET(self, headers_only=False): ''' GET request handler ''' logger = logging.getLogger('do_GET') self.reqtime = time.time() self.connected = True # Don't wait videodestroydelay if error happened self.errorhappened = True # Headers sent flag for fake headers UAs self.headerssent = False # Current greenlet self.requestgreenlet = gevent.getcurrent() # Connected client IP address self.clientip = self.request.getpeername()[0] if AceConfig.firewall: # If firewall enabled self.clientinrange = any(map(lambda i: ipaddr.IPAddress(self.clientip) \ in ipaddr.IPNetwork(i), AceConfig.firewallnetranges)) if (AceConfig.firewallblacklistmode and self.clientinrange) or \ (not AceConfig.firewallblacklistmode and not self.clientinrange): logger.info('Dropping connection from ' + self.clientip + ' due to ' + \ 'firewall rules') self.dieWithError(403) # 403 Forbidden return logger.info("Accepted connection from " + self.clientip + " path " + self.path) try: self.splittedpath = self.path.split('/') self.reqtype = self.splittedpath[1].lower() # If first parameter is 'pid' or 'torrent' or it should be handled # by plugin if not (self.reqtype in ('pid', 'torrent') or self.reqtype in AceStuff.pluginshandlers): self.dieWithError(400) # 400 Bad Request return except IndexError: self.dieWithError(400) # 400 Bad Request return # Handle request with plugin handler if self.reqtype in AceStuff.pluginshandlers: try: AceStuff.pluginshandlers.get(self.reqtype).handle( self, headers_only) except Exception as e: logger.error('Plugin exception: ' + repr(e)) logger.error(traceback.format_exc()) self.dieWithError() finally: self.closeConnection() return self.handleRequest(headers_only)
def handle(self, connection, headers_only=False): current_time = time.time() if connection.reqtype == 'favicon.ico': connection.send_response(404) return connection.send_response(200) connection.send_header('Content-type', 'text/html; charset=utf-8') connection.end_headers() if headers_only: return connection.wfile.write('<meta http-equiv="Refresh" content="60" />' '<html><body><h4>Connected clients: ' + str(self.stuff.clientcounter.total) + '</h4>') connection.wfile.write( '<h5>Concurrent connections limit: ' + str(self.config.maxconns) + '</h5><table border="1" cellspacing="0" cellpadding="3">') for i in self.stuff.clientcounter.clients: for c in self.stuff.clientcounter.clients[i]: connection.wfile.write('<tr><td>') if c.channelIcon: connection.wfile.write('<img src="' + c.channelIcon + '" width="40" height="16" /> ') if c.channelName: connection.wfile.write(c.channelName.encode('UTF8')) else: connection.wfile.write(i) connection.wfile.write('</td><td>' + c.handler.clientip + '</td>') clientinrange = any( map( lambda i: ipaddr.IPAddress(c.handler.clientip) in ipaddr.IPNetwork(i), localnetranges)) if clientinrange: connection.wfile.write('<td>' + 'Local IP adress' + '</td>') else: geo_ip_info = self.geo_ip_lookup(c.handler.clientip) connection.wfile.write( '<td>' + geo_ip_info.get('country').encode('utf-8') + ', ' + geo_ip_info.get('city').encode('utf-8') + '</td>') connection.wfile.write( '<td>' + time.strftime('%c', time.localtime(c.connectionTime)) + '</td>') connection.wfile.write('<td>' + time.strftime( "%H:%M:%S", time.gmtime(current_time - c.connectionTime)) + '</td></tr>') connection.wfile.write('</table></body></html>')
def perform_validation(self): logger = logging.getLogger('http_HTTPHandler.perform_validation') # If firewall enabled if PVRConfig.firewall: self.clientinrange = any(map(lambda i: ipaddr.IPAddress(self.clientip) \ in ipaddr.IPNetwork(i), PVRConfig.firewallnetranges)) if (PVRConfig.firewallblacklistmode and self.clientinrange) or \ (not PVRConfig.firewallblacklistmode and not self.clientinrange): logger.info('Dropping connection from ' + self.clientip + ' due to firewall rules') self.dieWithError(403) # 403 Forbidden raise Exception('Not a valid IP') logger.info("Accepted connection from " + self.clientip) logger.info("RequestURL " + self.path) logger.info("User Agent " + self.headers.get('User-Agent')) try: # If first parameter is 'pid' or 'torrent' or it should be handled # by plugin if not (self.reqtype in (clients.SopcastProcess.ENGINE_TYPE, clients.HLSClient.ENGINE_TYPE) or self.reqtype in clients.AceClient.ENGINE_TYPE or self.reqtype in PVRStuff.pluginshandlers): self.dieWithError(400) # 400 Bad Request raise Exception('Not valid handler') except IndexError: self.dieWithError(400) # 400 Bad Request raise Exception('Not a valid handler') # Check if third parameter exists # …/pid/blablablablabla/video.mpg # |_________| # And if it ends with regular video extension try: if len(self.splittedpath) > 2 and not self.path.endswith( ('.3gp', '.avi', '.flv', '.mkv', '.mov', '.mp4', '.mpeg', '.mpg', '.ogv', '.ts', '.asf')): logger.error( "Request seems like valid but no valid video extension was provided" ) self.dieWithError(400) raise Exception('Not a valid handler video stream') except IndexError: self.dieWithError(400) # 400 Bad Request raise Exception('Not a valid handler video stream')
def do_GET(self, headers_only=False): ''' GET request handler ''' logger = logging.getLogger('http_HTTPHandler') self.clientconnected = True # Don't wait videodestroydelay if error happened self.errorhappened = True # Headers sent flag for fake headers UAs self.headerssent = False # Current greenlet self.requestgreenlet = gevent.getcurrent() # Connected client IP address self.clientip = self.request.getpeername()[0] if AceConfig.firewall: # If firewall enabled self.clientinrange = any(map(lambda i: ipaddr.IPAddress(self.clientip) \ in ipaddr.IPNetwork(i), AceConfig.firewallnetranges)) if (AceConfig.firewallblacklistmode and self.clientinrange) or \ (not AceConfig.firewallblacklistmode and not self.clientinrange): logger.info('Dropping connection from ' + self.clientip + ' due to ' + \ 'firewall rules') self.dieWithError(403) # 403 Forbidden return logger.info("Accepted connection from " + self.clientip + " path " + self.path) try: self.splittedpath = self.path.split('/') self.reqtype = self.splittedpath[1].lower() # If first parameter is 'pid' or 'torrent' or it should be handled # by plugin if not (self.reqtype in ('pid', 'torrent') or self.reqtype in AceStuff.pluginshandlers): self.dieWithError(400) # 400 Bad Request return except IndexError: self.dieWithError(400) # 400 Bad Request return # Handle request with plugin handler if self.reqtype in AceStuff.pluginshandlers: try: AceStuff.pluginshandlers.get(self.reqtype).handle(self) except Exception as e: logger.error('Plugin exception: ', exc_info=True) self.dieWithError() finally: self.closeConnection() return # Check if third parameter exists # …/pid/blablablablabla/video.mpg # |_________| # And if it ends with regular video extension try: if not self.path.endswith( ('.3gp', '.avi', '.flv', '.mkv', '.mov', '.mp4', '.mpeg', '.mpg', '.ogv', '.ts')): logger.error( "Request seems like valid but no valid video extension was provided" ) self.dieWithError(400) return except IndexError: self.dieWithError(400) # 400 Bad Request return # Limit concurrent connections if AceConfig.maxconns > 0 and AceStuff.clientcounter.total >= AceConfig.maxconns: logger.debug("Maximum connections reached, can't serve this") self.dieWithError(503) # 503 Service Unavailable return # Pretend to work fine with Fake UAs or HEAD request. useragent = self.headers.get('User-Agent') fakeua = useragent and useragent in AceConfig.fakeuas if headers_only or fakeua: if fakeua: logger.debug("Got fake UA: " + self.headers.get('User-Agent')) # Return 200 and exit self.send_response(200) self.send_header("Content-Type", "video/mpeg") self.end_headers() self.closeConnection() return self.path_unquoted = urllib2.unquote(self.splittedpath[2]) # Make list with parameters self.params = list() for i in xrange(3, 8): try: self.params.append(int(self.splittedpath[i])) except (IndexError, ValueError): self.params.append('0') # Adding client to clientcounter clients = AceStuff.clientcounter.add(self.path_unquoted, self.clientip) # If we are the one client, but sucessfully got ace from clientcounter, # then somebody is waiting in the videodestroydelay state self.ace = AceStuff.clientcounter.getAce(self.path_unquoted) if not self.ace: shouldcreateace = True else: shouldcreateace = False # Use PID as VLC ID if PID requested # Or torrent url MD5 hash if torrent requested if self.reqtype == 'pid': self.vlcid = self.path_unquoted else: self.vlcid = hashlib.md5(self.path_unquoted).hexdigest() # If we don't use VLC and we're not the first client if clients != 1 and not AceConfig.vlcuse: AceStuff.clientcounter.delete(self.path_unquoted, self.clientip) logger.error( "Not the first client, cannot continue in non-VLC mode") self.dieWithError(503) # 503 Service Unavailable return if shouldcreateace: # If we are the only client, create AceClient try: self.ace = aceclient.AceClient( AceConfig.acehost, AceConfig.aceport, connect_timeout=AceConfig.aceconntimeout, result_timeout=AceConfig.aceresulttimeout) # Adding AceClient instance to pool AceStuff.clientcounter.addAce(self.path_unquoted, self.ace) logger.debug("AceClient created") except aceclient.AceException as e: logger.error("AceClient create exception: " + repr(e)) AceStuff.clientcounter.delete(self.path_unquoted, self.clientip) self.dieWithError(502) # 502 Bad Gateway return # Send fake headers if this User-Agent is in fakeheaderuas tuple if fakeua: logger.debug("Sending fake headers for " + useragent) self.send_response(200) self.send_header("Content-Type", "video/mpeg") self.end_headers() # Do not send real headers at all self.headerssent = True try: self.hanggreenlet = gevent.spawn(self.hangDetector) logger.debug("hangDetector spawned") gevent.sleep() # Initializing AceClient if shouldcreateace: self.ace.aceInit(gender=AceConfig.acesex, age=AceConfig.aceage, product_key=AceConfig.acekey, pause_delay=AceConfig.videopausedelay) logger.debug("AceClient inited") if self.reqtype == 'pid': contentinfo = self.ace.START( self.reqtype, { 'content_id': self.path_unquoted, 'file_indexes': self.params[0] }) elif self.reqtype == 'torrent': self.paramsdict = dict( zip(aceclient.acemessages.AceConst.START_TORRENT, self.params)) self.paramsdict['url'] = self.path_unquoted contentinfo = self.ace.START(self.reqtype, self.paramsdict) logger.debug("START done") # Getting URL self.url = self.ace.getUrl(AceConfig.videotimeout) # Rewriting host for remote Ace Stream Engine self.url = self.url.replace('127.0.0.1', AceConfig.acehost) self.errorhappened = False if shouldcreateace: logger.debug("Got url " + self.url) # If using VLC, add this url to VLC if AceConfig.vlcuse: # Force ffmpeg demuxing if set in config if AceConfig.vlcforceffmpeg: self.vlcprefix = 'http/ffmpeg://' else: self.vlcprefix = '' # Sleeping videodelay gevent.sleep(AceConfig.videodelay) AceStuff.vlcclient.startBroadcast( self.vlcid, self.vlcprefix + self.url, AceConfig.vlcmux, AceConfig.vlcpreaccess) # Sleep a bit, because sometimes VLC doesn't open port in # time gevent.sleep(0.5) # Building new VLC url if AceConfig.vlcuse: self.url = 'http://' + AceConfig.vlchost + \ ':' + str(AceConfig.vlcoutport) + '/' + self.vlcid logger.debug("VLC url " + self.url) # Sending client headers to videostream self.video = urllib2.Request(self.url) for key in self.headers.dict: self.video.add_header(key, self.headers.dict[key]) self.video = urllib2.urlopen(self.video) # Sending videostream headers to client if not self.headerssent: self.send_response(self.video.getcode()) if self.video.info().dict.has_key('connection'): del self.video.info().dict['connection'] if self.video.info().dict.has_key('server'): del self.video.info().dict['server'] if self.video.info().dict.has_key('transfer-encoding'): del self.video.info().dict['transfer-encoding'] if self.video.info().dict.has_key('keep-alive'): del self.video.info().dict['keep-alive'] for key in self.video.info().dict: self.send_header(key, self.video.info().dict[key]) # End headers. Next goes video data self.end_headers() logger.debug("Headers sent") if not AceConfig.vlcuse: # Sleeping videodelay gevent.sleep(AceConfig.videodelay) # Run proxyReadWrite self.proxyReadWrite() # Waiting until hangDetector is joined self.hanggreenlet.join() logger.debug("Request handler finished") except (aceclient.AceException, vlcclient.VlcException, urllib2.URLError) as e: logger.error("Exception: " + repr(e)) self.errorhappened = True self.dieWithError() except gevent.GreenletExit: # hangDetector told us about client disconnection pass except Exception as e: # Unknown exception logger.error("Unknown exception: " + repr(e)) self.errorhappened = True self.dieWithError() finally: logger.debug("END REQUEST") AceStuff.clientcounter.delete(self.path_unquoted, self.clientip) if not self.errorhappened and not AceStuff.clientcounter.get( self.path_unquoted): # If no error happened and we are the only client logger.debug("Sleeping for " + str(AceConfig.videodestroydelay) + " seconds") gevent.sleep(AceConfig.videodestroydelay) if not AceStuff.clientcounter.get(self.path_unquoted): logger.debug("That was the last client, destroying AceClient") if AceConfig.vlcuse: try: AceStuff.vlcclient.stopBroadcast(self.vlcid) except: pass self.ace.destroy() AceStuff.clientcounter.deleteAce(self.path_unquoted)
def handle(self, connection, headers_only=False): current_time = time.time() if connection.reqtype == 'favicon.ico': connection.send_response(404) return connection.wfile.write('<html><head>') connection.wfile.write( '<meta charset="UTF-8" http-equiv="Refresh" content="60"/>') connection.wfile.write('<title>AceProxy stat info</title>') connection.wfile.write( '<link rel="stylesheet" type="text/css" href="http://cloud.github.com/downloads/lafeber/world-flags-sprite/flags16.css"/>' ) connection.wfile.write( '<link rel="shortcut icon" href="http://i.piccy.info/i9/5777461ca749986f6fb4c4b06a70bfbe/1504856430/10417/1177931/SHesterenka_150x150.png" type="image/png">' ) connection.wfile.write('</head>') connection.wfile.write( '<body><div class="f16"><h4>Connected clients: ' + str(self.stuff.clientcounter.total) + '</h4>') connection.wfile.write( '<h5>Concurrent connections limit: ' + str(self.config.maxconns) + '</h5><table border="2" cellspacing="0" cellpadding="3">') connection.wfile.write( '<tr align=CENTER valign=BASELINE BGCOLOR="#eeeee5"><td>Channel name</td><td>Client IP</td><td>Client/Location</td><td>Start time</td><td>Duration</td></tr>' ) for i in self.stuff.clientcounter.clients: for c in self.stuff.clientcounter.clients[i]: connection.wfile.write('<tr><td>') if c.channelIcon: connection.wfile.write('<img src="' + c.channelIcon + '" width="40" height="16"/> ') if c.channelName: connection.wfile.write(c.channelName.encode('UTF8')) else: connection.wfile.write(i) connection.wfile.write('</td><td>' + c.handler.clientip + '</td>') clientinrange = any( map( lambda i: ipaddr.IPAddress(c.handler.clientip) in ipaddr.IPNetwork(i), localnetranges)) if clientinrange: connection.wfile.write('<td>' + self.mac_lookup( c.handler.clientip).encode('UTF8').strip() + '</td>') else: geo_ip_info = self.geo_ip_lookup(c.handler.clientip) connection.wfile.write( '<td>' + geo_ip_info.get('country').encode('UTF8') + ', ' + geo_ip_info.get('city').encode('UTF8') + ' <i class="flag ' + geo_ip_info.get( 'country_code').encode('UTF8').lower() + '"></i> </td>') connection.wfile.write( '<td>' + time.strftime('%c', time.localtime(c.connectionTime)) + '</td>') connection.wfile.write('<td align="center">' + time.strftime( "%H:%M:%S", time.gmtime(current_time - c.connectionTime)) + '</td></tr>') connection.wfile.write('</table></div></body></html>')
def handle(self, connection, headers_only=False): current_time = time.time() if connection.reqtype == 'favicon.ico': connection.send_response(404) return connection.send_response(200) connection.send_header('Content-type', 'text/html; charset=utf-8') connection.send_header('Connection', 'close') connection.end_headers() if headers_only: return # Sys Info cpu_nums = psutil.cpu_count() cpu_percent = psutil.cpu_percent() max_mem = psutil.virtual_memory() disk = psutil.disk_usage('/') connection.wfile.write('<html><head>') connection.wfile.write( '<meta charset="UTF-8" http-equiv="Refresh" content="60"/>') connection.wfile.write('<title>AceProxy stat info</title>') connection.wfile.write( '<link rel="stylesheet" type="text/css" href="http://cloud.github.com/downloads/lafeber/world-flags-sprite/flags16.css"/>' ) connection.wfile.write( '<link rel="shortcut icon" href="http://i.piccy.info/i9/5777461ca749986f6fb4c4b06a70bfbe/1504856430/10417/1177931/SHesterenka_150x150.png" type="image/png">' ) connection.wfile.write('<style>h5 {margin-bottom: -15px;}</style>') connection.wfile.write('</head>') connection.wfile.write('<body><div class="f16">') connection.wfile.write('<p>Connections limit: ' + str(self.config.maxconns) + ' Connected clients: ' + str(self.stuff.clientcounter.total) + '</p>') connection.wfile.write( '<table border="2" cellspacing="0" cellpadding="3">') connection.wfile.write( '<tr align=CENTER valign=BASELINE BGCOLOR="#eeeee5"><td>Channel name/CID</td><td>Client IP</td><td>Client/Location</td><td>Start time</td><td>Duration</td></tr>' ) for i in self.stuff.clientcounter.clients: for c in self.stuff.clientcounter.clients[i]: connection.wfile.write('<tr><td>') if c.channelIcon: connection.wfile.write('<img src="' + c.channelIcon + '" width="40" height="16"/> ') if c.channelName: connection.wfile.write(c.channelName.encode('UTF8')) else: connection.wfile.write(i) connection.wfile.write('</td><td>' + c.handler.clientip + '</td>') clientinrange = any( map( lambda i: ipaddr.IPAddress(c.handler.clientip) in ipaddr.IPNetwork(i), localnetranges)) if clientinrange: connection.wfile.write('<td>' + self.mac_lookup( c.handler.clientip).encode('UTF8').strip() + '</td>') else: geo_ip_info = self.geo_ip_lookup(c.handler.clientip) connection.wfile.write( '<td>' + geo_ip_info.get('country').encode('UTF8') + ', ' + geo_ip_info.get('city').encode('UTF8') + ' <i class="flag ' + geo_ip_info.get( 'country_code').encode('UTF8').lower() + '"></i> </td>') connection.wfile.write( '<td>' + time.strftime('%c', time.localtime(c.connectionTime)) + '</td>') connection.wfile.write('<td align="center">' + time.strftime( "%H:%M:%S", time.gmtime(current_time - c.connectionTime)) + '</td></tr>') connection.wfile.write('</table></div>') connection.wfile.write('<h5>SYSTEM INFO :</h5>') connection.wfile.write('<p><font size="-3">CPU cores: %s' % cpu_nums + ' used : %s' % cpu_percent + '%</br>') connection.wfile.write('RAM MiB ') connection.wfile.write( 'total: %s ' % str(round(max_mem.total / 2**20, 2)) + ' used: %s' % str(round(max_mem.used / 2**20, 2)) + ' free: %s </br>' % str(round(max_mem.available / 2**20, 2))) connection.wfile.write('DISK GiB ') connection.wfile.write( 'total: %s ' % str(round(disk.total / 2**30, 2)) + ' used: %s' % str(round(disk.used / 2**30, 2)) + ' free: %s </font></p>' % str(round(disk.free / 2**30, 2))) connection.wfile.write('</body></html>')