'基线重置,修复了一些 bug,fix(llvmlite): build_alloca_at_entry 在已终止入口块后在 br 后追加 alloca 致非法 IR嵌套循环(如 LoopTest.test_nested_loop 内层 for)内联新建循环变量 alloca 时,入口块已以 br 终止,block_append_text 把 alloca 追加到终止指令之后,生成不可达指令,llc 报 "instruction expected to be numbered %N or greater"。改用 block_insert_text_before_terminator:未终止等同追加,已终止插到终止指令之前;编号乱序由 RenumberSSA 重排处理。'

This commit is contained in:
TermiNexus committed 2026-09-07 15:05:50 +08:00
1 parent 62bceb6930
commit f53c2216aa
11 files changed
+2139 -117

No files matched your search

+664
View File
@@ -0,0 +1,664 @@
import t, c
from stdint import *
import string
import socket
import stdio
import stdlib
import requests
import openssl
# ============================================================
# requests/https.vp — HTTPS 客户端(openssl SSL/TLS + 证书核验)
#
# 与 requests(HTTP)同名 API,但走 TLS 并默认校验对端证书:
# import requests.https as rhttps
# resp = rhttps.get("https://example.com/", verify=True)
# if resp is not None:
# print(resp.status_code)
# print(resp.text)
# requests.release(resp)
#
# 说明:
# - verify=True 时校验证书链 + 主机名(hostname 校验 SSL_set1_host),
# 提供 ca_file 指向 PEM CA bundle;不提供则走系统默认路径
# (Windows 上通常为空,真实站点会因"无法验证证书链"失败返回 None)。
# - 失败时返回 None,可用 last_error() 获取原因文本。
# - 握手成功后可用 last_tls_info() 查看 TLS 版本 / 加密套件 / 对端证书主题。
# ============================================================
HTTPS_PORT: t.CDefine = 443
# 模块内部状态
_ossl_ready: bool = False
_socket_ready: bool = False
_err_store: t.CArray[t.CChar, 512] # 最近一次失败原因(静态缓冲)
_info_store: t.CArray[t.CChar, 512] # 最近一次成功握手的 TLS 元信息
_scratch_store: t.CArray[t.CChar, 512] # 临时拼接缓冲
_last_verify_val: INT = -1 # 最近一次握手后 SSL_get_verify_result(0=通过;-1=未启用)
_last_verify_flag: INT = -1 # 最近一次请求 verify 标志(1=开启;0=关闭;-1=未知)
def last_verify_result() -> int:
"""返回最近一次握手的证书校验结果:0 通过;>0 失败码;-1 未开启校验。"""
return _last_verify_val
def last_verify_enabled() -> int:
"""返回最近一次请求是否开启校验(1=是;0=否;-1=未知)。"""
return _last_verify_flag
# ============================================================
# 内部辅助
# ============================================================
def last_error() -> str:
"""返回最近一次失败的原因文本(无则空串)。"""
return _err_store
def last_tls_info() -> str:
"""返回最近一次成功握手的 TLS 信息(版本/套件/对端主题),无则空串。"""
return _info_store
def _RecordErrorText(text: str):
"""把失败原因写入静态缓冲 _err_store。"""
if text is None: return
_err_store[0] = 0
stdio.snprintf(_err_store, 512, "%s", text)
def _RecordInfoText(text: str):
"""把 TLS 元信息写入静态缓冲 _info_store。"""
if text is None: return
_info_store[0] = 0
stdio.snprintf(_info_store, 512, "%s", text)
def _EnsureReady() -> INT:
"""初始化 socket 与 openssl(均幂等)。"""
global _socket_ready, _ossl_ready
if not _socket_ready:
if socket.SocketInit() != 0:
_RecordErrorText("socket init failed")
return -1
_socket_ready = True
if not _ossl_ready:
if openssl.OPENSSL_init_ssl(0, None) != 1:
_RecordErrorText("OPENSSL_init_ssl failed")
return -1
_ossl_ready = True
return 0
def _ParseHttpsUrl(url: str, host_buf: str, host_size: INT, path_buf: str, path_size: INT, port: INT | t.CPtr) -> INT:
"""解析 https://host[:port][/path],端口缺省 443。"""
if url is None: return -1
if host_buf is None or path_buf is None or port is None: return -1
p: str = url
# Skip "https://"(8 字节)
if string.strncmp(p, "https://", 8) == 0:
p += 8
# Parse host
host_start: str = p
host_len: INT = 0
while p[0] != '\0' and p[0] != ':' and p[0] != '/':
host_len += 1
p += 1
if host_len == 0 or host_len >= host_size: return -1
string.strncpy(host_buf, host_start, host_len)
host_buf[host_len] = 0
# Parse port
if p[0] == ':':
p += 1
port_val: INT = 0
while p[0] >= '0' and p[0] <= '9':
port_val = port_val * 10 + INT(p[0] - '0')
p += 1
c.DerefAs(port, port_val)
else:
c.DerefAs(port, HTTPS_PORT)
# Parse path
if p[0] == '/':
path_start: str = p
path_len: INT = 0
while p[0] != '\0':
path_len += 1
p += 1
if path_len >= path_size: return -1
string.strncpy(path_buf, path_start, path_len)
path_buf[path_len] = 0
else:
if path_size < 2: return -1
path_buf[0] = '/'
path_buf[1] = 0
return 0
def _ScratchBuf() -> str:
"""返回静态拼接缓冲(512B,复用)。"""
return _scratch_store
def _TlsErrText():
"""把最近一次 openssl 错误队列文本写入静态 scratch 缓冲。"""
e: t.CUInt32T = openssl.ERR_get_error()
if e == 0:
_scratch_store[0] = 0
string.strncpy(_scratch_store, "openssl error (no detail)", 26)
return
openssl.ERR_error_string_n(e, _scratch_store, 512)
# ============================================================
# 核心请求
# ============================================================
def _HttpsRequest(method: str, url: str, verify: bool, ca_file: str, data: str, content_type: str) -> requests.Response | t.CPtr:
"""HTTPS GET/POST 核心实现。
verify=False 时跳过证书链/主机名校验(不推荐);verify=True 时
ca_file 提供 PEM CA bundle,否则使用系统默认 CA 路径。
"""
global _last_verify_val, _last_verify_flag
if requests._mbuddy is None: return None
_last_verify_flag = 1 if verify else 0
resp: requests.Response | t.CPtr = requests.create_response()
if resp is None: return None
if _EnsureReady() != 0:
requests.release(resp)
return None
# 临时缓冲(错误文本格式化;openssl 详情走模块级 scratch)
errmsg: str = requests._mbuddy.alloc(512)
if errmsg is None:
requests.release(resp)
return None
# ---- 解析 URL ----
host_buf: t.CArray[t.CChar, 256]
path_buf: t.CArray[t.CChar, 1024]
port: INT = 0
if _ParseHttpsUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0:
stdio.snprintf(errmsg, 512, "bad https url: %s", url)
_RecordErrorText(errmsg)
requests._mbuddy.free(errmsg)
requests.release(resp)
return None
# ---- 建立 TCP 连接 ----
sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM)
if sock.fd == socket.INVALID_SOCKET:
_RecordErrorText("socket() failed")
requests._mbuddy.free(errmsg)
requests.release(resp)
return None
if sock.connect(host_buf, port) != 0:
stdio.snprintf(errmsg, 512, "connect %s:%d failed", host_buf, port)
_RecordErrorText(errmsg)
sock.close()
requests._mbuddy.free(errmsg)
requests.release(resp)
return None
# ---- SSL_CTX / SSL ----
ctx: openssl.SslCtxPtr = openssl.SSL_CTX_new(openssl.TLS_client_method())
if ctx is None:
_RecordErrorText("SSL_CTX_new failed")
sock.close()
requests._mbuddy.free(errmsg)
requests.release(resp)
return None
if verify:
openssl.SSL_CTX_set_verify(ctx, openssl.SslVerifyPeer, None)
if ca_file is not None and ca_file[0] != 0:
if openssl.SSL_CTX_load_verify_locations(ctx, ca_file, None) != 1:
_TlsErrText()
stdio.snprintf(errmsg, 512, "load CA file failed: %s (%s)", ca_file, _ScratchBuf())
_RecordErrorText(errmsg)
openssl.SSL_CTX_free(ctx)
sock.close()
requests._mbuddy.free(errmsg)
requests.release(resp)
return None
else:
# 系统默认路径(Windows 上通常为空,证书链校验将失败)
openssl.SSL_CTX_set_default_verify_paths(ctx)
else:
openssl.SSL_CTX_set_verify(ctx, openssl.SslVerifyNone, None)
ssl: openssl.SslPtr = openssl.SSL_new(ctx)
if ssl is None:
_RecordErrorText("SSL_new failed")
openssl.SSL_CTX_free(ctx)
sock.close()
requests._mbuddy.free(errmsg)
requests.release(resp)
return None
openssl.SSL_set_fd(ssl, sock.fd)
# SNI(SSL_set_tlsext_host_name 是宏 → 直接 SSL_ctrl)
openssl.SSL_ctrl(ssl, openssl.SslCtrlSetTlsextHostname, openssl.TlsextNametypeHostName, host_buf)
# 主机名校验(TLS 内核对证书 SAN/CN 与 host 比对)
if verify:
openssl.SSL_set1_host(ssl, host_buf)
# ---- 握手 ----
hret: INT = openssl.SSL_connect(ssl)
if hret <= 0:
want: INT = openssl.SSL_get_error(ssl, hret)
_TlsErrText()
stdio.snprintf(errmsg, 512, "SSL_connect failed (want=%d): %s", want, _ScratchBuf())
_RecordErrorText(errmsg)
openssl.SSL_free(ssl)
openssl.SSL_CTX_free(ctx)
sock.close()
requests._mbuddy.free(errmsg)
requests.release(resp)
return None
# ---- 记录最近一次证书校验结果(供 last_verify_result 查询)----
if verify:
_last_verify_val = INT(openssl.SSL_get_verify_result(ssl))
else:
_last_verify_val = -1
# ---- 证书链校验结果复核 ----
if verify:
vres: t.CInt32T = openssl.SSL_get_verify_result(ssl)
if vres != 0:
reason: str = openssl.X509_verify_cert_error_string(vres)
if reason is None:
stdio.snprintf(errmsg, 512, "SSL certificate verify failed: error %d", INT(vres))
else:
stdio.snprintf(errmsg, 512, "SSL certificate verify failed (%d): %s", INT(vres), reason)
_RecordErrorText(errmsg)
openssl.SSL_free(ssl)
openssl.SSL_CTX_free(ctx)
sock.close()
requests._mbuddy.free(errmsg)
requests.release(resp)
return None
# ---- 记录 TLS 元信息(版本 / 套件 / 对端证书主题)----
name_buf: str = requests._mbuddy.alloc(512)
if name_buf is not None:
peer: openssl.X509Ptr = openssl.SSL_get1_peer_certificate(ssl)
if peer is not None:
subj: openssl.X509NamePtr = openssl.X509_get_subject_name(peer)
if subj is not None:
name_buf[0] = 0
openssl.X509_NAME_oneline(subj, name_buf, 512)
name_buf[511] = 0
openssl.X509_free(peer)
else:
name_buf[0] = 0
string.strncpy(name_buf, "(no peer certificate)", 21)
name_buf[21] = 0
ver: str = openssl.SSL_get_version(ssl)
cipher: str = openssl.SSL_CIPHER_get_name(openssl.SSL_get_current_cipher(ssl))
stdio.snprintf(errmsg, 512, "%s | cipher %s | peer: %s",
ver if ver is not None else "?", cipher if cipher is not None else "?", name_buf)
_RecordInfoText(errmsg)
requests._mbuddy.free(name_buf)
# ---- 组请求头并发送 ----
req_buf: str = requests._mbuddy.alloc(requests.HTTP_BUFSIZ)
if req_buf is None:
_RecordErrorText("alloc request buffer failed")
openssl.SSL_free(ssl)
openssl.SSL_CTX_free(ctx)
sock.close()
requests._mbuddy.free(errmsg)
requests.release(resp)
return None
body_len: INT = 0
is_post: bool = string.strcmp(method, "POST") == 0
if is_post:
body_len = INT(string.strlen(data)) if data is not None else 0
ct: str = content_type if content_type is not None else "application/x-www-form-urlencoded"
stdio.snprintf(req_buf, requests.HTTP_BUFSIZ,
"POST %s HTTP/1.1\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\nAccept-Encoding: gzip\r\nConnection: close\r\n\r\n",
path_buf, host_buf, ct, body_len)
else:
stdio.snprintf(req_buf, requests.HTTP_BUFSIZ,
"GET %s HTTP/1.1\r\nHost: %s\r\nAccept-Encoding: gzip\r\nConnection: close\r\n\r\n",
path_buf, host_buf)
hdr_len: INT = INT(string.strlen(req_buf))
sent: INT = openssl.SSL_write(ssl, req_buf, hdr_len)
if sent <= 0:
_TlsErrText()
stdio.snprintf(errmsg, 512, "SSL_write header failed: %s", _ScratchBuf())
_RecordErrorText(errmsg)
requests._mbuddy.free(req_buf)
openssl.SSL_free(ssl)
openssl.SSL_CTX_free(ctx)
sock.close()
requests._mbuddy.free(errmsg)
requests.release(resp)
return None
if is_post and body_len > 0 and data is not None:
openssl.SSL_write(ssl, data, body_len)
requests._mbuddy.free(req_buf)
# ---- 接收响应 ----
resp_buf: str = requests._mbuddy.alloc(requests.HTTP_BUFSIZ)
if resp_buf is None:
_RecordErrorText("alloc response buffer failed")
openssl.SSL_free(ssl)
openssl.SSL_CTX_free(ctx)
sock.close()
requests._mbuddy.free(errmsg)
requests.release(resp)
return None
total: INT = 0
while total < requests.HTTP_BUFSIZ - 1:
n: INT = openssl.SSL_read(ssl, resp_buf + total, requests.HTTP_BUFSIZ - 1 - total)
if n <= 0: break
total += n
resp_buf[total] = 0
# 关闭 TLS 与 TCP
openssl.SSL_shutdown(ssl)
openssl.SSL_free(ssl)
openssl.SSL_CTX_free(ctx)
sock.close()
resp._raw_buf = resp_buf
requests.parse_response(resp, total)
requests._mbuddy.free(errmsg)
return resp
# ============================================================
# 公共 API
# ============================================================
def _HttpsRedirectLoop(method: str, url: str, verify: bool, ca_file: str, data: str, content_type: str) -> requests.Response | t.CPtr:
"""HTTPS GET/POST + 重定向跟随(跨 http/https,最多 5 跳)。"""
if requests._mbuddy is None: return None
cur: str = requests._mbuddy.alloc(2048)
if cur is None: return None
if INT(string.strlen(url)) >= 2047:
_RecordErrorText("url too long")
requests._mbuddy.free(cur)
return None
string.strcpy(cur, url)
hop: INT = 0
while hop < 5:
resp: requests.Response | t.CPtr = _HttpsRequest(method, cur, verify, ca_file, data, content_type)
if resp is None:
requests._mbuddy.free(cur)
return None
code: INT = resp.status_code
if not (code >= 300 and code < 400):
requests._mbuddy.free(cur)
return resp
loc: str = requests._mbuddy.alloc(2048)
if loc is None:
requests._mbuddy.free(cur)
return resp
if requests.header_value(resp, "Location", loc, 2048) != 0:
requests._mbuddy.free(loc)
requests._mbuddy.free(cur)
return resp
nxt: str = requests._mbuddy.alloc(2048)
if nxt is None:
requests._mbuddy.free(loc)
requests._mbuddy.free(cur)
return resp
if requests._ResolveRedirectUrl(cur, loc, nxt, 2048) != 0:
_RecordErrorText("unresolvable redirect Location")
requests.release(resp)
requests._mbuddy.free(nxt)
requests._mbuddy.free(loc)
requests._mbuddy.free(cur)
return None
requests.release(resp)
# 跨协议分流:https → 继续本循环;http → 交给 requests(http)链
if string.strncmp(nxt, "https://", 8) != 0:
requests._mbuddy.free(loc)
requests._mbuddy.free(cur)
http_resp: requests.Response | t.CPtr = requests.get(nxt)
requests._mbuddy.free(nxt)
return http_resp
requests._mbuddy.free(loc)
requests._mbuddy.free(cur)
cur = nxt
hop += 1
_RecordErrorText("too many redirects")
requests._mbuddy.free(cur)
return None
def get(url: str, verify: bool = True, ca_file: str = None) -> requests.Response | t.CPtr:
"""HTTPS GET request(自动跟随 3xx 重定向,最多 5 跳)。
Args:
url: Full URL (e.g., "https://example.com/path")
verify: True 时校验证书链 + 主机名(默认)
ca_file: PEM CA bundle 路径;None 时使用系统默认 CA 路径
Returns:
Pointer to a Response object, None on failure (see last_error()).
"""
return _HttpsRedirectLoop("GET", url, verify, ca_file, None, None)
def post(url: str, data: str = None, content_type: str = "application/x-www-form-urlencoded",
verify: bool = True, ca_file: str = None) -> requests.Response | t.CPtr:
"""HTTPS POST request(自动跟随 3xx 重定向,最多 5 跳)。
Args:
url: Full URL
data: Request body data
content_type: Content-Type header
verify: True 时校验证书链 + 主机名(默认)
ca_file: PEM CA bundle 路径;None 时使用系统默认 CA 路径
Returns:
Pointer to a Response object, None on failure (see last_error()).
"""
return _HttpsRedirectLoop("POST", url, verify, ca_file, data, content_type)
# ============================================================
# 大文件 Range 下载原语(requests.download 使用,与 requests._DlOnce 镜像)
#
# 线程安全:本函数不使用 _mbuddy(请求/响应缓冲一律 stdlib),每个连接独立
# SSL_CTX/SSL/socket,供多线程并行切片并发调用(OPENSSL_init_ssl 由主线程
# 先 _EnsureReady 预热一次)。
#
# 返回: >=0 响应体字节数;-1 参数错;-2 3xx 重定向(Location 写 out_loc);
# -3 其它失败(last_error() 查看原因)。
# ============================================================
def _DlOnce(url: str, start: t.CSizeT, count: INT, verify: bool, ca_file: str,
dst: str, dst_cap: INT, out_status: INT | t.CPtr,
out_loc: str, out_loccap: INT,
out_total: t.CSizeT | t.CPtr) -> INT:
"""HTTPS 单次 Range 拉取(线程安全,见模块注释)。"""
global _last_verify_val, _last_verify_flag
if url is None or dst is None or dst_cap <= 0 \
or out_status is None or out_total is None:
return -1
c.Set(c.Deref(out_status), 0)
c.Set(c.Deref(out_total), 0)
if out_loc is not None and out_loccap > 0:
out_loc[0] = 0
_last_verify_flag = 1 if verify else 0
if _EnsureReady() != 0:
return -3
host_buf: t.CArray[t.CChar, 256]
path_buf: t.CArray[t.CChar, 1024]
port: INT = 0
if _ParseHttpsUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0:
_RecordErrorText("bad https url")
return -3
sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM)
if sock.fd == socket.INVALID_SOCKET:
_RecordErrorText("socket() failed")
return -3
if sock.connect(host_buf, port) != 0:
_RecordErrorText("connect failed")
sock.close()
return -3
ctx: openssl.SslCtxPtr = openssl.SSL_CTX_new(openssl.TLS_client_method())
if ctx is None:
_RecordErrorText("SSL_CTX_new failed")
sock.close()
return -3
if verify:
openssl.SSL_CTX_set_verify(ctx, openssl.SslVerifyPeer, None)
if ca_file is not None and ca_file[0] != 0:
if openssl.SSL_CTX_load_verify_locations(ctx, ca_file, None) != 1:
_RecordErrorText("load CA file failed")
openssl.SSL_CTX_free(ctx)
sock.close()
return -3
else:
openssl.SSL_CTX_set_default_verify_paths(ctx)
else:
openssl.SSL_CTX_set_verify(ctx, openssl.SslVerifyNone, None)
ssl: openssl.SslPtr = openssl.SSL_new(ctx)
if ssl is None:
_RecordErrorText("SSL_new failed")
openssl.SSL_CTX_free(ctx)
sock.close()
return -3
openssl.SSL_set_fd(ssl, sock.fd)
openssl.SSL_ctrl(ssl, openssl.SslCtrlSetTlsextHostname, openssl.TlsextNametypeHostName, host_buf)
if verify:
openssl.SSL_set1_host(ssl, host_buf)
hret: INT = openssl.SSL_connect(ssl)
if hret <= 0:
_RecordErrorText("SSL_connect failed")
openssl.SSL_free(ssl)
openssl.SSL_CTX_free(ctx)
sock.close()
return -3
if verify:
_last_verify_val = INT(openssl.SSL_get_verify_result(ssl))
if _last_verify_val != 0:
_RecordErrorText("SSL certificate verify failed")
openssl.SSL_free(ssl)
openssl.SSL_CTX_free(ctx)
sock.close()
return -3
else:
_last_verify_val = -1
# 组 Range 请求头(不带 Accept-Encoding,保证响应为原始字节)
req: str = stdlib.malloc(1024)
if req is None:
openssl.SSL_free(ssl)
openssl.SSL_CTX_free(ctx)
sock.close()
return -3
cnt: INT = count
if cnt < 0:
cnt = 0
end: t.CSizeT = start + t.CSizeT(cnt) - 1
if cnt <= 0:
end = start
stdio.snprintf(req, 1024,
"GET %s HTTP/1.1\r\nHost: %s\r\nRange: bytes=%zu-%zu\r\nConnection: close\r\n\r\n",
path_buf, host_buf, start, end)
sent: INT = openssl.SSL_write(ssl, req, INT(string.strlen(req)))
stdlib.free(req)
if sent <= 0:
_RecordErrorText("SSL_write failed")
openssl.SSL_free(ssl)
openssl.SSL_CTX_free(ctx)
sock.close()
return -3
total: INT = 0
tgt: INT = -1
while total < dst_cap - 1:
room: INT = dst_cap - 1 - total
if room > 4096:
room = 4096
n: INT = openssl.SSL_read(ssl, dst + total, room)
if n <= 0:
break
total += n
if tgt < 0:
bo: INT = requests._FindBodyStart(dst, total)
if bo >= 0:
cl: INT = requests._CLenOf(dst, total)
if cl >= 0:
tgt = bo + cl
if tgt >= 0 and total >= tgt:
break
openssl.SSL_shutdown(ssl)
openssl.SSL_free(ssl)
openssl.SSL_CTX_free(ctx)
sock.close()
dst[total] = 0
st: INT = requests._StatusRaw(dst)
c.Set(c.Deref(out_status), st)
if st == 0:
_RecordErrorText("empty response")
return -3
if requests._IsHttpRedirect(st):
if out_loc is not None and out_loccap > 0:
if requests._RawHeaderValue(dst, total, "Location", out_loc, out_loccap) != 0:
out_loc[0] = 0
return -2
if st != 200 and st != 206:
_RecordErrorText("http status not 200/206")
return -3
if st == 206:
c.Set(c.Deref(out_total), requests._CRTotalOf(dst, total))
else:
cl2: INT = requests._CLenOf(dst, total)
if cl2 > 0:
c.Set(c.Deref(out_total), t.CSizeT(cl2))
bo: INT = requests._FindBodyStart(dst, total)
if bo < 0 or bo >= total:
return 0
blen: INT = total - bo
if blen > cnt and cnt > 0:
blen = cnt
return blen