22typedef enum : uint16_t {
28typedef enum : uint32_t {
34typedef enum : int8_t {
53 return (
char)(((c >=
'A') && (c <=
'Z')) ? (c + (
'a' -
'A')) : c);
98 while (prefix[i] !=
'\0') {
110 while ((*s ==
' ') || (*s ==
'\t') || (*s ==
'\r')) {
114 while ((n > 0U) && ((s[n - 1U] ==
' ') || (s[n - 1U] ==
'\t') || (s[n - 1U] ==
'\r'))) {
151 while ((p < end) && (*p !=
'\n')) {
152 if ((n + 1U) < cap) {
165 char* hash =
strchr(buf,
'#');
166 if (hash !=
nullptr) {
190 char* colon =
strchr(line,
':');
191 if (colon ==
nullptr) {
197 return (*field)[0] !=
'\0';
217 if (
strcmp(agent,
"*") == 0) {
221 return (
int)
strlen(agent);
253 const char* p = text;
254 const char* end = text + len;
256 bool truncated =
false;
258 char* field =
nullptr;
259 char* value =
nullptr;
267 }
else if (spec > *best) {
295 return wildcard_target ? grp_wild : ((target >= 0) && (grp_spec == target));
316 if (value[0] !=
'\0') {
327 (void)snprintf(r->
path,
sizeof(r->
path),
"%s", value);
348 const double secs = strtod(value, &end);
349 if ((end == value) || (*end !=
'\0') || !isfinite(secs) || (secs <= 0.0)) {
406 const char* ua_token,
408 bool wildcard_target,
411 const char* p = text;
412 const char* end = text + len;
413 bool prev_agent =
false;
414 bool selected =
false;
416 bool grp_wild =
false;
418 bool truncated =
false;
420 char* field =
nullptr;
421 char* value =
nullptr;
433 }
else if (spec > grp_spec) {
452 if (out ==
nullptr) {
457 if ((text ==
nullptr) && (len != 0U)) {
461 if (ua_token ==
nullptr) {
474 if ((best < 0) && !wild) {
477 const bool wildcard_target = (best < 0) && wild;
502 const char* s = path;
503 size_t star = patlen + 1U;
504 const char* ss =
nullptr;
506 if ((pi < patlen) && (pat[pi] ==
'*')) {
510 }
else if ((pi < patlen) && (pat[pi] == *s)) {
513 }
else if ((star <= patlen) && (ss !=
nullptr)) {
522 if ((pi == patlen) && !anchored) {
526 while ((pi < patlen) && (pat[pi] ==
'*')) {
550 bool anchored =
false;
551 if ((len > 0U) && (pat[len - 1U] ==
'$')) {
564 for (
size_t i = 0U; i < robots->
count; ++i) {
570 if (((
int)r->
len > best_len) || (((
int)r->
len == best_len) && is_allow)) {
571 best_len = (int)r->
len;
580 if ((robots ==
nullptr) || (path ==
nullptr) || !robots->
valid) {
589 if ((robots ==
nullptr) || (path ==
nullptr)) {
603 return &cache->
hosts[i];
614 return &cache->
hosts[i];
623 const char* ua_token,
629 if ((cache ==
nullptr) || (scheme ==
nullptr) || (host ==
nullptr) || (ua_token ==
nullptr) ||
630 (fetch ==
nullptr) || (scratch ==
nullptr) || (scratch_cap == 0U) ||
631 ((
strcmp(scheme,
"http") != 0) && (
strcmp(scheme,
"https") != 0)) ||
640 (void)snprintf(e->
scheme,
sizeof(e->
scheme),
"%s", scheme);
641 (void)snprintf(e->
host,
sizeof(e->
host),
"%s", host);
643 const int url_len = snprintf(url,
sizeof(url),
"%s://%s/robots.txt", scheme, host);
644 if ((url_len < 0) || ((
size_t)url_len >=
sizeof(url))) {
@ k_ms_per_s
Milliseconds per second.
static void internal_harvest(const char *text, size_t len, const char *ua_token, int target, bool wildcard_target, mdl_robots_t *out)
Pass 2: collect rules/crawl-delay from the selected group(s).
mdl_robots_local_size_t
Local parse/format sizes.
@ k_robots_url_max
Max /robots.txt URL length.
@ k_robots_line_max
Max robots.txt line length.
static const mdl_robots_rule_t * internal_best_matching_rule(const mdl_robots_t *robots, const char *path)
Longest matching rule for path (Allow wins ties), or NULL.
void mdl_robots_parse(const char *text, size_t len, const char *ua_token, mdl_robots_t *out)
Parse robots.txt text for the group matching ua_token.
static bool internal_ci_prefix(const char *prefix, const char *s)
True if prefix (case-insensitive) is a prefix of s.
bool mdl_robots_allows(const mdl_robots_t *robots, const char *path)
Decide whether path is allowed by a parsed robots group.
static bool internal_robots_match(const char *pat, size_t len, const char *path)
Match a rule pattern (honouring a trailing $) against path.
static int internal_agent_spec(const char *agent, const char *ua_token)
Specificity of a robots user-agent token vs ours (-1 = no match).
static void internal_add_rule(mdl_robots_t *out, mdl_robots_rule_kind_t kind, const char *value)
Append an Allow/Disallow rule (non-empty patterns only).
mdl_robots_spec_t
"No user-agent match" sentinel for the specificity score.
@ k_spec_none
No group matched our user-agent.
mdl_robots_ms_t
Millisecond conversions and the crawl-delay ceiling.
@ k_crawl_cap_ms
Clamp a Crawl-delay to at most 60s.
static mdl_robots_cache_entry_t * internal_cache_slot(mdl_robots_cache_t *cache)
Pick a free cache slot, or the dedicated uncached overflow slot.
static bool internal_group_selected(int target, bool wildcard_target, int grp_spec, bool grp_wild)
True if a group of this specificity is the selected group.
static bool internal_scan_spec(const char *text, size_t len, const char *ua_token, int *best, bool *wild)
Pass 1: find the best specific match length and wildcard presence.
static mdl_robots_cache_entry_t * internal_cache_find(mdl_robots_cache_t *cache, const char *scheme, const char *host)
Locate an existing cache entry for one origin, or NULL if absent.
static char * internal_trim_ws(char *s)
Trim leading/trailing ASCII whitespace in place; return start.
static bool internal_glob_prefix(const char *pat, size_t patlen, const char *path, bool anchored)
Match pat (len patlen, * glob) against a prefix of path.
static bool internal_next_line(const char **pp, const char *end, char *buf, size_t cap, bool *truncated)
Read one line into buf; strip its # comment and trim whitespace.
static char internal_lower_ascii(char c)
ASCII lower-case of one character (locale-independent).
static bool internal_ieq(const char *a, const char *b)
Case-insensitive equality of two NUL-terminated strings.
const char * mdl_robots_disallow_reason(const mdl_robots_t *robots, const char *path)
Return the Disallow pattern that forbids path, or NULL if allowed.
static void internal_apply_directive(mdl_robots_t *out, const char *field, const char *value)
Apply one non-user-agent directive line to the selected group.
const mdl_robots_t * mdl_robots_cache_consult(mdl_robots_cache_t *cache, const char *scheme, const char *host, const char *ua_token, mdl_robots_fetch_fn fetch, void *ctx, char *scratch, size_t scratch_cap)
Return the cached robots rules for host, fetching on first contact.
static void internal_set_crawl(mdl_robots_t *out, const char *value)
Record the strictest Crawl-delay seen (clamped to the ceiling).
static bool internal_split_field(char *line, char **field, char **value)
Split a trimmed line into field/value on the first :.
robots.txt parser, path matcher, and per-host cache.
mdl_robots_fetch_result_t(* mdl_robots_fetch_fn)(void *ctx, const char *robots_url, char *buf, size_t cap, size_t *out_len)
Fetch-callback type: retrieve robots_url into buf.
@ k_mdl_robots_max_rules
Max Allow/Disallow rules retained.
@ k_mdl_robots_path_max
Max bytes per rule path pattern.
mdl_robots_rule_kind_t
Whether a rule permits or forbids a matching path.
@ k_mdl_rule_disallow
A Disallow rule.
@ k_mdl_rule_allow
An Allow rule.
mdl_robots_fetch_result_t
Outcome class of a robots.txt fetch, per RFC 9309 convention.
@ k_mdl_robots_fetch_denied
5xx status: disallow all.
@ k_mdl_robots_fetch_ok
A body was retrieved to parse.
@ k_mdl_robots_host_max
Max host string bytes.
@ k_mdl_robots_max_hosts
Distinct hosts cached per run.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
size_t strlen(const char *s)
Calculate string length.
char * strchr(const char *s, int c)
Locate first occurrence of character in string.
size_t strnlen(const char *s, size_t maxlen)
Calculate bounded string length.
One host's cached robots.txt outcome.
char scheme[6]
Lower-case http or https.
bool used
Entry is populated.
mdl_robots_t rules
Parsed rules for our UA.
char host[k_mdl_robots_host_max]
Host this entry describes.
bool disallow_all
5xx convention: refuse all.
Fixed-size per-host robots.txt cache for one run.
mdl_robots_cache_entry_t overflow
Full-cache scratch entry.
mdl_robots_cache_entry_t hosts[k_mdl_robots_max_hosts]
Cached hosts.
One Allow/Disallow rule from the selected group.
mdl_robots_rule_kind_t kind
Allow or disallow.
char path[k_mdl_robots_path_max]
Path pattern.
uint16_t len
Pattern length in bytes.
Rules and crawl-delay for the group matching our user-agent.
bool have_crawl_delay
A Crawl-delay was seen.
bool valid
False if input exceeded a bound.
uint32_t crawl_delay_ms
Crawl-delay in ms.
mdl_robots_rule_t rules[k_mdl_robots_max_rules]
Selected group's rules.
size_t count
Number of valid rules.