1 /**
2 * Copyright 2010 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 math module
23 */
24
25 /************************************************************************
26 * Includes
27 ***********************************************************************/
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <math.h>
33
34 #include "eval.h"
35
36 #include "module.h"
37
38 /************************************************************************
39 * Definitions
40 ***********************************************************************/
41
42 /************************************************************************
43 * Globals
44 ***********************************************************************/
45
46 /************************************************************************
47 * Local
48 ***********************************************************************/
49
50 /************************************************************************
51 * Commands
52 ***********************************************************************/
53 /**
54 * Evaluate a math expression, should be extended with >, <, >=,<=, == and !
55 * @param worker IN worker instance
56 * @param parent IN caller
57 * @param ptmp IN temporary pool for this function
58 * @return APR_SUCCESS or APR_EINVAL if expression is incorrect
59 */
block_MATH_EVAL(worker_t * worker,worker_t * parent,apr_pool_t * ptmp)60 static apr_status_t block_MATH_EVAL(worker_t *worker, worker_t *parent,
61 apr_pool_t *ptmp) {
62 apr_status_t status;
63 long val;
64 const char *value = store_get(worker->params, "1");
65 const char *var = store_get(worker->params, "2");
66 char *expr = apr_pstrdup(ptmp, value);
67 math_eval_t *eval_hook = math_eval_make(ptmp);
68
69 if (!value) {
70 worker_log(worker, LOG_ERR, "Missing expression");
71 return APR_EINVAL;
72 }
73
74 if (!var) {
75 worker_log(worker, LOG_ERR, "Missing variable");
76 return APR_EINVAL;
77 }
78
79 if ((status = math_evaluate(eval_hook, expr, &val)) != APR_SUCCESS) {
80 worker_log(worker, LOG_ERR, "Expression \"%s\" not valid", expr);
81 return status;
82 }
83
84 worker_var_set(parent, var, apr_ltoa(ptmp, val));
85 return APR_SUCCESS;
86 }
87
88 /**
89 * Legacy simple math evaluator us block_MATH_EVAL instead
90 * @param worker IN worker instance
91 * @param parent IN caller
92 * @param ptmp IN temporary pool for this function
93 * @return APR_SUCCESS or APR_EINVAL if expression is incorrect
94 */
block_MATH_OP(worker_t * worker,worker_t * parent,apr_pool_t * ptmp)95 static apr_status_t block_MATH_OP(worker_t *worker, worker_t *parent,
96 apr_pool_t *ptmp) {
97 const char *param;
98 const char *op;
99 apr_int64_t ileft;
100 apr_int64_t iright;
101 apr_int64_t result;
102
103 param = store_get(worker->params, "1");
104 if (param == NULL) {
105 worker_log(worker, LOG_ERR, "<left> value expected");
106 return APR_EINVAL;
107 }
108 ileft = apr_atoi64(param);
109
110 op = store_get(worker->params, "2");
111 if (op == NULL) {
112 worker_log(worker, LOG_ERR, "ADD, SUB, MUL or DIV expected");
113 return APR_EINVAL;
114 }
115
116 param = store_get(worker->params, "3");
117 if (param == NULL) {
118 worker_log(worker, LOG_ERR, "<right> value expected");
119 return APR_EINVAL;
120 }
121 iright = apr_atoi64(param);
122
123 param = store_get(worker->params, "4");
124 if (param == NULL) {
125 worker_log(worker, LOG_ERR, "<var> expected");
126 return APR_EINVAL;
127 }
128
129 /* do operation */
130 if (strcasecmp(op, "ADD") == 0) {
131 result = ileft + iright;
132 }
133 else if (strcasecmp(op, "SUB") == 0) {
134 result = ileft - iright;
135 }
136 else if (strcasecmp(op, "MUL") == 0) {
137 result = ileft * iright;
138 }
139 else if (strcasecmp(op, "DIV") == 0) {
140 if (iright == 0) {
141 worker_log(worker, LOG_ERR, "Division by zero");
142 return APR_EINVAL;
143 }
144 result = ileft / iright;
145 }
146 else {
147 worker_log(worker, LOG_ERR, "Unknown operant %s", op);
148 return APR_ENOTIMPL;
149 }
150
151 /* store it do var */
152 worker_var_set(parent, param, apr_off_t_toa(ptmp, result));
153
154 return APR_SUCCESS;
155 }
156
157 /**
158 * Generate a random number.
159 * @param worker IN worker instance
160 * @param parent IN caller
161 * @param ptmp IN temporary pool for this function
162 * @return APR_SUCCESS or APR_EINVAL if expression is incorrect
163 */
block_MATH_RAND(worker_t * worker,worker_t * parent,apr_pool_t * ptmp)164 static apr_status_t block_MATH_RAND(worker_t *worker, worker_t *parent,
165 apr_pool_t *ptmp) {
166 int start;
167 int end;
168 int result;
169
170 const char *val = store_get(worker->params, "1");
171 if (val == NULL) {
172 worker_log(worker, LOG_ERR, "No start defined");
173 return APR_EINVAL;
174 }
175 start = apr_atoi64(val);
176
177 val = store_get(worker->params, "2");
178 if (val == NULL) {
179 worker_log(worker, LOG_ERR, "No end defined");
180 return APR_EINVAL;
181 }
182 end = apr_atoi64(val);
183
184 val = store_get(worker->params, "3");
185 if (val == NULL) {
186 worker_log(worker, LOG_ERR, "No variable name specified");
187 return APR_EINVAL;
188 }
189
190 result = start + (rand() % (end - start));
191
192 worker_var_set(parent, val, apr_itoa(ptmp, result));
193
194 return APR_SUCCESS;
195 }
196
197 /************************************************************************
198 * Module
199 ***********************************************************************/
math_module_init(global_t * global)200 apr_status_t math_module_init(global_t * global) {
201 apr_status_t status;
202 if ((status =
203 module_command_new(global, "MATH", "_EVAL", "<expression> <var>",
204 "callculates <expression> and stores it in <var>",
205 block_MATH_EVAL)) != APR_SUCCESS) {
206 return status;
207 }
208
209 if ((status =
210 module_command_new(global, "MATH", "_OP", "<left> ADD|SUB|DIV|MUL <right> <variable>",
211 "Legacy math evaluator use _MATH:EVAL instead",
212 block_MATH_OP)) != APR_SUCCESS) {
213 return status;
214 }
215
216 if ((status =
217 module_command_new(global, "MATH", "_RAND", "<start> <end> <var>",
218 "Generates a number between <start> and <end> and stores result in"
219 "<var>",
220 block_MATH_RAND)) != APR_SUCCESS) {
221 return status;
222 }
223 return APR_SUCCESS;
224 }
225