diff options
Diffstat (limited to 'tests/server/getpart.c')
-rw-r--r-- | tests/server/getpart.c | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/tests/server/getpart.c b/tests/server/getpart.c new file mode 100644 index 00000000..a3b5f2fb --- /dev/null +++ b/tests/server/getpart.c @@ -0,0 +1,422 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#define CURL_NO_OLDIES + +#include "setup.h" + +#include "getpart.h" + +#define ENABLE_CURLX_PRINTF +/* make the curlx header define all printf() functions to use the curlx_* + versions instead */ +#include "curlx.h" /* from the private lib dir */ + +/* just to please base64.h we create a fake struct */ +struct SessionHandle { + int fake; +}; + +#include "curl_base64.h" +#include "curl_memory.h" + +/* include memdebug.h last */ +#include "memdebug.h" + +#define EAT_SPACE(p) while(*(p) && ISSPACE(*(p))) (p)++ + +#define EAT_WORD(p) while(*(p) && !ISSPACE(*(p)) && ('>' != *(p))) (p)++ + +#ifdef DEBUG_GETPART +#define show(x) printf x +#else +#define show(x) +#endif + +#if defined(_MSC_VER) && defined(_DLL) +# pragma warning(disable:4232) /* MSVC extension, dllimport identity */ +#endif + +curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc; +curl_free_callback Curl_cfree = (curl_free_callback)free; +curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc; +curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)strdup; +curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; + +#if defined(_MSC_VER) && defined(_DLL) +# pragma warning(default:4232) /* MSVC extension, dllimport identity */ +#endif + +/* + * readline() + * + * Reads a complete line from a file into a dynamically allocated buffer. + * + * Calling function may call this multiple times with same 'buffer' + * and 'bufsize' pointers to avoid multiple buffer allocations. Buffer + * will be reallocated and 'bufsize' increased until whole line fits in + * buffer before returning it. + * + * Calling function is responsible to free allocated buffer. + * + * This function may return: + * GPE_OUT_OF_MEMORY + * GPE_END_OF_FILE + * GPE_OK + */ + +static int readline(char **buffer, size_t *bufsize, FILE *stream) +{ + size_t offset = 0; + size_t length; + char *newptr; + + if(!*buffer) { + *buffer = malloc(128); + if(!*buffer) + return GPE_OUT_OF_MEMORY; + *bufsize = 128; + } + + for(;;) { + int bytestoread = curlx_uztosi(*bufsize - offset); + + if(!fgets(*buffer + offset, bytestoread, stream)) + return (offset != 0) ? GPE_OK : GPE_END_OF_FILE ; + + length = offset + strlen(*buffer + offset); + if(*(*buffer + length - 1) == '\n') + break; + offset = length; + if(length < *bufsize - 1) + continue; + + newptr = realloc(*buffer, *bufsize * 2); + if(!newptr) + return GPE_OUT_OF_MEMORY; + *buffer = newptr; + *bufsize *= 2; + } + + return GPE_OK; +} + +/* + * appenddata() + * + * This appends data from a given source buffer to the end of the used part of + * a destination buffer. Arguments relative to the destination buffer are, the + * address of a pointer to the destination buffer 'dst_buf', the length of data + * in destination buffer excluding potential null string termination 'dst_len', + * the allocated size of destination buffer 'dst_alloc'. All three destination + * buffer arguments may be modified by this function. Arguments relative to the + * source buffer are, a pointer to the source buffer 'src_buf' and indication + * whether the source buffer is base64 encoded or not 'src_b64'. + * + * If the source buffer is indicated to be base64 encoded, this appends the + * decoded data, binary or whatever, to the destination. The source buffer + * may not hold binary data, only a null terminated string is valid content. + * + * Destination buffer will be enlarged and relocated as needed. + * + * Calling function is responsible to provide preallocated destination + * buffer and also to deallocate it when no longer needed. + * + * This function may return: + * GPE_OUT_OF_MEMORY + * GPE_OK + */ + +static int appenddata(char **dst_buf, /* dest buffer */ + size_t *dst_len, /* dest buffer data length */ + size_t *dst_alloc, /* dest buffer allocated size */ + char *src_buf, /* source buffer */ + int src_b64) /* != 0 if source is base64 encoded */ +{ + size_t need_alloc, src_len; + union { + unsigned char *as_uchar; + char *as_char; + } buf64; + + src_len = strlen(src_buf); + if(!src_len) + return GPE_OK; + + buf64.as_char = NULL; + + if(src_b64) { + /* base64 decode the given buffer */ + src_len = Curl_base64_decode(src_buf, &buf64.as_uchar); + src_buf = buf64.as_char; + if(!src_len || !src_buf) { + /* + ** currently there is no way to tell apart an OOM condition in + ** Curl_base64_decode() from zero length decoded data. For now, + ** let's just assume it is an OOM condition, currently we have + ** no input for this function that decodes to zero length data. + */ + if(buf64.as_char) + free(buf64.as_char); + return GPE_OUT_OF_MEMORY; + } + } + + need_alloc = src_len + *dst_len + 1; + + /* enlarge destination buffer if required */ + if(need_alloc > *dst_alloc) { + size_t newsize = need_alloc * 2; + char *newptr = realloc(*dst_buf, newsize); + if(!newptr) { + if(buf64.as_char) + free(buf64.as_char); + return GPE_OUT_OF_MEMORY; + } + *dst_alloc = newsize; + *dst_buf = newptr; + } + + /* memcpy to support binary blobs */ + memcpy(*dst_buf + *dst_len, src_buf, src_len); + *dst_len += src_len; + *(*dst_buf + *dst_len) = '\0'; + + if(buf64.as_char) + free(buf64.as_char); + + return GPE_OK; +} + +/* + * getpart() + * + * This returns whole contents of specified XML-like section and subsection + * from the given file. This is mostly used to retrieve a specific part from + * a test definition file for consumption by test suite servers. + * + * Data is returned in a dynamically allocated buffer, a pointer to this data + * and the size of the data is stored at the addresses that caller specifies. + * + * If the returned data is a string the returned size will be the length of + * the string excluding null termination. Otherwise it will just be the size + * of the returned binary data. + * + * Calling function is responsible to free returned buffer. + * + * This function may return: + * GPE_NO_BUFFER_SPACE + * GPE_OUT_OF_MEMORY + * GPE_OK + */ + +int getpart(char **outbuf, size_t *outlen, + const char *main, const char *sub, FILE *stream) +{ +# define MAX_TAG_LEN 79 + char couter[MAX_TAG_LEN+1]; /* current outermost section */ + char cmain[MAX_TAG_LEN+1]; /* current main section */ + char csub[MAX_TAG_LEN+1]; /* current sub section */ + char ptag[MAX_TAG_LEN+1]; /* potential tag */ + char patt[MAX_TAG_LEN+1]; /* potential attributes */ + char *buffer = NULL; + char *ptr; + char *end; + union { + ssize_t sig; + size_t uns; + } len; + size_t bufsize = 0; + size_t outalloc = 256; + int in_wanted_part = 0; + int base64 = 0; + int error; + + enum { + STATE_OUTSIDE = 0, + STATE_OUTER = 1, + STATE_INMAIN = 2, + STATE_INSUB = 3, + STATE_ILLEGAL = 4 + } state = STATE_OUTSIDE; + + *outlen = 0; + *outbuf = malloc(outalloc); + if(!*outbuf) + return GPE_OUT_OF_MEMORY; + *(*outbuf) = '\0'; + + couter[0] = cmain[0] = csub[0] = ptag[0] = patt[0] = '\0'; + + while((error = readline(&buffer, &bufsize, stream)) == GPE_OK) { + + ptr = buffer; + EAT_SPACE(ptr); + + if('<' != *ptr) { + if(in_wanted_part) { + show(("=> %s", buffer)); + error = appenddata(outbuf, outlen, &outalloc, buffer, base64); + if(error) + break; + } + continue; + } + + ptr++; + + if('/' == *ptr) { + /* + ** closing section tag + */ + + ptr++; + end = ptr; + EAT_WORD(end); + if((len.sig = end - ptr) > MAX_TAG_LEN) { + error = GPE_NO_BUFFER_SPACE; + break; + } + memcpy(ptag, ptr, len.uns); + ptag[len.uns] = '\0'; + + if((STATE_INSUB == state) && !strcmp(csub, ptag)) { + /* end of current sub section */ + state = STATE_INMAIN; + csub[0] = '\0'; + if(in_wanted_part) { + /* end of wanted part */ + in_wanted_part = 0; + break; + } + } + else if((STATE_INMAIN == state) && !strcmp(cmain, ptag)) { + /* end of current main section */ + state = STATE_OUTER; + cmain[0] = '\0'; + if(in_wanted_part) { + /* end of wanted part */ + in_wanted_part = 0; + break; + } + } + else if((STATE_OUTER == state) && !strcmp(couter, ptag)) { + /* end of outermost file section */ + state = STATE_OUTSIDE; + couter[0] = '\0'; + if(in_wanted_part) { + /* end of wanted part */ + in_wanted_part = 0; + break; + } + } + + } + else if(!in_wanted_part) { + /* + ** opening section tag + */ + + /* get potential tag */ + end = ptr; + EAT_WORD(end); + if((len.sig = end - ptr) > MAX_TAG_LEN) { + error = GPE_NO_BUFFER_SPACE; + break; + } + memcpy(ptag, ptr, len.uns); + ptag[len.uns] = '\0'; + + /* ignore comments, doctypes and xml declarations */ + if(('!' == ptag[0]) || ('?' == ptag[0])) { + show(("* ignoring (%s)", buffer)); + continue; + } + + /* get all potential attributes */ + ptr = end; + EAT_SPACE(ptr); + end = ptr; + while(*end && ('>' != *end)) + end++; + if((len.sig = end - ptr) > MAX_TAG_LEN) { + error = GPE_NO_BUFFER_SPACE; + break; + } + memcpy(patt, ptr, len.uns); + patt[len.uns] = '\0'; + + if(STATE_OUTSIDE == state) { + /* outermost element (<testcase>) */ + strcpy(couter, ptag); + state = STATE_OUTER; + continue; + } + else if(STATE_OUTER == state) { + /* start of a main section */ + strcpy(cmain, ptag); + state = STATE_INMAIN; + continue; + } + else if(STATE_INMAIN == state) { + /* start of a sub section */ + strcpy(csub, ptag); + state = STATE_INSUB; + if(!strcmp(cmain, main) && !strcmp(csub, sub)) { + /* start of wanted part */ + in_wanted_part = 1; + if(strstr(patt, "base64=")) + /* bit rough test, but "mostly" functional, */ + /* treat wanted part data as base64 encoded */ + base64 = 1; + } + continue; + } + + } + + if(in_wanted_part) { + show(("=> %s", buffer)); + error = appenddata(outbuf, outlen, &outalloc, buffer, base64); + if(error) + break; + } + + } /* while */ + + if(buffer) + free(buffer); + + if(error != GPE_OK) { + if(error == GPE_END_OF_FILE) + error = GPE_OK; + else { + if(*outbuf) + free(*outbuf); + *outbuf = NULL; + *outlen = 0; + } + } + + return error; +} + |