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 "private-libwebsockets.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=";
81 case LWSRS_NO_ACTIVE_RANGE:
82 rp->state = LWSRS_COMPLETED;
85 case LWSRS_BYTES_EQ: // looking for "bytes="
86 if (c != beq[rp->pos]) {
87 rp->state = LWSRS_SYNTAX;
91 rp->state = LWSRS_FIRST;
100 rp->state = LWSRS_STARTING;
106 rp->state = LWSRS_ENDING;
110 if (!(c >= '0' && c <= '9')) {
111 rp->state = LWSRS_SYNTAX;
114 rp->start = (rp->start * 10) + (c - '0');
119 if (c == ',' || c == '\0') {
120 rp->state = LWSRS_FIRST;
124 /* by the end of this, start and end are always valid if the range still is */
126 if (!rp->start_valid) { /* eg, -500 */
127 if (rp->end > rp->extent)
128 rp->end = rp->extent;
130 rp->start = rp->extent - rp->end;
131 rp->end = rp->extent - 1;
134 rp->end = rp->extent - 1;
138 /* end must be >= start or ignore it */
139 if (rp->end < rp->start) {
142 rp->state = LWSRS_COMPLETED;
146 return 1; /* issue range */
149 if (!(c >= '0' && c <= '9')) {
150 rp->state = LWSRS_SYNTAX;
153 rp->end = (rp->end * 10) + (c - '0');
163 lws_ranges_reset(struct lws_range_parsing *rp)
171 rp->state = LWSRS_BYTES_EQ;
175 * returns count of valid ranges
178 lws_ranges_init(struct lws *wsi, struct lws_range_parsing *rp,
179 unsigned long long extent)
184 rp->count_ranges = 0;
186 lws_ranges_reset(rp);
187 rp->state = LWSRS_COMPLETED;
191 if (lws_hdr_copy(wsi, (char *)rp->buf, sizeof(rp->buf),
192 WSI_TOKEN_HTTP_RANGE) <= 0)
195 rp->state = LWSRS_BYTES_EQ;
197 while (lws_ranges_next(rp)) {
199 rp->agg += rp->end - rp->start + 1;
202 lwsl_debug("%s: count %d\n", __func__, rp->count_ranges);
203 lws_ranges_reset(rp);
205 if (rp->did_try && !rp->count_ranges)
206 return -1; /* "not satisfiable */
210 return rp->count_ranges;