import string import socket import stdio import stdlib import requests import openssl import json import memhub # ============================================================ # requests/https.vp - HTTPS client (openssl SSL/TLS + certificate verification) # # Same API names as requests (HTTP), but over TLS and by default it verifies the peer certificate: # 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) # # Notes: # - with verify=True it verifies the certificate chain + hostname (hostname check via SSL_set1_host), # provide ca_file pointing to a PEM CA bundle; if not provided it uses the system default path # (on Windows this is usually empty, so real sites fail with "unable to verify certificate chain" and return None). # - on failure returns None; use last_error() to get the reason text. # - after a successful handshake, use last_tls_info() to view the TLS version / cipher suite / peer certificate subject. # ============================================================ define HTTPS_PORT = 443 # Module-internal state _ossl_ready: bool = False _socket_ready: bool = False _err_store: [512]char # last failure reason (static buffer) _info_store: [512]char # TLS metadata of last successful handshake _scratch_store: [512]char # scratch concat buffer _last_verify_val: int = -1 # last SSL_get_verify_result (0=ok; -1=disabled) _last_verify_flag: int = -1 # last request verify flag (1=on; 0=off; -1=unknown) # ============================================================ # SSE streaming receive area (post_stream only; single request, polled by UI thread). # _st_len written bytes; _st_consumed consumed cursor; _st_state 0=running 1=done(2xx) 2=fail; _st_status HTTP code. # ============================================================ define STREAM_CAP = 262144 _st_buf: [STREAM_CAP]char _st_len: sizet = 0 _st_consumed: sizet = 0 _st_state: int = 0 _st_status: int = 0 _st_err: [512]char def stream_begin(): """Start a new streaming receive: reset buffer/cursor/state.""" global _st_len, _st_consumed, _st_state, _st_status _st_len = 0 _st_consumed = 0 _st_state = 0 _st_status = 0 _st_err[0] = 0 def stream_pull(out: str, cap: int) -> int: """Copy unconsumed delta into out (NUL-terminated); return bytes copied.""" global _st_consumed if out is None or cap <= 1: return 0 avail: int = 0 if _st_len > _st_consumed: avail = int(_st_len - _st_consumed) if avail > cap - 1: avail = cap - 1 for i in range(int(sizet(avail))): out[i] = _st_buf[_st_consumed + i] out[sizet(avail)] = 0 _st_consumed += sizet(avail) return avail def stream_state() -> int: """0=running 1=done(2xx) 2=failed.""" return _st_state def stream_status() -> int: """HTTP status code; negative means network/parse error.""" return _st_status def stream_error_text() -> str: """Failure reason text (when _st_state==2).""" return _st_err def last_verify_result() -> int: """Last cert verify result: 0=ok; >0=failure code; -1=verify disabled.""" return _last_verify_val def last_verify_enabled() -> int: """Whether last request enabled verify (1=yes; 0=no; -1=unknown).""" return _last_verify_flag # ============================================================ # internal helpers # ============================================================ def last_error() -> str: """Last failure reason text (empty string if none).""" return _err_store def last_tls_info() -> str: """Last successful handshake TLS info (version/cipher/peer subject), empty if none.""" return _info_store def _RecordErrorText(text: str): """Write failure reason into static buffer _err_store.""" if text is None: return _err_store[0] = 0 stdio.snprintf(_err_store, 512, "%s", text) def _RecordInfoText(text: str): """Write TLS metadata into static buffer _info_store.""" if text is None: return _info_store[0] = 0 stdio.snprintf(_info_store, 512, "%s", text) def _EnsureReady() -> int: """Initialize socket and openssl (both idempotent).""" 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*) -> int: """Parse https://host[:port][/path]; default port 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 bytes) 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 *port = port_val else: *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: """Return static concat buffer (512B, reused).""" return _scratch_store def _TlsErrText(): """Write last openssl error-queue text into static scratch buffer.""" e: uint32 = 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) # ============================================================ # Core request # ============================================================ def _HttpsRequest(method: str, url: str, verify: bool, ca_file: str, data: str, content_type: str, auth: str = None) -> requests.Response*: """HTTPS GET/POST core. verify=False skips cert chain/hostname checks (not recommended); verify=True uses ca_file PEM bundle (else system default); auth adds Authorization header on POST only. """ 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* = requests.create_response() if resp is None: return None if _EnsureReady() != 0: requests.release(resp) return None # Temp buffer for error text; openssl details go to module scratch. errmsg: str = requests._mbuddy.alloc(512) if errmsg is None: requests.release(resp) return None # ---- Parse URL ---- host_buf: [256]char path_buf: [1024]char port: int = 0 if _ParseHttpsUrl(url, host_buf, 256, path_buf, 1024, &port) != 0: stdio.snprintf(errmsg, 512, "bad https url: %s", url) _RecordErrorText(errmsg) requests._mbuddy.free(errmsg) requests.release(resp) return None # ---- Establish TCP connection ---- 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: # System default paths (usually empty on Windows; cert chain check will fail). 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 is a macro -> call SSL_ctrl directly) openssl.SSL_ctrl(ssl, openssl.SslCtrlSetTlsextHostname, openssl.TlsextNametypeHostName, host_buf) # Hostname verification (TLS core compares cert SAN/CN against host) if verify: openssl.SSL_set1_host(ssl, host_buf) # ---- Handshake ---- 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 # ---- Record last cert verify result (for last_verify_result) ---- if verify: _last_verify_val = int(openssl.SSL_get_verify_result(ssl)) else: _last_verify_val = -1 # ---- Re-check cert chain verify result ---- if verify: vres: int32 = 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 # ---- Record TLS metadata (version / cipher / peer subject) ---- 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) # ---- Build request headers and send ---- 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" # Build header in stages so Authorization can be inserted on demand (only when auth non-empty). hdr_off: int = 0 hdr_cap: int = requests.HTTP_BUFSIZ stdio.snprintf(req_buf, hdr_cap, "POST %s HTTP/1.1\r\nHost: %s\r\n", path_buf, host_buf) hdr_off = int(string.strlen(req_buf)) if auth is not None and auth[0] != 0: stdio.snprintf(req_buf + hdr_off, hdr_cap - hdr_off, "Authorization: %s\r\n", auth) hdr_off = int(string.strlen(req_buf)) stdio.snprintf(req_buf + hdr_off, hdr_cap - hdr_off, "Content-Type: %s\r\nContent-Length: %d\r\nAccept-Encoding: gzip\r\nConnection: close\r\n\r\n", 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) # ---- Receive response (buffer auto-doubles, supports MB bodies) ---- resp_cap: int = requests.HTTP_BUFSIZ resp_buf: str = requests._mbuddy.alloc(sizet(resp_cap)) 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 True: room: int = resp_cap - 1 - total if room <= 0: # Buffer full but more data may follow: double capacity (hard cap 256MB, runaway-guard). if resp_cap >= 268435456: break resp_cap = resp_cap * 2 nb: rawptr = requests._mbuddy.realloc(resp_buf, sizet(resp_cap)) if nb is None: _RecordErrorText("realloc response buffer failed") requests._mbuddy.free(resp_buf) openssl.SSL_free(ssl) openssl.SSL_CTX_free(ctx) sock.close() requests._mbuddy.free(errmsg) requests.release(resp) return None resp_buf = bytes(uint64(nb)) room = resp_cap - 1 - total n: int = openssl.SSL_read(ssl, resp_buf + total, room) if n <= 0: break total += n resp_buf[total] = 0 # Close TLS and 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 # ============================================================ # Public API # ============================================================ def _HttpsRedirectLoop(method: str, url: str, verify: bool, ca_file: str, data: str, content_type: str, auth: str = None) -> requests.Response*: """HTTPS GET/POST with redirect following (cross http/https, max 5 hops). auth is passed through to _HttpsRequest; note Authorization also follows cross-host redirects. """ 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) for hop in range(5): resp: requests.Response* = _HttpsRequest(method, cur, verify, ca_file, data, content_type, auth) 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) # Cross-scheme dispatch: https -> continue loop; http -> hand to requests (http) chain if string.strncmp(nxt, "https://", 8) != 0: requests._mbuddy.free(loc) requests._mbuddy.free(cur) http_resp: requests.Response* = requests.get(nxt) requests._mbuddy.free(nxt) return http_resp requests._mbuddy.free(loc) requests._mbuddy.free(cur) cur = nxt _RecordErrorText("too many redirects") requests._mbuddy.free(cur) return None def get(url: str, verify: bool = True, ca_file: str = None) -> requests.Response*: """HTTPS GET (follows 3xx redirects, max 5 hops). verify checks cert chain + hostname; ca_file is a PEM CA bundle path, None uses system default. Returns Response* or None. """ 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, auth: str = None) -> requests.Response*: """HTTPS POST (follows 3xx redirects, max 5 hops). verify checks cert chain + hostname; ca_file PEM CA bundle (None = system default); auth optional "Bearer ", sent when non-empty. """ return _HttpsRedirectLoop("POST", url, verify, ca_file, data, content_type, auth) # ============================================================ # SSE streaming Chat Completions (post_stream): sends Accept: text/event-stream and extracts # choices[0].delta.content from data:{json} lines into _st_buf; blocking, returns HTTP status or -1/-2. # ============================================================ def _SseDeltaContent(root: json.JsonValue*) -> str: """Extract choices[0].delta.content from a stream data event; None if absent.""" if root is None or not root.is_object(): return None cv: json.JsonValue* = root["choices"] if cv is None or not cv.is_array(): return None m0: json.JsonValue* = cv.get_item(0) if m0 is None or not m0.is_object(): return None dv: json.JsonValue* = m0["delta"] if dv is None or not dv.is_object(): return None content_v: json.JsonValue* = dv["content"] if content_v is None or not content_v.is_string(): return None return content_v.as_string() def _StreamAppendContent(txt: str): """Append delta content to _st_buf (truncate on overflow).""" global _st_len if txt is None: return pos: sizet = _st_len i: sizet = 0 while txt[i] != 0: if pos >= sizet(STREAM_CAP) - 1: break _st_buf[pos] = txt[i] pos += 1 i += 1 _st_len = pos def _SetStreamFail(rc: int): """Finish stream failure: copy reason from _err_store and set state.""" global _st_state, _st_status _st_state = 2 _st_status = rc stdio.snprintf(_st_err, 512, "%s", _err_store) def post_stream(url: str, data: str, content_type: str = "application/json", verify: bool = True, ca_file: str = None, auth: str = None) -> int: """SSE streaming POST (blocking; call from a background thread). data must be a JSON body containing "stream":true. Returns HTTP status; negative means network/parse failure. """ global _st_state, _st_status if requests._mbuddy is None: return -1 _st_state = 0 _st_status = 0 # Winsock/openssl init (idempotent; first call may run on a background thread) if _EnsureReady() != 0: _SetStreamFail(-1) return -1 # ---- Connect/TLS (same as _HttpsRequest) ---- errmsg: str = requests._mbuddy.alloc(512) if errmsg is None: return -1 host_buf: [256]char path_buf: [1024]char port: int = 0 if _ParseHttpsUrl(url, host_buf, 256, path_buf, 1024, &port) != 0: stdio.snprintf(errmsg, 512, "bad https url: %s", url) _RecordErrorText(errmsg) _SetStreamFail(-1) requests._mbuddy.free(errmsg) return -1 sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM) if sock.fd == socket.INVALID_SOCKET: _RecordErrorText("socket() failed") _SetStreamFail(-1) requests._mbuddy.free(errmsg) return -1 if sock.connect(host_buf, port) != 0: stdio.snprintf(errmsg, 512, "connect %s:%d failed", host_buf, port) _RecordErrorText(errmsg) _SetStreamFail(-1) sock.close() requests._mbuddy.free(errmsg) return -1 ctx: openssl.SslCtxPtr = openssl.SSL_CTX_new(openssl.TLS_client_method()) if ctx is None: _RecordErrorText("SSL_CTX_new failed") _SetStreamFail(-1) sock.close() requests._mbuddy.free(errmsg) return -1 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) _SetStreamFail(-1) openssl.SSL_CTX_free(ctx) sock.close() requests._mbuddy.free(errmsg) return -1 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") _SetStreamFail(-1) openssl.SSL_CTX_free(ctx) sock.close() requests._mbuddy.free(errmsg) return -1 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: want: int = openssl.SSL_get_error(ssl, hret) _TlsErrText() stdio.snprintf(errmsg, 512, "SSL_connect failed (want=%d): %s", want, _ScratchBuf()) _RecordErrorText(errmsg) _SetStreamFail(-1) openssl.SSL_free(ssl) openssl.SSL_CTX_free(ctx) sock.close() requests._mbuddy.free(errmsg) return -1 if verify: vres: int32 = 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) _SetStreamFail(-1) openssl.SSL_free(ssl) openssl.SSL_CTX_free(ctx) sock.close() requests._mbuddy.free(errmsg) return -1 # ---- Build request headers (POST + Accept: text/event-stream) and send ---- req_buf: str = requests._mbuddy.alloc(requests.HTTP_BUFSIZ) if req_buf is None: _RecordErrorText("alloc request buffer failed") _SetStreamFail(-1) openssl.SSL_free(ssl) openssl.SSL_CTX_free(ctx) sock.close() requests._mbuddy.free(errmsg) return -1 body_len: int = int(string.strlen(data)) if data is not None else 0 ct: str = content_type if content_type is not None else "application/json" hdr_off: int = 0 stdio.snprintf(req_buf, requests.HTTP_BUFSIZ, "POST %s HTTP/1.1\r\nHost: %s\r\n", path_buf, host_buf) hdr_off = int(string.strlen(req_buf)) if auth is not None and auth[0] != 0: stdio.snprintf(req_buf + hdr_off, requests.HTTP_BUFSIZ - hdr_off, "Authorization: %s\r\n", auth) hdr_off = int(string.strlen(req_buf)) stdio.snprintf(req_buf + hdr_off, requests.HTTP_BUFSIZ - hdr_off, "Content-Type: %s\r\nContent-Length: %d\r\nAccept: text/event-stream\r\nConnection: close\r\n\r\n", ct, body_len) 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) _SetStreamFail(-1) requests._mbuddy.free(req_buf) openssl.SSL_free(ssl) openssl.SSL_CTX_free(ctx) sock.close() requests._mbuddy.free(errmsg) return -1 if body_len > 0 and data is not None: openssl.SSL_write(ssl, data, body_len) requests._mbuddy.free(req_buf) # ---- Read response: skip headers -> parse SSE lines -> extract delta.content ---- rd: str = requests._mbuddy.alloc(16384) if rd is None: _RecordErrorText("alloc stream buffer failed") _SetStreamFail(-1) openssl.SSL_free(ssl) openssl.SSL_CTX_free(ctx) sock.close() requests._mbuddy.free(errmsg) return -1 # JSON pool (reset per event, sized for one data event) pmem: str = stdlib.malloc(524288) if pmem is None: _RecordErrorText("alloc json pool failed") _SetStreamFail(-1) requests._mbuddy.free(rd) openssl.SSL_free(ssl) openssl.SSL_CTX_free(ctx) sock.close() requests._mbuddy.free(errmsg) return -1 jpool: memhub.MemPool* = memhub.MemPool(pmem, 524288) leftover: [16384]char llen: int = 0 header_done: int = 0 status_code: int = 0 had_read: int = 0 while True: n: int = openssl.SSL_read(ssl, rd, 16384) if n <= 0: break had_read = 1 # 1) Append to leftover ai: int = 0 while ai < n and llen < 16383: leftover[llen] = rd[ai] llen += 1 ai += 1 # 2) Process line by line while True: # Find line end \n nl: int = -1 for k in range(int(llen)): if leftover[k] == 10: nl = k break if nl < 0: break e: int = nl if e > 0 and leftover[e - 1] == 13: e -= 1 leftover[e] = 0 line: str = leftover if header_done == 0: if string.strncmp(line, "HTTP/", 5) == 0: # Status code: HTTP/1.1 200 OK sp: int = 0 while line[sp] != 0 and line[sp] != ' ': sp += 1 if line[sp] == ' ': sp += 1 code_val: int = 0 while line[sp] >= '0' and line[sp] <= '9': code_val = code_val * 10 + int(line[sp] - '0') sp += 1 status_code = code_val if e == 0: header_done = 1 else: if e > 0 and line[0] != ':': if string.strncmp(line, "data:", 5) == 0: pl: str = line + 5 while pl[0] == ' ': pl += 1 if pl[0] != 0: if string.strncmp(pl, "[DONE]", 6) != 0 or pl[6] != 0: jpool.reset() ev: json.JsonValue* = json.parse(jpool, pl) dtx: str = _SseDeltaContent(ev) if dtx is not None: _StreamAppendContent(dtx) # 3) Remove processed line rem: int = llen - (nl + 1) for j2 in range(int(rem)): leftover[j2] = leftover[nl + 1 + j2] llen = rem # ---- Wrap up ---- openssl.SSL_shutdown(ssl) openssl.SSL_free(ssl) openssl.SSL_CTX_free(ctx) sock.close() requests._mbuddy.free(rd) stdlib.free(pmem) requests._mbuddy.free(errmsg) if status_code == 0: if had_read == 0: _RecordErrorText("no response data") else: _RecordErrorText("missing HTTP status line") _SetStreamFail(-2) return -2 _st_status = status_code if status_code >= 200 and status_code < 300: _st_state = 1 else: _st_state = 2 stdio.snprintf(_st_err, 512, "HTTP %d (check Key/model/address or account quota)", status_code) return status_code # ============================================================ # Large-file Range download primitive for requests.download. Thread-safe: no _mbuddy, # independent SSL_CTX/SSL/socket per connection. Returns body bytes>=0; -1 arg; -2 redirect; -3 failure. # ============================================================ def _DlOnce(url: str, start: sizet, count: int, verify: bool, ca_file: str, dst: str, dst_cap: int, out_status: int*, out_loc: str, out_loccap: int, out_total: sizet*) -> int: """HTTPS single Range fetch (thread-safe; see module comment).""" 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 *out_status = 0 *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: [256]char path_buf: [1024]char port: int = 0 if _ParseHttpsUrl(url, host_buf, 256, path_buf, 1024, &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 # Build Range request header (no Accept-Encoding, so response is raw bytes) 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: sizet = start + sizet(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) *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: *out_total = requests._CRTotalOf(dst, total) else: cl2: int = requests._CLenOf(dst, total) if cl2 > 0: *out_total = sizet(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