HttpLib — HTTP Client Library
Comprehensive HTTP client for Plan9Basic. RESTful API interactions, file transfers, form uploads, and full HTTP protocol support across all platforms. 92 functions.
| Category | Count | Description |
|---|---|---|
| Error Handling | 4 | http_error, http_errormsg$, http_strerror$, http_clearerror |
| Client Management | 4 | http_client# (2 overloads), http_free, http_reset# |
| Configuration | 11 | Base URL, timeouts, user-agent, content type, accept, redirects, SSL |
| Query Parameters | 4 | http_param#, http_param$, http_paramremove#, http_paramclear# |
| Custom Headers | 5 | http_header#, http_header$, http_headerremove#, http_headerclear#, http_headercount |
| Authentication | 4 | http_basicauth#, http_bearerauth#, http_customauth#, http_clearauth# |
| Cookies | 5 | http_cookie#, http_cookie$, http_cookieremove#, http_cookieclear#, http_cookiecount |
| Proxy | 3 | http_proxy#, http_proxyauth#, http_clearproxy# |
| Form Data | 10 | Create, fields, files (3 overloads), clear, count, URL-encode, free |
| Sync HTTP Methods | 11 | GET, POST (3), PUT (2), PATCH, DELETE, HEAD, OPTIONS |
| Async HTTP Methods | 6 | GET, POST, PUT, DELETE, PATCH async + http_busy |
| Response Access | 20 | Status, body, headers, cookies, content info, category checks |
| File Operations | 4 | http_download, http_upload$, http_uploadput$, http_postfile$ |
| Encoding Utilities | 4 | http_urlencode$, http_urldecode$, http_htmlencode$, http_htmldecode$ |
| Simple Functions | 3 | http_simpleget$, http_simplepost$, http_simpledownload |
Platform Considerations
| Platform | Approach | Reason |
|---|---|---|
| Desktop (Windows, macOS, Linux) | Synchronous functions | Simple, blocking — main thread is fine |
| Mobile (Android, iOS) | Asynchronous + polling | Non-blocking to avoid ANR / UI freeze |
' Desktop - synchronous (simple) let client# = http_client#("https://api.example.com") let response$ = http_get$(client#, "/data") println http_body$(client#)
' Mobile - async with timer polling http_get_async(client#, "/data") function OnTimer(sender#) local x if http_busy(client#) = 0 then timer_enabled#(sender#, 0) println http_body$(client#) end if end function
Error Handling
| Code | Constant | Description |
|---|---|---|
| 0 | ERR_NONE | No error |
| 1 | ERR_INVALID_CLIENT | Invalid or null client pointer |
| 2 | ERR_INVALID_URL | Malformed URL |
| 3 | ERR_CONNECTION | Network connection failed |
| 4 | ERR_TIMEOUT | Request timed out |
| 5 | ERR_SSL | SSL/TLS certificate error |
| 6 | ERR_INVALID_ARGUMENT | Invalid function argument |
| 7 | ERR_FILE | File read/write error |
| 8 | ERR_AUTH | Authentication failed |
| 9 | ERR_INVALID_RESPONSE | Malformed response |
| 10 | ERR_INVALID_FORM | Invalid form data pointer |
| Function | Signature | Description |
|---|---|---|
http_error() | http_error@ | Last error code (0–10) |
http_errormsg$() | http_errormsg$@ | Detailed error message from last operation |
http_strerror$(code) | http_strerror$@n | Description for a specific error code |
http_clearerror() | http_clearerror@ | Clear error state |
let errcode = http_error() let errmsg$ = http_errormsg$() let desc$ = http_strerror$(errcode) let result = http_clearerror()
Client Management
| Function | Signature | Description |
|---|---|---|
http_client#() | http_client#@ | Create HTTP client (no base URL) |
http_client#(baseUrl$) | http_client#@$ | Create client with base URL |
http_free(client#) | http_free@# | Free client resources |
http_reset#(client#) | http_reset#@# | Reset client to defaults |
' Create with base URL let client# = http_client#("https://api.example.com") ' ... use client ... ' Free when done let x = http_free(client#)
Configuration
All configuration functions return the client pointer for chaining.
| Function | Signature | Description |
|---|---|---|
http_baseurl#(c#, url$) | http_baseurl#@#$ | Set base URL |
http_baseurl$(c#) | http_baseurl$@# | Get base URL |
http_timeout#(c#, ms) | http_timeout#@#n | Set connection timeout (milliseconds) |
http_timeout(c#) | http_timeout@# | Get connection timeout |
http_responsetimeout#(c#, ms) | http_responsetimeout#@#n | Set response timeout |
http_useragent#(c#, ua$) | http_useragent#@#$ | Set User-Agent header |
http_contenttype#(c#, ct$) | http_contenttype#@#$ | Set Content-Type header |
http_accept#(c#, accept$) | http_accept#@#$ | Set Accept header |
http_followredirects#(c#, n) | http_followredirects#@#n | Enable/disable redirects (1/0) |
http_maxredirects#(c#, n) | http_maxredirects#@#n | Set max redirect count |
http_validatessl#(c#, n) | http_validatessl#@#n | Enable/disable SSL validation (1/0) |
let client# = http_client#("https://api.example.com") let client# = http_timeout#(client#, 30000) let client# = http_useragent#(client#, "MyApp/1.0") let client# = http_contenttype#(client#, "application/json") let client# = http_accept#(client#, "application/json") let client# = http_followredirects#(client#, 1) let client# = http_maxredirects#(client#, 5) let client# = http_validatessl#(client#, 1)
Query Parameters
| Function | Signature | Description |
|---|---|---|
http_param#(c#, key$, val$) | http_param#@#$$ | Add/update query parameter |
http_param$(c#, key$) | http_param$@#$ | Get parameter value |
http_paramremove#(c#, key$) | http_paramremove#@#$ | Remove parameter |
http_paramclear#(c#) | http_paramclear#@# | Clear all parameters |
let client# = http_param#(client#, "page", "1") let client# = http_param#(client#, "limit", "20") ' Requests now append ?page=1&limit=20 let val$ = http_param$(client#, "page") ' "1" let client# = http_paramremove#(client#, "page")
ⓘ Note: Parameters are automatically URL-encoded and appended to all requests.
Custom Headers
| Function | Signature | Description |
|---|---|---|
http_header#(c#, name$, val$) | http_header#@#$$ | Set custom header |
http_header$(c#, name$) | http_header$@#$ | Get header value |
http_headerremove#(c#, name$) | http_headerremove#@#$ | Remove header |
http_headerclear#(c#) | http_headerclear#@# | Clear all custom headers |
http_headercount(c#) | http_headercount@# | Number of custom headers |
let client# = http_header#(client#, "X-API-Key", "abc123") let client# = http_header#(client#, "X-Request-ID", "req-456") let key$ = http_header$(client#, "X-API-Key")
Authentication
| Function | Signature | Description |
|---|---|---|
http_basicauth#(c#, user$, pass$) | http_basicauth#@#$$ | Basic authentication (username/password) |
http_bearerauth#(c#, token$) | http_bearerauth#@#$ | Bearer token authentication |
http_customauth#(c#, value$) | http_customauth#@#$ | Custom Authorization header value |
http_clearauth#(c#) | http_clearauth#@# | Clear authentication |
' Basic auth let client# = http_basicauth#(client#, "username", "password") ' Bearer token let client# = http_bearerauth#(client#, "eyJhbGciOiJIUzI1NiIs...") ' Custom let client# = http_customauth#(client#, "ApiKey my-secret-key") ' Clear let client# = http_clearauth#(client#)
Cookie Management
| Function | Signature | Description |
|---|---|---|
http_cookie#(c#, name$, val$) | http_cookie#@#$$ | Set request cookie |
http_cookie$(c#, name$) | http_cookie$@#$ | Get cookie value |
http_cookieremove#(c#, name$) | http_cookieremove#@#$ | Remove cookie |
http_cookieclear#(c#) | http_cookieclear#@# | Clear all cookies |
http_cookiecount(c#) | http_cookiecount@# | Number of cookies |
let client# = http_cookie#(client#, "session", "abc123") let sess$ = http_cookie$(client#, "session") let count = http_cookiecount(client#)
Proxy Configuration
| Function | Signature | Description |
|---|---|---|
http_proxy#(c#, host$, port) | http_proxy#@#$n | Set proxy server |
http_proxyauth#(c#, user$, pass$) | http_proxyauth#@#$$ | Set proxy authentication |
http_clearproxy#(c#) | http_clearproxy#@# | Clear proxy settings |
let client# = http_proxy#(client#, "proxy.example.com", 8080) let client# = http_proxyauth#(client#, "proxyuser", "proxypass")
Form Data
Build complex multipart forms with text fields and multiple file attachments.
| Function | Signature | Description |
|---|---|---|
http_form#() | http_form#@ | Create empty form data |
http_formfield#(f#, name$, val$) | http_formfield#@#$$ | Add text field |
http_formfile#(f#, name$, path$) | http_formfile#@#$$ | Add file (uses original filename) |
http_formfilenamed#(f#, name$, path$, fn$) | http_formfilenamed#@#$$$ | Add file with custom filename |
http_formfiletype#(f#, name$, path$, fn$, ct$) | http_formfiletype#@#$$$$ | Add file with name and content type |
http_formfieldcount(f#) | http_formfieldcount@# | Count of text fields |
http_formfilecount(f#) | http_formfilecount@# | Count of files |
http_formurlencoded$(f#) | http_formurlencoded$@# | URL-encoded string (text fields only) |
http_formclear#(f#) | http_formclear#@# | Clear all fields and files |
http_formfree(f#) | http_formfree@# | Free form data |
' Build a form with text fields and file let form# = http_form#() let form# = http_formfield#(form#, "title", "Report") let form# = http_formfield#(form#, "department", "Finance") let form# = http_formfile#(form#, "document", "C:\Reports\Q4.pdf") ' POST as multipart/form-data (supports files) let resp$ = http_postform$(client#, "/upload", form#) ' POST as URL-encoded (text fields only) let resp$ = http_postformurl$(client#, "/login", form#) ' PUT as multipart let resp$ = http_putform$(client#, "/update", form#) let x = http_formfree(form#)
Synchronous HTTP Methods
Block until request completes. Ideal for desktop platforms.
| Function | Signature | Description |
|---|---|---|
http_get$(c#, url$) | http_get$@#$ | GET request |
http_post$(c#, url$, body$) | http_post$@#$$ | POST with body |
http_postform$(c#, url$, form#) | http_postform$@#$# | POST multipart form (files + fields) |
http_postformurl$(c#, url$, form#) | http_postformurl$@#$# | POST URL-encoded form (text only) |
http_postformstr$(c#, url$, data$) | http_postformstr$@#$$ | POST raw form string |
http_put$(c#, url$, body$) | http_put$@#$$ | PUT with body |
http_putform$(c#, url$, form#) | http_putform$@#$# | PUT multipart form |
http_patch$(c#, url$, body$) | http_patch$@#$$ | PATCH with body |
http_delete$(c#, url$) | http_delete$@#$ | DELETE request |
http_head(c#, url$) | http_head@#$ | HEAD request (returns status code) |
http_options$(c#, url$) | http_options$@#$ | OPTIONS request |
let client# = http_client#("https://api.example.com") let client# = http_contenttype#(client#, "application/json") ' GET let users$ = http_get$(client#, "/api/users") ' POST let body$ = "{\"name\":\"John\",\"email\":\"john@test.com\"}" let result$ = http_post$(client#, "/api/users", body$) ' PUT let update$ = http_put$(client#, "/api/users/123", "{\"name\":\"Updated\"}") ' DELETE let del$ = http_delete$(client#, "/api/users/123") ' HEAD let status = http_head(client#, "/api/resource") println "Content-Length: "; http_contentlength(client#)
Asynchronous HTTP (Polling)
For mobile platforms. Functions return immediately — poll with http_busy() for completion.
| Function | Signature | Description |
|---|---|---|
http_get_async(c#, url$) | http_get_async@#$ | Start async GET |
http_post_async(c#, url$, body$) | http_post_async@#$$ | Start async POST |
http_put_async(c#, url$, body$) | http_put_async@#$$ | Start async PUT |
http_delete_async(c#, url$) | http_delete_async@#$ | Start async DELETE |
http_patch_async(c#, url$, body$) | http_patch_async@#$$ | Start async PATCH |
http_busy(c#) | http_busy@# | 1 = request in progress, 0 = done |
' Recommended async pattern with timer polling let client# = Pointer#(0) let timer# = Pointer#(0) let frm# = form#("Async Demo") let lbl# = label#(frm#, "Ready", 10, 10) let btn# = button#(frm#, "Fetch", 10, 50, 120, 40) button_onclick#(btn#, "OnFetchClick") timer# = timer#(frm#, 100) timer_enabled#(timer#, 0) timer_ontimer#(timer#, "OnPollTimer") form_show(frm#) function OnFetchClick(sender#) client# = http_client#("https://httpbin.org") label_text#(lbl#, "Loading...") http_get_async(client#, "/get") timer_enabled#(timer#, 1) end function function OnPollTimer(sender#) local x if http_busy(client#) = 0 then timer_enabled#(timer#, 0) if http_ok(client#) <> 0 then label_text#(lbl#, "Status: " + str$(http_status(client#))) else label_text#(lbl#, "Error: " + http_errormsg$()) end if let x = http_free(client#) end if end function
⚠ Warning: On Android/iOS, always use async functions to avoid ANR (Application Not Responding). Desktop can use either sync or async.
Response Access
Status & Body
| Function | Signature | Description |
|---|---|---|
http_status(c#) | http_status@# | HTTP status code (200, 404, etc.) |
http_statustext$(c#) | http_statustext$@# | Status text ("OK", "Not Found", etc.) |
http_ok(c#) | http_ok@# | Success? (non-zero if 2xx) |
http_isredirect(c#) | http_isredirect@# | 3xx redirect? (1/0) |
http_isclienterror(c#) | http_isclienterror@# | 4xx client error? (1/0) |
http_isservererror(c#) | http_isservererror@# | 5xx server error? (1/0) |
http_body$(c#) | http_body$@# | Response body as string |
http_bodybase64$(c#) | http_bodybase64$@# | Response body as Base64 (binary content) |
http_savebody(c#, path$) | http_savebody@#$ | Save body to file |
Response Headers
| Function | Signature | Description |
|---|---|---|
http_respheader$(c#, name$) | http_respheader$@#$ | Get specific response header |
http_respheaders$(c#) | http_respheaders$@# | All response headers as text |
http_respheadercount(c#) | http_respheadercount@# | Number of response headers |
http_respheadername$(c#, idx) | http_respheadername$@#n | Header name by 0-based index |
http_respheadervalue$(c#, idx) | http_respheadervalue$@#n | Header value by 0-based index |
Response Cookies & Info
| Function | Signature | Description |
|---|---|---|
http_respcookie$(c#, name$) | http_respcookie$@#$ | Get specific response cookie |
http_respcookies$(c#) | http_respcookies$@# | All response cookies as text |
http_respcookiecount(c#) | http_respcookiecount@# | Number of response cookies |
http_respcontenttype$(c#) | http_respcontenttype$@# | Response content type |
http_contentlength(c#) | http_contentlength@# | Response content length |
http_redirecturl$(c#) | http_redirecturl$@# | Redirect URL (3xx responses) |
if http_ok(client#) <> 0 then println "Status: "; http_status(client#); " "; http_statustext$(client#) println "Body: "; http_body$(client#) println "Content-Type: "; http_respcontenttype$(client#) ' Iterate headers for i = 0 to http_respheadercount(client#) - 1 println http_respheadername$(client#, i); ": "; http_respheadervalue$(client#, i) next endif
File Operations
| Function | Signature | Description |
|---|---|---|
http_download(c#, url$, path$) | http_download@#$$ | Download file (non-zero = success) |
http_upload$(c#, url$, path$) | http_upload$@#$$ | Upload file as POST (raw body) |
http_uploadput$(c#, url$, path$) | http_uploadput$@#$$ | Upload file as PUT (raw body) |
http_postfile$(c#, url$, field$, path$) | http_postfile$@#$$$ | Upload as single-file multipart POST |
' Download if http_download(client#, "/files/doc.pdf", "C:\downloads\doc.pdf") <> 0 then println "Downloaded!" else println "Failed: "; http_errormsg$() endif ' Upload let resp$ = http_upload$(client#, "/upload", "C:\file.bin") let resp$ = http_postfile$(client#, "/upload", "file", "C:\docs\report.pdf")
Encoding Utilities
| Function | Signature | Description |
|---|---|---|
http_urlencode$(text$) | http_urlencode$@$ | URL-encode a string |
http_urldecode$(text$) | http_urldecode$@$ | URL-decode a string |
http_htmlencode$(text$) | http_htmlencode$@$ | HTML-encode (escape < > & etc.) |
http_htmldecode$(text$) | http_htmldecode$@$ | HTML-decode entities |
let enc$ = http_urlencode$("hello world & more") ' "hello%20world%20%26%20more" let dec$ = http_urldecode$("hello%20world") ' "hello world" let html$ = http_htmlencode$("<script>alert('hi')</script>") ' "<script>alert('hi')</script>" let back$ = http_htmldecode$("<p>") ' "<p>"
Simple Functions
Quick one-off requests without creating a client.
| Function | Signature | Description |
|---|---|---|
http_simpleget$(url$) | http_simpleget$@$ | Simple GET request |
http_simplepost$(url$, body$) | http_simplepost$@$$ | Simple POST request |
http_simpledownload(url$, path$) | http_simpledownload@$$ | Simple file download (1/0) |
let response$ = http_simpleget$("https://api.example.com/data") let body$ = "{\"key\":\"value\"}" let response$ = http_simplepost$("https://api.example.com/data", body$) let ok = http_simpledownload("https://example.com/file.zip", "C:\file.zip")
Complete Examples
REST API Client (Desktop)
let api# = http_client#("https://jsonplaceholder.typicode.com") let api# = http_accept#(api#, "application/json") ' GET let users$ = http_get$(api#, "/users") if http_ok(api#) <> 0 then println "Users: " + users$ end if ' POST let newUser$ = "{\"name\":\"John\",\"email\":\"john@test.com\"}" let result$ = http_post$(api#, "/users", newUser$) println "Created: " + result$ let x = http_free(api#)
File Upload with Form Fields
let client# = http_client#("https://upload.example.com") let client# = http_bearerauth#(client#, myToken$) let form# = http_form#() let form# = http_formfield#(form#, "title", "Quarterly Report") let form# = http_formfield#(form#, "department", "Finance") let form# = http_formfile#(form#, "document", "C:\Reports\Q4-2024.pdf") let response$ = http_postform$(client#, "/api/reports/upload", form#) if http_ok(client#) <> 0 then println "Upload complete!" else println "Failed: " + stri$(http_status(client#)) end if let x = http_formfree(form#) let x = http_free(client#)
Login with Session Cookie
let client# = http_client#("https://app.example.com") let form# = http_form#() let form# = http_formfield#(form#, "username", "john") let form# = http_formfield#(form#, "password", "secret123") let response$ = http_postformurl$(client#, "/login", form#) if http_ok(client#) <> 0 then let sessionId$ = http_respcookie$(client#, "session_id") let client# = http_cookie#(client#, "session_id", sessionId$) let data$ = http_get$(client#, "/api/dashboard") println data$ end if let x = http_formfree(form#) let x = http_free(client#)
Mobile Async HTTP Tests
' Async HTTP demo for Android/iOS let client# = Pointer#(0) let timer# = Pointer#(0) let testNum = 0 let frm# = form#("Mobile HTTP Demo") let memo# = memo#(frm#, 10, 10, 380, 350, "") let btnRun# = button#(frm#, "Run Tests", 10, 370, 120, 40) button_onclick#(btnRun#, "OnRunClick") timer# = timer#(frm#, 50) timer_enabled#(timer#, 0) timer_ontimer#(timer#, "OnPollTimer") form_show(frm#) function OnRunClick(sender#) memo_clear#(memo#) memo_addline#(memo#, "Starting tests...") client# = http_client#("https://httpbin.org") testNum = 0 StartNextTest() end function function StartNextTest() testNum = testNum + 1 if testNum = 1 then memo_addline#(memo#, "Test 1: GET...") http_get_async(client#, "/get") timer_enabled#(timer#, 1) else if testNum = 2 then memo_addline#(memo#, "Test 2: POST...") http_post_async(client#, "/post", "{\"test\":true}") timer_enabled#(timer#, 1) else memo_addline#(memo#, "All tests complete!") let x = http_free(client#) end if end function function OnPollTimer(sender#) if http_busy(client#) = 0 then timer_enabled#(timer#, 0) if http_ok(client#) <> 0 then memo_addline#(memo#, " OK: " + str$(http_status(client#))) else memo_addline#(memo#, " FAIL: " + http_errormsg$()) end if StartNextTest() end if end function
Quick Reference
Error & Client (8)
| Function | Signature | Description |
|---|---|---|
http_error() | http_error@ | Last error code |
http_errormsg$() | http_errormsg$@ | Error message |
http_strerror$(n) | http_strerror$@n | Error code description |
http_clearerror() | http_clearerror@ | Clear errors |
http_client#() / http_client#(url$) | http_client#@[/$] | Create client |
http_free(c#) | http_free@# | Free client |
http_reset#(c#) | http_reset#@# | Reset client |
Config & Setup (27)
| Function | Signature | Description |
|---|---|---|
http_baseurl#/$ | http_timeout#/timeout | various | URL & timeouts |
http_useragent# | contenttype# | accept# | @#$ | Headers |
http_followredirects# | maxredirects# | validatessl# | @#n | Behavior |
http_param#/$, paramremove#, paramclear# | various | Query params (4) |
http_header#/$, headerremove#, headerclear#, headercount | various | Custom headers (5) |
http_basicauth# | bearerauth# | customauth# | clearauth# | various | Auth (4) |
http_cookie#/$, cookieremove#, cookieclear#, cookiecount | various | Cookies (5) |
http_proxy#, proxyauth#, clearproxy# | various | Proxy (3) |
Form Data (10)
| Function | Signature | Description |
|---|---|---|
http_form#() | http_form#@ | Create form |
http_formfield#(f#, n$, v$) | http_formfield#@#$$ | Add text field |
http_formfile#/filenamed#/filetype# | various | Add file (3 overloads) |
http_formfieldcount/filecount/formurlencoded$/formclear#/formfree | various | Utilities (5) |
HTTP Methods (17)
| Function | Signature | Description |
|---|---|---|
http_get$/post$/put$/patch$/delete$ | various | Sync methods (5 core) |
http_postform$/postformurl$/postformstr$/putform$ | various | Form methods (4) |
http_head/http_options$ | various | HEAD & OPTIONS (2) |
http_get/post/put/delete/patch_async | various | Async methods (5) |
http_busy(c#) | http_busy@# | Check async completion |
Response (20), Files (4), Encoding (4), Simple (3)
| Function | Signature | Description |
|---|---|---|
http_status/statustext$/ok/isredirect/isclienterror/isservererror | various | Status checks (6) |
http_body$/bodybase64$/savebody | various | Body access (3) |
http_respheader$/respheaders$/respheadercount/name$/value$ | various | Response headers (5) |
http_respcookie$/respcookies$/respcookiecount | various | Response cookies (3) |
http_respcontenttype$/contentlength/redirecturl$ | various | Other info (3) |
http_download/upload$/uploadput$/postfile$ | various | File ops (4) |
http_urlencode$/urldecode$/htmlencode$/htmldecode$ | various | Encoding (4) |
http_simpleget$/simplepost$/simpledownload | various | No-client shortcuts (3) |
92 functions across 15 categories.