Annotation of embedaddon/curl/tests/server/getpart.c, revision 1.1.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>