]> granicus.if.org Git - apache/blob - server/util_expr_scan.l
Fix wrong condition that may lead to NULL being set as 'Vary' header
[apache] / server / util_expr_scan.l
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  *  ap_expr_scan.l, based on ssl_expr_scan.l from mod_ssl
19  */
20
21 /*  _________________________________________________________________
22 **
23 **  Expression Scanner
24 **  _________________________________________________________________
25 */
26
27 %pointer
28 %option batch
29 %option never-interactive
30 %option nodefault
31 %option noyywrap
32 %option reentrant
33 %option bison-bridge
34 %option warn
35 %option noinput nounput noyy_top_state
36 %option stack
37 %x str
38 %x var
39 %x vararg
40 %x regex regex_flags
41
42 %{
43 #include "util_expr_private.h"
44 #include "util_expr_parse.h"
45
46 #undef  YY_INPUT
47 #define YY_INPUT(buf,result,max_size)                       \
48 {                                                           \
49     if ((result = MIN(max_size, yyextra->inputbuf           \
50                               + yyextra->inputlen           \
51                               - yyextra->inputptr)) <= 0)   \
52     {                                                       \
53         result = YY_NULL;                                   \
54     }                                                       \
55     else {                                                  \
56         memcpy(buf, yyextra->inputptr, result);             \
57         yyextra->inputptr += result;                        \
58     }                                                       \
59 }
60
61 #define YY_EXTRA_TYPE ap_expr_parse_ctx_t*
62
63 #define PERROR(msg) yyextra->error2 = msg ; return T_ERROR;
64
65 #define str_ptr     (yyextra->scan_ptr)
66 #define str_buf     (yyextra->scan_buf)
67 #define str_del     (yyextra->scan_del)
68
69 %}
70
71
72 %%
73
74   char  regex_buf[MAX_STRING_LEN];
75   char *regex_ptr = NULL;
76   char  regex_del = '\0';
77
78  /*
79   * Whitespaces
80   */
81 [ \t\n]+ { 
82     /* NOP */
83 }
84
85  /*
86   * strings ("..." and '...')
87   */
88 ["'] {
89     str_ptr = str_buf;
90     str_del = yytext[0];
91     BEGIN(str);
92     return T_STR_BEGIN;
93 }
94 <str>["'] {
95     if (yytext[0] == str_del) {
96         if (YY_START == var) {
97             PERROR("Unterminated variable in string");
98         }
99         else if (str_ptr == str_buf) {
100             BEGIN(INITIAL);
101             return T_STR_END;
102         }
103         else {
104             /* return what we have so far and scan delimiter again */
105             *str_ptr = '\0';
106             yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
107             yyless(0);
108             str_ptr = str_buf;
109             return T_STRING;
110         }
111     }
112     else {
113         *str_ptr++ = yytext[0];
114     }
115 }
116 <str,var,vararg>\n {
117     PERROR("Unterminated string or variable");
118 }
119 <str,var,vararg><<EOF>> {
120     PERROR("Unterminated string or variable");
121 }
122 <str,vararg>\\[0-7]{1,3} {
123     int result;
124
125     (void)sscanf(yytext+1, "%o", &result);
126     if (result > 0xff) {
127         PERROR("Escape sequence out of bound");
128     }
129     else {
130         *str_ptr++ = result;
131     }
132 }
133 <str,vararg>\\[0-9]+ {
134     PERROR("Bad escape sequence");
135 }
136 <str,vararg>\\n { *str_ptr++ = '\n'; }
137 <str,vararg>\\r { *str_ptr++ = '\r'; }
138 <str,vararg>\\t { *str_ptr++ = '\t'; }
139 <str,vararg>\\b { *str_ptr++ = '\b'; }
140 <str,vararg>\\f { *str_ptr++ = '\f'; }
141 <str,vararg>\\(.|\n) {
142     *str_ptr++ = yytext[1];
143 }
144
145  /* regexp backref inside string/arg */
146 <str,vararg>[$][0-9] {
147     if (str_ptr != str_buf) {
148         /* return what we have so far and scan '$x' again */
149         *str_ptr = '\0';
150         yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
151         str_ptr = str_buf;
152         yyless(0);
153         return T_STRING;
154     }
155     else {
156         yylval->num = yytext[1] - '0';
157         return T_REGEX_BACKREF;
158     }
159 }
160
161 <str,vararg>[^\\\n"'%}$]+ {
162     char *cp = yytext;
163     while (*cp != '\0')
164         *str_ptr++ = *cp++;
165 }
166
167  /* variable inside string/arg */
168 <str,vararg>%\{ {
169     if (str_ptr != str_buf) {
170         /* return what we have so far and scan '%{' again */
171         *str_ptr = '\0';
172         yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
173         yyless(0);
174         str_ptr = str_buf;
175         return T_STRING;
176     }
177     else {
178         yy_push_state(var, yyscanner);
179         return T_VAR_BEGIN;
180     }
181 }
182
183 <vararg>[%$] {
184      *str_ptr++ = yytext[0];
185 }
186
187 <str>[%}$] {
188      *str_ptr++ = yytext[0];
189 }
190
191 %\{ {
192     yy_push_state(var, yyscanner);
193     return T_VAR_BEGIN;
194 }
195
196 [$][0-9] {
197     yylval->num = yytext[1] - '0';
198     return T_REGEX_BACKREF;
199 }
200
201  /*
202   * fixed name variable expansion %{XXX} and function call in %{func:arg} syntax
203   */
204 <var>[a-zA-Z][a-zA-Z0-9_]* {
205     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
206     return T_ID;
207 }
208
209 <var>\} {
210     yy_pop_state(yyscanner);
211     return T_VAR_END;
212 }
213
214 <var>: {
215     BEGIN(vararg);
216     return yytext[0];
217 }
218
219 <var>.|\n {
220     char *msg = apr_psprintf(yyextra->pool,
221                              "Invalid character in variable name '%c'", yytext[0]);
222     PERROR(msg);
223 }
224
225 <vararg>\} {
226     if (str_ptr != str_buf) {
227         /* return what we have so far and scan '}' again */
228         *str_ptr = '\0';
229         yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
230         str_ptr = str_buf;
231         yyless(0);
232         return T_STRING;
233     }
234     else {
235         yy_pop_state(yyscanner);
236         return T_VAR_END;
237     }
238 }
239
240  /*
241   * Regular Expression
242   */
243 "m"[/#$%^,;:_\?\|\^\-\!\.\'\"] {
244     regex_del = yytext[1];
245     regex_ptr = regex_buf;
246     BEGIN(regex);
247 }
248 "/" {
249     regex_del = yytext[0];
250     regex_ptr = regex_buf;
251     BEGIN(regex);
252 }
253 <regex>.|\n {
254     if (yytext[0] == regex_del) {
255         *regex_ptr = '\0';
256         BEGIN(regex_flags);
257     }
258     else {
259         *regex_ptr++ = yytext[0];
260     }
261 }
262 <regex_flags>i {
263     yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
264     BEGIN(INITIAL);
265     return T_REGEX_I;
266 }
267 <regex_flags>.|\n {
268     yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
269     yyless(0);
270     BEGIN(INITIAL);
271     return T_REGEX;
272 }
273 <regex_flags><<EOF>> {
274     yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
275     BEGIN(INITIAL);
276     return T_REGEX;
277 }
278
279  /*
280   * Operators
281   */
282 ==?   { return T_OP_STR_EQ; }
283 "!="  { return T_OP_STR_NE; }
284 "<"   { return T_OP_STR_LT; }
285 "<="  { return T_OP_STR_LE; }
286 ">"   { return T_OP_STR_GT; }
287 ">="  { return T_OP_STR_GE; }
288 "=~"  { return T_OP_REG; }
289 "!~"  { return T_OP_NRE; }
290 "and" { return T_OP_AND; }
291 "&&"  { return T_OP_AND; }
292 "or"  { return T_OP_OR; }
293 "||"  { return T_OP_OR; }
294 "not" { return T_OP_NOT; }
295 "!"   { return T_OP_NOT; }
296 "."   { return T_OP_CONCAT; }
297 "-in"  { return T_OP_IN; }
298 "-eq"  { return T_OP_EQ; }
299 "-ne"  { return T_OP_NE; }
300 "-ge"  { return T_OP_GE; }
301 "-le"  { return T_OP_LE; }
302 "-gt"  { return T_OP_GT; }
303 "-lt"  { return T_OP_LT; }
304
305  /* for compatibility with ssl_expr */
306 "lt"  { return T_OP_LT; }
307 "le"  { return T_OP_LE; }
308 "gt"  { return T_OP_GT; }
309 "ge"  { return T_OP_GE; }
310 "ne"  { return T_OP_NE; }
311 "eq"  { return T_OP_EQ; }
312 "in"  { return T_OP_IN; }
313
314 "-"[a-zA-Z_] {
315     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
316     return T_OP_UNARY;
317 }
318
319 "-"[a-zA-Z_][a-zA-Z_0-9]+ {
320     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
321     return T_OP_BINARY;
322 }
323
324  /*
325   * Specials
326   */
327 "true"  { return T_TRUE; }
328 "false" { return T_FALSE; }
329
330  /*
331   * Digits
332   */
333 -?[0-9]+ {
334     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
335     return T_DIGIT;
336 }
337
338  /*
339   * Identifiers
340   */
341 [a-zA-Z][a-zA-Z0-9_]* {
342     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
343     return T_ID;
344 }
345
346  /*
347   * These are parts of the grammar and are returned as is
348   */
349 [(){},:] {
350     return yytext[0];
351 }
352
353  /*
354   * Anything else is an error
355   */
356 .|\n {
357     char *msg = apr_psprintf(yyextra->pool, "Parse error near '%c'", yytext[0]);
358     PERROR(msg);
359 }
360
361 %%
362
363