Summary
Implement the telnet protocol (RFC 854) so that telnet:// URLs work as a drop-in replacement for curl's telnet support.
What Needs to Be Implemented
Protocol handler (crates/liburlx/src/protocol/telnet.rs)
- Raw TCP bidirectional pipe: telnet is essentially a raw TCP connection with optional negotiation
- IAC escaping on send: any
0xFF byte in upload data must be doubled (0xFF → 0xFF 0xFF) per RFC 854
- IAC stripping on receive: parse and strip telnet command sequences from received data:
- 3-byte commands:
IAC WILL/WONT/DO/DONT <option> (255, 251-254, option)
- Subnegotiation:
IAC SB ... IAC SE (255 250 ... 255 240)
- Escaped literal:
IAC IAC → single 0xFF
- Negotiation responses: respond to server-initiated negotiation (WILL → DONT, DO → WONT for simplicity, or accept BINARY/SGA)
- Upload support: send data from
--upload-file (file or - for stdin) to the server
- Timeout support:
--max-time / -m should trigger exit code 28 on timeout
Wiring
crates/liburlx/src/protocol/mod.rs: add pub mod telnet;
crates/liburlx/src/easy.rs (scheme dispatch ~line 6328): add "telnet" arm before the fallback scheme => case
crates/urlx-cli/src/args.rs (protocol list ~line 210): add telnet to the protocols vec in --version output. This is critical — the curl test runner checks --version output for telnet in the Protocols line and skips all telnet tests if it's missing.
--telnet-option / -t CLI flag (args.rs line 2370): currently accepted but ignored. Wire it through to the protocol handler for options like TTYPE=vt100, XDISPLOC=, NEW_ENV=var,val
Reference
- curl's implementation:
vendor/curl/lib/telnet.c (~1600 lines, but much of it is platform-specific poll loop code)
- curl's telnet constants:
vendor/curl/lib/arpa_telnet.h
- Telnet negotiation test server:
vendor/curl/tests/negtelnetserver.py
telnet is already in KNOWN_SCHEMES in crates/liburlx/src/url.rs (line 405) with default port 23
Acceptance Criteria — Curl Tests
The following curl tests must pass after implementation:
| Test |
Description |
Server |
Key behavior |
| 1326 |
TELNET to HTTP server (stdin upload) |
http |
telnet://host:port --upload-file - sends stdin bytes verbatim; verifies protocol output matches |
| 1327 |
TELNET file upload |
http |
telnet://host:port -T file.txt uploads file contents verbatim |
| 1452 |
Basic TELNET negotiation |
telnet (negtelnetserver.py) |
telnet://host:port --upload-file - with actual telnet negotiation; verifies echoed data on stdout |
| 1548 |
TELNET read stdin without upload file |
http |
-m 1 telnet://host:port — expected to timeout with exit code 28 |
Tests 1326 and 1327 are currently skipped because telnet is not in the --version Protocols line. Tests 1452 and 1548 are beyond the current test range (1-1400) but should also pass.
No regressions: all 1,302 currently-passing tests must continue to pass.
Non-Goals
- telnet over TLS (telnets://) — curl doesn't support this either
- Interactive terminal mode — curl's telnet is batch-oriented (upload data, read response)
Summary
Implement the telnet protocol (RFC 854) so that
telnet://URLs work as a drop-in replacement for curl's telnet support.What Needs to Be Implemented
Protocol handler (
crates/liburlx/src/protocol/telnet.rs)0xFFbyte in upload data must be doubled (0xFF→0xFF 0xFF) per RFC 854IAC WILL/WONT/DO/DONT <option>(255, 251-254, option)IAC SB ... IAC SE(255 250 ... 255 240)IAC IAC→ single0xFF--upload-file(file or-for stdin) to the server--max-time/-mshould trigger exit code 28 on timeoutWiring
crates/liburlx/src/protocol/mod.rs: addpub mod telnet;crates/liburlx/src/easy.rs(scheme dispatch ~line 6328): add"telnet"arm before the fallbackscheme =>casecrates/urlx-cli/src/args.rs(protocol list ~line 210): addtelnetto theprotocolsvec in--versionoutput. This is critical — the curl test runner checks--versionoutput fortelnetin the Protocols line and skips all telnet tests if it's missing.--telnet-option/-tCLI flag (args.rs line 2370): currently accepted but ignored. Wire it through to the protocol handler for options likeTTYPE=vt100,XDISPLOC=,NEW_ENV=var,valReference
vendor/curl/lib/telnet.c(~1600 lines, but much of it is platform-specific poll loop code)vendor/curl/lib/arpa_telnet.hvendor/curl/tests/negtelnetserver.pytelnetis already inKNOWN_SCHEMESincrates/liburlx/src/url.rs(line 405) with default port 23Acceptance Criteria — Curl Tests
The following curl tests must pass after implementation:
telnet://host:port --upload-file -sends stdin bytes verbatim; verifies protocol output matchestelnet://host:port -T file.txtuploads file contents verbatimtelnet://host:port --upload-file -with actual telnet negotiation; verifies echoed data on stdout-m 1 telnet://host:port— expected to timeout with exit code 28Tests 1326 and 1327 are currently skipped because
telnetis not in the--versionProtocols line. Tests 1452 and 1548 are beyond the current test range (1-1400) but should also pass.No regressions: all 1,302 currently-passing tests must continue to pass.
Non-Goals