diff options
author | Maros Priputen <maros.priputen@student.tuke.sk> | 2019-10-30 09:43:14 +0100 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2019-11-28 13:05:20 +0100 |
commit | 18e5cb77e986911063da8ab6bf254d632b2de6ea (patch) | |
tree | e86358f792c99440d2cb2eebe3a8518514816cc1 /src | |
parent | 1ff63fa69baf617eee856ea30db7ae23134e46fd (diff) |
curl: two new command line options for etags
--etag-compare and --etag-save
Suggested-by: Paul Hoffman
Fixes #4277
Closes #4543
Diffstat (limited to 'src')
-rw-r--r-- | src/tool_cb_hdr.c | 54 | ||||
-rw-r--r-- | src/tool_cb_hdr.h | 3 | ||||
-rw-r--r-- | src/tool_cfgable.c | 2 | ||||
-rw-r--r-- | src/tool_cfgable.h | 2 | ||||
-rw-r--r-- | src/tool_getparam.c | 10 | ||||
-rw-r--r-- | src/tool_help.c | 4 | ||||
-rw-r--r-- | src/tool_operate.c | 101 | ||||
-rw-r--r-- | src/tool_operate.h | 1 |
8 files changed, 176 insertions, 1 deletions
diff --git a/src/tool_cb_hdr.c b/src/tool_cb_hdr.c index b0880f186..77224adba 100644 --- a/src/tool_cb_hdr.c +++ b/src/tool_cb_hdr.c @@ -59,6 +59,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) struct HdrCbData *hdrcbdata = &per->hdrcbdata; struct OutStruct *outs = &per->outs; struct OutStruct *heads = &per->heads; + struct OutStruct *etag_save = &per->etag_save; const char *str = ptr; const size_t cb = size * nmemb; const char *end = (char *)ptr + cb; @@ -96,6 +97,59 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) } /* + * Write etag to file when --etag-save option is given. + * etag string that we want is enveloped in double quotes + */ + if(etag_save->config->etag_save_file && etag_save->stream) { + /* match only header that start with etag (case insensitive) */ + if(curl_strnequal(str, "etag:", 5)) { + char *etag_h = NULL; + char *first = NULL; + char *last = NULL; + size_t etag_length = 0; + + etag_h = ptr; + /* point to first occurence of double quote */ + first = memchr(etag_h, '\"', cb); + + /* + * if server side messed with the etag header and doesn't include + * double quotes around the etag, kindly exit with a warning + */ + + if(!first) { + warnf( + etag_save->config->global, + "\nReceived header etag is missing double quote/s\n"); + return 1; + } + else { + /* discard first double quote */ + first++; + } + + /* point to last occurence of double quote */ + last = memchr(first, '\"', cb); + + if(!last) { + warnf( + etag_save->config->global, + "\nReceived header etag is missing double quote/s\n"); + return 1; + } + + /* get length of desired etag */ + etag_length = (size_t)last - (size_t)first; + + fwrite(first, size, etag_length, etag_save->stream); + /* terminate with new line */ + fputc('\n', etag_save->stream); + } + + (void)fflush(etag_save->stream); + } + + /* * This callback sets the filename where output shall be written when * curl options --remote-name (-O) and --remote-header-name (-J) have * been simultaneously given and additionally server returns an HTTP diff --git a/src/tool_cb_hdr.h b/src/tool_cb_hdr.h index cf544dfcb..ec5772f55 100644 --- a/src/tool_cb_hdr.h +++ b/src/tool_cb_hdr.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -43,6 +43,7 @@ struct HdrCbData { struct OperationConfig *config; struct OutStruct *outs; struct OutStruct *heads; + struct OutStruct *etag_save; bool honor_cd_filename; }; diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index efa8c50b2..f802a5a31 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -128,6 +128,8 @@ static void free_config_fields(struct OperationConfig *config) Curl_safefree(config->pubkey); Curl_safefree(config->hostpubmd5); Curl_safefree(config->engine); + Curl_safefree(config->etag_save_file); + Curl_safefree(config->etag_compare_file); Curl_safefree(config->request_target); Curl_safefree(config->customrequest); Curl_safefree(config->krblevel); diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 4372cc6fc..32e811eaa 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -156,6 +156,8 @@ struct OperationConfig { char *pubkey; char *hostpubmd5; char *engine; + char *etag_save_file; + char *etag_compare_file; bool crlf; char *customrequest; char *krblevel; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 75faff34d..3efc23e1e 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -268,6 +268,8 @@ static const struct LongShort aliases[]= { {"E9", "proxy-tlsv1", ARG_NONE}, {"EA", "socks5-basic", ARG_BOOL}, {"EB", "socks5-gssapi", ARG_BOOL}, + {"EC", "etag-save", ARG_FILENAME}, + {"ED", "etag-compare", ARG_FILENAME}, {"f", "fail", ARG_BOOL}, {"fa", "fail-early", ARG_BOOL}, {"fb", "styled-output", ARG_BOOL}, @@ -1697,6 +1699,14 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ config->socks5_auth &= ~CURLAUTH_GSSAPI; break; + case 'C': + GetStr(&config->etag_save_file, nextarg); + break; + + case 'D': + GetStr(&config->etag_compare_file, nextarg); + break; + default: /* unknown flag */ return PARAM_OPTION_UNKNOWN; } diff --git a/src/tool_help.c b/src/tool_help.c index 21900108b..8d3f34547 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -131,6 +131,10 @@ static const struct helptxt helptext[] = { "EGD socket path for random data"}, {" --engine <name>", "Crypto engine to use"}, + {" --etag-save <file>", + "Get an ETag from response header and save it to a FILE"}, + {" --etag-compare <file>", + "Get an ETag from a file and send a conditional request"}, {" --expect100-timeout <seconds>", "How long to wait for 100-continue"}, {"-f, --fail", diff --git a/src/tool_operate.c b/src/tool_operate.c index 4b2ffb55b..23971f112 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -644,6 +644,12 @@ static CURLcode post_per_transfer(struct GlobalConfig *global, if(per->heads.alloc_filename) Curl_safefree(per->heads.filename); + if(per->etag_save.fopened && per->etag_save.stream) + fclose(per->etag_save.stream); + + if(per->etag_save.alloc_filename) + Curl_safefree(per->etag_save.filename); + curl_easy_cleanup(per->curl); if(outs->alloc_filename) free(outs->filename); @@ -834,6 +840,7 @@ static CURLcode single_transfer(struct GlobalConfig *global, struct OutStruct *outs; struct InStruct *input; struct OutStruct *heads; + struct OutStruct *etag_save; struct HdrCbData *hdrcbdata = NULL; CURL *curl = curl_easy_init(); result = add_per_transfer(&per); @@ -882,6 +889,99 @@ static CURLcode single_transfer(struct GlobalConfig *global, } } + /* disallowing simultaneous use of --etag-save and --etag-compare */ + if(config->etag_save_file && config->etag_compare_file) { + warnf( + config->global, + "Cannot use --etag-save and --etag-compare at the same time\n"); + + result = CURLE_UNKNOWN_OPTION; + break; + } + + /* --etag-save */ + etag_save = &per->etag_save; + etag_save->stream = stdout; + etag_save->config = config; + if(config->etag_save_file) { + /* open file for output: */ + if(strcmp(config->etag_save_file, "-")) { + FILE *newfile = fopen(config->etag_save_file, "wb"); + if(!newfile) { + warnf( + config->global, + "Failed to open %s\n", config->etag_save_file); + + result = CURLE_WRITE_ERROR; + break; + } + else { + etag_save->filename = config->etag_save_file; + etag_save->s_isreg = TRUE; + etag_save->fopened = TRUE; + etag_save->stream = newfile; + } + } + else { + /* always use binary mode for protocol header output */ + set_binmode(etag_save->stream); + } + } + + /* --etag-compare */ + if(config->etag_compare_file) { + char *etag_from_file = NULL; + char *header = NULL; + size_t file_size = 0; + + /* open file for reading: */ + FILE *file = fopen(config->etag_compare_file, FOPEN_READTEXT); + if(!file) { + warnf( + config->global, + "Failed to open %s\n", config->etag_compare_file); + + result = CURLE_READ_ERROR; + break; + } + + /* get file size */ + fseek(file, 0, SEEK_END); + file_size = ftell(file); + + /* + * check if file is empty, if it's not load etag + * else continue with empty etag + */ + if(file_size != 0) { + fseek(file, 0, SEEK_SET); + file2string(&etag_from_file, file); + + header = aprintf("If-None-Match: \"%s\"", etag_from_file); + } + else { + header = aprintf("If-None-Match: \"\""); + } + + if(!header) { + warnf( + config->global, + "Failed to allocate memory for custom etag header\n"); + + result = CURLE_OUT_OF_MEMORY; + break; + } + + /* add Etag from file to list of custom headers */ + add2list(&config->headers, header); + + Curl_safefree(header); + Curl_safefree(etag_from_file); + + if(file) { + fclose(file); + } + } hdrcbdata = &per->hdrcbdata; @@ -1769,6 +1869,7 @@ static CURLcode single_transfer(struct GlobalConfig *global, hdrcbdata->outs = outs; hdrcbdata->heads = heads; + hdrcbdata->etag_save = etag_save; hdrcbdata->global = global; hdrcbdata->config = config; diff --git a/src/tool_operate.h b/src/tool_operate.h index 7223db767..39227c0f3 100644 --- a/src/tool_operate.h +++ b/src/tool_operate.h @@ -48,6 +48,7 @@ struct per_transfer { struct ProgressData progressbar; struct OutStruct outs; struct OutStruct heads; + struct OutStruct etag_save; struct InStruct input; struct HdrCbData hdrcbdata; char errorbuffer[CURL_ERROR_SIZE]; |