Creación de un servidor web proxy en Python | conjunto 2 – Part 1

Requisito previo: Creación de un servidor web proxy en Python – Set1 

En este tutorial, se agregan algunas características interesantes para hacerlo más útil. 

  • Añadir listas negras de dominios . por ej. google.com, facebook.com. Cree una lista de BLACKLIST_DOMAINS en nuestro dictamen de configuración. Por ahora, simplemente ignore o descarte las requests recibidas para dominios en la lista negra. (Idealmente, debemos responder con una respuesta prohibida). 
      
# Check if the host:port is blacklisted
for i in range(0, len(config['BLACKLIST_DOMAINS'])):
    if config['BLACKLIST_DOMAINS'][i] in url:
        conn.close()
return
  • Para agregar bloqueo de host: digamos, es posible que deba permitir conexiones de una subred en particular o conexión para una persona en particular. Para agregar esto, cree una lista de todos los hosts permitidos. Dado que los hosts también pueden ser una subred, agregue expresiones regulares para hacer coincidir las direcciones IP, específicamente las direcciones IPV4. “ Las direcciones IPv4 se representan canónicamente en notación decimal de puntos, que consta de cuatro números decimales, cada uno de los cuales va del 0 al 255, separados por puntos, por ejemplo, 172.16.254.1. Cada parte representa un grupo de 8 bits (octeto) de la dirección.”
  • Uso de expresiones regulares para hacer coincidir las direcciones IP correctas: 
    • Cree un nuevo método, _ishostAllowed en la clase Servidor, y use el módulo fnmatch para hacer coincidir las expresiones regulares. Iterar a través de todas las expresiones regulares y permitir la solicitud si coincide con alguna de ellas. Si no se encuentra que la dirección de un cliente sea parte de ninguna expresión regular, envíe una respuesta PROHIBIDA. Nuevamente, por ahora, omita esta parte de creación de respuesta.

Nota: Estaremos creando un servidor web personalizado completo en los próximos tutoriales, allí se creará una función createResponse para manejar la creación de la respuesta genérica.

def _ishostAllowed(self, host):

    """ Check if host is allowed to access
        the content """
    for wildcard in config['HOST_ALLOWED']:
        if fnmatch.fnmatch(host, wildcard):
            return True
    return False

La expresión regular de coincidencia de host predeterminada sería ‘*’ para que coincida con todos los hosts. Sin embargo, también se puede usar la expresión regular de la forma ‘192.168.*’. El servidor actualmente procesa requests pero no muestra ningún mensaje, por lo que no conocemos el estado del servidor. Sus mensajes deben registrarse en la consola. Para ello, utilice el módulo de registro, ya que es seguro para subprocesos. (el servidor tiene varios subprocesos, si lo recuerda).

Importe el módulo y establezca su configuración inicial.  

logging.basicConfig(level = logging.DEBUG,
format = '[%(CurrentTime)-10s] (%(ThreadName)-10s) %(message)s',)
  • Cree un método separado que registre cada mensaje : páselo como un argumento, con datos adicionales como el nombre del hilo y la hora actual para realizar un seguimiento de los registros. Además, cree una función que coloree los registros para que se vean bonitos en STDOUT. 
    Para lograr esto, agregue un booleano en la configuración, COLORED_LOGGING, y cree una nueva función que coloree cada mensaje que se le pasa en función del LOG_LEVEL.
def log(self, log_level, client, msg):

    """ Log the messages to appropriate place """
    LoggerDict = {
       'CurrentTime' : strftime("%a, %d %b %Y %X", localtime()),
       'ThreadName' : threading.currentThread().getName()
    }
    if client == -1: # Main Thread
        formatedMSG = msg
    else: # Child threads or Request Threads
        formatedMSG = '{0}:{1} {2}'.format(client[0], client[1], msg)
    logging.debug('%s', utils.colorizeLog(config['COLORED_LOGGING'],
    log_level, formatedMSG), extra=LoggerDict)
  • Cree un nuevo módulo, ColorizePython.py:  contiene una clase pycolors que mantiene una lista de códigos de color. Separe esto en otro módulo para que el código sea modular y siga los estándares PEP8.
# ColorizePython.py
class pycolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m' # End color
BOLD = '\033[1m'
UNDERLINE = '\033[4m'

Módulo: 

import ColorizePython

Método: 

def colorizeLog(shouldColorize, log_level, msg):
    ## Higher is the log_level in the log()
    ## argument, the lower is its priority.
    colorize_log = {
    "NORMAL": ColorizePython.pycolors.ENDC,
    "WARNING": ColorizePython.pycolors.WARNING,
    "SUCCESS": ColorizePython.pycolors.OKGREEN,
    "FAIL": ColorizePython.pycolors.FAIL,
    "RESET": ColorizePython.pycolors.ENDC
    }

    if shouldColorize.lower() == "true":
        if log_level in colorize_log:
            return colorize_log[str(log_level)] + msg + colorize_log['RESET']
        return colorize_log["NORMAL"] + msg + colorize_log["RESET"]
    return msg 
  • Dado que colorizeLog no es una función de una clase de servidor, se crea como un módulo separado llamado utils.py que almacena toda la utilidad que hace que el código sea más fácil de entender y coloca este método allí. Agregue mensajes de registro apropiados donde sea necesario, especialmente cuando cambie el estado del servidor .
  • Modifique el método de apagado en el servidor para salir de todos los subprocesos en ejecución antes de salir de la aplicación. threading.enumerate() itera sobre todos los subprocesos en ejecución, por lo que no necesitamos mantener una lista de ellos. El comportamiento del módulo de subprocesos es inesperado cuando intentamos finalizar main_thread. La documentación oficial también establece esto:

“join() genera un RuntimeError si se intenta unir el subproceso actual, ya que eso provocaría un punto muerto. También es un error unirse() a un hilo antes de que se haya iniciado y los intentos de hacerlo generan la misma excepción”. 

Por lo tanto, sáltelo apropiadamente. Aquí está el código para el mismo. 

def shutdown(self, signum, frame):
    """ Handle the exiting server. Clean all traces """
    self.log("WARNING", -1, 'Shutting down gracefully...')
    main_thread = threading.currentThread() # Wait for all clients to exit
    for t in threading.enumerate():
        if t is main_thread:
            continue
            self.log("FAIL", -1, 'joining ' + t.getName())
        t.join()
        self.serverSocket.close()
    sys.exit(0)

Si tiene algún comentario/sugerencia/consulta, no dude en preguntar. 🙂 
 

Si también desea exhibir su blog aquí, consulte GBlog para escribir un blog invitado en GeeksforGeeks.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *