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>