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 
26 static 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 
34 struct WriteThis {
35   char *readptr;
36   curl_off_t sizeleft;
37 };
38 
read_callback(char * ptr,size_t size,size_t nmemb,void * userp)39 static 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 
once(char * URL,bool oldstyle)80 static 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 
250 test_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 
cyclic_add(void)261 static 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 
test(char * URL)285 int 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