ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
http_range.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file http_range.cpp
6 * @brief Shared single-range `Range: bytes=...` parser. See http_range.h.
7 */
8
9#include "server/http_range.h"
10
11#if PC_ENABLE_RANGE
12
13#include <string.h> // strncasecmp, strchr
14
15int http_parse_byte_range(const char *hdr, size_t size, size_t *out_start, size_t *out_end)
16{
17 if (!hdr)
18 {
19 return 0;
20 }
21 // Require the "bytes=" unit (case-insensitive).
22 if (strncasecmp(hdr, "bytes=", 6) != 0)
23 {
24 return 0;
25 }
26 const char *p = hdr + 6;
27 while (*p == ' ')
28 {
29 p++;
30 }
31 if (strchr(p, ',')) // multi-range not supported -> fall back to full 200
32 {
33 return 0;
34 }
35
36 bool have_start = false;
37 bool have_end = false;
38 size_t start = 0;
39 size_t end = 0;
40 const size_t SZMAX = (size_t)-1;
41 if (*p >= '0' && *p <= '9')
42 {
43 have_start = true;
44 while (*p >= '0' && *p <= '9')
45 {
46 size_t d = (size_t)(*p++ - '0');
47 // Saturate on overflow: a start past SIZE_MAX is past EOF -> 416, never wraps.
48 start = (start > (SZMAX - d) / 10) ? SZMAX : start * 10 + d;
49 }
50 }
51 if (*p != '-')
52 {
53 return 0; // malformed
54 }
55 p++;
56 if (*p >= '0' && *p <= '9')
57 {
58 have_end = true;
59 end = 0;
60 while (*p >= '0' && *p <= '9')
61 {
62 size_t d = (size_t)(*p++ - '0');
63 end = (end > (SZMAX - d) / 10) ? SZMAX : end * 10 + d; // saturate -> clamps to last byte
64 }
65 }
66 while (*p == ' ')
67 {
68 p++;
69 }
70 if (*p != '\0')
71 {
72 return 0; // trailing garbage -> ignore the header
73 }
74
75 if (!have_start)
76 {
77 // Suffix form "bytes=-N": the last N bytes.
78 if (!have_end || end == 0)
79 {
80 return -1; // "-" alone, or "-0" -> unsatisfiable
81 }
82 if (size == 0)
83 {
84 return -1;
85 }
86 start = (end >= size) ? 0 : (size - end);
87 end = size - 1;
88 }
89 else
90 {
91 if (start >= size)
92 {
93 return -1; // start past EOF -> unsatisfiable
94 }
95 if (!have_end || end >= size)
96 {
97 end = size - 1; // open-ended or clamped to last byte
98 }
99 if (start > end)
100 {
101 return -1;
102 }
103 }
104 *out_start = start;
105 *out_end = end;
106 return 1;
107}
108
109#endif // PC_ENABLE_RANGE
Shared single-range Range: bytes=... parser (RFC 7233), used by static file serving and the edge cach...