1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel (at) 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.haxx.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 43 typedef struct { 44 unsigned int flags; /* ORed flags as above. */ 45 CURLcode result; /* Code that should be returned by curl_easy_perform(). */ 46 } testparams; 47 48 static const 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, 68 CURLE_HTTP_RETURNED_ERROR }, 69 { F_RESUME | F_HTTP416 | F_FAIL | F_CONTENTRANGE | F_IGNOREBODY, 70 CURLE_HTTP_RETURNED_ERROR } 71 }; 72 73 static int hasbody; 74 75 static size_t writedata(char *data, size_t size, size_t nmemb, void *userdata) 76 { 77 (void) data; 78 (void) userdata; 79 80 if(size && nmemb) 81 hasbody = 1; 82 return size * nmemb; 83 } 84 85 static int onetest(CURL *curl, const char *url, const testparams *p) 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, "bad error code (%d): resume=%s, fail=%s, http416=%s, " 104 "content-range=%s, expected=%d\n", 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 128 int 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); 151 152 curl_easy_cleanup(curl); 153 curl_global_cleanup(); 154 return status; 155 156 test_cleanup: 157 158 curl_easy_cleanup(curl); 159 curl_global_cleanup(); 160 161 return (int)res; 162 } 163