File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / tests / server / getpart.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:16 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>