113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci#include "tool_setup.h" 2513498266Sopenharmony_ci 2613498266Sopenharmony_ci#define ENABLE_CURLX_PRINTF 2713498266Sopenharmony_ci 2813498266Sopenharmony_ci/* use our own printf() functions */ 2913498266Sopenharmony_ci#include "curlx.h" 3013498266Sopenharmony_ci#include "tool_cfgable.h" 3113498266Sopenharmony_ci#include "tool_writeout_json.h" 3213498266Sopenharmony_ci#include "tool_writeout.h" 3313498266Sopenharmony_ci 3413498266Sopenharmony_ci#define MAX_JSON_STRING 100000 3513498266Sopenharmony_ci 3613498266Sopenharmony_ci/* provide the given string in dynbuf as a quoted json string, but without the 3713498266Sopenharmony_ci outer quotes. The buffer is not inited by this function. 3813498266Sopenharmony_ci 3913498266Sopenharmony_ci Return 0 on success, non-zero on error. 4013498266Sopenharmony_ci*/ 4113498266Sopenharmony_ciint jsonquoted(const char *in, size_t len, 4213498266Sopenharmony_ci struct curlx_dynbuf *out, bool lowercase) 4313498266Sopenharmony_ci{ 4413498266Sopenharmony_ci const unsigned char *i = (unsigned char *)in; 4513498266Sopenharmony_ci const unsigned char *in_end = &i[len]; 4613498266Sopenharmony_ci CURLcode result = CURLE_OK; 4713498266Sopenharmony_ci 4813498266Sopenharmony_ci for(; (i < in_end) && !result; i++) { 4913498266Sopenharmony_ci switch(*i) { 5013498266Sopenharmony_ci case '\\': 5113498266Sopenharmony_ci result = curlx_dyn_addn(out, "\\\\", 2); 5213498266Sopenharmony_ci break; 5313498266Sopenharmony_ci case '\"': 5413498266Sopenharmony_ci result = curlx_dyn_addn(out, "\\\"", 2); 5513498266Sopenharmony_ci break; 5613498266Sopenharmony_ci case '\b': 5713498266Sopenharmony_ci result = curlx_dyn_addn(out, "\\b", 2); 5813498266Sopenharmony_ci break; 5913498266Sopenharmony_ci case '\f': 6013498266Sopenharmony_ci result = curlx_dyn_addn(out, "\\f", 2); 6113498266Sopenharmony_ci break; 6213498266Sopenharmony_ci case '\n': 6313498266Sopenharmony_ci result = curlx_dyn_addn(out, "\\n", 2); 6413498266Sopenharmony_ci break; 6513498266Sopenharmony_ci case '\r': 6613498266Sopenharmony_ci result = curlx_dyn_addn(out, "\\r", 2); 6713498266Sopenharmony_ci break; 6813498266Sopenharmony_ci case '\t': 6913498266Sopenharmony_ci result = curlx_dyn_addn(out, "\\t", 2); 7013498266Sopenharmony_ci break; 7113498266Sopenharmony_ci default: 7213498266Sopenharmony_ci if(*i < 32) 7313498266Sopenharmony_ci result = curlx_dyn_addf(out, "\\u%04x", *i); 7413498266Sopenharmony_ci else { 7513498266Sopenharmony_ci char o = *i; 7613498266Sopenharmony_ci if(lowercase && (o >= 'A' && o <= 'Z')) 7713498266Sopenharmony_ci /* do not use tolower() since that's locale specific */ 7813498266Sopenharmony_ci o |= ('a' - 'A'); 7913498266Sopenharmony_ci result = curlx_dyn_addn(out, &o, 1); 8013498266Sopenharmony_ci } 8113498266Sopenharmony_ci break; 8213498266Sopenharmony_ci } 8313498266Sopenharmony_ci } 8413498266Sopenharmony_ci if(result) 8513498266Sopenharmony_ci return (int)result; 8613498266Sopenharmony_ci return 0; 8713498266Sopenharmony_ci} 8813498266Sopenharmony_ci 8913498266Sopenharmony_civoid jsonWriteString(FILE *stream, const char *in, bool lowercase) 9013498266Sopenharmony_ci{ 9113498266Sopenharmony_ci struct curlx_dynbuf out; 9213498266Sopenharmony_ci curlx_dyn_init(&out, MAX_JSON_STRING); 9313498266Sopenharmony_ci 9413498266Sopenharmony_ci if(!jsonquoted(in, strlen(in), &out, lowercase)) { 9513498266Sopenharmony_ci fputc('\"', stream); 9613498266Sopenharmony_ci if(curlx_dyn_len(&out)) 9713498266Sopenharmony_ci fputs(curlx_dyn_ptr(&out), stream); 9813498266Sopenharmony_ci fputc('\"', stream); 9913498266Sopenharmony_ci } 10013498266Sopenharmony_ci curlx_dyn_free(&out); 10113498266Sopenharmony_ci} 10213498266Sopenharmony_ci 10313498266Sopenharmony_civoid ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[], 10413498266Sopenharmony_ci struct per_transfer *per, CURLcode per_result) 10513498266Sopenharmony_ci{ 10613498266Sopenharmony_ci int i; 10713498266Sopenharmony_ci 10813498266Sopenharmony_ci fputs("{", stream); 10913498266Sopenharmony_ci 11013498266Sopenharmony_ci for(i = 0; mappings[i].name != NULL; i++) { 11113498266Sopenharmony_ci if(mappings[i].writefunc && 11213498266Sopenharmony_ci mappings[i].writefunc(stream, &mappings[i], per, per_result, true)) 11313498266Sopenharmony_ci fputs(",", stream); 11413498266Sopenharmony_ci } 11513498266Sopenharmony_ci 11613498266Sopenharmony_ci /* The variables are sorted in alphabetical order but as a special case 11713498266Sopenharmony_ci curl_version (which is not actually a --write-out variable) is last. */ 11813498266Sopenharmony_ci fprintf(stream, "\"curl_version\":"); 11913498266Sopenharmony_ci jsonWriteString(stream, curl_version(), FALSE); 12013498266Sopenharmony_ci fprintf(stream, "}"); 12113498266Sopenharmony_ci} 12213498266Sopenharmony_ci 12313498266Sopenharmony_ci#ifdef _MSC_VER 12413498266Sopenharmony_ci/* warning C4706: assignment within conditional expression */ 12513498266Sopenharmony_ci#pragma warning(disable:4706) 12613498266Sopenharmony_ci#endif 12713498266Sopenharmony_ci 12813498266Sopenharmony_civoid headerJSON(FILE *stream, struct per_transfer *per) 12913498266Sopenharmony_ci{ 13013498266Sopenharmony_ci struct curl_header *header; 13113498266Sopenharmony_ci struct curl_header *prev = NULL; 13213498266Sopenharmony_ci 13313498266Sopenharmony_ci fputc('{', stream); 13413498266Sopenharmony_ci while((header = curl_easy_nextheader(per->curl, CURLH_HEADER, -1, 13513498266Sopenharmony_ci prev))) { 13613498266Sopenharmony_ci if(header->amount > 1) { 13713498266Sopenharmony_ci if(!header->index) { 13813498266Sopenharmony_ci /* act on the 0-index entry and pull the others in, then output in a 13913498266Sopenharmony_ci JSON list */ 14013498266Sopenharmony_ci size_t a = header->amount; 14113498266Sopenharmony_ci size_t i = 0; 14213498266Sopenharmony_ci char *name = header->name; 14313498266Sopenharmony_ci if(prev) 14413498266Sopenharmony_ci fputs(",\n", stream); 14513498266Sopenharmony_ci jsonWriteString(stream, header->name, TRUE); 14613498266Sopenharmony_ci fputc(':', stream); 14713498266Sopenharmony_ci prev = header; 14813498266Sopenharmony_ci fputc('[', stream); 14913498266Sopenharmony_ci do { 15013498266Sopenharmony_ci jsonWriteString(stream, header->value, FALSE); 15113498266Sopenharmony_ci if(++i >= a) 15213498266Sopenharmony_ci break; 15313498266Sopenharmony_ci fputc(',', stream); 15413498266Sopenharmony_ci if(curl_easy_header(per->curl, name, i, CURLH_HEADER, 15513498266Sopenharmony_ci -1, &header)) 15613498266Sopenharmony_ci break; 15713498266Sopenharmony_ci } while(1); 15813498266Sopenharmony_ci fputc(']', stream); 15913498266Sopenharmony_ci } 16013498266Sopenharmony_ci } 16113498266Sopenharmony_ci else { 16213498266Sopenharmony_ci if(prev) 16313498266Sopenharmony_ci fputs(",\n", stream); 16413498266Sopenharmony_ci jsonWriteString(stream, header->name, TRUE); 16513498266Sopenharmony_ci fputc(':', stream); 16613498266Sopenharmony_ci fputc('[', stream); 16713498266Sopenharmony_ci jsonWriteString(stream, header->value, FALSE); 16813498266Sopenharmony_ci fputc(']', stream); 16913498266Sopenharmony_ci prev = header; 17013498266Sopenharmony_ci } 17113498266Sopenharmony_ci } 17213498266Sopenharmony_ci fputs("\n}", stream); 17313498266Sopenharmony_ci} 174