用Python创建代理Web服务器S2

先决条件:在Python中创建代理Web服务器– Set1
在本教程中, 添加了一些有趣的功能以使其更有用。

  • 将网域加入黑名单。对于前google.com, facebook.com。在我们的配置字典中创建BLACKLIST_DOMAINS的列表。现在, 只需忽略/删除收到的列入黑名单的域的请求即可。 (理想情况下, 我们必须以禁止的回应来回应。)
    # 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地址:
    • 在Server类中创建一个新方法_ishostAllowed, 并使用fnmatch模块来匹配正则表达式。遍历所有正则表达式, 如果匹配任何正则表达式则允许请求。如果没有发现客户地址是任何正则表达式的一部分, 则发送一个FORBIDDEN响应。再次, 现在跳过此响应创建部分。
注意:在接下来的教程中, 我们将创建完整的自定义Web服务器, 在那里将创建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'

【用Python创建代理Web服务器S2】模块:
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)

如果你有任何意见/建议/疑问, 请随时提问。 ??
关于作者:
Pinkesh Badjatiya来自海得拉巴(IIIT)海德拉巴。可见他的项目工作这里。
如果你还希望在此处展示你的博客, 请参阅日志用于在lsbin上撰写访客博客。
首先, 你的面试准备可通过以下方式增强你的数据结构概念:Python DS课程。

    推荐阅读