Return to getpart.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / tests / server |
1.1 ! misho 1: /*************************************************************************** ! 2: * _ _ ____ _ ! 3: * Project ___| | | | _ \| | ! 4: * / __| | | | |_) | | ! 5: * | (__| |_| | _ <| |___ ! 6: * \___|\___/|_| \_\_____| ! 7: * ! 8: * Copyright (C) 1998 - 2020, 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 https://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 Curl_easy { ! 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: #if defined(WIN32) && defined(UNICODE) ! 62: curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; ! 63: #endif ! 64: ! 65: #if defined(_MSC_VER) && defined(_DLL) ! 66: # pragma warning(default:4232) /* MSVC extension, dllimport identity */ ! 67: #endif ! 68: ! 69: ! 70: /* ! 71: * Curl_convert_clone() returns a malloced copy of the source string (if ! 72: * returning CURLE_OK), with the data converted to network format. This ! 73: * function is used by base64 code in libcurl built to support data ! 74: * conversion. This is a DUMMY VERSION that returns data unmodified - for ! 75: * use by the test server only. ! 76: */ ! 77: CURLcode Curl_convert_clone(struct Curl_easy *data, ! 78: const char *indata, ! 79: size_t insize, ! 80: char **outbuf); ! 81: CURLcode Curl_convert_clone(struct Curl_easy *data, ! 82: const char *indata, ! 83: size_t insize, ! 84: char **outbuf) ! 85: { ! 86: char *convbuf; ! 87: (void)data; ! 88: ! 89: convbuf = malloc(insize); ! 90: if(!convbuf) ! 91: return CURLE_OUT_OF_MEMORY; ! 92: ! 93: memcpy(convbuf, indata, insize); ! 94: *outbuf = convbuf; ! 95: return CURLE_OK; ! 96: } ! 97: ! 98: /* ! 99: * readline() ! 100: * ! 101: * Reads a complete line from a file into a dynamically allocated buffer. ! 102: * ! 103: * Calling function may call this multiple times with same 'buffer' ! 104: * and 'bufsize' pointers to avoid multiple buffer allocations. Buffer ! 105: * will be reallocated and 'bufsize' increased until whole line fits in ! 106: * buffer before returning it. ! 107: * ! 108: * Calling function is responsible to free allocated buffer. ! 109: * ! 110: * This function may return: ! 111: * GPE_OUT_OF_MEMORY ! 112: * GPE_END_OF_FILE ! 113: * GPE_OK ! 114: */ ! 115: ! 116: static int readline(char **buffer, size_t *bufsize, FILE *stream) ! 117: { ! 118: size_t offset = 0; ! 119: char *newptr; ! 120: ! 121: if(!*buffer) { ! 122: *buffer = malloc(128); ! 123: if(!*buffer) ! 124: return GPE_OUT_OF_MEMORY; ! 125: *bufsize = 128; ! 126: } ! 127: ! 128: for(;;) { ! 129: size_t length; ! 130: int bytestoread = curlx_uztosi(*bufsize - offset); ! 131: ! 132: if(!fgets(*buffer + offset, bytestoread, stream)) ! 133: return (offset != 0) ? GPE_OK : GPE_END_OF_FILE; ! 134: ! 135: length = offset + strlen(*buffer + offset); ! 136: if(*(*buffer + length - 1) == '\n') ! 137: break; ! 138: offset = length; ! 139: if(length < *bufsize - 1) ! 140: continue; ! 141: ! 142: newptr = realloc(*buffer, *bufsize * 2); ! 143: if(!newptr) ! 144: return GPE_OUT_OF_MEMORY; ! 145: *buffer = newptr; ! 146: *bufsize *= 2; ! 147: } ! 148: ! 149: return GPE_OK; ! 150: } ! 151: ! 152: /* ! 153: * appenddata() ! 154: * ! 155: * This appends data from a given source buffer to the end of the used part of ! 156: * a destination buffer. Arguments relative to the destination buffer are, the ! 157: * address of a pointer to the destination buffer 'dst_buf', the length of data ! 158: * in destination buffer excluding potential null string termination 'dst_len', ! 159: * the allocated size of destination buffer 'dst_alloc'. All three destination ! 160: * buffer arguments may be modified by this function. Arguments relative to the ! 161: * source buffer are, a pointer to the source buffer 'src_buf' and indication ! 162: * whether the source buffer is base64 encoded or not 'src_b64'. ! 163: * ! 164: * If the source buffer is indicated to be base64 encoded, this appends the ! 165: * decoded data, binary or whatever, to the destination. The source buffer ! 166: * may not hold binary data, only a null terminated string is valid content. ! 167: * ! 168: * Destination buffer will be enlarged and relocated as needed. ! 169: * ! 170: * Calling function is responsible to provide preallocated destination ! 171: * buffer and also to deallocate it when no longer needed. ! 172: * ! 173: * This function may return: ! 174: * GPE_OUT_OF_MEMORY ! 175: * GPE_OK ! 176: */ ! 177: ! 178: static int appenddata(char **dst_buf, /* dest buffer */ ! 179: size_t *dst_len, /* dest buffer data length */ ! 180: size_t *dst_alloc, /* dest buffer allocated size */ ! 181: char *src_buf, /* source buffer */ ! 182: int src_b64) /* != 0 if source is base64 encoded */ ! 183: { ! 184: size_t need_alloc = 0; ! 185: size_t src_len = strlen(src_buf); ! 186: ! 187: if(!src_len) ! 188: return GPE_OK; ! 189: ! 190: need_alloc = src_len + *dst_len + 1; ! 191: ! 192: if(src_b64) { ! 193: if(src_buf[src_len - 1] == '\r') ! 194: src_len--; ! 195: ! 196: if(src_buf[src_len - 1] == '\n') ! 197: src_len--; ! 198: } ! 199: ! 200: /* enlarge destination buffer if required */ ! 201: if(need_alloc > *dst_alloc) { ! 202: size_t newsize = need_alloc * 2; ! 203: char *newptr = realloc(*dst_buf, newsize); ! 204: if(!newptr) { ! 205: return GPE_OUT_OF_MEMORY; ! 206: } ! 207: *dst_alloc = newsize; ! 208: *dst_buf = newptr; ! 209: } ! 210: ! 211: /* memcpy to support binary blobs */ ! 212: memcpy(*dst_buf + *dst_len, src_buf, src_len); ! 213: *dst_len += src_len; ! 214: *(*dst_buf + *dst_len) = '\0'; ! 215: ! 216: return GPE_OK; ! 217: } ! 218: ! 219: static int decodedata(char **buf, /* dest buffer */ ! 220: size_t *len) /* dest buffer data length */ ! 221: { ! 222: CURLcode error = CURLE_OK; ! 223: unsigned char *buf64 = NULL; ! 224: size_t src_len = 0; ! 225: ! 226: if(!*len) ! 227: return GPE_OK; ! 228: ! 229: /* base64 decode the given buffer */ ! 230: error = Curl_base64_decode(*buf, &buf64, &src_len); ! 231: if(error) ! 232: return GPE_OUT_OF_MEMORY; ! 233: ! 234: if(!src_len) { ! 235: /* ! 236: ** currently there is no way to tell apart an OOM condition in ! 237: ** Curl_base64_decode() from zero length decoded data. For now, ! 238: ** let's just assume it is an OOM condition, currently we have ! 239: ** no input for this function that decodes to zero length data. ! 240: */ ! 241: free(buf64); ! 242: ! 243: return GPE_OUT_OF_MEMORY; ! 244: } ! 245: ! 246: /* memcpy to support binary blobs */ ! 247: memcpy(*buf, buf64, src_len); ! 248: *len = src_len; ! 249: *(*buf + src_len) = '\0'; ! 250: ! 251: free(buf64); ! 252: ! 253: return GPE_OK; ! 254: } ! 255: ! 256: /* ! 257: * getpart() ! 258: * ! 259: * This returns whole contents of specified XML-like section and subsection ! 260: * from the given file. This is mostly used to retrieve a specific part from ! 261: * a test definition file for consumption by test suite servers. ! 262: * ! 263: * Data is returned in a dynamically allocated buffer, a pointer to this data ! 264: * and the size of the data is stored at the addresses that caller specifies. ! 265: * ! 266: * If the returned data is a string the returned size will be the length of ! 267: * the string excluding null termination. Otherwise it will just be the size ! 268: * of the returned binary data. ! 269: * ! 270: * Calling function is responsible to free returned buffer. ! 271: * ! 272: * This function may return: ! 273: * GPE_NO_BUFFER_SPACE ! 274: * GPE_OUT_OF_MEMORY ! 275: * GPE_OK ! 276: */ ! 277: ! 278: int getpart(char **outbuf, size_t *outlen, ! 279: const char *main, const char *sub, FILE *stream) ! 280: { ! 281: # define MAX_TAG_LEN 79 ! 282: char couter[MAX_TAG_LEN + 1]; /* current outermost section */ ! 283: char cmain[MAX_TAG_LEN + 1]; /* current main section */ ! 284: char csub[MAX_TAG_LEN + 1]; /* current sub section */ ! 285: char ptag[MAX_TAG_LEN + 1]; /* potential tag */ ! 286: char patt[MAX_TAG_LEN + 1]; /* potential attributes */ ! 287: char *buffer = NULL; ! 288: char *ptr; ! 289: char *end; ! 290: union { ! 291: ssize_t sig; ! 292: size_t uns; ! 293: } len; ! 294: size_t bufsize = 0; ! 295: size_t outalloc = 256; ! 296: int in_wanted_part = 0; ! 297: int base64 = 0; ! 298: int error; ! 299: ! 300: enum { ! 301: STATE_OUTSIDE = 0, ! 302: STATE_OUTER = 1, ! 303: STATE_INMAIN = 2, ! 304: STATE_INSUB = 3, ! 305: STATE_ILLEGAL = 4 ! 306: } state = STATE_OUTSIDE; ! 307: ! 308: *outlen = 0; ! 309: *outbuf = malloc(outalloc); ! 310: if(!*outbuf) ! 311: return GPE_OUT_OF_MEMORY; ! 312: *(*outbuf) = '\0'; ! 313: ! 314: couter[0] = cmain[0] = csub[0] = ptag[0] = patt[0] = '\0'; ! 315: ! 316: while((error = readline(&buffer, &bufsize, stream)) == GPE_OK) { ! 317: ! 318: ptr = buffer; ! 319: EAT_SPACE(ptr); ! 320: ! 321: if('<' != *ptr) { ! 322: if(in_wanted_part) { ! 323: show(("=> %s", buffer)); ! 324: error = appenddata(outbuf, outlen, &outalloc, buffer, base64); ! 325: if(error) ! 326: break; ! 327: } ! 328: continue; ! 329: } ! 330: ! 331: ptr++; ! 332: ! 333: if('/' == *ptr) { ! 334: /* ! 335: ** closing section tag ! 336: */ ! 337: ! 338: ptr++; ! 339: end = ptr; ! 340: EAT_WORD(end); ! 341: len.sig = end - ptr; ! 342: if(len.sig > MAX_TAG_LEN) { ! 343: error = GPE_NO_BUFFER_SPACE; ! 344: break; ! 345: } ! 346: memcpy(ptag, ptr, len.uns); ! 347: ptag[len.uns] = '\0'; ! 348: ! 349: if((STATE_INSUB == state) && !strcmp(csub, ptag)) { ! 350: /* end of current sub section */ ! 351: state = STATE_INMAIN; ! 352: csub[0] = '\0'; ! 353: if(in_wanted_part) { ! 354: /* end of wanted part */ ! 355: in_wanted_part = 0; ! 356: ! 357: /* Do we need to base64 decode the data? */ ! 358: if(base64) { ! 359: error = decodedata(outbuf, outlen); ! 360: if(error) ! 361: return error; ! 362: } ! 363: break; ! 364: } ! 365: } ! 366: else if((STATE_INMAIN == state) && !strcmp(cmain, ptag)) { ! 367: /* end of current main section */ ! 368: state = STATE_OUTER; ! 369: cmain[0] = '\0'; ! 370: if(in_wanted_part) { ! 371: /* end of wanted part */ ! 372: in_wanted_part = 0; ! 373: ! 374: /* Do we need to base64 decode the data? */ ! 375: if(base64) { ! 376: error = decodedata(outbuf, outlen); ! 377: if(error) ! 378: return error; ! 379: } ! 380: break; ! 381: } ! 382: } ! 383: else if((STATE_OUTER == state) && !strcmp(couter, ptag)) { ! 384: /* end of outermost file section */ ! 385: state = STATE_OUTSIDE; ! 386: couter[0] = '\0'; ! 387: if(in_wanted_part) { ! 388: /* end of wanted part */ ! 389: in_wanted_part = 0; ! 390: break; ! 391: } ! 392: } ! 393: ! 394: } ! 395: else if(!in_wanted_part) { ! 396: /* ! 397: ** opening section tag ! 398: */ ! 399: ! 400: /* get potential tag */ ! 401: end = ptr; ! 402: EAT_WORD(end); ! 403: len.sig = end - ptr; ! 404: if(len.sig > MAX_TAG_LEN) { ! 405: error = GPE_NO_BUFFER_SPACE; ! 406: break; ! 407: } ! 408: memcpy(ptag, ptr, len.uns); ! 409: ptag[len.uns] = '\0'; ! 410: ! 411: /* ignore comments, doctypes and xml declarations */ ! 412: if(('!' == ptag[0]) || ('?' == ptag[0])) { ! 413: show(("* ignoring (%s)", buffer)); ! 414: continue; ! 415: } ! 416: ! 417: /* get all potential attributes */ ! 418: ptr = end; ! 419: EAT_SPACE(ptr); ! 420: end = ptr; ! 421: while(*end && ('>' != *end)) ! 422: end++; ! 423: len.sig = end - ptr; ! 424: if(len.sig > MAX_TAG_LEN) { ! 425: error = GPE_NO_BUFFER_SPACE; ! 426: break; ! 427: } ! 428: memcpy(patt, ptr, len.uns); ! 429: patt[len.uns] = '\0'; ! 430: ! 431: if(STATE_OUTSIDE == state) { ! 432: /* outermost element (<testcase>) */ ! 433: strcpy(couter, ptag); ! 434: state = STATE_OUTER; ! 435: continue; ! 436: } ! 437: else if(STATE_OUTER == state) { ! 438: /* start of a main section */ ! 439: strcpy(cmain, ptag); ! 440: state = STATE_INMAIN; ! 441: continue; ! 442: } ! 443: else if(STATE_INMAIN == state) { ! 444: /* start of a sub section */ ! 445: strcpy(csub, ptag); ! 446: state = STATE_INSUB; ! 447: if(!strcmp(cmain, main) && !strcmp(csub, sub)) { ! 448: /* start of wanted part */ ! 449: in_wanted_part = 1; ! 450: if(strstr(patt, "base64=")) ! 451: /* bit rough test, but "mostly" functional, */ ! 452: /* treat wanted part data as base64 encoded */ ! 453: base64 = 1; ! 454: } ! 455: continue; ! 456: } ! 457: ! 458: } ! 459: ! 460: if(in_wanted_part) { ! 461: show(("=> %s", buffer)); ! 462: error = appenddata(outbuf, outlen, &outalloc, buffer, base64); ! 463: if(error) ! 464: break; ! 465: } ! 466: ! 467: } /* while */ ! 468: ! 469: free(buffer); ! 470: ! 471: if(error != GPE_OK) { ! 472: if(error == GPE_END_OF_FILE) ! 473: error = GPE_OK; ! 474: else { ! 475: free(*outbuf); ! 476: *outbuf = NULL; ! 477: *outlen = 0; ! 478: } ! 479: } ! 480: ! 481: return error; ! 482: }