Home | History | Annotate | Download | only in libtest
      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