6 n__url__safe_8h
gullradriel edited this page 2026-10-09 00:55:18 +02:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

include/nilorea/n_url_safe.h

Hardened, bounded URL + HTTP/1.x response-head parsing for a safe fetcher. More...

Structures

Name
struct n_url_safe_head
The response-head fields a fetcher acts on.
struct n_url_safe
The parts of an absolute http(s) URL.

Functions

Name
int n_url_safe_resolve(const char * base, size_t base_len, const char * loc, size_t loc_len, char * out, size_t cap)
resolve a redirect Location against a request URL
int n_url_safe_parse(const char * url, size_t len, n_url_safe * out)
parse an absolute http(s) URL [url, url+len) into a bounded struct
int n_url_safe_head_parse(const char * buf, size_t len, n_url_safe_head * out)
parse an HTTP/1.x response head from [buf, buf+len)
int n_url_safe_find(const char * text, size_t len, char * out, size_t cap)
find the first http(s) URL in a block of text

Defines

Name
N_URL_SAFE_MIME_MAX
Longest captured Content-Type (mime), parameters dropped.
N_URL_SAFE_MAX
Longest URL / path / Location accepted.
N_URL_SAFE_HOST_MAX
Longest hostname / IP literal accepted (RFC 1035 limit).
N_URL_SAFE_HEAD_MAX
Largest response head (status line + headers, through CRLFCRLF) accepted.

Detailed Description

Hardened, bounded URL + HTTP/1.x response-head parsing for a safe fetcher.

Author: Castagnier Mickael

Version: 1.0

A deliberately narrow, non-allocating companion to the general n_url API (n_network.h) – for the kind of program that fetches an ATTACKER-SUPPLIED http(s) URL (link previews, webhooks, avatar imports, ...). Where n_url_parse is a full, allocating URL model (query params, canonicalize, build), these fill a caller-owned stack struct, reject SSRF / phishing vectors (userinfo, non-http(s) scheme, bad host/port), and cap every field – so a hostile URL or server response can neither over-read nor allocate. Pair with n_ssrf to classify the resolved address, and drive the sockets/TLS in the caller.

Provides: split an absolute URL into parts, parse the response head (status + the few headers a fetcher acts on), resolve a redirect Location, and find the first URL in a block of text.

Functions Documentation

function n_url_safe_resolve

int n_url_safe_resolve(
    const char * base,
    size_t base_len,
    const char * loc,
    size_t loc_len,
    char * out,
    size_t cap
)

resolve a redirect Location against a request URL

Parameters:

  • base the request URL
  • base_len its length
  • loc the Location value
  • loc_len its length
  • out output buffer for the absolute URL
  • cap capacity of out (including the NUL)

Return: 1 on success, 0 otherwise

Handles an absolute http(s) target, a scheme-relative "//host/..." and a root-relative "/path"; a bare relative path is refused (returns 0). The result is re-validated with n_url_safe_parse.

function n_url_safe_parse

int n_url_safe_parse(
    const char * url,
    size_t len,
    n_url_safe * out
)

parse an absolute http(s) URL [url, url+len) into a bounded struct

Parameters:

  • url the URL bytes
  • len number of bytes in url
  • out the parsed URL to fill

Return: 1 on success, 0 otherwise

Rejects a non-http(s) scheme, userinfo ("user@host" – an SSRF / phishing vector), an empty or over-long host, a bad port, control bytes, and anything longer than the caps. IPv6 literals in brackets are accepted (brackets stripped into host).

function n_url_safe_head_parse

int n_url_safe_head_parse(
    const char * buf,
    size_t len,
    n_url_safe_head * out
)

parse an HTTP/1.x response head from [buf, buf+len)

Parameters:

  • buf the received bytes
  • len number of bytes in buf
  • out the parsed head to fill

Return: 1 on success, 0 otherwise

Returns 1 only when a complete head (through CRLFCRLF) is present and the status line is well-formed; 0 if incomplete, malformed, or larger than N_URL_SAFE_HEAD_MAX. On success out->head_len is the offset of the body. Header names are matched case-insensitively; unknown headers are ignored. Bounded and over-read safe.

function n_url_safe_find

int n_url_safe_find(
    const char * text,
    size_t len,
    char * out,
    size_t cap
)

find the first http(s) URL in a block of text

Parameters:

  • text the text to scan
  • len its length
  • out output buffer for the found URL
  • cap capacity of out (including the NUL)

Return: 1 if a URL was found, 0 otherwise

Writes it to out (cap includes the NUL). Trailing sentence punctuation is trimmed. The candidate must pass n_url_safe_parse (so a userinfo / malformed URL is skipped, and scanning continues), which makes this a safe trigger: it never surfaces a URL n_url_safe_parse would reject.

Macros Documentation

define N_URL_SAFE_MIME_MAX

#define N_URL_SAFE_MIME_MAX 127u

Longest captured Content-Type (mime), parameters dropped.

define N_URL_SAFE_MAX

#define N_URL_SAFE_MAX 1024u

Longest URL / path / Location accepted.

define N_URL_SAFE_HOST_MAX

#define N_URL_SAFE_HOST_MAX 253u

Longest hostname / IP literal accepted (RFC 1035 limit).

define N_URL_SAFE_HEAD_MAX

#define N_URL_SAFE_HEAD_MAX 16384u

Largest response head (status line + headers, through CRLFCRLF) accepted.

Source code

/*
 * Nilorea Library
 * Copyright (C) 2005-2026 Castagnier Mickael
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#ifndef N_URL_SAFE_H
#define N_URL_SAFE_H

#include <stddef.h>
#include <stdint.h>

#define N_URL_SAFE_HOST_MAX 253u
#define N_URL_SAFE_MAX 1024u
#define N_URL_SAFE_MIME_MAX 127u
#define N_URL_SAFE_HEAD_MAX 16384u

typedef struct {
    int https; 
    uint16_t port;
    char host[N_URL_SAFE_HOST_MAX + 1];
    char path[N_URL_SAFE_MAX + 1];
} n_url_safe;

typedef struct {
    int status;                                 
    long long content_length;                   
    int chunked;                                
    size_t head_len;                            
    char location[N_URL_SAFE_MAX + 1];          
    char content_type[N_URL_SAFE_MIME_MAX + 1]; 
} n_url_safe_head;

int n_url_safe_parse(const char* url, size_t len, n_url_safe* out);

int n_url_safe_head_parse(const char* buf, size_t len, n_url_safe_head* out);

int n_url_safe_resolve(const char* base, size_t base_len, const char* loc, size_t loc_len, char* out, size_t cap);

int n_url_safe_find(const char* text, size_t len, char* out, size_t cap);

#endif /* N_URL_SAFE_H */