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