• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 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  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 #if !defined(LIB670) && !defined(LIB671)
26 #define CURL_DISABLE_DEPRECATION  /* Using and testing the form api */
27 #endif
28 
29 #include "test.h"
30 
31 #include <time.h>
32 
33 #include "memdebug.h"
34 
35 #define PAUSE_TIME      2
36 
37 
38 static const char name[] = "field";
39 
40 struct ReadThis {
41   CURL *easy;
42   time_t origin;
43   int count;
44 };
45 
46 
read_callback(char * ptr,size_t size,size_t nmemb,void * userp)47 static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp)
48 {
49   struct ReadThis *pooh = (struct ReadThis *) userp;
50   time_t delta;
51 
52   if(size * nmemb < 1)
53     return 0;
54 
55   switch(pooh->count++) {
56   case 0:
57     *ptr = '\x41'; /* ASCII A. */
58     return 1;
59   case 1:
60     pooh->origin = time(NULL);
61     return CURL_READFUNC_PAUSE;
62   case 2:
63     delta = time(NULL) - pooh->origin;
64     *ptr = delta >= PAUSE_TIME? '\x42': '\x41'; /* ASCII A or B. */
65     return 1;
66   case 3:
67     return 0;
68   }
69   fprintf(stderr, "Read callback called after EOF\n");
70   exit(1);
71 }
72 
73 #if !defined(LIB670) && !defined(LIB672)
xferinfo(void * clientp,curl_off_t dltotal,curl_off_t dlnow,curl_off_t ultotal,curl_off_t ulnow)74 static int xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
75                     curl_off_t ultotal, curl_off_t ulnow)
76 {
77   struct ReadThis *pooh = (struct ReadThis *) clientp;
78 
79   (void) dltotal;
80   (void) dlnow;
81   (void) ultotal;
82   (void) ulnow;
83 
84   if(pooh->origin) {
85     time_t delta = time(NULL) - pooh->origin;
86 
87     if(delta >= 4 * PAUSE_TIME) {
88       fprintf(stderr, "unpausing failed: drain problem?\n");
89       return CURLE_ABORTED_BY_CALLBACK;
90     }
91 
92     if(delta >= PAUSE_TIME)
93       curl_easy_pause(pooh->easy, CURLPAUSE_CONT);
94   }
95 
96   return 0;
97 }
98 #endif
99 
test(char * URL)100 int test(char *URL)
101 {
102 #if defined(LIB670) || defined(LIB671)
103   curl_mime *mime = NULL;
104   curl_mimepart *part;
105 #else
106   CURLFORMcode formrc;
107   struct curl_httppost *formpost = NULL;
108   struct curl_httppost *lastptr = NULL;
109 #endif
110 #if defined(LIB670) || defined(LIB672)
111   CURLM *multi = NULL;
112   CURLMcode mres;
113   CURLMsg *msg;
114   int msgs_left;
115   int still_running = 0;
116 #endif
117 
118   struct ReadThis pooh;
119   CURLcode result;
120   int res = TEST_ERR_FAILURE;
121 
122   /*
123    * Check proper pausing/unpausing from a mime or form read callback.
124    */
125 
126   if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
127     fprintf(stderr, "curl_global_init() failed\n");
128     return TEST_ERR_MAJOR_BAD;
129   }
130 
131   pooh.origin = (time_t) 0;
132   pooh.count = 0;
133   pooh.easy = curl_easy_init();
134 
135   /* First set the URL that is about to receive our POST. */
136   test_setopt(pooh.easy, CURLOPT_URL, URL);
137 
138   /* get verbose debug output please */
139   test_setopt(pooh.easy, CURLOPT_VERBOSE, 1L);
140 
141   /* include headers in the output */
142   test_setopt(pooh.easy, CURLOPT_HEADER, 1L);
143 
144 #if defined(LIB670) || defined(LIB671)
145   /* Build the mime tree. */
146   mime = curl_mime_init(pooh.easy);
147   part = curl_mime_addpart(mime);
148   result = curl_mime_name(part, name);
149   if(result) {
150     fprintf(stderr,
151             "Something went wrong when building the mime structure: %d\n",
152             (int) result);
153     goto test_cleanup;
154   }
155 
156   res = curl_mime_data_cb(part, (curl_off_t) 2, read_callback,
157                           NULL, NULL, &pooh);
158 
159   /* Bind mime data to its easy handle. */
160   if(!res)
161     test_setopt(pooh.easy, CURLOPT_MIMEPOST, mime);
162 #else
163   /* Build the form. */
164   formrc = curl_formadd(&formpost, &lastptr,
165                         CURLFORM_COPYNAME, name,
166                         CURLFORM_STREAM, &pooh,
167                         CURLFORM_CONTENTLEN, (curl_off_t) 2,
168                         CURLFORM_END);
169   if(formrc) {
170     fprintf(stderr, "curl_formadd() = %d\n", (int) formrc);
171     goto test_cleanup;
172   }
173 
174   /* We want to use our own read function. */
175   test_setopt(pooh.easy, CURLOPT_READFUNCTION, read_callback);
176 
177   /* Send a multi-part formpost. */
178   test_setopt(pooh.easy, CURLOPT_HTTPPOST, formpost);
179 #endif
180 
181 #if defined(LIB670) || defined(LIB672)
182   /* Use the multi interface. */
183   multi = curl_multi_init();
184   mres = curl_multi_add_handle(multi, pooh.easy);
185   while(!mres) {
186     struct timeval timeout;
187     int rc = 0;
188     fd_set fdread;
189     fd_set fdwrite;
190     fd_set fdexcept;
191     int maxfd = -1;
192 
193     mres = curl_multi_perform(multi, &still_running);
194     if(!still_running || mres != CURLM_OK)
195       break;
196 
197     if(pooh.origin) {
198       time_t delta = time(NULL) - pooh.origin;
199 
200       if(delta >= 4 * PAUSE_TIME) {
201         fprintf(stderr, "unpausing failed: drain problem?\n");
202         res = CURLE_OPERATION_TIMEDOUT;
203         break;
204       }
205 
206       if(delta >= PAUSE_TIME)
207         curl_easy_pause(pooh.easy, CURLPAUSE_CONT);
208     }
209 
210     FD_ZERO(&fdread);
211     FD_ZERO(&fdwrite);
212     FD_ZERO(&fdexcept);
213     timeout.tv_sec = 0;
214     timeout.tv_usec = 1000000 * PAUSE_TIME / 10;
215     mres = curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcept, &maxfd);
216     if(mres)
217       break;
218 #if defined(WIN32) || defined(_WIN32)
219     if(maxfd == -1)
220       Sleep(100);
221     else
222 #endif
223     rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcept, &timeout);
224     if(rc == -1) {
225       fprintf(stderr, "Select error\n");
226       break;
227     }
228   }
229 
230   if(mres != CURLM_OK)
231     for(;;) {
232       msg = curl_multi_info_read(multi, &msgs_left);
233       if(!msg)
234         break;
235       if(msg->msg == CURLMSG_DONE) {
236         result = msg->data.result;
237         res = (int) result;
238       }
239     }
240 
241   curl_multi_remove_handle(multi, pooh.easy);
242   curl_multi_cleanup(multi);
243 
244 #else
245   /* Use the easy interface. */
246   test_setopt(pooh.easy, CURLOPT_XFERINFODATA, &pooh);
247   test_setopt(pooh.easy, CURLOPT_XFERINFOFUNCTION, xferinfo);
248   test_setopt(pooh.easy, CURLOPT_NOPROGRESS, 0L);
249   result = curl_easy_perform(pooh.easy);
250   res = (int) result;
251 #endif
252 
253 
254 test_cleanup:
255   curl_easy_cleanup(pooh.easy);
256 #if defined(LIB670) || defined(LIB671)
257   curl_mime_free(mime);
258 #else
259   curl_formfree(formpost);
260 #endif
261 
262   curl_global_cleanup();
263   return res;
264 }
265