• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 
27 /*
28  * RFC7233 examples
29  *
30  * o  The first 500 bytes (byte offsets 0-499, inclusive):
31  *
32  *      bytes=0-499
33  *
34  * o  The second 500 bytes (byte offsets 500-999, inclusive):
35  *
36  *      bytes=500-999
37  *
38  * o  The final 500 bytes (byte offsets 9500-9999, inclusive):
39  *
40  *      bytes=-500
41  *
42  * Or:
43  *
44  *      bytes=9500-
45  *
46  * o  The first and last bytes only (bytes 0 and 9999):
47  *
48  *      bytes=0-0,-1
49  *
50  * o  Other valid (but not canonical) specifications of the second 500
51  *    bytes (byte offsets 500-999, inclusive):
52  *
53  *      bytes=500-600,601-999
54  *      bytes=500-700,601-999
55  */
56 
57 /*
58  * returns 1 if the range struct represents a usable range
59  *   if no ranges header, you get one of these for the whole
60  *   file.  Otherwise you get one for each valid range in the
61  *   header.
62  *
63  * returns 0 if no further valid range forthcoming; rp->state
64  *   may be LWSRS_SYNTAX or LWSRS_COMPLETED
65  */
66 
67 int
lws_ranges_next(struct lws_range_parsing * rp)68 lws_ranges_next(struct lws_range_parsing *rp)
69 {
70 	static const char * const beq = "bytes=";
71 
72 	while (1) {
73 
74 		char c = rp->buf[rp->pos];
75 
76 		switch (rp->state) {
77 		case LWSRS_SYNTAX:
78 		case LWSRS_COMPLETED:
79 			return 0;
80 
81 		case LWSRS_NO_ACTIVE_RANGE:
82 			rp->state = LWSRS_COMPLETED;
83 			return 0;
84 
85 		case LWSRS_BYTES_EQ: // looking for "bytes="
86 			if (c != beq[rp->pos]) {
87 				rp->state = LWSRS_SYNTAX;
88 				return -1;
89 			}
90 			if (rp->pos == 5)
91 				rp->state = LWSRS_FIRST;
92 			break;
93 
94 		case LWSRS_FIRST:
95 			rp->start = 0;
96 			rp->end = 0;
97 			rp->start_valid = 0;
98 			rp->end_valid = 0;
99 
100 			rp->state = LWSRS_STARTING;
101 
102 			// fallthru
103 
104 		case LWSRS_STARTING:
105 			if (c == '-') {
106 				rp->state = LWSRS_ENDING;
107 				break;
108 			}
109 
110 			if (!(c >= '0' && c <= '9')) {
111 				rp->state = LWSRS_SYNTAX;
112 				return 0;
113 			}
114 			rp->start = (unsigned long long)(((unsigned long long)rp->start * 10) + (unsigned long long)(c - '0'));
115 			rp->start_valid = 1;
116 			break;
117 
118 		case LWSRS_ENDING:
119 			if (c == ',' || c == '\0') {
120 				rp->state = LWSRS_FIRST;
121 				if (c == ',')
122 					rp->pos++;
123 
124 				/*
125 				 * By the end of this, start and end are
126 				 * always valid if the range still is
127 				 */
128 
129 				if (!rp->start_valid) { /* eg, -500 */
130 					if (rp->end > rp->extent)
131 						rp->end = rp->extent;
132 
133 					rp->start = rp->extent - rp->end;
134 					rp->end = rp->extent - 1;
135 				} else
136 					if (!rp->end_valid)
137 						rp->end = rp->extent - 1;
138 
139 				rp->did_try = 1;
140 
141 				/* end must be >= start or ignore it */
142 				if (rp->end < rp->start) {
143 					if (c == ',')
144 						break;
145 					rp->state = LWSRS_COMPLETED;
146 					return 0;
147 				}
148 
149 				return 1; /* issue range */
150 			}
151 
152 			if (!(c >= '0' && c <= '9')) {
153 				rp->state = LWSRS_SYNTAX;
154 				return 0;
155 			}
156 			rp->end = (unsigned long long)(((unsigned long long)rp->end * 10) + (unsigned long long)(c - '0'));
157 			rp->end_valid = 1;
158 			break;
159 		}
160 
161 		rp->pos++;
162 	}
163 }
164 
165 void
lws_ranges_reset(struct lws_range_parsing * rp)166 lws_ranges_reset(struct lws_range_parsing *rp)
167 {
168 	rp->pos = 0;
169 	rp->ctr = 0;
170 	rp->start = 0;
171 	rp->end = 0;
172 	rp->start_valid = 0;
173 	rp->end_valid = 0;
174 	rp->state = LWSRS_BYTES_EQ;
175 }
176 
177 /*
178  * returns count of valid ranges
179  */
180 int
lws_ranges_init(struct lws * wsi,struct lws_range_parsing * rp,unsigned long long extent)181 lws_ranges_init(struct lws *wsi, struct lws_range_parsing *rp,
182 		unsigned long long extent)
183 {
184 	rp->agg = 0;
185 	rp->send_ctr = 0;
186 	rp->inside = 0;
187 	rp->count_ranges = 0;
188 	rp->did_try = 0;
189 	lws_ranges_reset(rp);
190 	rp->state = LWSRS_COMPLETED;
191 
192 	rp->extent = extent;
193 
194 	if (lws_hdr_copy(wsi, (char *)rp->buf, sizeof(rp->buf),
195 			 WSI_TOKEN_HTTP_RANGE) <= 0)
196 		return 0;
197 
198 	rp->state = LWSRS_BYTES_EQ;
199 
200 	while (lws_ranges_next(rp)) {
201 		rp->count_ranges++;
202 		rp->agg += rp->end - rp->start + 1;
203 	}
204 
205 	lwsl_debug("%s: count %d\n", __func__, rp->count_ranges);
206 	lws_ranges_reset(rp);
207 
208 	if (rp->did_try && !rp->count_ranges)
209 		return -1; /* "not satisfiable */
210 
211 	lws_ranges_next(rp);
212 
213 	return rp->count_ranges;
214 }
215