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