2 * libwebsockets - small server side websockets and web server implementation
4 * RFC7233 ranges parser
6 * Copyright (C) 2016 Andy Green <andy@warmcat.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation:
11 * version 2.1 of the License.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24 #include "core/private.h"
29 * o The first 500 bytes (byte offsets 0-499, inclusive):
33 * o The second 500 bytes (byte offsets 500-999, inclusive):
37 * o The final 500 bytes (byte offsets 9500-9999, inclusive):
45 * o The first and last bytes only (bytes 0 and 9999):
49 * o Other valid (but not canonical) specifications of the second 500
50 * bytes (byte offsets 500-999, inclusive):
52 * bytes=500-600,601-999
53 * bytes=500-700,601-999
57 * returns 1 if the range struct represents a usable range
58 * if no ranges header, you get one of these for the whole
59 * file. Otherwise you get one for each valid range in the
62 * returns 0 if no further valid range forthcoming; rp->state
63 * may be LWSRS_SYNTAX or LWSRS_COMPLETED
67 lws_ranges_next(struct lws_range_parsing *rp)
69 static const char * const beq = "bytes=";
73 char c = rp->buf[rp->pos];
80 case LWSRS_NO_ACTIVE_RANGE:
81 rp->state = LWSRS_COMPLETED;
84 case LWSRS_BYTES_EQ: // looking for "bytes="
85 if (c != beq[rp->pos]) {
86 rp->state = LWSRS_SYNTAX;
90 rp->state = LWSRS_FIRST;
99 rp->state = LWSRS_STARTING;
105 rp->state = LWSRS_ENDING;
109 if (!(c >= '0' && c <= '9')) {
110 rp->state = LWSRS_SYNTAX;
113 rp->start = (rp->start * 10) + (c - '0');
118 if (c == ',' || c == '\0') {
119 rp->state = LWSRS_FIRST;
124 * By the end of this, start and end are
125 * always valid if the range still is
128 if (!rp->start_valid) { /* eg, -500 */
129 if (rp->end > rp->extent)
130 rp->end = rp->extent;
132 rp->start = rp->extent - rp->end;
133 rp->end = rp->extent - 1;
136 rp->end = rp->extent - 1;
140 /* end must be >= start or ignore it */
141 if (rp->end < rp->start) {
144 rp->state = LWSRS_COMPLETED;
148 return 1; /* issue range */
151 if (!(c >= '0' && c <= '9')) {
152 rp->state = LWSRS_SYNTAX;
155 rp->end = (rp->end * 10) + (c - '0');
165 lws_ranges_reset(struct lws_range_parsing *rp)
173 rp->state = LWSRS_BYTES_EQ;
177 * returns count of valid ranges
180 lws_ranges_init(struct lws *wsi, struct lws_range_parsing *rp,
181 unsigned long long extent)
186 rp->count_ranges = 0;
188 lws_ranges_reset(rp);
189 rp->state = LWSRS_COMPLETED;
193 if (lws_hdr_copy(wsi, (char *)rp->buf, sizeof(rp->buf),
194 WSI_TOKEN_HTTP_RANGE) <= 0)
197 rp->state = LWSRS_BYTES_EQ;
199 while (lws_ranges_next(rp)) {
201 rp->agg += rp->end - rp->start + 1;
204 lwsl_debug("%s: count %d\n", __func__, rp->count_ranges);
205 lws_ranges_reset(rp);
207 if (rp->did_try && !rp->count_ranges)
208 return -1; /* "not satisfiable */
212 return rp->count_ranges;