DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
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 DETWS_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 return 0;
19 // Require the "bytes=" unit (case-insensitive).
20 if (strncasecmp(hdr, "bytes=", 6) != 0)
21 return 0;
22 const char *p = hdr + 6;
23 while (*p == ' ')
24 p++;
25 if (strchr(p, ',')) // multi-range not supported -> fall back to full 200
26 return 0;
27
28 bool have_start = false;
29 bool have_end = false;
30 size_t start = 0;
31 size_t end = 0;
32 const size_t SZMAX = (size_t)-1;
33 if (*p >= '0' && *p <= '9')
34 {
35 have_start = true;
36 while (*p >= '0' && *p <= '9')
37 {
38 size_t d = (size_t)(*p++ - '0');
39 // Saturate on overflow: a start past SIZE_MAX is past EOF -> 416, never wraps.
40 start = (start > (SZMAX - d) / 10) ? SZMAX : start * 10 + d;
41 }
42 }
43 if (*p != '-')
44 return 0; // malformed
45 p++;
46 if (*p >= '0' && *p <= '9')
47 {
48 have_end = true;
49 end = 0;
50 while (*p >= '0' && *p <= '9')
51 {
52 size_t d = (size_t)(*p++ - '0');
53 end = (end > (SZMAX - d) / 10) ? SZMAX : end * 10 + d; // saturate -> clamps to last byte
54 }
55 }
56 while (*p == ' ')
57 p++;
58 if (*p != '\0')
59 return 0; // trailing garbage -> ignore the header
60
61 if (!have_start)
62 {
63 // Suffix form "bytes=-N": the last N bytes.
64 if (!have_end || end == 0)
65 return -1; // "-" alone, or "-0" -> unsatisfiable
66 if (size == 0)
67 return -1;
68 start = (end >= size) ? 0 : (size - end);
69 end = size - 1;
70 }
71 else
72 {
73 if (start >= size)
74 return -1; // start past EOF -> unsatisfiable
75 if (!have_end || end >= size)
76 end = size - 1; // open-ended or clamped to last byte
77 if (start > end)
78 return -1;
79 }
80 *out_start = start;
81 *out_end = end;
82 return 1;
83}
84
85#endif // DETWS_ENABLE_RANGE
Shared single-range Range: bytes=... parser (RFC 7233), used by static file serving and the edge cach...