#!/usr/bin/env python

"""
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

# 导入必要的模块
from lib.core.data import conf  # 导入配置信息
from lib.core.enums import HTTP_HEADER  # 导入HTTP头部常量定义
from thirdparty.six.moves import urllib as _urllib  # 导入urllib模块并重命名为_urllib,用于处理URL和HTTP请求

class ChunkedHandler(_urllib.request.HTTPHandler):
    """
    用于确保在使用分块传输编码(Chunked Transfer-Encoding)时HTTPHandler能正常工作的处理器类
    继承自urllib的HTTPHandler类,主要用于处理HTTP请求的发送
    分块传输编码允许HTTP消息在不预先知道消息总长度的情况下进行传输
    """

    def _http_request(self, request):
        """
        处理HTTP请求的核心方法
        参数:
            request: HTTP请求对象,包含请求的所有信息(如URL、头部、数据等)
        返回:
            处理后的request对象
        """
        # 获取请求的主机名,优先使用get_host()方法(新版本),如果不存在则使用host属性(旧版本)
        host = request.get_host() if hasattr(request, "get_host") else request.host
        if not host:
            # 如果没有指定主机名则抛出异常,因为HTTP请求必须知道发送到哪个主机
            raise _urllib.error.URLError("no host given")

        if request.data is not None:  # 如果是POST请求(包含数据)
            data = request.data
            # 如果没有设置Content-Type头,则设置为默认的表单格式
            # application/x-www-form-urlencoded 是最常见的POST数据格式
            if not request.has_header(HTTP_HEADER.CONTENT_TYPE):
                request.add_unredirected_header(HTTP_HEADER.CONTENT_TYPE, "application/x-www-form-urlencoded")
            # 如果没有设置Content-Length头且不使用分块传输,则设置内容长度
            # Content-Length告诉服务器请求体的具体长度
            if not request.has_header(HTTP_HEADER.CONTENT_LENGTH) and not conf.chunked:
                request.add_unredirected_header(HTTP_HEADER.CONTENT_LENGTH, "%d" % len(data))

        # 设置用于选择的主机名
        sel_host = host
        # 如果使用了代理,则从请求选择器中解析出实际的主机名
        # 代理请求时,请求行中包含完整的URL,需要从中提取出真实的主机名
        if request.has_proxy():
            sel_host = _urllib.parse.urlsplit(request.get_selector()).netloc

        # 如果没有设置Host头,则添加Host头
        # Host头是HTTP/1.1必需的头部,用于指定服务器的域名和端口号
        if not request.has_header(HTTP_HEADER.HOST):
            request.add_unredirected_header(HTTP_HEADER.HOST, sel_host)
        # 遍历父类中定义的额外头部信息
        for name, value in self.parent.addheaders:
            name = name.capitalize()  # 将头部名称首字母大写,符合HTTP协议规范
            # 如果请求中没有该头部,则添加到请求中
            # 这确保了自定义头部不会覆盖已有的头部
            if not request.has_header(name):
                request.add_unredirected_header(name, value)
        return request

    # 将_http_request方法赋值给http_request,使其成为标准的处理方法
    # 这是一种Python的惯用法,允许在保留原始方法的同时提供一个公开的接口
    http_request = _http_request
