open
https://gitlab.synchro.net/main/sbbs/-/issues/1148
## Summary
Any second HTTPS GET to the **same host** in a single Synchronet JS process fails with `Error: Unable to read status` thrown out of `HTTPRequest.ReadStatus()`. The first HTTPS request to a given host succeeds; the second fails. Plain HTTP repeats (no TLS) work fine. Looks like a TLS-session-cache issue in the cryptlib-backed socket layer, not in `exec/load/http.js` itself.
## Minimal Repro
Run in `jsexec` (Win32 release build, but seen across builds):
```javascript
require('http.js', 'HTTPRequest');
for (var i = 1; i <= 3; i++) {
var h = new HTTPRequest(undefined, undefined, undefined, 30);
try {
h.Get("
https://gitlab.synchro.net/api/v4/projects/13");
writeln("call " + i + ": rc=" + h.response_code + " body.len=" + h.body.length);
} catch (e) {
writeln("call " + i + ": ERR: " + e);
}
}
```
Output:
```
call 1: rc=200 body.len=946
call 2: ERR: Error: Unable to read status
call 3: ERR: Error: Unable to read status
```
The error originates at `HTTPRequest.prototype.ReadStatus` in `exec/load/http.js`:
```javascript
HTTPRequest.prototype.ReadStatus = function() {
this.status_line = this.sock.recvline(4096, this.recv_timeout);
if (this.status_line == null)
throw new Error("Unable to read status");
// ...
};
```
`this.sock.recvline()` returns null on the 2nd request to the same host, indicating the TLS handshake either fails or the connection drops before any status bytes arrive.
## Things I Tried That Did NOT Fix It
- Using a fresh `HTTPRequest` object per call (not just reusing one)
- Explicitly `http.sock.close()` and `http.sock = undefined` between calls
- Sleeping 2s between calls (`mswait(2000)`)
- Clearing `http.body = undefined` before the 2nd `Get` (in case `SetupGet` was reusing it -- it does NOT reset `this.body`, which is a latent bug but not the cause here)
- Letting the redirect-follow logic run (no redirects involved at this URL)
## Things That DO Work
- A second HTTPS request to a **DIFFERENT host** succeeds (call 1 to gitlab → call 2 to httpbin.org → both work)
- BUT after the intervening different-host call, going BACK to the original host on call 3 fails again
- Plain HTTP repeats to the same host: all calls succeed (no TLS, no problem)
## Hypothesis
The cryptlib `ssl_session` socket attribute (set by `http.js` `SendRequest` at line 129) caches per-host TLS session state. On a 2nd connection to the same host the cached session is stale / invalid for resumption, and the new TCP+TLS attempt either:
a) Tries to resume a closed session and the handshake fails silently
b) Cryptlib's per-host session cache holds a reference to the freed previous-socket session and corrupts the new connection
Either way `recvline()` returns null instead of a status line.
## Impact
Blocks any JS module that wants to make multiple HTTPS requests in one process, such as:
- `chat_llm.js` retrieval crawlers wanting to use the GitLab REST API (`/api/v4/projects/<id>/issues` is paginated -- a real-world script needs 10+ calls to fetch all issues)
- Any future module pulling RSS / web content for grounding / mirroring
- IRC adapters that want to do periodic HTTPS polls
Current workaround in `chat_llm.js` is to read GitLab data from locally captured webhook JSONL files (`data/gitissue.jsonl`, `data/gitpush.jsonl`) instead of the API. Works on vert (which receives the upstream webhook feed) but isn't portable to other Synchronet installs.
## Environment
- Synchronet 3.22a (Win32, Release build)
- Single-process jsexec invocation
- Affected hosts: gitlab.synchro.net, httpbin.org (any HTTPS host)
- Cryptlib version: whatever ships in this build
— *Authored by Claude (Claude Code), on behalf of @rswindell*
--- SBBSecho 3.37-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)