Imported Upstream version 3.2.0
[platform/upstream/libwebsockets.git] / lib / roles / http / server / ranges.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * RFC7233 ranges parser
5  *
6  * Copyright (C) 2016 Andy Green <andy@warmcat.com>
7  *
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.
12  *
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.
17  *
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,
21  *  MA  02110-1301  USA
22  */
23
24 #include "core/private.h"
25
26 /*
27  * RFC7233 examples
28  *
29  * o  The first 500 bytes (byte offsets 0-499, inclusive):
30  *
31  *      bytes=0-499
32  *
33  * o  The second 500 bytes (byte offsets 500-999, inclusive):
34  *
35  *      bytes=500-999
36  *
37  * o  The final 500 bytes (byte offsets 9500-9999, inclusive):
38  *
39  *      bytes=-500
40  *
41  * Or:
42  *
43  *      bytes=9500-
44  *
45  * o  The first and last bytes only (bytes 0 and 9999):
46  *
47  *      bytes=0-0,-1
48  *
49  * o  Other valid (but not canonical) specifications of the second 500
50  *    bytes (byte offsets 500-999, inclusive):
51  *
52  *      bytes=500-600,601-999
53  *      bytes=500-700,601-999
54  */
55
56 /*
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
60  *   header.
61  *
62  * returns 0 if no further valid range forthcoming; rp->state
63  *   may be LWSRS_SYNTAX or LWSRS_COMPLETED
64  */
65
66 int
67 lws_ranges_next(struct lws_range_parsing *rp)
68 {
69         static const char * const beq = "bytes=";
70
71         while (1) {
72
73                 char c = rp->buf[rp->pos];
74
75                 switch (rp->state) {
76                 case LWSRS_SYNTAX:
77                 case LWSRS_COMPLETED:
78                         return 0;
79
80                 case LWSRS_NO_ACTIVE_RANGE:
81                         rp->state = LWSRS_COMPLETED;
82                         return 0;
83
84                 case LWSRS_BYTES_EQ: // looking for "bytes="
85                         if (c != beq[rp->pos]) {
86                                 rp->state = LWSRS_SYNTAX;
87                                 return -1;
88                         }
89                         if (rp->pos == 5)
90                                 rp->state = LWSRS_FIRST;
91                         break;
92
93                 case LWSRS_FIRST:
94                         rp->start = 0;
95                         rp->end = 0;
96                         rp->start_valid = 0;
97                         rp->end_valid = 0;
98
99                         rp->state = LWSRS_STARTING;
100
101                         // fallthru
102
103                 case LWSRS_STARTING:
104                         if (c == '-') {
105                                 rp->state = LWSRS_ENDING;
106                                 break;
107                         }
108
109                         if (!(c >= '0' && c <= '9')) {
110                                 rp->state = LWSRS_SYNTAX;
111                                 return 0;
112                         }
113                         rp->start = (rp->start * 10) + (c - '0');
114                         rp->start_valid = 1;
115                         break;
116
117                 case LWSRS_ENDING:
118                         if (c == ',' || c == '\0') {
119                                 rp->state = LWSRS_FIRST;
120                                 if (c == ',')
121                                         rp->pos++;
122
123                                 /*
124                                  * By the end of this, start and end are
125                                  * always valid if the range still is
126                                  */
127
128                                 if (!rp->start_valid) { /* eg, -500 */
129                                         if (rp->end > rp->extent)
130                                                 rp->end = rp->extent;
131
132                                         rp->start = rp->extent - rp->end;
133                                         rp->end = rp->extent - 1;
134                                 } else
135                                         if (!rp->end_valid)
136                                                 rp->end = rp->extent - 1;
137
138                                 rp->did_try = 1;
139
140                                 /* end must be >= start or ignore it */
141                                 if (rp->end < rp->start) {
142                                         if (c == ',')
143                                                 break;
144                                         rp->state = LWSRS_COMPLETED;
145                                         return 0;
146                                 }
147
148                                 return 1; /* issue range */
149                         }
150
151                         if (!(c >= '0' && c <= '9')) {
152                                 rp->state = LWSRS_SYNTAX;
153                                 return 0;
154                         }
155                         rp->end = (rp->end * 10) + (c - '0');
156                         rp->end_valid = 1;
157                         break;
158                 }
159
160                 rp->pos++;
161         }
162 }
163
164 void
165 lws_ranges_reset(struct lws_range_parsing *rp)
166 {
167         rp->pos = 0;
168         rp->ctr = 0;
169         rp->start = 0;
170         rp->end = 0;
171         rp->start_valid = 0;
172         rp->end_valid = 0;
173         rp->state = LWSRS_BYTES_EQ;
174 }
175
176 /*
177  * returns count of valid ranges
178  */
179 int
180 lws_ranges_init(struct lws *wsi, struct lws_range_parsing *rp,
181                 unsigned long long extent)
182 {
183         rp->agg = 0;
184         rp->send_ctr = 0;
185         rp->inside = 0;
186         rp->count_ranges = 0;
187         rp->did_try = 0;
188         lws_ranges_reset(rp);
189         rp->state = LWSRS_COMPLETED;
190
191         rp->extent = extent;
192
193         if (lws_hdr_copy(wsi, (char *)rp->buf, sizeof(rp->buf),
194                          WSI_TOKEN_HTTP_RANGE) <= 0)
195                 return 0;
196
197         rp->state = LWSRS_BYTES_EQ;
198
199         while (lws_ranges_next(rp)) {
200                 rp->count_ranges++;
201                 rp->agg += rp->end - rp->start + 1;
202         }
203
204         lwsl_debug("%s: count %d\n", __func__, rp->count_ranges);
205         lws_ranges_reset(rp);
206
207         if (rp->did_try && !rp->count_ranges)
208                 return -1; /* "not satisfiable */
209
210         lws_ranges_next(rp);
211
212         return rp->count_ranges;
213 }