tool_writeout_json.c (4886B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@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.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 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 #include "tool_setup.h" 25 26 #include "tool_cfgable.h" 27 #include "tool_writeout_json.h" 28 #include "tool_writeout.h" 29 30 #define MAX_JSON_STRING 100000 31 32 /* provide the given string in dynbuf as a quoted json string, but without the 33 outer quotes. The buffer is not inited by this function. 34 35 Return 0 on success, non-zero on error. 36 */ 37 int jsonquoted(const char *in, size_t len, 38 struct dynbuf *out, bool lowercase) 39 { 40 const unsigned char *i = (const unsigned char *)in; 41 const unsigned char *in_end = &i[len]; 42 CURLcode result = CURLE_OK; 43 44 for(; (i < in_end) && !result; i++) { 45 switch(*i) { 46 case '\\': 47 result = curlx_dyn_addn(out, "\\\\", 2); 48 break; 49 case '\"': 50 result = curlx_dyn_addn(out, "\\\"", 2); 51 break; 52 case '\b': 53 result = curlx_dyn_addn(out, "\\b", 2); 54 break; 55 case '\f': 56 result = curlx_dyn_addn(out, "\\f", 2); 57 break; 58 case '\n': 59 result = curlx_dyn_addn(out, "\\n", 2); 60 break; 61 case '\r': 62 result = curlx_dyn_addn(out, "\\r", 2); 63 break; 64 case '\t': 65 result = curlx_dyn_addn(out, "\\t", 2); 66 break; 67 default: 68 if(*i < 32) 69 result = curlx_dyn_addf(out, "\\u%04x", *i); 70 else { 71 char o = (char)*i; 72 if(lowercase && (o >= 'A' && o <= 'Z')) 73 /* do not use tolower() since that is locale specific */ 74 o |= ('a' - 'A'); 75 result = curlx_dyn_addn(out, &o, 1); 76 } 77 break; 78 } 79 } 80 if(result) 81 return (int)result; 82 return 0; 83 } 84 85 void jsonWriteString(FILE *stream, const char *in, bool lowercase) 86 { 87 struct dynbuf out; 88 curlx_dyn_init(&out, MAX_JSON_STRING); 89 90 if(!jsonquoted(in, strlen(in), &out, lowercase)) { 91 fputc('\"', stream); 92 if(curlx_dyn_len(&out)) 93 fputs(curlx_dyn_ptr(&out), stream); 94 fputc('\"', stream); 95 } 96 curlx_dyn_free(&out); 97 } 98 99 void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[], 100 size_t nentries, 101 struct per_transfer *per, CURLcode per_result) 102 { 103 size_t i; 104 105 fputs("{", stream); 106 107 for(i = 0; i < nentries; i++) { 108 if(mappings[i].writefunc && 109 mappings[i].writefunc(stream, &mappings[i], per, per_result, true)) 110 fputs(",", stream); 111 } 112 113 /* The variables are sorted in alphabetical order but as a special case 114 curl_version (which is not actually a --write-out variable) is last. */ 115 fprintf(stream, "\"curl_version\":"); 116 jsonWriteString(stream, curl_version(), FALSE); 117 fprintf(stream, "}"); 118 } 119 120 void headerJSON(FILE *stream, struct per_transfer *per) 121 { 122 struct curl_header *header; 123 struct curl_header *prev = NULL; 124 125 fputc('{', stream); 126 while((header = curl_easy_nextheader(per->curl, CURLH_HEADER, -1, 127 prev)) != NULL) { 128 if(header->amount > 1) { 129 if(!header->index) { 130 /* act on the 0-index entry and pull the others in, then output in a 131 JSON list */ 132 size_t a = header->amount; 133 size_t i = 0; 134 char *name = header->name; 135 if(prev) 136 fputs(",\n", stream); 137 jsonWriteString(stream, header->name, TRUE); 138 fputc(':', stream); 139 prev = header; 140 fputc('[', stream); 141 do { 142 jsonWriteString(stream, header->value, FALSE); 143 if(++i >= a) 144 break; 145 fputc(',', stream); 146 if(curl_easy_header(per->curl, name, i, CURLH_HEADER, 147 -1, &header)) 148 break; 149 } while(1); 150 fputc(']', stream); 151 } 152 } 153 else { 154 if(prev) 155 fputs(",\n", stream); 156 jsonWriteString(stream, header->name, TRUE); 157 fputc(':', stream); 158 fputc('[', stream); 159 jsonWriteString(stream, header->value, FALSE); 160 fputc(']', stream); 161 prev = header; 162 } 163 } 164 fputs("\n}", stream); 165 }