Loading CHANGES +4 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,10 @@ Changelog Yang Tse (14 Feb 2010) - Overhauled test suite getpart() function. Fixing potential out of bounds stack and memory overwrites triggered with huge test case definitions. Daniel Stenberg (13 Feb 2010) - Martin Hager reported and fixed a problem with a missing quote in libcurl.m4 Loading tests/server/getpart.c +286 −125 Original line number Diff line number Diff line Loading @@ -41,11 +41,11 @@ struct SessionHandle { /* include memdebug.h last */ #include "memdebug.h" #define EAT_SPACE(ptr) while( ptr && *ptr && ISSPACE(*ptr) ) ptr++ #define EAT_WORD(ptr) while( ptr && *ptr && !ISSPACE(*ptr) && \ ('>' != *ptr)) ptr++ #define EAT_SPACE(p) while(*(p) && ISSPACE(*(p))) (p)++ #ifdef DEBUG #define EAT_WORD(p) while(*(p) && !ISSPACE(*(p)) && ('>' != *(p))) (p)++ #ifdef DEBUG_GETPART #define show(x) printf x #else #define show(x) Loading @@ -65,191 +65,352 @@ curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; # pragma warning(default:4232) /* MSVC extension, dllimport identity */ #endif static char *appendstring(char *string, /* original string */ char *buffer, /* to append */ size_t *stringlen, /* length of string */ size_t *stralloc, /* allocated size */ char base64) /* 1 if base64 encoded */ /* * readline() * * Reads a complete line from a file into a dynamically allocated buffer. * * Calling function may call this multiple times with same 'buffer' * and 'bufsize' pointers to avoid multiple buffer allocations. Buffer * will be reallocated and 'bufsize' increased until whole line fits in * buffer before returning it. * * Calling function is responsible to free allocated buffer. * * This function may return: * GPE_OUT_OF_MEMORY * GPE_END_OF_FILE * GPE_OK */ static int readline(char **buffer, size_t *bufsize, FILE *stream) { size_t offset = 0; size_t length; char *newptr; if(!*buffer) { *buffer = malloc(128); if(!*buffer) return GPE_OUT_OF_MEMORY; *bufsize = 128; } for(;;) { if(!fgets(*buffer + offset, (int)(*bufsize - offset), stream)) return (offset != 0) ? GPE_OK : GPE_END_OF_FILE ; length = offset + strlen(*buffer + offset); if(*(*buffer + length - 1) == '\n') break; offset = length; if(length < *bufsize - 1) continue; newptr = realloc(*buffer, *bufsize * 2); if(!newptr) return GPE_OUT_OF_MEMORY; *buffer = newptr; *bufsize *= 2; } return GPE_OK; } /* * appenddata() * * This appends data from a given source buffer to the end of the used part of * a destination buffer. Arguments relative to the destination buffer are, the * address of a pointer to the destination buffer 'dst_buf', the length of data * in destination buffer excluding potential null string termination 'dst_len', * the allocated size of destination buffer 'dst_alloc'. All three destination * buffer arguments may be modified by this function. Arguments relative to the * source buffer are, a pointer to the source buffer 'src_buf' and indication * whether the source buffer is base64 encoded or not 'src_b64'. * * If the source buffer is indicated to be base64 encoded, this appends the * decoded data, binary or whatever, to the destination. The source buffer * may not hold binary data, only a null terminated string is valid content. * * Destination buffer will be enlarged and relocated as needed. * * Calling function is responsible to provide preallocated destination * buffer and also to deallocate it when no longer needed. * * This function may return: * GPE_OUT_OF_MEMORY * GPE_OK */ static int appenddata(char **dst_buf, /* dest buffer */ size_t *dst_len, /* dest buffer data length */ size_t *dst_alloc, /* dest buffer allocated size */ char *src_buf, /* source buffer */ int src_b64) /* != 0 if source is base64 encoded */ { size_t need_alloc, src_len; union { unsigned char *as_uchar; char *as_char; } buf64; size_t len = strlen(buffer); size_t needed_len = len + *stringlen + 1; src_len = strlen(src_buf); if(!src_len) return GPE_OK; buf64.as_char = NULL; if(base64) { /* decode the given buffer first */ len = Curl_base64_decode(buffer, &buf64.as_uchar); /* updated len */ buffer = buf64.as_char; needed_len = len + *stringlen + 1; /* recalculate */ if(src_b64) { /* base64 decode the given buffer */ src_len = Curl_base64_decode(src_buf, &buf64.as_uchar); src_buf = buf64.as_char; if(!src_len || !src_buf) { /* ** currently there is no way to tell apart an OOM condition in ** Curl_base64_decode() from zero length decoded data. For now, ** let's just assume it is an OOM condition, currently we have ** no input for this function that decodes to zero length data. */ if(buf64.as_char) free(buf64.as_char); return GPE_OUT_OF_MEMORY; } } if(needed_len >= *stralloc) { char *newptr; size_t newsize = needed_len*2; /* get twice the needed size */ need_alloc = src_len + *dst_len + 1; newptr = realloc(string, newsize); if(newptr) { string = newptr; *stralloc = newsize; } else { /* enlarge destination buffer if required */ if(need_alloc > *dst_alloc) { size_t newsize = need_alloc * 2; char *newptr = realloc(*dst_buf, newsize); if(!newptr) { if(buf64.as_char) free(buf64.as_char); return NULL; return GPE_OUT_OF_MEMORY; } *dst_alloc = newsize; *dst_buf = newptr; } /* memcpy to support binary blobs */ memcpy(&string[*stringlen], buffer, len); *stringlen += len; string[*stringlen]=0; memcpy(*dst_buf + *dst_len, src_buf, src_len); *dst_len += src_len; *(*dst_buf + *dst_len) = '\0'; if(buf64.as_char) free(buf64.as_char); return string; return GPE_OK; } const char *spitout(FILE *stream, const char *main, const char *sub, size_t *size) /* * getpart() * * This returns whole contents of specified XML-like section and subsection * from the given file. This is mostly used to retrieve a specific part from * a test definition file for consumption by test suite servers. * * Data is returned in a dynamically allocated buffer, a pointer to this data * and the size of the data is stored at the addresses that caller specifies. * * If the returned data is a string the returned size will be the length of * the string excluding null termination. Otherwise it will just be the size * of the returned binary data. * * Calling function is responsible to free returned buffer. * * This function may return: * GPE_NO_BUFFER_SPACE * GPE_OUT_OF_MEMORY * GPE_OK */ int getpart(char **outbuf, size_t *outlen, const char *main, const char *sub, FILE *stream) { char buffer[8192]; /* big enough for anything */ char cmain[128]=""; /* current main section */ char csub[128]=""; /* current sub section */ # define MAX_TAG_LEN 79 char couter[MAX_TAG_LEN+1]; /* current outermost section */ char cmain[MAX_TAG_LEN+1]; /* current main section */ char csub[MAX_TAG_LEN+1]; /* current sub section */ char ptag[MAX_TAG_LEN+1]; /* potential tag */ char patt[MAX_TAG_LEN+1]; /* potential attributes */ char *buffer = NULL; char *ptr; char *end; char display = 0; char *string; size_t stringlen=0; size_t stralloc=256; char base64 = 0; /* set to 1 if true */ size_t length; size_t bufsize = 0; size_t outalloc = 256; int in_wanted_part = 0; int base64 = 0; int error; enum { STATE_OUTSIDE, STATE_OUTER, STATE_INMAIN, STATE_INSUB, STATE_ILLEGAL STATE_OUTSIDE = 0, STATE_OUTER = 1, STATE_INMAIN = 2, STATE_INSUB = 3, STATE_ILLEGAL = 4 } state = STATE_OUTSIDE; string = malloc(stralloc); if(!string) return NULL; *outlen = 0; *outbuf = malloc(outalloc); if(!*outbuf) return GPE_OUT_OF_MEMORY; *(*outbuf) = '\0'; string[0] = 0; /* zero first byte in case of no data */ couter[0] = cmain[0] = csub[0] = ptag[0] = patt[0] = '\0'; while(fgets(buffer, sizeof(buffer), stream)) { while((error = readline(&buffer, &bufsize, stream)) == GPE_OK) { ptr = buffer; /* pass white spaces */ EAT_SPACE(ptr); if('<' != *ptr) { if(display) { if(in_wanted_part) { show(("=> %s", buffer)); string = appendstring(string, buffer, &stringlen, &stralloc, base64); show(("* %s\n", buffer)); error = appenddata(outbuf, outlen, &outalloc, buffer, base64); if(error) break; } continue; } ptr++; EAT_SPACE(ptr); if('/' == *ptr) { /* end of a section */ ptr++; EAT_SPACE(ptr); /* ** closing section tag */ ptr++; end = ptr; EAT_WORD(end); *end = 0; if((length = end - ptr) > MAX_TAG_LEN) { error = GPE_NO_BUFFER_SPACE; break; } memcpy(ptag, ptr, length); ptag[length] = '\0'; if((state == STATE_INSUB) && !strcmp(csub, ptr)) { /* this is the end of the currently read sub section */ state--; csub[0]=0; /* no sub anymore */ display=0; if((STATE_INSUB == state) && !strcmp(csub, ptag)) { /* end of current sub section */ state = STATE_INMAIN; csub[0] = '\0'; if(in_wanted_part) { /* end of wanted part */ in_wanted_part = 0; break; } else if((state == STATE_INMAIN) && !strcmp(cmain, ptr)) { /* this is the end of the currently read main section */ state--; cmain[0]=0; /* no main anymore */ display=0; } else if(state == STATE_OUTER) { /* this is the end of the outermost file section */ state--; else if((STATE_INMAIN == state) && !strcmp(cmain, ptag)) { /* end of current main section */ state = STATE_OUTER; cmain[0] = '\0'; if(in_wanted_part) { /* end of wanted part */ in_wanted_part = 0; break; } } else if((STATE_OUTER == state) && !strcmp(couter, ptag)) { /* end of outermost file section */ state = STATE_OUTSIDE; couter[0] = '\0'; if(in_wanted_part) { /* end of wanted part */ in_wanted_part = 0; break; } } else if(!display) { /* this is the beginning of a section */ } else if(!in_wanted_part) { /* ** opening section tag */ /* get potential tag */ end = ptr; EAT_WORD(end); *end = 0; switch(state) { case STATE_OUTSIDE: /* Skip over the outermost element (<testcase>), but if it turns out to be a comment, completely ignore it below */ strcpy(cmain, ptr); state = STATE_OUTER; if((length = end - ptr) > MAX_TAG_LEN) { error = GPE_NO_BUFFER_SPACE; break; case STATE_OUTER: strcpy(cmain, ptr); state = STATE_INMAIN; break; case STATE_INMAIN: strcpy(csub, ptr); state = STATE_INSUB; break; default: } memcpy(ptag, ptr, length); ptag[length] = '\0'; /* ignore comments, doctypes and xml declarations */ if(('!' == ptag[0]) || ('?' == ptag[0])) { show(("* ignoring (%s)", buffer)); continue; } /* get all potential attributes */ ptr = end; EAT_SPACE(ptr); end = ptr; while(*end && ('>' != *end)) end++; if((length = end - ptr) > MAX_TAG_LEN) { error = GPE_NO_BUFFER_SPACE; break; } memcpy(patt, ptr, length); patt[length] = '\0'; if(!end[1] != '>') { /* There might be attributes here. Check for those we know of and care about. */ if(strstr(&end[1], "base64=")) { /* rough and dirty, but "mostly" functional */ /* Treat all data as base64 encoded */ base64 = 1; if(STATE_OUTSIDE == state) { /* outermost element (<testcase>) */ strcpy(couter, ptag); state = STATE_OUTER; continue; } else if(STATE_OUTER == state) { /* start of a main section */ strcpy(cmain, ptag); state = STATE_INMAIN; continue; } else if(STATE_INMAIN == state) { /* start of a sub section */ strcpy(csub, ptag); state = STATE_INSUB; if(!strcmp(cmain, main) && !strcmp(csub, sub)) { /* start of wanted part */ in_wanted_part = 1; if(strstr(patt, "base64=")) /* bit rough test, but "mostly" functional, */ /* treat wanted part data as base64 encoded */ base64 = 1; } if(display) { string = appendstring(string, buffer, &stringlen, &stralloc, base64); show(("* %s\n", buffer)); continue; } if((STATE_INSUB == state) && !strcmp(cmain, main) && !strcmp(csub, sub)) { show(("* (%d bytes) %s\n", stringlen, buffer)); display = 1; /* start displaying */ } else if ((*cmain == '?') || (*cmain == '!') || (*csub == '!')) { /* Ignore comments, DOCTYPEs and XML declarations */ show(("%d ignoring (%s/%s)\n", state, cmain, csub)); state--; if(in_wanted_part) { show(("=> %s", buffer)); error = appenddata(outbuf, outlen, &outalloc, buffer, base64); if(error) break; } } /* while */ if(buffer) free(buffer); if(error != GPE_OK) { if(error == GPE_END_OF_FILE) error = GPE_OK; else { show(("%d (%s/%s): %s\n", state, cmain, csub, buffer)); display = 0; /* no display */ if(*outbuf) free(*outbuf); *outbuf = NULL; *outlen = 0; } } *size = stringlen; return string; return error; } tests/server/getpart.h +13 −6 Original line number Diff line number Diff line #ifndef HEADER_SERVER_GETPART_H #define HEADER_SERVER_GETPART_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | Loading @@ -5,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms Loading @@ -20,8 +22,13 @@ * * $Id$ ***************************************************************************/ const char * spitout(FILE *stream, const char *main, const char *sub, size_t *size); #define GPE_NO_BUFFER_SPACE -2 #define GPE_OUT_OF_MEMORY -1 #define GPE_OK 0 #define GPE_END_OF_FILE 1 int getpart(char **outbuf, size_t *outlen, const char *main, const char *sub, FILE *stream); #endif /* HEADER_SERVER_GETPART_H */ tests/server/rtspd.c +44 −9 Original line number Diff line number Diff line Loading @@ -423,9 +423,14 @@ static int ProcessRequest(struct httprequest *req) char *rtp_scratch = NULL; /* get the custom server control "commands" */ cmd = (char *)spitout(stream, "reply", "servercmd", &cmdsize); ptr = cmd; error = getpart(&cmd, &cmdsize, "reply", "servercmd", stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); req->open = FALSE; /* closes connection */ return 1; /* done */ } ptr = cmd; if(cmdsize) { logmsg("Found a reply-servercmd section!"); Loading Loading @@ -505,6 +510,8 @@ static int ProcessRequest(struct httprequest *req) } while(ptr && *ptr); logmsg("Done parsing server commands"); } if(cmd) free(cmd); } } else { Loading Loading @@ -950,13 +957,20 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) return 0; } else { buffer = spitout(stream, "reply", partbuf, &count); ptr = (char *)buffer; error = getpart(&buffer, &count, "reply", partbuf, stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); return 0; } ptr = (char *)buffer; } if(got_exit_signal) if(got_exit_signal) { if(ptr) free(ptr); return -1; } /* re-open the same file again */ stream=fopen(filename, "rb"); Loading @@ -965,17 +979,30 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", filename); logmsg("Couldn't open test file"); if(ptr) free(ptr); return 0; } else { /* get the custom server control "commands" */ cmd = (char *)spitout(stream, "reply", "postcmd", &cmdsize); error = getpart(&cmd, &cmdsize, "reply", "postcmd", stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); if(ptr) free(ptr); return 0; } } } if(got_exit_signal) if(got_exit_signal) { if(ptr) free(ptr); if(cmd) free(cmd); return -1; } /* If the word 'swsclose' is present anywhere in the reply chunk, the connection will be closed after the data has been sent to the requesting Loading @@ -997,6 +1024,10 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", RESPONSE_DUMP); logmsg("couldn't create logfile: " RESPONSE_DUMP); if(ptr) free(ptr); if(cmd) free(cmd); return -1; } Loading Loading @@ -1045,7 +1076,6 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) req->rtp_buffersize = 0; } do { res = fclose(dump); } while(res && ((error = ERRNO) == EINTR)); Loading @@ -1053,8 +1083,13 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) logmsg("Error closing file %s error: %d %s", RESPONSE_DUMP, error, strerror(error)); if(got_exit_signal) if(got_exit_signal) { if(ptr) free(ptr); if(cmd) free(cmd); return -1; } if(sendfailure) { logmsg("Sending response failed. Only (%zu bytes) of (%zu bytes) were sent", Loading tests/server/sws.c +43 −8 Original line number Diff line number Diff line Loading @@ -389,8 +389,13 @@ static int ProcessRequest(struct httprequest *req) int num=0; /* get the custom server control "commands" */ cmd = (char *)spitout(stream, "reply", "servercmd", &cmdsize); error = getpart(&cmd, &cmdsize, "reply", "servercmd", stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); req->open = FALSE; /* closes connection */ return 1; /* done */ } if(cmdsize) { logmsg("Found a reply-servercmd section!"); Loading Loading @@ -423,8 +428,9 @@ static int ProcessRequest(struct httprequest *req) else { logmsg("funny instruction found: %s", cmd); } free(cmd); } if(cmd) free(cmd); } } else { Loading Loading @@ -863,13 +869,20 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) return 0; } else { buffer = spitout(stream, "reply", partbuf, &count); ptr = (char *)buffer; error = getpart(&ptr, &count, "reply", partbuf, stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); return 0; } buffer = ptr; } if(got_exit_signal) if(got_exit_signal) { if(ptr) free(ptr); return -1; } /* re-open the same file again */ stream=fopen(filename, "rb"); Loading @@ -878,17 +891,30 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", filename); logmsg("Couldn't open test file"); if(ptr) free(ptr); return 0; } else { /* get the custom server control "commands" */ cmd = (char *)spitout(stream, "reply", "postcmd", &cmdsize); error = getpart(&cmd, &cmdsize, "reply", "postcmd", stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); if(ptr) free(ptr); return 0; } } } if(got_exit_signal) if(got_exit_signal) { if(ptr) free(ptr); if(cmd) free(cmd); return -1; } /* If the word 'swsclose' is present anywhere in the reply chunk, the connection will be closed after the data has been sent to the requesting Loading @@ -910,6 +936,10 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", RESPONSE_DUMP); logmsg("couldn't create logfile: " RESPONSE_DUMP); if(ptr) free(ptr); if(cmd) free(cmd); return -1; } Loading Loading @@ -945,8 +975,13 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) logmsg("Error closing file %s error: %d %s", RESPONSE_DUMP, error, strerror(error)); if(got_exit_signal) if(got_exit_signal) { if(ptr) free(ptr); if(cmd) free(cmd); return -1; } if(sendfailure) { logmsg("Sending response failed. Only (%zu bytes) of (%zu bytes) were sent", Loading Loading
CHANGES +4 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,10 @@ Changelog Yang Tse (14 Feb 2010) - Overhauled test suite getpart() function. Fixing potential out of bounds stack and memory overwrites triggered with huge test case definitions. Daniel Stenberg (13 Feb 2010) - Martin Hager reported and fixed a problem with a missing quote in libcurl.m4 Loading
tests/server/getpart.c +286 −125 Original line number Diff line number Diff line Loading @@ -41,11 +41,11 @@ struct SessionHandle { /* include memdebug.h last */ #include "memdebug.h" #define EAT_SPACE(ptr) while( ptr && *ptr && ISSPACE(*ptr) ) ptr++ #define EAT_WORD(ptr) while( ptr && *ptr && !ISSPACE(*ptr) && \ ('>' != *ptr)) ptr++ #define EAT_SPACE(p) while(*(p) && ISSPACE(*(p))) (p)++ #ifdef DEBUG #define EAT_WORD(p) while(*(p) && !ISSPACE(*(p)) && ('>' != *(p))) (p)++ #ifdef DEBUG_GETPART #define show(x) printf x #else #define show(x) Loading @@ -65,191 +65,352 @@ curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; # pragma warning(default:4232) /* MSVC extension, dllimport identity */ #endif static char *appendstring(char *string, /* original string */ char *buffer, /* to append */ size_t *stringlen, /* length of string */ size_t *stralloc, /* allocated size */ char base64) /* 1 if base64 encoded */ /* * readline() * * Reads a complete line from a file into a dynamically allocated buffer. * * Calling function may call this multiple times with same 'buffer' * and 'bufsize' pointers to avoid multiple buffer allocations. Buffer * will be reallocated and 'bufsize' increased until whole line fits in * buffer before returning it. * * Calling function is responsible to free allocated buffer. * * This function may return: * GPE_OUT_OF_MEMORY * GPE_END_OF_FILE * GPE_OK */ static int readline(char **buffer, size_t *bufsize, FILE *stream) { size_t offset = 0; size_t length; char *newptr; if(!*buffer) { *buffer = malloc(128); if(!*buffer) return GPE_OUT_OF_MEMORY; *bufsize = 128; } for(;;) { if(!fgets(*buffer + offset, (int)(*bufsize - offset), stream)) return (offset != 0) ? GPE_OK : GPE_END_OF_FILE ; length = offset + strlen(*buffer + offset); if(*(*buffer + length - 1) == '\n') break; offset = length; if(length < *bufsize - 1) continue; newptr = realloc(*buffer, *bufsize * 2); if(!newptr) return GPE_OUT_OF_MEMORY; *buffer = newptr; *bufsize *= 2; } return GPE_OK; } /* * appenddata() * * This appends data from a given source buffer to the end of the used part of * a destination buffer. Arguments relative to the destination buffer are, the * address of a pointer to the destination buffer 'dst_buf', the length of data * in destination buffer excluding potential null string termination 'dst_len', * the allocated size of destination buffer 'dst_alloc'. All three destination * buffer arguments may be modified by this function. Arguments relative to the * source buffer are, a pointer to the source buffer 'src_buf' and indication * whether the source buffer is base64 encoded or not 'src_b64'. * * If the source buffer is indicated to be base64 encoded, this appends the * decoded data, binary or whatever, to the destination. The source buffer * may not hold binary data, only a null terminated string is valid content. * * Destination buffer will be enlarged and relocated as needed. * * Calling function is responsible to provide preallocated destination * buffer and also to deallocate it when no longer needed. * * This function may return: * GPE_OUT_OF_MEMORY * GPE_OK */ static int appenddata(char **dst_buf, /* dest buffer */ size_t *dst_len, /* dest buffer data length */ size_t *dst_alloc, /* dest buffer allocated size */ char *src_buf, /* source buffer */ int src_b64) /* != 0 if source is base64 encoded */ { size_t need_alloc, src_len; union { unsigned char *as_uchar; char *as_char; } buf64; size_t len = strlen(buffer); size_t needed_len = len + *stringlen + 1; src_len = strlen(src_buf); if(!src_len) return GPE_OK; buf64.as_char = NULL; if(base64) { /* decode the given buffer first */ len = Curl_base64_decode(buffer, &buf64.as_uchar); /* updated len */ buffer = buf64.as_char; needed_len = len + *stringlen + 1; /* recalculate */ if(src_b64) { /* base64 decode the given buffer */ src_len = Curl_base64_decode(src_buf, &buf64.as_uchar); src_buf = buf64.as_char; if(!src_len || !src_buf) { /* ** currently there is no way to tell apart an OOM condition in ** Curl_base64_decode() from zero length decoded data. For now, ** let's just assume it is an OOM condition, currently we have ** no input for this function that decodes to zero length data. */ if(buf64.as_char) free(buf64.as_char); return GPE_OUT_OF_MEMORY; } } if(needed_len >= *stralloc) { char *newptr; size_t newsize = needed_len*2; /* get twice the needed size */ need_alloc = src_len + *dst_len + 1; newptr = realloc(string, newsize); if(newptr) { string = newptr; *stralloc = newsize; } else { /* enlarge destination buffer if required */ if(need_alloc > *dst_alloc) { size_t newsize = need_alloc * 2; char *newptr = realloc(*dst_buf, newsize); if(!newptr) { if(buf64.as_char) free(buf64.as_char); return NULL; return GPE_OUT_OF_MEMORY; } *dst_alloc = newsize; *dst_buf = newptr; } /* memcpy to support binary blobs */ memcpy(&string[*stringlen], buffer, len); *stringlen += len; string[*stringlen]=0; memcpy(*dst_buf + *dst_len, src_buf, src_len); *dst_len += src_len; *(*dst_buf + *dst_len) = '\0'; if(buf64.as_char) free(buf64.as_char); return string; return GPE_OK; } const char *spitout(FILE *stream, const char *main, const char *sub, size_t *size) /* * getpart() * * This returns whole contents of specified XML-like section and subsection * from the given file. This is mostly used to retrieve a specific part from * a test definition file for consumption by test suite servers. * * Data is returned in a dynamically allocated buffer, a pointer to this data * and the size of the data is stored at the addresses that caller specifies. * * If the returned data is a string the returned size will be the length of * the string excluding null termination. Otherwise it will just be the size * of the returned binary data. * * Calling function is responsible to free returned buffer. * * This function may return: * GPE_NO_BUFFER_SPACE * GPE_OUT_OF_MEMORY * GPE_OK */ int getpart(char **outbuf, size_t *outlen, const char *main, const char *sub, FILE *stream) { char buffer[8192]; /* big enough for anything */ char cmain[128]=""; /* current main section */ char csub[128]=""; /* current sub section */ # define MAX_TAG_LEN 79 char couter[MAX_TAG_LEN+1]; /* current outermost section */ char cmain[MAX_TAG_LEN+1]; /* current main section */ char csub[MAX_TAG_LEN+1]; /* current sub section */ char ptag[MAX_TAG_LEN+1]; /* potential tag */ char patt[MAX_TAG_LEN+1]; /* potential attributes */ char *buffer = NULL; char *ptr; char *end; char display = 0; char *string; size_t stringlen=0; size_t stralloc=256; char base64 = 0; /* set to 1 if true */ size_t length; size_t bufsize = 0; size_t outalloc = 256; int in_wanted_part = 0; int base64 = 0; int error; enum { STATE_OUTSIDE, STATE_OUTER, STATE_INMAIN, STATE_INSUB, STATE_ILLEGAL STATE_OUTSIDE = 0, STATE_OUTER = 1, STATE_INMAIN = 2, STATE_INSUB = 3, STATE_ILLEGAL = 4 } state = STATE_OUTSIDE; string = malloc(stralloc); if(!string) return NULL; *outlen = 0; *outbuf = malloc(outalloc); if(!*outbuf) return GPE_OUT_OF_MEMORY; *(*outbuf) = '\0'; string[0] = 0; /* zero first byte in case of no data */ couter[0] = cmain[0] = csub[0] = ptag[0] = patt[0] = '\0'; while(fgets(buffer, sizeof(buffer), stream)) { while((error = readline(&buffer, &bufsize, stream)) == GPE_OK) { ptr = buffer; /* pass white spaces */ EAT_SPACE(ptr); if('<' != *ptr) { if(display) { if(in_wanted_part) { show(("=> %s", buffer)); string = appendstring(string, buffer, &stringlen, &stralloc, base64); show(("* %s\n", buffer)); error = appenddata(outbuf, outlen, &outalloc, buffer, base64); if(error) break; } continue; } ptr++; EAT_SPACE(ptr); if('/' == *ptr) { /* end of a section */ ptr++; EAT_SPACE(ptr); /* ** closing section tag */ ptr++; end = ptr; EAT_WORD(end); *end = 0; if((length = end - ptr) > MAX_TAG_LEN) { error = GPE_NO_BUFFER_SPACE; break; } memcpy(ptag, ptr, length); ptag[length] = '\0'; if((state == STATE_INSUB) && !strcmp(csub, ptr)) { /* this is the end of the currently read sub section */ state--; csub[0]=0; /* no sub anymore */ display=0; if((STATE_INSUB == state) && !strcmp(csub, ptag)) { /* end of current sub section */ state = STATE_INMAIN; csub[0] = '\0'; if(in_wanted_part) { /* end of wanted part */ in_wanted_part = 0; break; } else if((state == STATE_INMAIN) && !strcmp(cmain, ptr)) { /* this is the end of the currently read main section */ state--; cmain[0]=0; /* no main anymore */ display=0; } else if(state == STATE_OUTER) { /* this is the end of the outermost file section */ state--; else if((STATE_INMAIN == state) && !strcmp(cmain, ptag)) { /* end of current main section */ state = STATE_OUTER; cmain[0] = '\0'; if(in_wanted_part) { /* end of wanted part */ in_wanted_part = 0; break; } } else if((STATE_OUTER == state) && !strcmp(couter, ptag)) { /* end of outermost file section */ state = STATE_OUTSIDE; couter[0] = '\0'; if(in_wanted_part) { /* end of wanted part */ in_wanted_part = 0; break; } } else if(!display) { /* this is the beginning of a section */ } else if(!in_wanted_part) { /* ** opening section tag */ /* get potential tag */ end = ptr; EAT_WORD(end); *end = 0; switch(state) { case STATE_OUTSIDE: /* Skip over the outermost element (<testcase>), but if it turns out to be a comment, completely ignore it below */ strcpy(cmain, ptr); state = STATE_OUTER; if((length = end - ptr) > MAX_TAG_LEN) { error = GPE_NO_BUFFER_SPACE; break; case STATE_OUTER: strcpy(cmain, ptr); state = STATE_INMAIN; break; case STATE_INMAIN: strcpy(csub, ptr); state = STATE_INSUB; break; default: } memcpy(ptag, ptr, length); ptag[length] = '\0'; /* ignore comments, doctypes and xml declarations */ if(('!' == ptag[0]) || ('?' == ptag[0])) { show(("* ignoring (%s)", buffer)); continue; } /* get all potential attributes */ ptr = end; EAT_SPACE(ptr); end = ptr; while(*end && ('>' != *end)) end++; if((length = end - ptr) > MAX_TAG_LEN) { error = GPE_NO_BUFFER_SPACE; break; } memcpy(patt, ptr, length); patt[length] = '\0'; if(!end[1] != '>') { /* There might be attributes here. Check for those we know of and care about. */ if(strstr(&end[1], "base64=")) { /* rough and dirty, but "mostly" functional */ /* Treat all data as base64 encoded */ base64 = 1; if(STATE_OUTSIDE == state) { /* outermost element (<testcase>) */ strcpy(couter, ptag); state = STATE_OUTER; continue; } else if(STATE_OUTER == state) { /* start of a main section */ strcpy(cmain, ptag); state = STATE_INMAIN; continue; } else if(STATE_INMAIN == state) { /* start of a sub section */ strcpy(csub, ptag); state = STATE_INSUB; if(!strcmp(cmain, main) && !strcmp(csub, sub)) { /* start of wanted part */ in_wanted_part = 1; if(strstr(patt, "base64=")) /* bit rough test, but "mostly" functional, */ /* treat wanted part data as base64 encoded */ base64 = 1; } if(display) { string = appendstring(string, buffer, &stringlen, &stralloc, base64); show(("* %s\n", buffer)); continue; } if((STATE_INSUB == state) && !strcmp(cmain, main) && !strcmp(csub, sub)) { show(("* (%d bytes) %s\n", stringlen, buffer)); display = 1; /* start displaying */ } else if ((*cmain == '?') || (*cmain == '!') || (*csub == '!')) { /* Ignore comments, DOCTYPEs and XML declarations */ show(("%d ignoring (%s/%s)\n", state, cmain, csub)); state--; if(in_wanted_part) { show(("=> %s", buffer)); error = appenddata(outbuf, outlen, &outalloc, buffer, base64); if(error) break; } } /* while */ if(buffer) free(buffer); if(error != GPE_OK) { if(error == GPE_END_OF_FILE) error = GPE_OK; else { show(("%d (%s/%s): %s\n", state, cmain, csub, buffer)); display = 0; /* no display */ if(*outbuf) free(*outbuf); *outbuf = NULL; *outlen = 0; } } *size = stringlen; return string; return error; }
tests/server/getpart.h +13 −6 Original line number Diff line number Diff line #ifndef HEADER_SERVER_GETPART_H #define HEADER_SERVER_GETPART_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | Loading @@ -5,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms Loading @@ -20,8 +22,13 @@ * * $Id$ ***************************************************************************/ const char * spitout(FILE *stream, const char *main, const char *sub, size_t *size); #define GPE_NO_BUFFER_SPACE -2 #define GPE_OUT_OF_MEMORY -1 #define GPE_OK 0 #define GPE_END_OF_FILE 1 int getpart(char **outbuf, size_t *outlen, const char *main, const char *sub, FILE *stream); #endif /* HEADER_SERVER_GETPART_H */
tests/server/rtspd.c +44 −9 Original line number Diff line number Diff line Loading @@ -423,9 +423,14 @@ static int ProcessRequest(struct httprequest *req) char *rtp_scratch = NULL; /* get the custom server control "commands" */ cmd = (char *)spitout(stream, "reply", "servercmd", &cmdsize); ptr = cmd; error = getpart(&cmd, &cmdsize, "reply", "servercmd", stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); req->open = FALSE; /* closes connection */ return 1; /* done */ } ptr = cmd; if(cmdsize) { logmsg("Found a reply-servercmd section!"); Loading Loading @@ -505,6 +510,8 @@ static int ProcessRequest(struct httprequest *req) } while(ptr && *ptr); logmsg("Done parsing server commands"); } if(cmd) free(cmd); } } else { Loading Loading @@ -950,13 +957,20 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) return 0; } else { buffer = spitout(stream, "reply", partbuf, &count); ptr = (char *)buffer; error = getpart(&buffer, &count, "reply", partbuf, stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); return 0; } ptr = (char *)buffer; } if(got_exit_signal) if(got_exit_signal) { if(ptr) free(ptr); return -1; } /* re-open the same file again */ stream=fopen(filename, "rb"); Loading @@ -965,17 +979,30 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", filename); logmsg("Couldn't open test file"); if(ptr) free(ptr); return 0; } else { /* get the custom server control "commands" */ cmd = (char *)spitout(stream, "reply", "postcmd", &cmdsize); error = getpart(&cmd, &cmdsize, "reply", "postcmd", stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); if(ptr) free(ptr); return 0; } } } if(got_exit_signal) if(got_exit_signal) { if(ptr) free(ptr); if(cmd) free(cmd); return -1; } /* If the word 'swsclose' is present anywhere in the reply chunk, the connection will be closed after the data has been sent to the requesting Loading @@ -997,6 +1024,10 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", RESPONSE_DUMP); logmsg("couldn't create logfile: " RESPONSE_DUMP); if(ptr) free(ptr); if(cmd) free(cmd); return -1; } Loading Loading @@ -1045,7 +1076,6 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) req->rtp_buffersize = 0; } do { res = fclose(dump); } while(res && ((error = ERRNO) == EINTR)); Loading @@ -1053,8 +1083,13 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) logmsg("Error closing file %s error: %d %s", RESPONSE_DUMP, error, strerror(error)); if(got_exit_signal) if(got_exit_signal) { if(ptr) free(ptr); if(cmd) free(cmd); return -1; } if(sendfailure) { logmsg("Sending response failed. Only (%zu bytes) of (%zu bytes) were sent", Loading
tests/server/sws.c +43 −8 Original line number Diff line number Diff line Loading @@ -389,8 +389,13 @@ static int ProcessRequest(struct httprequest *req) int num=0; /* get the custom server control "commands" */ cmd = (char *)spitout(stream, "reply", "servercmd", &cmdsize); error = getpart(&cmd, &cmdsize, "reply", "servercmd", stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); req->open = FALSE; /* closes connection */ return 1; /* done */ } if(cmdsize) { logmsg("Found a reply-servercmd section!"); Loading Loading @@ -423,8 +428,9 @@ static int ProcessRequest(struct httprequest *req) else { logmsg("funny instruction found: %s", cmd); } free(cmd); } if(cmd) free(cmd); } } else { Loading Loading @@ -863,13 +869,20 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) return 0; } else { buffer = spitout(stream, "reply", partbuf, &count); ptr = (char *)buffer; error = getpart(&ptr, &count, "reply", partbuf, stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); return 0; } buffer = ptr; } if(got_exit_signal) if(got_exit_signal) { if(ptr) free(ptr); return -1; } /* re-open the same file again */ stream=fopen(filename, "rb"); Loading @@ -878,17 +891,30 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", filename); logmsg("Couldn't open test file"); if(ptr) free(ptr); return 0; } else { /* get the custom server control "commands" */ cmd = (char *)spitout(stream, "reply", "postcmd", &cmdsize); error = getpart(&cmd, &cmdsize, "reply", "postcmd", stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); if(ptr) free(ptr); return 0; } } } if(got_exit_signal) if(got_exit_signal) { if(ptr) free(ptr); if(cmd) free(cmd); return -1; } /* If the word 'swsclose' is present anywhere in the reply chunk, the connection will be closed after the data has been sent to the requesting Loading @@ -910,6 +936,10 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", RESPONSE_DUMP); logmsg("couldn't create logfile: " RESPONSE_DUMP); if(ptr) free(ptr); if(cmd) free(cmd); return -1; } Loading Loading @@ -945,8 +975,13 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) logmsg("Error closing file %s error: %d %s", RESPONSE_DUMP, error, strerror(error)); if(got_exit_signal) if(got_exit_signal) { if(ptr) free(ptr); if(cmd) free(cmd); return -1; } if(sendfailure) { logmsg("Sending response failed. Only (%zu bytes) of (%zu bytes) were sent", Loading