From 781344e3f8f90faf5c04932407c64fed9274d1cf Mon Sep 17 00:00:00 2001 From: Mathias Gumz Date: Sat, 1 Feb 2020 18:55:24 +0100 Subject: [PATCH] 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. --- docs/cmdline-opts/write-out.d | 3 + packages/Symbian/group/curl.mmp | 1 + src/Makefile.inc | 2 + src/tool_writeout.c | 5 + src/tool_writeout_json.c | 223 ++++++++++++++++++++++++++++++++ src/tool_writeout_json.h | 28 ++++ 6 files changed, 262 insertions(+) create mode 100644 src/tool_writeout_json.c create mode 100644 src/tool_writeout_json.h diff --git a/docs/cmdline-opts/write-out.d b/docs/cmdline-opts/write-out.d index 2fc0ff21a5fdfe..9024d32e059969 100644 --- a/docs/cmdline-opts/write-out.d +++ b/docs/cmdline-opts/write-out.d @@ -50,6 +50,9 @@ curl CONNECT request. (Added in 7.12.4) .B http_version The http version that was effectively used. (Added in 7.50.0) .TP +.B json +A JSON object with all available keys. +.TP .B local_ip The IP address of the local end of the most recently done connection - can be either IPv4 or IPv6 (Added in 7.29.0) diff --git a/packages/Symbian/group/curl.mmp b/packages/Symbian/group/curl.mmp index 14ccf141968919..361e0a6201ba13 100644 --- a/packages/Symbian/group/curl.mmp +++ b/packages/Symbian/group/curl.mmp @@ -45,6 +45,7 @@ SOURCE \ tool_vms.c \ tool_writeenv.c \ tool_writeout.c \ + tool_writeout_json.c \ tool_xattr.c SOURCEPATH ../../../lib diff --git a/src/Makefile.inc b/src/Makefile.inc index dd6b9d336c1c53..ac96f6514665d9 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -62,6 +62,7 @@ CURL_CFILES = \ tool_util.c \ tool_vms.c \ tool_writeout.c \ + tool_writeout_json.c \ tool_xattr.c CURL_HFILES = \ @@ -107,6 +108,7 @@ CURL_HFILES = \ tool_version.h \ tool_vms.h \ tool_writeout.h \ + tool_writeout_json.h \ tool_xattr.h CURL_RCFILES = curl.rc diff --git a/src/tool_writeout.c b/src/tool_writeout.c index 27b2ac50df1e2b..82482a178f3c5a 100644 --- a/src/tool_writeout.c +++ b/src/tool_writeout.c @@ -25,6 +25,7 @@ #include "curlx.h" #include "tool_cfgable.h" #include "tool_writeout.h" +#include "tool_writeout_json.h" #include "memdebug.h" /* keep this as LAST include */ @@ -62,6 +63,7 @@ typedef enum { VAR_SCHEME, VAR_STDOUT, VAR_STDERR, + VAR_JSON, VAR_NUM_OF_VARS /* must be the last */ } replaceid; @@ -105,6 +107,7 @@ static const struct variable replacements[]={ {"scheme", VAR_SCHEME}, {"stdout", VAR_STDOUT}, {"stderr", VAR_STDERR}, + {"json", VAR_JSON}, {NULL, VAR_NONE} }; @@ -334,6 +337,8 @@ void ourWriteOut(CURL *curl, struct OutStruct *outs, const char *writeinfo) case VAR_STDERR: stream = stderr; break; + case VAR_JSON: + ourWriteOutJSON(curl, outs, stream); default: break; } diff --git a/src/tool_writeout_json.c b/src/tool_writeout_json.c new file mode 100644 index 00000000000000..fc8ebb766dc375 --- /dev/null +++ b/src/tool_writeout_json.c @@ -0,0 +1,223 @@ +/*************************************************************************** + * _ _ ____ _ + * 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" + + +typedef enum { + JSON_NONE, + JSON_STRING, + JSON_LONG, + JSON_TIME, + JSON_VERSION, + JSON_FILENAME +} jsontype; + +struct mapping { + const char *key; + jsontype type; + CURLINFO cinfo; +}; + +static const struct mapping mappings[]={ + {"url_effective", JSON_STRING, CURLINFO_EFFECTIVE_URL}, + {"http_code", JSON_LONG, CURLINFO_RESPONSE_CODE}, + {"response_code", JSON_LONG, CURLINFO_RESPONSE_CODE}, + {"http_connect", JSON_LONG, CURLINFO_HTTP_CONNECTCODE}, + {"time_total", JSON_TIME, CURLINFO_TOTAL_TIME_T}, + {"time_namelookup", JSON_TIME, CURLINFO_NAMELOOKUP_TIME_T}, + {"time_connect", JSON_TIME, CURLINFO_CONNECT_TIME_T}, + {"time_appconnect", JSON_TIME, CURLINFO_APPCONNECT_TIME_T}, + {"time_pretransfer", JSON_TIME, CURLINFO_PRETRANSFER_TIME_T}, + {"time_starttransfer", JSON_TIME, CURLINFO_STARTTRANSFER_TIME_T}, + {"size_header", JSON_LONG, CURLINFO_HEADER_SIZE}, + {"size_request", JSON_LONG, CURLINFO_REQUEST_SIZE}, + {"size_download", JSON_LONG, CURLINFO_SIZE_DOWNLOAD_T}, + {"size_upload", JSON_LONG, CURLINFO_SIZE_UPLOAD_T}, + {"speed_download", JSON_TIME, CURLINFO_SPEED_DOWNLOAD_T}, + {"speed_upload", JSON_TIME, CURLINFO_SPEED_UPLOAD_T}, + {"content_type", JSON_STRING, CURLINFO_CONTENT_TYPE}, + {"num_connects", JSON_LONG, CURLINFO_NUM_CONNECTS}, + {"time_redirect", JSON_TIME, CURLINFO_REDIRECT_TIME_T}, + {"num_redirects", JSON_LONG, CURLINFO_REDIRECT_COUNT}, + {"ftp_entry_path", JSON_STRING, CURLINFO_FTP_ENTRY_PATH}, + {"redirect_url", JSON_STRING, CURLINFO_REDIRECT_URL}, + {"ssl_verify_result", JSON_LONG, CURLINFO_SSL_VERIFYRESULT}, + {"proxy_ssl_verify_result", JSON_LONG, CURLINFO_PROXY_SSL_VERIFYRESULT}, + {"filename_effective", JSON_FILENAME, CURLINFO_NONE}, + {"remote_ip", JSON_STRING, CURLINFO_PRIMARY_IP}, + {"remote_port", JSON_LONG, CURLINFO_PRIMARY_PORT}, + {"local_ip", JSON_STRING, CURLINFO_LOCAL_IP}, + {"local_port", JSON_LONG, CURLINFO_LOCAL_PORT}, + {"http_version", JSON_VERSION, CURLINFO_HTTP_VERSION}, + {"scheme", JSON_STRING, CURLINFO_SCHEME}, + {NULL, JSON_NONE, CURLINFO_NONE} +}; + +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 json_escape(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 write_time(FILE *stream, CURL *curl, const char *key, CURLINFO cinfo) +{ + long val = 0; + if(CURLE_OK == curl_easy_getinfo(curl, cinfo, &val)) { + long s = val / 1000000l; + long ms = val % 1000000l; + fprintf(stream, "\"%s\":%ld.%06ld", key, s, ms); + return 1; + } + return 0; +} + +static int write_string(FILE *stream, CURL *curl, const char *key, CURLINFO cinfo) +{ + char *valp = NULL; + if((CURLE_OK == curl_easy_getinfo(curl, cinfo, &valp)) && valp) { + fprintf(stream, "\"%s\":\"", key); + json_escape(stream, valp); + fprintf(stream, "\""); + return 1; + } + return 0; +} + +static int write_long(FILE *stream, CURL *curl, const char *key, CURLINFO cinfo) +{ + long val = 0; + if(CURLE_OK == curl_easy_getinfo(curl, cinfo, &val)) { + fprintf(stream, "\"%s\":%ld", key, val); + return 1; + } + return 0; +} + +static int write_filename(FILE *stream, const char* key, const char *filename) +{ + if(filename) { + fprintf(stream, "\"%s\":\"", key); + json_escape(stream, filename); + fprintf(stream, "\""); + } + else { + fprintf(stream, "\"%s\":null", key); + } + return 1; +} + +static int write_version(FILE *stream, CURL *curl, const char *key, CURLINFO cinfo) +{ + long version = 0; + if(CURLE_OK == curl_easy_getinfo(curl, cinfo, &version) && + (version >= 0) && + (version < (long)(sizeof(http_version)/sizeof(char *)))) { + fprintf(stream, "\"%s\":\"%s\"", key, http_version[version]); + return 1; + } + return 0; +} + +void ourWriteOutJSON(CURL *curl, struct OutStruct *outs, FILE *stream) +{ + int i; + + fputs("{", stream); + for(i = 0; mappings[i].key != NULL; i++) { + const char *key = mappings[i].key; + CURLINFO cinfo = mappings[i].cinfo; + int ok = 0; + switch(mappings[i].type) { + case JSON_STRING: + ok = write_string(stream, curl, key, cinfo); + break; + case JSON_LONG: + ok = write_long(stream, curl, key, cinfo); + break; + case JSON_TIME: + ok = write_time(stream, curl, key, cinfo); + break; + case JSON_FILENAME: + ok = write_filename(stream, outs->filename, key); + break; + case JSON_VERSION: + ok = write_version(stream, curl, key, cinfo); + break; + default: + break; + } + + if(ok) { + fputs(",", stream); + } + } + fprintf(stream, "\"curl_version\":\"%s\"}", curl_version()); +} diff --git a/src/tool_writeout_json.h b/src/tool_writeout_json.h new file mode 100644 index 00000000000000..c9cb47fb603fcb --- /dev/null +++ b/src/tool_writeout_json.h @@ -0,0 +1,28 @@ +#ifndef HEADER_CURL_TOOL_WRITEOUT_JSON_H +#define HEADER_CURL_TOOL_WRITEOUT_JSON_H +/*************************************************************************** + * _ _ ____ _ + * 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" + +void ourWriteOutJSON(CURL *curl, struct OutStruct *outs, FILE *stream); + +#endif /* HEADER_CURL_TOOL_WRITEOUT_H */