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