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 util.
23 */
24
25 /************************************************************************
26 * Includes
27 ***********************************************************************/
28 #include <config.h>
29 #include <apr.h>
30 #include <apr_strings.h>
31 #include <apr_file_io.h>
32 #include <apr_env.h>
33
34 #include "defines.h"
35 #include "util.h"
36
37
38 /************************************************************************
39 * Definitions
40 ***********************************************************************/
41
42
43 /************************************************************************
44 * Forward declaration
45 ***********************************************************************/
46
47
48 /************************************************************************
49 * Implementation
50 ***********************************************************************/
51
52 /**
53 * This function is taken from apr. The apr_tokenize_to_argv do remove
54 * all leftover "\", but this breaks up my httest completly.
55 *
56 * @param pool IN Context from which pool allocations will occur.
57 * @arg_str IN Input argument string for conversion to argv[].
58 * @argv_out IN Output location. This is a pointer to an array
59 * of pointers to strings (ie. &(char *argv[]).
60 * This value will be allocated from the contexts
61 * pool and filled in with copies of the tokens
62 * found during parsing of the arg_str.
63 * @param with_quotes IN do not strip quotes from quoted string
64 *
65 * @return SUCCESS
66 */
my_tokenize_to_argv(const char * arg_str,char *** argv_out,apr_pool_t * pool,int with_quotes)67 apr_status_t my_tokenize_to_argv(const char *arg_str, char ***argv_out,
68 apr_pool_t *pool, int with_quotes)
69 {
70 const char *cp;
71 const char *ct;
72 int isquoted, numargs = 0, argnum;
73
74 #define SKIP_WHITESPACE(cp) \
75 for ( ; *cp == ' ' || *cp == '\t'; ) { \
76 cp++; \
77 };
78
79 #define CHECK_QUOTATION(cp,isquoted) \
80 isquoted = 0; \
81 if (*cp == '"') { \
82 isquoted = 1; \
83 cp++; \
84 } \
85 else if (*cp == '\'') { \
86 isquoted = 2; \
87 cp++; \
88 }
89
90 /* DETERMINE_NEXTSTRING:
91 * At exit, cp will point to one of the following: NULL, SPACE, TAB or QUOTE.
92 * NULL implies the argument string has been fully traversed.
93 */
94 #define DETERMINE_NEXTSTRING(cp,isquoted) \
95 for ( ; *cp != '\0'; cp++) { \
96 if ( (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t' || \
97 *(cp+1) == '"' || *(cp+1) == '\''))) { \
98 cp++; \
99 continue; \
100 } \
101 if ( (!isquoted && (*cp == ' ' || *cp == '\t')) \
102 || (isquoted == 1 && *cp == '"') \
103 || (isquoted == 2 && *cp == '\'') ) { \
104 break; \
105 } \
106 }
107
108 cp = arg_str;
109 SKIP_WHITESPACE(cp);
110 ct = cp;
111
112 /* This is ugly and expensive, but if anyone wants to figure a
113 * way to support any number of args without counting and
114 * allocating, please go ahead and change the code.
115 *
116 * Must account for the trailing NULL arg.
117 */
118 numargs = 1;
119 while (*ct != '\0') {
120 CHECK_QUOTATION(ct, isquoted);
121 DETERMINE_NEXTSTRING(ct, isquoted);
122 if (*ct != '\0') {
123 ct++;
124 }
125 numargs++;
126 SKIP_WHITESPACE(ct);
127 }
128 *argv_out = apr_palloc(pool, numargs * sizeof(char*));
129
130 /* determine first argument */
131 for (argnum = 0; argnum < (numargs-1); argnum++) {
132 SKIP_WHITESPACE(cp);
133 CHECK_QUOTATION(cp, isquoted);
134 ct = cp;
135 DETERMINE_NEXTSTRING(cp, isquoted);
136 cp++;
137 /* do not swallow quotes */
138 if (isquoted && with_quotes) {
139 (*argv_out)[argnum] = apr_palloc(pool, (cp+1) - (ct-1));
140 apr_cpystrn((*argv_out)[argnum], ct-1, (cp+1) - (ct-1));
141 }
142 else {
143 (*argv_out)[argnum] = apr_palloc(pool, cp - ct);
144 apr_cpystrn((*argv_out)[argnum], ct, cp - ct);
145 }
146 }
147 (*argv_out)[argnum] = NULL;
148
149 return APR_SUCCESS;
150 }
151
152 /**
153 * @deprecitated: should do everything with new my_get_args
154 * get a string starting/ending with a char, unescape this char if found as an
155 * escape sequence.
156 *
157 * @param string IN <char><string with escaped <char>><char>
158 * @param last OUT pointer to next char after cutted string
159 *
160 * @return <string with unescaped <char>>
161 * @note: Example: "foo bar \"hallo velo\"" -> foo bar "hallo velo"
162 */
my_unescape(char * string,char ** last)163 char *my_unescape(char *string, char **last) {
164 char *result;
165 char enclose;
166 apr_size_t i;
167 apr_size_t j;
168 apr_size_t len;
169
170 if (!string) {
171 return string;
172 }
173
174 len = strlen(string);
175
176 enclose = string[0];
177 result = string;
178 for (i = 1, j = 0; i < len; i++, j++) {
179 /* check if we have an escape char */
180 if (string[i] == '\\') {
181 /* lookahead */
182 ++i;
183 /* if lookahead is not \ or " store the \ too, else skip */
184 if (string[i] != '\\' && string[i] != enclose) {
185 result[j] = '\\';
186 ++j;
187 }
188 }
189 /* break if we got the first char unescaped */
190 else if (string[i] == enclose) {
191 ++i;
192 break;
193 }
194 /* store char in result */
195 result[j] = string[i];
196 }
197 result[j] = 0;
198 *last = &string[i];
199 return result;
200 }
201
202 /**
203 * Deep table copy
204 *
205 * @param p IN pool
206 * @param orig IN orig table
207 *
208 * @return copy of orig
209 */
my_table_deep_copy(apr_pool_t * p,apr_table_t * orig)210 apr_table_t *my_table_deep_copy(apr_pool_t *p, apr_table_t *orig) {
211 apr_table_entry_t *e;
212 apr_table_t *dest;
213 int i;
214 apr_size_t size;
215
216 if (!orig) {
217 dest = apr_table_make(p, 5);
218 return dest;
219 }
220
221 size = apr_table_elts(orig)->nelts;
222
223 if (size < 5) {
224 size = 5;
225 }
226 dest = apr_table_make(p, size);
227 e = (apr_table_entry_t *) apr_table_elts(orig)->elts;
228 for (i = 0; i < apr_table_elts(orig)->nelts; ++i) {
229 apr_table_add(dest, e[i].key, e[i].val);
230 }
231
232 return dest;
233 }
234
235 /**
236 * Swallow table copy
237 *
238 * @param p IN pool
239 * @param orig IN orig table
240 *
241 * @return copy of orig
242 */
my_table_swallow_copy(apr_pool_t * p,apr_table_t * orig)243 apr_table_t *my_table_swallow_copy(apr_pool_t *p, apr_table_t *orig) {
244 apr_table_entry_t *e;
245 apr_table_t *dest;
246 int i;
247 apr_size_t size;
248
249 if (!orig) {
250 dest = apr_table_make(p, 5);
251 return dest;
252 }
253
254 size = apr_table_elts(orig)->nelts;
255
256 if (size < 5) {
257 size = 5;
258 }
259 dest = apr_table_make(p, size);
260 e = (apr_table_entry_t *) apr_table_elts(orig)->elts;
261 for (i = 0; i < apr_table_elts(orig)->nelts; ++i) {
262 apr_table_addn(dest, apr_pstrdup(p, e[i].key), e[i].val);
263 }
264
265 return dest;
266 }
267
268 /**
269 * get the status string
270 *
271 * @param p IN pool
272 * @param rc IN status to print
273 *
274 * @return status string
275 */
my_status_str(apr_pool_t * p,apr_status_t rc)276 char *my_status_str(apr_pool_t * p, apr_status_t rc) {
277 char *text = apr_pcalloc(p, 201);
278 apr_strerror(rc, text, 200);
279 return text;
280 }
281
282
283 /**
284 * splits arguments into a table
285 *
286 * @param line IN string of params
287 * @param params INOUT table to store params
288 */
my_get_args(char * line,store_t * params,apr_pool_t * pool)289 void my_get_args(char *line, store_t *params, apr_pool_t *pool) {
290 int i;
291 char **argv;
292
293 if (my_tokenize_to_argv(line, &argv, pool, 0) == APR_SUCCESS) {
294 for (i = 0; argv[i] != NULL; i++) {
295 /* store value by his index */
296 store_set(params, apr_itoa(pool, i), argv[i]);
297 }
298 }
299 }
300
301 /**
302 * display copyright information
303 *
304 * @param program name
305 */
copyright(const char * progname)306 void copyright(const char *progname) {
307 printf("%s " PACKAGE_VERSION "\n", progname);
308 printf("\nCopyright (C) 2006 Free Software Foundation, Inc.\n"
309 "This is free software; see the source for copying conditions. There is NO\n"
310 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
311 printf("\nWritten by Christian Liesch\n");
312 }
313
314 /**
315 * filename
316 *
317 * @param path IN path to file
318 *
319 * @return last part of path
320 */
filename(apr_pool_t * pool,const char * path)321 const char *filename(apr_pool_t *pool, const char *path) {
322 char *tmp;
323 char *elem;
324 char *last;
325
326 char *old = NULL;
327
328 tmp = apr_pstrdup(pool, path);
329 elem = apr_strtok(tmp, "/", &last);
330 while (elem) {
331 old = elem;
332 elem = apr_strtok(NULL, "/", &last);
333 }
334
335 return old;
336 }
337
338 /**
339 * 2 hex digit number to char borowed from apache sourc
340 *
341 * @param what IN hex to convert
342 *
343 * @return char
344 */
x2c(const char * what)345 char x2c(const char *what) {
346 register char digit;
347
348 #if !APR_CHARSET_EBCDIC
349 digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10
350 : (what[0] - '0'));
351 digit *= 16;
352 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10
353 : (what[1] - '0'));
354 #else /*APR_CHARSET_EBCDIC*/
355 char xstr[5];
356 xstr[0]='0';
357 xstr[1]='x';
358 xstr[2]=what[0];
359 xstr[3]=what[1];
360 xstr[4]='\0';
361 digit = apr_xlate_conv_byte(ap_hdrs_from_ascii,
362 0xFF & strtol(xstr, NULL, 16));
363 #endif /*APR_CHARSET_EBCDIC*/
364 return (digit);
365 }
366
367