1 /**
2  * Copyright 2006 Christian Liesch
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * 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  * @file
19  *
20  * @Author christian liesch <liesch@gmx.ch>
21  *
22  * Implementation of the HTTP Test Tool htt_regex.
23  */
24 
25 /************************************************************************
26  * Includes
27  ***********************************************************************/
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <apr.h>
33 #include <apr_strings.h>
34 
35 #include "defines.h"
36 #include "regex.h"
37 
38 
39 /************************************************************************
40  * Definitions
41  ***********************************************************************/
42 
43 struct htt_regex_s {
44   const char *pattern;
45   int match;
46   void *re_pcre;
47   apr_size_t re_nsub;
48   apr_size_t re_erroffset;
49 };
50 
51 #ifndef POSIX_MALLOC_THRESHOLD
52 #define POSIX_MALLOC_THRESHOLD (10)
53 #endif
54 
55 
56 /************************************************************************
57  * Forward declaration
58  ***********************************************************************/
59 
60 static apr_status_t htt_regex_cleanup(void *preg);
61 
62 
63 /************************************************************************
64  * Implementation
65  ***********************************************************************/
66 
67 /**
68  * Compile a pattern to a regular expression
69  *
70  * @param p IN pool
71  * @param pattern IN pattern to compile
72  * @param error IN error string
73  * @param erroff IN offset into pattern wherer compilation fails
74  *
75  * @return regular express on success else NULL
76  */
htt_regexcomp(apr_pool_t * p,const char * pattern,const char ** error,int * erroff)77 htt_regex_t *htt_regexcomp(apr_pool_t * p, const char *pattern,
78                   const char **error, int *erroff) {
79   htt_regex_t *preg = apr_palloc(p, sizeof *preg);
80 
81   preg->match = 0;
82   preg->pattern = apr_pstrdup(p, pattern);
83 
84   preg->re_pcre = pcre_compile(pattern, 0, error, erroff, NULL);
85   preg->re_erroffset = *erroff;
86 
87   if (preg->re_pcre == NULL) {
88     return NULL;
89   }
90 
91   pcre_fullinfo((const pcre *)preg->re_pcre, NULL, PCRE_INFO_CAPTURECOUNT, &(preg->re_nsub));
92 
93   apr_pool_cleanup_register(p, (void *) preg, htt_regex_cleanup,
94                             apr_pool_cleanup_null);
95 
96   return preg;
97 }
98 
99 /**
100  * Execute a string on a compiled regular expression
101  *
102  * @param preg IN regular expression
103  * @param data IN data to parse
104  * @param len IN data length
105  * @param nmatch IN number of matches
106  * @param pmatch IN offest of matched substrings
107  * @param eflags IN extended flags see pcre.h
108  *
109  * @return 0 on success
110  */
htt_regexec(htt_regex_t * preg,const char * data,apr_size_t len,apr_size_t nmatch,regmatch_t pmatch[],int eflags)111 int htt_regexec(htt_regex_t * preg, const char *data, apr_size_t len,
112             apr_size_t nmatch, regmatch_t pmatch[], int eflags) {
113   int rc;
114   int options = 0;
115   int *ovector = NULL;
116   int small_ovector[POSIX_MALLOC_THRESHOLD * 3];
117   int allocated_ovector = 0;
118 
119   ((htt_regex_t *) preg)->re_erroffset = (apr_size_t) (-1); /* Only has meaning after compile */
120 
121   if (nmatch > 0) {
122     if (nmatch <= POSIX_MALLOC_THRESHOLD) {
123       ovector = &(small_ovector[0]);
124     }
125     else {
126       ovector = (int *) malloc(sizeof(int) * nmatch * 3);
127       allocated_ovector = 1;
128     }
129   }
130 
131   rc = pcre_exec((const pcre *) preg->re_pcre, NULL, data,
132                  len, 0, options, ovector, nmatch * 3);
133 
134   if (rc == 0) {
135     rc = nmatch;                /* All captured slots were filled in */
136   }
137 
138   if (rc >= 0) {
139     apr_size_t i;
140     for (i = 0; i < (apr_size_t) rc; i++) {
141       pmatch[i].rm_so = ovector[i * 2];
142       pmatch[i].rm_eo = ovector[i * 2 + 1];
143     }
144     if (allocated_ovector) {
145       free(ovector);
146     }
147     for (; i < nmatch; i++)
148       pmatch[i].rm_so = pmatch[i].rm_eo = -1;
149     ++preg->match;
150     return 0;
151   }
152   else {
153     if (allocated_ovector) {
154       free(ovector);
155     }
156     return rc;
157   }
158 }
159 
160 /**
161  * returns number of matches on this regular expression
162  *
163  * @param preg IN regular expression
164  *
165  * @return number of matches
166  */
htt_regexhits(htt_regex_t * preg)167 int htt_regexhits(htt_regex_t * preg) {
168   return preg->match;
169 }
170 
171 /**
172  * return pattern of compiled htt_regex
173  * @param preg IN regular expression
174  * @return pattern
175  */
htt_regexpattern(htt_regex_t * reg)176 const char *htt_regexpattern(htt_regex_t *reg) {
177   return reg->pattern;
178 }
179 
180 /**
181  * Clean up function for pool cleanup
182  *
183  * @preg IN compiled regular expression
184  *
185  * @return APR_SUCCESS
186  */
htt_regex_cleanup(void * preg)187 static apr_status_t htt_regex_cleanup(void *preg) {
188   pcre_free(((htt_regex_t *) preg)->re_pcre);
189   return APR_SUCCESS;
190 }
191 
192