Annotation of embedaddon/curl/tests/server/getpart.c, revision 1.1
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>