From 04c03416e68fd635a15cae8201872f5c29fdcca8 Mon Sep 17 00:00:00 2001 From: Mathias Gumz Date: Sat, 1 Feb 2020 18:55:24 +0100 Subject: writeout: support to generate JSON output This commit adds support to generate JSON via the writeout feature: -w "%{json}" It leverages the existing infrastructure as much as possible. Thus, generating the JSON on STDERR is possible by: -w "%{stderr}%{json}" This implements a variant of https://github.com/curl/curl/wiki/JSON#--write-out-json. Closes #4870 --- src/tool_writeout_json.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 src/tool_writeout_json.c (limited to 'src/tool_writeout_json.c') diff --git a/src/tool_writeout_json.c b/src/tool_writeout_json.c new file mode 100644 index 000000000..99252ecb8 --- /dev/null +++ b/src/tool_writeout_json.c @@ -0,0 +1,181 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "tool_setup.h" + +#define ENABLE_CURLX_PRINTF + +/* use our own printf() functions */ +#include "curlx.h" +#include "tool_cfgable.h" +#include "tool_writeout_json.h" +#include "tool_writeout.h" + + +static const char *http_version[] = { + "0", /* CURL_HTTP_VERSION_NONE */ + "1", /* CURL_HTTP_VERSION_1_0 */ + "1.1", /* CURL_HTTP_VERSION_1_1 */ + "2" /* CURL_HTTP_VERSION_2 */ + "3" /* CURL_HTTP_VERSION_3 */ +}; + +static void jsonEscape(FILE *stream, const char *in) +{ + const char *i = in; + const char *in_end = in + strlen(in); + + for(; i < in_end; i++) { + switch(*i) { + case '\\': + fputs("\\\\", stream); + break; + case '\"': + fputs("\\\"", stream); + break; + case '\b': + fputs("\\b", stream); + break; + case '\f': + fputs("\\f", stream); + break; + case '\n': + fputs("\\n", stream); + break; + case '\r': + fputs("\\r", stream); + break; + case '\t': + fputs("\\t", stream); + break; + default: + if (*i < 32) { + fprintf(stream, "u%04x", *i); + } + else { + fputc(*i, stream); + } + break; + }; + } +} + +static int writeTime(FILE *str, CURL *curl, const char *key, CURLINFO ci) +{ + curl_off_t val = 0; + if(CURLE_OK == curl_easy_getinfo(curl, ci, &val)) { + curl_off_t s = val / 1000000l; + curl_off_t ms = val % 1000000l; + fprintf(str, "\"%s\":%ld.%06ld", key, s, ms); + return 1; + } + return 0; +} + +static int writeString(FILE *str, CURL *curl, const char *key, CURLINFO ci) +{ + char *valp = NULL; + if((CURLE_OK == curl_easy_getinfo(curl, ci, &valp)) && valp) { + fprintf(str, "\"%s\":\"", key); + jsonEscape(str, valp); + fprintf(str, "\""); + return 1; + } + return 0; +} + +static int writeLong(FILE *str, CURL *curl, const char *key, CURLINFO ci) +{ + curl_off_t val = 0; + if(CURLE_OK == curl_easy_getinfo(curl, ci, &val)) { + fprintf(str, "\"%s\":%ld", key, val); + return 1; + } + return 0; +} + +static int writeFilename(FILE *str, const char *key, const char *filename) +{ + if(filename) { + fprintf(str, "\"%s\":\"", key); + jsonEscape(str, filename); + fprintf(str, "\""); + } + else { + fprintf(str, "\"%s\":null", key); + } + return 1; +} + +static int writeVersion(FILE *str, CURL *curl, const char *key, CURLINFO ci) +{ + long version = 0; + if(CURLE_OK == curl_easy_getinfo(curl, ci, &version) && + (version >= 0) && + (version < (long)(sizeof(http_version)/sizeof(char *)))) { + fprintf(str, "\"%s\":\"%s\"", key, http_version[version]); + return 1; + } + return 0; +} + +void ourWriteOutJSON(const struct writeoutvar mappings[], CURL *curl, + struct OutStruct *outs, FILE *stream) +{ + int i; + + fputs("{", stream); + for(i = 0; mappings[i].name != NULL; i++) { + const char *name = mappings[i].name; + CURLINFO cinfo = mappings[i].cinfo; + int ok = 0; + + if(mappings[i].is_ctrl == 1) { + continue; + } + + switch(mappings[i].jsontype) { + case JSON_STRING: + ok = writeString(stream, curl, name, cinfo); + break; + case JSON_LONG: + ok = writeLong(stream, curl, name, cinfo); + break; + case JSON_TIME: + ok = writeTime(stream, curl, name, cinfo); + break; + case JSON_FILENAME: + ok = writeFilename(stream, name, outs->filename); + break; + case JSON_VERSION: + ok = writeVersion(stream, curl, name, cinfo); + break; + default: + break; + } + + if(ok) { + fputs(",", stream); + } + } + + fprintf(stream, "\"curl_version\":\"%s\"}", curl_version()); +} -- cgit v1.2.3