diff options
Diffstat (limited to 'thirdparty/lws/server/ranges.c')
-rw-r--r-- | thirdparty/lws/server/ranges.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/thirdparty/lws/server/ranges.c b/thirdparty/lws/server/ranges.c new file mode 100644 index 0000000000..bc1578d733 --- /dev/null +++ b/thirdparty/lws/server/ranges.c @@ -0,0 +1,214 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * RFC7233 ranges parser + * + * Copyright (C) 2016 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "private-libwebsockets.h" + +/* + * RFC7233 examples + * + * o The first 500 bytes (byte offsets 0-499, inclusive): + * + * bytes=0-499 + * + * o The second 500 bytes (byte offsets 500-999, inclusive): + * + * bytes=500-999 + * + * o The final 500 bytes (byte offsets 9500-9999, inclusive): + * + * bytes=-500 + * + * Or: + * + * bytes=9500- + * + * o The first and last bytes only (bytes 0 and 9999): + * + * bytes=0-0,-1 + * + * o Other valid (but not canonical) specifications of the second 500 + * bytes (byte offsets 500-999, inclusive): + * + * bytes=500-600,601-999 + * bytes=500-700,601-999 + */ + +/* + * returns 1 if the range struct represents a usable range + * if no ranges header, you get one of these for the whole + * file. Otherwise you get one for each valid range in the + * header. + * + * returns 0 if no further valid range forthcoming; rp->state + * may be LWSRS_SYNTAX or LWSRS_COMPLETED + */ + +int +lws_ranges_next(struct lws_range_parsing *rp) +{ + static const char * const beq = "bytes="; + char c; + + while (1) { + + c = rp->buf[rp->pos]; + + switch (rp->state) { + case LWSRS_SYNTAX: + case LWSRS_COMPLETED: + return 0; + + case LWSRS_NO_ACTIVE_RANGE: + rp->state = LWSRS_COMPLETED; + return 0; + + case LWSRS_BYTES_EQ: // looking for "bytes=" + if (c != beq[rp->pos]) { + rp->state = LWSRS_SYNTAX; + return -1; + } + if (rp->pos == 5) + rp->state = LWSRS_FIRST; + break; + + case LWSRS_FIRST: + rp->start = 0; + rp->end = 0; + rp->start_valid = 0; + rp->end_valid = 0; + + rp->state = LWSRS_STARTING; + + // fallthru + + case LWSRS_STARTING: + if (c == '-') { + rp->state = LWSRS_ENDING; + break; + } + + if (!(c >= '0' && c <= '9')) { + rp->state = LWSRS_SYNTAX; + return 0; + } + rp->start = (rp->start * 10) + (c - '0'); + rp->start_valid = 1; + break; + + case LWSRS_ENDING: + if (c == ',' || c == '\0') { + rp->state = LWSRS_FIRST; + if (c == ',') + rp->pos++; + + /* + * By the end of this, start and end are + * always valid if the range still is + */ + + if (!rp->start_valid) { /* eg, -500 */ + if (rp->end > rp->extent) + rp->end = rp->extent; + + rp->start = rp->extent - rp->end; + rp->end = rp->extent - 1; + } else + if (!rp->end_valid) + rp->end = rp->extent - 1; + + rp->did_try = 1; + + /* end must be >= start or ignore it */ + if (rp->end < rp->start) { + if (c == ',') + break; + rp->state = LWSRS_COMPLETED; + return 0; + } + + return 1; /* issue range */ + } + + if (!(c >= '0' && c <= '9')) { + rp->state = LWSRS_SYNTAX; + return 0; + } + rp->end = (rp->end * 10) + (c - '0'); + rp->end_valid = 1; + break; + } + + rp->pos++; + } +} + +void +lws_ranges_reset(struct lws_range_parsing *rp) +{ + rp->pos = 0; + rp->ctr = 0; + rp->start = 0; + rp->end = 0; + rp->start_valid = 0; + rp->end_valid = 0; + rp->state = LWSRS_BYTES_EQ; +} + +/* + * returns count of valid ranges + */ +int +lws_ranges_init(struct lws *wsi, struct lws_range_parsing *rp, + unsigned long long extent) +{ + rp->agg = 0; + rp->send_ctr = 0; + rp->inside = 0; + rp->count_ranges = 0; + rp->did_try = 0; + lws_ranges_reset(rp); + rp->state = LWSRS_COMPLETED; + + rp->extent = extent; + + if (lws_hdr_copy(wsi, (char *)rp->buf, sizeof(rp->buf), + WSI_TOKEN_HTTP_RANGE) <= 0) + return 0; + + rp->state = LWSRS_BYTES_EQ; + + while (lws_ranges_next(rp)) { + rp->count_ranges++; + rp->agg += rp->end - rp->start + 1; + } + + lwsl_debug("%s: count %d\n", __func__, rp->count_ranges); + lws_ranges_reset(rp); + + if (rp->did_try && !rp->count_ranges) + return -1; /* "not satisfiable */ + + lws_ranges_next(rp); + + return rp->count_ranges; +} |