xref: /third_party/curl/tests/libtest/lib670.c (revision 13498266)
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      5
36
37
38static const char name[] = "field";
39
40struct ReadThis {
41  CURL *easy;
42  time_t origin;
43  int count;
44};
45
46
47static 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)
74static 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
100int 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)
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
254test_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