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>