Revert changes relative to lib/*.[ch] recent renaming
[platform/upstream/curl.git] / tests / server / getpart.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 #include "server_setup.h"
23
24 #include "getpart.h"
25
26 #define ENABLE_CURLX_PRINTF
27 /* make the curlx header define all printf() functions to use the curlx_*
28    versions instead */
29 #include "curlx.h" /* from the private lib dir */
30
31 /* just to please curl_base64.h we create a fake struct */
32 struct SessionHandle {
33   int fake;
34 };
35
36 #include "curl_base64.h"
37 #include "curl_memory.h"
38
39 /* include memdebug.h last */
40 #include "memdebug.h"
41
42 #define EAT_SPACE(p) while(*(p) && ISSPACE(*(p))) (p)++
43
44 #define EAT_WORD(p)  while(*(p) && !ISSPACE(*(p)) && ('>' != *(p))) (p)++
45
46 #ifdef DEBUG_GETPART
47 #define show(x) printf x
48 #else
49 #define show(x) Curl_nop_stmt
50 #endif
51
52 #if defined(_MSC_VER) && defined(_DLL)
53 #  pragma warning(disable:4232) /* MSVC extension, dllimport identity */
54 #endif
55
56 curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
57 curl_free_callback Curl_cfree = (curl_free_callback)free;
58 curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
59 curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)strdup;
60 curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
61
62 #if defined(_MSC_VER) && defined(_DLL)
63 #  pragma warning(default:4232) /* MSVC extension, dllimport identity */
64 #endif
65
66 /*
67  * readline()
68  *
69  * Reads a complete line from a file into a dynamically allocated buffer.
70  *
71  * Calling function may call this multiple times with same 'buffer'
72  * and 'bufsize' pointers to avoid multiple buffer allocations. Buffer
73  * will be reallocated and 'bufsize' increased until whole line fits in
74  * buffer before returning it.
75  *
76  * Calling function is responsible to free allocated buffer.
77  *
78  * This function may return:
79  *   GPE_OUT_OF_MEMORY
80  *   GPE_END_OF_FILE
81  *   GPE_OK
82  */
83
84 static int readline(char **buffer, size_t *bufsize, FILE *stream)
85 {
86   size_t offset = 0;
87   size_t length;
88   char *newptr;
89
90   if(!*buffer) {
91     *buffer = malloc(128);
92     if(!*buffer)
93       return GPE_OUT_OF_MEMORY;
94     *bufsize = 128;
95   }
96
97   for(;;) {
98     int bytestoread = curlx_uztosi(*bufsize - offset);
99
100     if(!fgets(*buffer + offset, bytestoread, stream))
101       return (offset != 0) ? GPE_OK : GPE_END_OF_FILE ;
102
103     length = offset + strlen(*buffer + offset);
104     if(*(*buffer + length - 1) == '\n')
105       break;
106     offset = length;
107     if(length < *bufsize - 1)
108       continue;
109
110     newptr = realloc(*buffer, *bufsize * 2);
111     if(!newptr)
112       return GPE_OUT_OF_MEMORY;
113     *buffer = newptr;
114     *bufsize *= 2;
115   }
116
117   return GPE_OK;
118 }
119
120 /*
121  * appenddata()
122  *
123  * This appends data from a given source buffer to the end of the used part of
124  * a destination buffer. Arguments relative to the destination buffer are, the
125  * address of a pointer to the destination buffer 'dst_buf', the length of data
126  * in destination buffer excluding potential null string termination 'dst_len',
127  * the allocated size of destination buffer 'dst_alloc'. All three destination
128  * buffer arguments may be modified by this function. Arguments relative to the
129  * source buffer are, a pointer to the source buffer 'src_buf' and indication
130  * whether the source buffer is base64 encoded or not 'src_b64'.
131  *
132  * If the source buffer is indicated to be base64 encoded, this appends the
133  * decoded data, binary or whatever, to the destination. The source buffer
134  * may not hold binary data, only a null terminated string is valid content.
135  *
136  * Destination buffer will be enlarged and relocated as needed.
137  *
138  * Calling function is responsible to provide preallocated destination
139  * buffer and also to deallocate it when no longer needed.
140  *
141  * This function may return:
142  *   GPE_OUT_OF_MEMORY
143  *   GPE_OK
144  */
145
146 static int appenddata(char  **dst_buf,   /* dest buffer */
147                       size_t *dst_len,   /* dest buffer data length */
148                       size_t *dst_alloc, /* dest buffer allocated size */
149                       char   *src_buf,   /* source buffer */
150                       int     src_b64)   /* != 0 if source is base64 encoded */
151 {
152   size_t need_alloc, src_len;
153   union {
154     unsigned char *as_uchar;
155              char *as_char;
156   } buf64;
157
158   src_len = strlen(src_buf);
159   if(!src_len)
160     return GPE_OK;
161
162   buf64.as_char = NULL;
163
164   if(src_b64) {
165     /* base64 decode the given buffer */
166     int error = (int) Curl_base64_decode(src_buf, &buf64.as_uchar, &src_len);
167     if(error)
168       return GPE_OUT_OF_MEMORY;
169     src_buf = buf64.as_char;
170     if(!src_len || !src_buf) {
171       /*
172       ** currently there is no way to tell apart an OOM condition in
173       ** Curl_base64_decode() from zero length decoded data. For now,
174       ** let's just assume it is an OOM condition, currently we have
175       ** no input for this function that decodes to zero length data.
176       */
177       if(buf64.as_char)
178         free(buf64.as_char);
179       return GPE_OUT_OF_MEMORY;
180     }
181   }
182
183   need_alloc = src_len + *dst_len + 1;
184
185   /* enlarge destination buffer if required */
186   if(need_alloc > *dst_alloc) {
187     size_t newsize = need_alloc * 2;
188     char *newptr = realloc(*dst_buf, newsize);
189     if(!newptr) {
190       if(buf64.as_char)
191         free(buf64.as_char);
192       return GPE_OUT_OF_MEMORY;
193     }
194     *dst_alloc = newsize;
195     *dst_buf = newptr;
196   }
197
198   /* memcpy to support binary blobs */
199   memcpy(*dst_buf + *dst_len, src_buf, src_len);
200   *dst_len += src_len;
201   *(*dst_buf + *dst_len) = '\0';
202
203   if(buf64.as_char)
204     free(buf64.as_char);
205
206   return GPE_OK;
207 }
208
209 /*
210  * getpart()
211  *
212  * This returns whole contents of specified XML-like section and subsection
213  * from the given file. This is mostly used to retrieve a specific part from
214  * a test definition file for consumption by test suite servers.
215  *
216  * Data is returned in a dynamically allocated buffer, a pointer to this data
217  * and the size of the data is stored at the addresses that caller specifies.
218  *
219  * If the returned data is a string the returned size will be the length of
220  * the string excluding null termination. Otherwise it will just be the size
221  * of the returned binary data.
222  *
223  * Calling function is responsible to free returned buffer.
224  *
225  * This function may return:
226  *   GPE_NO_BUFFER_SPACE
227  *   GPE_OUT_OF_MEMORY
228  *   GPE_OK
229  */
230
231 int getpart(char **outbuf, size_t *outlen,
232             const char *main, const char *sub, FILE *stream)
233 {
234 # define MAX_TAG_LEN 79
235   char couter[MAX_TAG_LEN+1]; /* current outermost section */
236   char cmain[MAX_TAG_LEN+1];  /* current main section */
237   char csub[MAX_TAG_LEN+1];   /* current sub section */
238   char ptag[MAX_TAG_LEN+1];   /* potential tag */
239   char patt[MAX_TAG_LEN+1];   /* potential attributes */
240   char *buffer = NULL;
241   char *ptr;
242   char *end;
243   union {
244     ssize_t sig;
245      size_t uns;
246   } len;
247   size_t bufsize = 0;
248   size_t outalloc = 256;
249   int in_wanted_part = 0;
250   int base64 = 0;
251   int error;
252
253   enum {
254     STATE_OUTSIDE = 0,
255     STATE_OUTER   = 1,
256     STATE_INMAIN  = 2,
257     STATE_INSUB   = 3,
258     STATE_ILLEGAL = 4
259   } state = STATE_OUTSIDE;
260
261   *outlen = 0;
262   *outbuf = malloc(outalloc);
263   if(!*outbuf)
264     return GPE_OUT_OF_MEMORY;
265   *(*outbuf) = '\0';
266
267   couter[0] = cmain[0] = csub[0] = ptag[0] = patt[0] = '\0';
268
269   while((error = readline(&buffer, &bufsize, stream)) == GPE_OK) {
270
271     ptr = buffer;
272     EAT_SPACE(ptr);
273
274     if('<' != *ptr) {
275       if(in_wanted_part) {
276         show(("=> %s", buffer));
277         error = appenddata(outbuf, outlen, &outalloc, buffer, base64);
278         if(error)
279           break;
280       }
281       continue;
282     }
283
284     ptr++;
285
286     if('/' == *ptr) {
287       /*
288       ** closing section tag
289       */
290
291       ptr++;
292       end = ptr;
293       EAT_WORD(end);
294       if((len.sig = end - ptr) > MAX_TAG_LEN) {
295         error = GPE_NO_BUFFER_SPACE;
296         break;
297       }
298       memcpy(ptag, ptr, len.uns);
299       ptag[len.uns] = '\0';
300
301       if((STATE_INSUB == state) && !strcmp(csub, ptag)) {
302         /* end of current sub section */
303         state = STATE_INMAIN;
304         csub[0] = '\0';
305         if(in_wanted_part) {
306           /* end of wanted part */
307           in_wanted_part = 0;
308           break;
309         }
310       }
311       else if((STATE_INMAIN == state) && !strcmp(cmain, ptag)) {
312         /* end of current main section */
313         state = STATE_OUTER;
314         cmain[0] = '\0';
315         if(in_wanted_part) {
316           /* end of wanted part */
317           in_wanted_part = 0;
318           break;
319         }
320       }
321       else if((STATE_OUTER == state) && !strcmp(couter, ptag)) {
322         /* end of outermost file section */
323         state = STATE_OUTSIDE;
324         couter[0] = '\0';
325         if(in_wanted_part) {
326           /* end of wanted part */
327           in_wanted_part = 0;
328           break;
329         }
330       }
331
332     }
333     else if(!in_wanted_part) {
334       /*
335       ** opening section tag
336       */
337
338       /* get potential tag */
339       end = ptr;
340       EAT_WORD(end);
341       if((len.sig = end - ptr) > MAX_TAG_LEN) {
342         error = GPE_NO_BUFFER_SPACE;
343         break;
344       }
345       memcpy(ptag, ptr, len.uns);
346       ptag[len.uns] = '\0';
347
348       /* ignore comments, doctypes and xml declarations */
349       if(('!' == ptag[0]) || ('?' == ptag[0])) {
350         show(("* ignoring (%s)", buffer));
351         continue;
352       }
353
354       /* get all potential attributes */
355       ptr = end;
356       EAT_SPACE(ptr);
357       end = ptr;
358       while(*end && ('>' != *end))
359         end++;
360       if((len.sig = end - ptr) > MAX_TAG_LEN) {
361         error = GPE_NO_BUFFER_SPACE;
362         break;
363       }
364       memcpy(patt, ptr, len.uns);
365       patt[len.uns] = '\0';
366
367       if(STATE_OUTSIDE == state) {
368         /* outermost element (<testcase>) */
369         strcpy(couter, ptag);
370         state = STATE_OUTER;
371         continue;
372       }
373       else if(STATE_OUTER == state) {
374         /* start of a main section */
375         strcpy(cmain, ptag);
376         state = STATE_INMAIN;
377         continue;
378       }
379       else if(STATE_INMAIN == state) {
380         /* start of a sub section */
381         strcpy(csub, ptag);
382         state = STATE_INSUB;
383         if(!strcmp(cmain, main) && !strcmp(csub, sub)) {
384           /* start of wanted part */
385           in_wanted_part = 1;
386           if(strstr(patt, "base64="))
387               /* bit rough test, but "mostly" functional, */
388               /* treat wanted part data as base64 encoded */
389               base64 = 1;
390         }
391         continue;
392       }
393
394     }
395
396     if(in_wanted_part) {
397       show(("=> %s", buffer));
398       error = appenddata(outbuf, outlen, &outalloc, buffer, base64);
399       if(error)
400         break;
401     }
402
403   } /* while */
404
405   if(buffer)
406     free(buffer);
407
408   if(error != GPE_OK) {
409     if(error == GPE_END_OF_FILE)
410       error = GPE_OK;
411     else {
412       if(*outbuf)
413         free(*outbuf);
414       *outbuf = NULL;
415       *outlen = 0;
416     }
417   }
418
419   return error;
420 }
421