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 /*
27 Check range/resume returned error codes and data presence.
28
29 The input parameters are:
30 - CURLOPT_RANGE/CURLOPT_RESUME_FROM
31 - CURLOPT_FAILONERROR
32 - Returned http code (2xx/416)
33 - Content-Range header present in reply.
34
35 */
36
37 #include "memdebug.h"
38
39 #define F_RESUME (1 << 0) /* resume/range. */
40 #define F_HTTP416 (1 << 1) /* Server returns http code 416. */
41 #define F_FAIL (1 << 2) /* Fail on error. */
42 #define F_CONTENTRANGE (1 << 3) /* Server sends content-range hdr. */
43 #define F_IGNOREBODY (1 << 4) /* Body should be ignored. */
44
45 struct testparams {
46 unsigned int flags; /* ORed flags as above. */
47 CURLcode result; /* Code that should be returned by curl_easy_perform(). */
48 };
49
50 static const struct testparams testparams[] = {
51 { 0, CURLE_OK },
52 { F_CONTENTRANGE, CURLE_OK },
53 { F_FAIL, CURLE_OK },
54 { F_FAIL | F_CONTENTRANGE, CURLE_OK },
55 { F_HTTP416, CURLE_OK },
56 { F_HTTP416 | F_CONTENTRANGE, CURLE_OK },
57 { F_HTTP416 | F_FAIL | F_IGNOREBODY,
58 CURLE_HTTP_RETURNED_ERROR },
59 { F_HTTP416 | F_FAIL | F_CONTENTRANGE | F_IGNOREBODY,
60 CURLE_HTTP_RETURNED_ERROR },
61 { F_RESUME | F_IGNOREBODY,
62 CURLE_RANGE_ERROR },
63 { F_RESUME | F_CONTENTRANGE, CURLE_OK },
64 { F_RESUME | F_FAIL | F_IGNOREBODY,
65 CURLE_RANGE_ERROR },
66 { F_RESUME | F_FAIL | F_CONTENTRANGE, CURLE_OK },
67 { F_RESUME | F_HTTP416 | F_IGNOREBODY, CURLE_OK },
68 { F_RESUME | F_HTTP416 | F_CONTENTRANGE | F_IGNOREBODY, CURLE_OK },
69 { F_RESUME | F_HTTP416 | F_FAIL | F_IGNOREBODY, CURLE_OK },
70 { F_RESUME | F_HTTP416 | F_FAIL | F_CONTENTRANGE | F_IGNOREBODY,
71 CURLE_OK }
72 };
73
74 static int hasbody;
75
writedata(char * data,size_t size,size_t nmemb,void * userdata)76 static size_t writedata(char *data, size_t size, size_t nmemb, void *userdata)
77 {
78 (void) data;
79 (void) userdata;
80
81 if(size && nmemb)
82 hasbody = 1;
83 return size * nmemb;
84 }
85
onetest(CURL * curl,const char * url,const struct testparams * p,size_t num)86 static int onetest(CURL *curl, const char *url, const struct testparams *p,
87 size_t num)
88 {
89 CURLcode res;
90 unsigned int replyselector;
91 char urlbuf[256];
92
93 replyselector = (p->flags & F_CONTENTRANGE) ? 1 : 0;
94 if(p->flags & F_HTTP416)
95 replyselector += 2;
96 msnprintf(urlbuf, sizeof(urlbuf), "%s%04u", url, replyselector);
97 test_setopt(curl, CURLOPT_URL, urlbuf);
98 test_setopt(curl, CURLOPT_VERBOSE, 1L);
99 test_setopt(curl, CURLOPT_RESUME_FROM, (p->flags & F_RESUME) ? 3 : 0);
100 test_setopt(curl, CURLOPT_RANGE, !(p->flags & F_RESUME) ?
101 "3-1000000": (char *) NULL);
102 test_setopt(curl, CURLOPT_FAILONERROR, (p->flags & F_FAIL) ? 1 : 0);
103 hasbody = 0;
104 res = curl_easy_perform(curl);
105 if(res != p->result) {
106 printf("%zd: bad error code (%d): resume=%s, fail=%s, http416=%s, "
107 "content-range=%s, expected=%d\n", num, res,
108 (p->flags & F_RESUME) ? "yes": "no",
109 (p->flags & F_FAIL) ? "yes": "no",
110 (p->flags & F_HTTP416) ? "yes": "no",
111 (p->flags & F_CONTENTRANGE) ? "yes": "no",
112 p->result);
113 return 1;
114 }
115 if(hasbody && (p->flags & F_IGNOREBODY)) {
116 printf("body should be ignored and is not: resume=%s, fail=%s, "
117 "http416=%s, content-range=%s\n",
118 (p->flags & F_RESUME) ? "yes": "no",
119 (p->flags & F_FAIL) ? "yes": "no",
120 (p->flags & F_HTTP416) ? "yes": "no",
121 (p->flags & F_CONTENTRANGE) ? "yes": "no");
122 return 1;
123 }
124 return 0;
125
126 test_cleanup:
127
128 return 1;
129 }
130
131 /* for debugging: */
132 /* #define SINGLETEST 9 */
133
test(char * URL)134 CURLcode test(char *URL)
135 {
136 CURLcode res;
137 CURL *curl;
138 size_t i;
139 int status = 0;
140
141 if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
142 fprintf(stderr, "curl_global_init() failed\n");
143 return TEST_ERR_MAJOR_BAD;
144 }
145
146 for(i = 0; i < sizeof(testparams) / sizeof(testparams[0]); i++) {
147 curl = curl_easy_init();
148 if(!curl) {
149 fprintf(stderr, "curl_easy_init() failed\n");
150 curl_global_cleanup();
151 return TEST_ERR_MAJOR_BAD;
152 }
153
154 test_setopt(curl, CURLOPT_WRITEFUNCTION, writedata);
155
156 #ifdef SINGLETEST
157 if(SINGLETEST == i)
158 #endif
159 status |= onetest(curl, URL, testparams + i, i);
160 curl_easy_cleanup(curl);
161 }
162
163 curl_global_cleanup();
164 printf("%d\n", status);
165 return (CURLcode)status;
166
167 test_cleanup:
168
169 curl_easy_cleanup(curl);
170 curl_global_cleanup();
171
172 return res;
173 }
174