Рубрики

Создание прокси-сервера в Python | Набор 2

Предварительное условие : создание прокси-сервера в Python — Set1

В этом уроке добавлено несколько интересных функций, чтобы сделать его более полезным.

  • Добавить черный список доменов . Например google.com, facebook.com. Создайте список BLACKLIST_DOMAINS в нашей конфигурации dict. Пока просто игнорируйте / отбрасывайте запросы, полученные для занесенных в черный список доменов. (В идеале мы должны ответить запрещенным ответом.)
          
    # 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
    
  • Чтобы добавить блокировку хоста: скажем, вам может потребоваться разрешить соединения из определенной подсети или соединения для конкретного человека. Чтобы добавить это, создайте список всех разрешенных хостов. Поскольку узлы также могут быть подсетью, добавьте регулярное выражение для сопоставления IP-адресов, в частности адресов IPV4. «Адреса IPv4 канонически представлены в десятичной системе счисления, которая состоит из четырех десятичных чисел, каждое в диапазоне от 0 до 255, разделенных точками, например, 172.16.254.1. Каждая часть представляет группу из 8 битов (октет) адреса ».
  • Использование регулярных выражений для сопоставления правильных IP-адресов:
    • Создайте новый метод _ishostAllowed в классе Server и используйте модуль fnmatch для сопоставления регулярным выражениям. Переберите все регулярные выражения и разрешите запрос, если он соответствует любому из них. Если не обнаружено, что адрес клиента является частью какого-либо регулярного выражения, отправьте ответ FORBIDDEN. Опять же, пока пропустите эту часть создания ответа.

Примечание: мы будем создавать полноценный пользовательский веб-сервер в следующих уроках, там будет сделано создание функции createResponse для обработки создания общего ответа.

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

Регулярное выражение соответствия хоста по умолчанию будет '*', чтобы соответствовать всем хостам. Тем не менее, также можно использовать регулярное выражение в форме «192.168. *». Сервер в настоящее время обрабатывает запросы, но не показывает никаких сообщений, поэтому мы не знаем о состоянии сервера. Его сообщения должны быть зарегистрированы на консоли. Для этого используйте модуль логирования, так как он безопасен для потоков. (сервер многопоточный, если вы помните.)

Импортируйте модуль и настройте его начальную конфигурацию.

logging.basicConfig(level = logging.DEBUG,
format = '[%(CurrentTime)-10s] (%(ThreadName)-10s) %(message)s',)
  • Создайте отдельный метод, который регистрирует каждое сообщение : передайте его как аргумент с дополнительными данными, такими как имя потока и текущее время, чтобы отслеживать журналы. Также создайте функцию, которая раскрашивает логи так, чтобы они выглядели красиво на STDOUT.
    Чтобы добиться этого, добавьте логическое значение в конфигурации COLORED_LOGGING и создайте новую функцию, которая раскрашивает каждую передаваемую ей сообщение на основе 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)
  • Создайте новый модуль ColorizePython.py: он содержит класс pycolors, который поддерживает список цветовых кодов. Разделите это на другой модуль, чтобы сделать код модульным и следовать стандартам 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'

Модуль:

import ColorizePython

Метод:

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
  • Поскольку colorizeLog не является функцией серверного класса, он создается как отдельный модуль с именем utils.py, в котором хранятся все утилиты, облегчающие понимание кода, и помещающие этот метод в него. Добавьте соответствующие сообщения журнала, где это необходимо, особенно когда состояние сервера изменяется.
  • Измените метод завершения работы на сервере, чтобы закрыть все запущенные потоки перед выходом из приложения. threading.enumerate () выполняет итерации по всем запущенным потокам, поэтому нам не нужно вести их список. Поведение модуля потоков является неожиданным, когда мы пытаемся завершить main_thread. Официальная документация также гласит:

«Join () вызывает RuntimeError, если предпринята попытка присоединиться к текущему потоку, так как это приведет к взаимоблокировке. Также ошибка присоединения () к потоку до его запуска, и попытка сделать это вызывает то же исключение ».

Итак, пропустите это соответствующим образом. Вот код для того же.

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)

Если у вас есть какие-либо комментарии / предложения / вопросы, не стесняйтесь спрашивать. 🙂

Об авторе:

Пинкеш Баджатия родом из IIIT Хайдарабада. Он — вундеркинд с множеством проектов, достойных внимания. Его проектную работу можно увидеть здесь.

Если вы также хотите продемонстрировать свой блог здесь, пожалуйста, смотрите GBlog для записи гостевого блога на GeeksforGeeks.

Рекомендуемые посты:

Создание прокси-сервера в Python | Набор 2

0.00 (0%) 0 votes