Riscos urls fetching
Skills repository for RISC OS agents
npx -y skills add gerph/riscos-agent-skills --skill riscos-urls-fetchingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Fetch URL or URI contents on RISC OS using the Acorn URL_Fetcher module, URL_Register, URL_GetURL, URL_Status, URL_ReadData, URL_Stop, URL_Deregister, URL_ParseURL, proxy setup, protocol enumeration, or URL fetcher protocol modules.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
19.4 KB, as published. Nobody here has run it
Fetching URLs on RISC OS
Use this skill when code needs to retrieve the contents of a URL/URI on RISC OS. In RISC OS practice, URL and URI are often used interchangeably, but this API is named URL.
The Acorn URL Fetcher module provides a uniform client interface to protocol fetcher modules such as HTTP, HTTPS, FTP, Gopher, File, and similar schemes. It fetches data; it is not the same as launching a URL in the desktop. For desktop launching, use the riscos-urls-launching skill.
Public reference: https://gerph.github.io/riscos-prminxml-staging/prm/html/acorn/url_fetcher/url_fetcher.html
Client fetch workflow
A client fetch is performed in a URL session. A session is valid until deregistered and must not be reused for another object fetch.
The usual sequence is:
- Call
URL_Registerto obtain a session identifier. - Optionally call
URL_SetProxyfor session-specific proxy or no-proxy rules. - Call
URL_GetURLto start the transfer. - In a desktop task, keep multitasking while repeatedly calling
URL_ReadDataand processing returned blocks. - Use
URL_Statuswhen progress or response information is needed. - Call
URL_Deregisterwhen finished. If the user aborts, callURL_Stopfirst, thenURL_Deregister.
URL_ReadData returns a complete HTTP-compatible response stream: status line, headers, blank line, then body data. Protocol modules should use HTTP/1.0 style responses where possible; clients that only want the body must parse and skip the response headers.
For simple stream-style wrappers, such as a FILE * replacement, a useful minimal pattern is:
- Treat a local prefix such as
URL:as an application convention, strip it, and pass the real URL including its scheme toURL_GetURL. - Call
URL_Register, save the returnedR1session identifier, and explicitly provide it asR1to every later URL SWI for clarity. - For a plain read-only fetch, use
URL_GetURLwithR0bit 0 set only when providing a User-Agent inR6,R2 = 1for GET,R3pointing at the URL, and no request body inR4. - If
URL_ReadDatareturns no bytes and the status has neither the completed bit nor the error bit set, yield while waiting. Desktop tasks should poll from their normal event loop; old command-style examples may useOS_UpCallreason 6 to sleep briefly. - When presenting only the entity body, discard the returned status line and headers on the first read by scanning for the blank line. HTTP-style line endings are normally CRLF; robust code should handle either CRLF or LF.
- On read completion, consume any bytes reported in
R4before treating the transfer as EOF; completion status and available data should not cause the final copied bytes to be discarded. - On open/start errors after
URL_Register, callURL_Deregisterbefore freeing local state. On normal close,URL_Deregisteris sufficient.
When wrapping the API with callbacks, it is useful to remember the last status word and call the data callback when either data is returned or the status changes. Some wrapper clients expect to receive zero-length callbacks for status-only changes. If a callback asks to cancel, mark the transfer aborted and defer freeing the handle until after the callback has returned; otherwise callback re-entrancy can leave the poll loop holding a freed pointer.
For throughput, a wrapper may coalesce small URL_ReadData chunks before delivering them to its caller, but it must flush accumulated data when the status changes, the buffer fills, or the transfer completes. Data returned with a status transition still belongs to the stream and must not be dropped.
For buffered wrappers that retain the whole response before handing it off, a useful general pattern is:
- Grow the accumulation buffer in chunks before it becomes completely full, so the next
URL_ReadDatacall can continue appending without copying partial state into a temporary buffer. - Treat header detection as a streaming state machine. Append bytes first, then scan the accumulated prefix for the first blank line; only fire any "headers available" hook once.
- Cache the final status, response code, and extent before deregistering the session, so callers can still inspect completion state after transport cleanup.
- If
URL_Statushas not yet produced a usable response code when the header block is complete, parse the numeric code directly from the leadingHTTP/x.y nnnstatus line as a fallback. - When saving or exposing only the entity body from a buffered response, compute and retain the body offset once the header terminator is known instead of reparsing the whole buffer repeatedly.
Client SWIs
Define the client SWIs as:
#define URL_Register 0x83e00
#define URL_GetURL 0x83e01
#define URL_Status 0x83e02
#define URL_ReadData 0x83e03
#define URL_SetProxy 0x83e04
#define URL_Stop 0x83e05
#define URL_Deregister 0x83e06
#define URL_ParseURL 0x83e07
#define URL_EnumerateSchemes 0x83e08
#define URL_EnumerateProxies 0x83e09
In C code, prefer the exported header when it is available:
#include "URL/URLFetcher.h"
It defines the SWIs, method values such as urlmethod_getobject, status helpers such as URL_Status_Complete, proxy constants, protocol flags, and the url_parseurl_components_t parsing structures.
URL_Register &83E00
Initialises a client session.
- Entry:
R0 = 0. - Exit:
R1 = session identifier.
Multiple sessions per application are permitted. The module has no fixed session limit beyond available memory.
URL_GetURL &83E01
Starts a transfer.
- Entry
R0: flags. - Entry
R0bit 0:R6contains a User-Agent string pointer. - Entry
R0bit 1:R4points to a data block of lengthR5; if clear,R4points to a zero-terminated string andR5must be2. - Entry
R1: session identifier. - Entry
R2: method word. Bits 0-7 are the protocol-dependent method number; bits 8-15 are method-dependent; bits 16-31 are reserved. - Entry
R3: zero-terminated URL string including its scheme. - Entry
R4: request data block, usually HTTP-style headers, a blank line, then optional entity body. - Entry
R5: length ofR4data block ifR0bit 1 is set, otherwise2. - Entry
R6: User-Agent string ifR0bit 0 is set;NULLor an empty string means use the default. - Exit
R0: protocol status word.
For a plain GET, the most common client shape is:
R2 = 1R3 = pointer to zero-terminated URLR4 = 0R5 = 2R6 = 0unless passing a User-Agent
If the caller is supplying extra request headers or request data, treat R4
and R5 according to the flags rather than assuming a zero-terminated string.
For HTTP POST-style requests, put the extra request headers and entity body in R4; do not include the HTTP request line. For simple authenticated GET requests, the data block can just contain extra header lines, for example Authorization: Basic ... followed by CRLF; set R0 bit 1 and pass the exact byte length in R5.
Method numbers in R2 bits 0-7:
1: FTPRETR/LIST, HTTPGET, "get this object".2: HTTPHEAD, "get entity headers".3: HTTPOPTIONS, "get server options".4: HTTPPOST.5: HTTPTRACE.6: reserved to Acorn; do not use.7: reserved to Acorn; do not use.8: FTPSTOR, HTTPPUT, "store this object".9: FTPMKD, "create directory".10: FTPRMD, "remove directory".11: FTPRNFR/RNTO, "rename object".12: FTPDELE, HTTPDELETE, "delete object".13: FTPSTOU, "store object unique".
Method numbers 0 and 255 are reserved and must not be used. Method numbers 128-254 are reserved for private non-distributed modules.
URL_Status &83E02
Reports session progress.
- Entry:
R0 = 0,R1 = session identifier. - Exit
R0: cumulative status word. - Exit
R2: server response code, using HTTP-style response numbers such as200,401, or404. - Exit
R3: total body bytes read so far. - Exit
R4: approximate total transaction bytes if known, or-1.
Status bits are cumulative and must be tested bitwise:
- Bit 0: connected to server.
- Bit 1: request sent.
- Bit 2: request data sent.
- Bit 3: initial response received.
- Bit 4: transfer in progress.
- Bit 5: all data received.
- Bit 6: error occurred.
Do not assume status values progress in a strict sequence.
URL_Status_Complete is commonly defined by client headers as bit 5 OR bit 6 (URL_Status_AllDone | URL_Status_Aborted). Polling code should stop when either completion bit is set, then inspect the aborted/error bit to distinguish success from failure. The approximate extent in R4 may be unknown before entity transfer starts; progress wrappers often wait until URL_Status_Transfer is set before treating it as the expected body size.
URL_ReadData &83E03
Reads pending response data.
- Entry:
R0 = 0,R1 = session identifier. - Entry
R2: receive buffer. - Entry
R3: receive buffer size. - Exit
R0: status word. - Exit
R4: bytes copied intoR2. - Exit
R5: bytes still to be read if known,0when complete, or-1if unknown.
Keep calling while data is available or until the transfer has completed. When R5 is 0, all data has been read. URL_Stop is not required after a normal completion; URL_Deregister will perform final cleanup.
If URL_ReadData returns an error, treat the transfer as failed or aborted and still clean up through the usual deregistration path.
When writing wrappers, do not drop the final block merely because completion is
also reported in the returned status word. Consume the bytes in R4 first.
Response headers
The response stream starts with a response/status line followed by headers, a blank line, and then the entity body. Code that needs just the body should split this stream itself or use a small state machine while data arrives.
Robust header splitting should recognise all of these blank-line forms:
- CR CR
- LF LF
- CR LF CR LF
- LF CR LF CR
If headers are accumulated for later parsing, include the terminating blank line in the accumulated header block so the parser can terminate the final field safely. Header parsers commonly ignore the first response/status line, split later lines at the first colon, trim whitespace after the colon, and compare field names case-insensitively. Continuation lines begin with space or tab and belong to the preceding header value.
URL_Stop &83E05
Aborts an active request.
- Entry:
R0 = 0,R1 = session identifier. - Exit
R0: status word.
Use this for premature termination, such as a user cancelling or quitting during a download. It is an error if there is no request associated with the session.
URL_Deregister &83E06
Frees the client session and all session-specific state, including proxy settings.
- Entry:
R0 = 0,R1 = session identifier. - Exit
R0: status word.
Call this exactly once for each successful URL_Register, even on error paths. Deregistration automatically stops any associated protocol transfer that has not already been stopped.
Proxy handling
Use URL_SetProxy (&83E04) to configure proxies.
- Entry
R0 = 0. - Entry
R1: session identifier, or0for global proxy settings. - Entry
R2: proxy base URL string, such ashttp://www-cache.example:8080/; use0to clear proxy settings for the session. - Entry
R3: URL prefix to proxy, such ashttp:orftp:, when setting a proxy. - Entry
R4:0for proxy this prefix,1for do not proxy.
Proxy selection order is: client no-proxy, client proxy, global no-proxy, global proxy. Session settings therefore override global settings.
Use URL_EnumerateProxies (&83E09) to inspect proxy and no-proxy lists:
- Entry
R0bit 0 clear: enumerate proxy entries. - Entry
R0bit 0 set: enumerate no-proxy entries. - Entry
R1: session identifier, or0for global settings. - Entry
R2: context, initially0. - Exit
R2: next context, or-1when finished. - Exit
R3: read-only URL or no-proxy prefix. - Exit
R4: read-only proxy URL for proxy enumeration; meaningless for no-proxy enumeration.
Do not update proxy lists while enumerating; the module may duplicate or miss entries.
URL parsing and resolving
Use URL_ParseURL (&83E07) instead of hand-parsing URLs.
Common entry registers:
R0bit 0:R5gives the number of words in the data block; if clear, 10 words are assumed.R0bit 1: escape character codes 0-31 and 127 using hex encoding. Avoid this unless required.R1: reason code.R2: base URL string.R3: relative URL string, orNULL.R4: data block or output buffer.R5: block size in words whenR0bit 0 is set, or buffer size for quick resolve.
The classic parser block has 10 component slots:
- Fully canonicalised URL.
- Scheme/protocol, lower-case.
- Hostname, lower-case.
- Port.
- Username.
- Password.
- FTP account.
- Path.
- Query.
- Fragment.
The exported URL/URLFetcher.h header also defines url_parseurl_components_t and url_parseurl_componentsizes_t with an 11th minimal component after fragment. When using those structures, set URL_ParseURL_WordLengthGiven and pass sizeof(url_parseurl_components_t) / sizeof(char *) or sizeof(url_parseurl_componentsizes_t) / sizeof(size_t) in R5, otherwise the default 10-word block will not cover the extra field.
Reason codes:
0: return required component buffer lengths in theR4word block. Lengths include the zero terminator; absent fields are zero.1: copy component strings into buffers whose pointers are supplied in theR4word block; unused component pointers may be zero.2: compose a canonical URL from component strings supplied in theR4word block.3: quick-resolve a full URL into the buffer atR4, with buffer length inR5.
For simple relative URL resolution, prefer reason 3. Size the buffer as strlen(base) + strlen(relative) + 4; if hex escaping is requested, multiply that estimate by three. On exit from reason 3, R5 is the remaining buffer space, or negative if the buffer was too small.
The path component does not start with / unless the parsed URL explicitly included one. In http://example/path, the slash after the hostname is a separator, not part of the path.
A safe full decomposition pattern is:
- Call reason
0withURL_ParseURL_WordLengthGivento fill a size structure. SetURL_ParseURL_EscapeCharactersif the caller wants control characters escaped in the returned strings. - Sum the returned component sizes. Lengths already include terminators, and absent fields have length zero.
- Allocate one block containing the pointer structure followed by string storage.
- Set each pointer to the next string slot, or
NULLfor zero-length components. - Call reason
1with the pointer structure and the same word count.
Free the single allocated block when finished. This pattern avoids guessing output lengths and keeps all component strings in one allocation.
Scheme enumeration
Use URL_EnumerateSchemes (&83E08) to discover available fetch schemes.
- Entry:
R0 = 0,R1 = context, initially0. - Exit
R1: next context, or-1when finished. - Exit
R2: read-only scheme string, if not finished. - Exit
R3: read-only help string. - Exit
R4: protocol module SWI base. - Exit
R5: protocol module version multiplied by 100.
Do not assume enumeration remains stable if protocol modules are loaded or removed between calls. If the URL Fetcher cannot handle a scheme, consider handing it to the URI handler for desktop launching instead.
The module is primed with knowledge of schemes including mailto:, telnet:, finger:, file:, filer_opendir:, filer_run:, local:, gopher:, ftp:, http:, https:, and whois:.
Implementing protocol fetcher modules
Most applications should not call protocol module SWIs directly. Implement this section only when writing a URL Fetcher protocol module.
Register the protocol module with URL_ProtocolRegister (&83E20):
- Entry
R0bit 0:R5contains protocol flags. - Entry
R0bit 1:R6contains default port number. - Entry
R1: protocol module SWI base. - Entry
R2: supported scheme string, such ashttp:. - Entry
R3: version multiplied by 100. - Entry
R4: informational string, up to 50 characters, or0. - Entry
R5: protocol flags ifR0bit 0 set. - Entry
R6: default port ifR0bit 1 set.
Protocol flags:
- Bit 0: path is not Unix-like.
- Bit 1: no parsing should be performed for this scheme.
- Bit 2: scheme allows
user@before the hostname. - Bit 3: hash character is allowed in hostname, for example
file:. - Bit 4: no hostname component, for example
mailto:. - Bit 5: remove leading
..path components.
Use URL_ProtocolDeregister (&83E21) from finalisation code:
- Entry:
R0 = 0,R1 = protocol module SWI base. - Exit
R1: number of client sessions that were using the module.
The URL module calls protocol modules through four SWIs starting at the registered SWI base:
Protocol_GetData: SWI base +0.Protocol_Status: SWI base +1.Protocol_ReadData: SWI base +2.Protocol_Stop: SWI base +3.
Protocol modules must return standard SWI-not-known error &1E6 for unsupported SWIs. If a module supports multiple protocols, keep its internal protocol SWI bases at least 16 SWIs apart. Protocol-specific extra SWIs should be allocated from the top of the chunk downwards.
The session identifiers used between the URL module and protocol modules are private to the URL module and are not the same as client session identifiers.
Service calls and command
Service calls:
Service_URLProtocolModule(&83E00), reason0: URL module started. Protocol modules should re-register.Service_URLProtocolModule(&83E00), reason1: URL module dying. Protocol modules should stop talking to it.Service_URLProtocolModule_ProtocolModule(&83E01), reason0: a protocol module registered.Service_URLProtocolModule_ProtocolModule(&83E01), reason1: a protocol module deregistered.
These service calls must not be claimed; preserve registers unless the API explicitly says otherwise.
The *URLProtoShow command displays registered protocol modules and their SWI bases. Use it for diagnostics.
Common URL errors
URL module errors occupy &80DE00 to &80DE1F. Common client-facing errors include:
&80DE00: session ID not found.&80DE01: out of memory.&80DE02: no matching fetcher for the URL.&80DE04: session already used for a fetch; sessions cannot be reused.&80DE05: no fetch in progress because it has already been terminated.&80DE07: no fetch in progress becauseURL_GetURLhas not been called.&80DE0A: unable to parse URL.
Protocol-specific errors use their own ranges and should be handled as normal _kernel_oserror results.
Practical test coverage
When you implement or review URL fetch support, exercise these behaviours separately:
- session create and destroy
- simple GET
- GET with explicit headers and User-Agent
- status polling during and after transfer
- repeated
URL_ReadDatauntil completion - stop/abort path
- session and global proxy handling
- proxy enumeration
- URL parsing and relative resolution
- scheme enumeration
- protocol register and deregister paths