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