ah: allow configurable ah hold timeout
[platform/upstream/libwebsockets.git] / lib / 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 "private-libwebsockets.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         char c;
71
72         while (1) {
73
74                 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 = (rp->start * 10) + (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                                 /* by the end of this, start and end are always valid if the range still is */
125
126                                 if (!rp->start_valid) { /* eg, -500 */
127                                         if (rp->end > rp->extent)
128                                                 rp->end = rp->extent;
129
130                                         rp->start = rp->extent - rp->end;
131                                         rp->end = rp->extent - 1;
132                                 } else
133                                         if (!rp->end_valid)
134                                                 rp->end = rp->extent - 1;
135
136                                 rp->did_try = 1;
137
138                                 /* end must be >= start or ignore it */
139                                 if (rp->end < rp->start) {
140                                         if (c == ',')
141                                                 break;
142                                         rp->state = LWSRS_COMPLETED;
143                                         return 0;
144                                 }
145
146                                 return 1; /* issue range */
147                         }
148
149                         if (!(c >= '0' && c <= '9')) {
150                                 rp->state = LWSRS_SYNTAX;
151                                 return 0;
152                         }
153                         rp->end = (rp->end * 10) + (c - '0');
154                         rp->end_valid = 1;
155                         break;
156                 }
157
158                 rp->pos++;
159         }
160 }
161
162 void
163 lws_ranges_reset(struct lws_range_parsing *rp)
164 {
165         rp->pos = 0;
166         rp->ctr = 0;
167         rp->start = 0;
168         rp->end = 0;
169         rp->start_valid = 0;
170         rp->end_valid = 0;
171         rp->state = LWSRS_BYTES_EQ;
172 }
173
174 /*
175  * returns count of valid ranges
176  */
177 int
178 lws_ranges_init(struct lws *wsi, struct lws_range_parsing *rp,
179                 unsigned long long extent)
180 {
181         rp->agg = 0;
182         rp->send_ctr = 0;
183         rp->inside = 0;
184         rp->count_ranges = 0;
185         rp->did_try = 0;
186         lws_ranges_reset(rp);
187         rp->state = LWSRS_COMPLETED;
188
189         rp->extent = extent;
190
191         if (lws_hdr_copy(wsi, (char *)rp->buf, sizeof(rp->buf),
192                          WSI_TOKEN_HTTP_RANGE) <= 0)
193                 return 0;
194
195         rp->state = LWSRS_BYTES_EQ;
196
197         while (lws_ranges_next(rp)) {
198                 rp->count_ranges++;
199                 rp->agg += rp->end - rp->start + 1;
200         }
201
202         lwsl_debug("%s: count %d\n", __func__, rp->count_ranges);
203         lws_ranges_reset(rp);
204
205         if (rp->did_try && !rp->count_ranges)
206                 return -1; /* "not satisfiable */
207
208         lws_ranges_next(rp);
209
210         return rp->count_ranges;
211 }