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.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 "test.h"
23
24#include "memdebug.h"
25
26static char data[]=
27#ifdef CURL_DOES_CONVERSIONS
28 /* ASCII representation with escape sequences for non-ASCII platforms */
29 "\x64\x75\x6d\x6d\x79\x0a";
30#else
31 "dummy\n";
32#endif
33
34struct WriteThis {
35 char *readptr;
36 curl_off_t sizeleft;
37};
38
39static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp)
40{
41#ifdef LIB644
42 static int count = 0;
43 (void)ptr;
44 (void)size;
45 (void)nmemb;
46 (void)userp;
47 switch(count++) {
48 case 0: /* Return a single byte. */
49 *ptr = '\n';
50 return 1;
51 case 1: /* Request abort. */
52 return CURL_READFUNC_ABORT;
53 }
54 printf("Wrongly called >2 times\n");
55 exit(1); /* trigger major failure */
56#else
57
58 struct WriteThis *pooh = (struct WriteThis *)userp;
59 int eof = !*pooh->readptr;
60
61 if(size*nmemb < 1)
62 return 0;
63
64#ifndef LIB645
65 eof = pooh->sizeleft <= 0;
66 if(!eof)
67 pooh->sizeleft--;
68#endif
69
70 if(!eof) {
71 *ptr = *pooh->readptr; /* copy one single byte */
72 pooh->readptr++; /* advance pointer */
73 return 1; /* we return 1 byte at a time! */
74 }
75
76 return 0; /* no more data left to deliver */
77#endif
78}
79
80static int once(char *URL, bool oldstyle)
81{
82 CURL *curl;
83 CURLcode res = CURLE_OK;
84
85 curl_mime *mime = NULL;
86 curl_mimepart *part = NULL;
87 struct WriteThis pooh;
88 struct WriteThis pooh2;
89 curl_off_t datasize = -1;
90
91 pooh.readptr = data;
92#ifndef LIB645
93 datasize = (curl_off_t)strlen(data);
94#endif
95 pooh.sizeleft = datasize;
96
97 curl = curl_easy_init();
98 if(!curl) {
99 fprintf(stderr, "curl_easy_init() failed\n");
100 curl_global_cleanup();
101 return TEST_ERR_MAJOR_BAD;
102 }
103
104 mime = curl_mime_init(curl);
105 if(!mime) {
106 fprintf(stderr, "curl_mime_init() failed\n");
107 curl_easy_cleanup(curl);
108 curl_global_cleanup();
109 return TEST_ERR_MAJOR_BAD;
110 }
111
112 part = curl_mime_addpart(mime);
113 if(!part) {
114 fprintf(stderr, "curl_mime_addpart(1) failed\n");
115 curl_mime_free(mime);
116 curl_easy_cleanup(curl);
117 curl_global_cleanup();
118 return TEST_ERR_MAJOR_BAD;
119 }
120
121 /* Fill in the file upload part */
122 if(oldstyle) {
123 res = curl_mime_name(part, "sendfile");
124 if(!res)
125 res = curl_mime_data_cb(part, datasize, read_callback,
126 NULL, NULL, &pooh);
127 if(!res)
128 res = curl_mime_filename(part, "postit2.c");
129 }
130 else {
131 /* new style */
132 res = curl_mime_name(part, "sendfile alternative");
133 if(!res)
134 res = curl_mime_data_cb(part, datasize, read_callback,
135 NULL, NULL, &pooh);
136 if(!res)
137 res = curl_mime_filename(part, "file name 2");
138 }
139
140 if(res)
141 printf("curl_mime_xxx(1) = %s\n", curl_easy_strerror(res));
142
143 /* Now add the same data with another name and make it not look like
144 a file upload but still using the callback */
145
146 pooh2.readptr = data;
147#ifndef LIB645
148 datasize = (curl_off_t)strlen(data);
149#endif
150 pooh2.sizeleft = datasize;
151
152 part = curl_mime_addpart(mime);
153 if(!part) {
154 fprintf(stderr, "curl_mime_addpart(2) failed\n");
155 curl_mime_free(mime);
156 curl_easy_cleanup(curl);
157 curl_global_cleanup();
158 return TEST_ERR_MAJOR_BAD;
159 }
160 /* Fill in the file upload part */
161 res = curl_mime_name(part, "callbackdata");
162 if(!res)
163 res = curl_mime_data_cb(part, datasize, read_callback,
164 NULL, NULL, &pooh2);
165
166 if(res)
167 printf("curl_mime_xxx(2) = %s\n", curl_easy_strerror(res));
168
169 part = curl_mime_addpart(mime);
170 if(!part) {
171 fprintf(stderr, "curl_mime_addpart(3) failed\n");
172 curl_mime_free(mime);
173 curl_easy_cleanup(curl);
174 curl_global_cleanup();
175 return TEST_ERR_MAJOR_BAD;
176 }
177
178 /* Fill in the filename field */
179 res = curl_mime_name(part, "filename");
180 if(!res)
181 res = curl_mime_data(part,
182#ifdef CURL_DOES_CONVERSIONS
183 /* ASCII representation with escape
184 sequences for non-ASCII platforms */
185 "\x70\x6f\x73\x74\x69\x74\x32\x2e\x63",
186#else
187 "postit2.c",
188#endif
189 CURL_ZERO_TERMINATED);
190
191 if(res)
192 printf("curl_mime_xxx(3) = %s\n", curl_easy_strerror(res));
193
194 /* Fill in a submit field too */
195 part = curl_mime_addpart(mime);
196 if(!part) {
197 fprintf(stderr, "curl_mime_addpart(4) failed\n");
198 curl_mime_free(mime);
199 curl_easy_cleanup(curl);
200 curl_global_cleanup();
201 return TEST_ERR_MAJOR_BAD;
202 }
203 res = curl_mime_name(part, "submit");
204 if(!res)
205 res = curl_mime_data(part,
206#ifdef CURL_DOES_CONVERSIONS
207 /* ASCII representation with escape
208 sequences for non-ASCII platforms */
209 "\x73\x65\x6e\x64",
210#else
211 "send",
212#endif
213 CURL_ZERO_TERMINATED);
214
215 if(res)
216 printf("curl_mime_xxx(4) = %s\n", curl_easy_strerror(res));
217
218 part = curl_mime_addpart(mime);
219 if(!part) {
220 fprintf(stderr, "curl_mime_addpart(5) failed\n");
221 curl_mime_free(mime);
222 curl_easy_cleanup(curl);
223 curl_global_cleanup();
224 return TEST_ERR_MAJOR_BAD;
225 }
226 res = curl_mime_name(part, "somename");
227 if(!res)
228 res = curl_mime_filename(part, "somefile.txt");
229 if(!res)
230 res = curl_mime_data(part, "blah blah", 9);
231
232 if(res)
233 printf("curl_mime_xxx(5) = %s\n", curl_easy_strerror(res));
234
235 /* First set the URL that is about to receive our POST. */
236 test_setopt(curl, CURLOPT_URL, URL);
237
238 /* send a multi-part mimepost */
239 test_setopt(curl, CURLOPT_MIMEPOST, mime);
240
241 /* get verbose debug output please */
242 test_setopt(curl, CURLOPT_VERBOSE, 1L);
243
244 /* include headers in the output */
245 test_setopt(curl, CURLOPT_HEADER, 1L);
246
247 /* Perform the request, res will get the return code */
248 res = curl_easy_perform(curl);
249
250test_cleanup:
251
252 /* always cleanup */
253 curl_easy_cleanup(curl);
254
255 /* now cleanup the mimepost structure */
256 curl_mime_free(mime);
257
258 return res;
259}
260
261static int cyclic_add(void)
262{
263 CURL *easy = curl_easy_init();
264 curl_mime *mime = curl_mime_init(easy);
265 curl_mimepart *part = curl_mime_addpart(mime);
266 CURLcode a1 = curl_mime_subparts(part, mime);
267
268 if(a1 == CURLE_BAD_FUNCTION_ARGUMENT) {
269 curl_mime *submime = curl_mime_init(easy);
270 curl_mimepart *subpart = curl_mime_addpart(submime);
271
272 curl_mime_subparts(part, submime);
273 a1 = curl_mime_subparts(subpart, mime);
274 }
275
276 curl_mime_free(mime);
277 curl_easy_cleanup(easy);
278 if(a1 != CURLE_BAD_FUNCTION_ARGUMENT)
279 /* that should have failed */
280 return 1;
281
282 return 0;
283}
284
285int test(char *URL)
286{
287 int res;
288
289 if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
290 fprintf(stderr, "curl_global_init() failed\n");
291 return TEST_ERR_MAJOR_BAD;
292 }
293
294 res = once(URL, TRUE); /* old */
295 if(!res)
296 res = once(URL, FALSE); /* new */
297
298 if(!res)
299 res = cyclic_add();
300
301 curl_global_cleanup();
302
303 return res;
304}
305