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 45struct testparams { 46 unsigned int flags; /* ORed flags as above. */ 47 CURLcode result; /* Code that should be returned by curl_easy_perform(). */ 48}; 49 50static const struct testparams params[] = { 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 74static int hasbody; 75 76static 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 86static 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 126test_cleanup: 127 128 return 1; 129} 130 131/* for debugging: */ 132/* #define SINGLETEST 9 */ 133 134int 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(params) / sizeof(params[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, params + i, i); 160 curl_easy_cleanup(curl); 161 } 162 163 curl_global_cleanup(); 164 printf("%d\n", status); 165 return status; 166 167test_cleanup: 168 169 curl_easy_cleanup(curl); 170 curl_global_cleanup(); 171 172 return (int)res; 173} 174