1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2020, 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.haxx.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 ***************************************************************************/
22 #include "tool_setup.h"
23
24 #define ENABLE_CURLX_PRINTF
25
26 /* use our own printf() functions */
27 #include "curlx.h"
28 #include "tool_cfgable.h"
29 #include "tool_writeout_json.h"
30 #include "tool_writeout.h"
31
32
33 static const char *http_version[] = {
34 "0", /* CURL_HTTP_VERSION_NONE */
35 "1", /* CURL_HTTP_VERSION_1_0 */
36 "1.1", /* CURL_HTTP_VERSION_1_1 */
37 "2", /* CURL_HTTP_VERSION_2 */
38 "3" /* CURL_HTTP_VERSION_3 */
39 };
40
jsonEscape(FILE * stream,const char * in)41 static void jsonEscape(FILE *stream, const char *in)
42 {
43 const char *i = in;
44 const char *in_end = in + strlen(in);
45
46 for(; i < in_end; i++) {
47 switch(*i) {
48 case '\\':
49 fputs("\\\\", stream);
50 break;
51 case '\"':
52 fputs("\\\"", stream);
53 break;
54 case '\b':
55 fputs("\\b", stream);
56 break;
57 case '\f':
58 fputs("\\f", stream);
59 break;
60 case '\n':
61 fputs("\\n", stream);
62 break;
63 case '\r':
64 fputs("\\r", stream);
65 break;
66 case '\t':
67 fputs("\\t", stream);
68 break;
69 default:
70 if (*i < 32) {
71 fprintf(stream, "u%04x", *i);
72 }
73 else {
74 fputc(*i, stream);
75 }
76 break;
77 };
78 }
79 }
80
writeTime(FILE * str,CURL * curl,const char * key,CURLINFO ci)81 static int writeTime(FILE *str, CURL *curl, const char *key, CURLINFO ci)
82 {
83 curl_off_t val = 0;
84 if(CURLE_OK == curl_easy_getinfo(curl, ci, &val)) {
85 curl_off_t s = val / 1000000l;
86 curl_off_t ms = val % 1000000l;
87 fprintf(str, "\"%s\":%" CURL_FORMAT_CURL_OFF_T
88 ".%06" CURL_FORMAT_CURL_OFF_T, key, s, ms);
89 return 1;
90 }
91 return 0;
92 }
93
writeString(FILE * str,CURL * curl,const char * key,CURLINFO ci)94 static int writeString(FILE *str, CURL *curl, const char *key, CURLINFO ci)
95 {
96 char *valp = NULL;
97 if((CURLE_OK == curl_easy_getinfo(curl, ci, &valp)) && valp) {
98 fprintf(str, "\"%s\":\"", key);
99 jsonEscape(str, valp);
100 fprintf(str, "\"");
101 return 1;
102 }
103 return 0;
104 }
105
writeLong(FILE * str,CURL * curl,const char * key,CURLINFO ci,struct per_transfer * per,const struct writeoutvar * wovar)106 static int writeLong(FILE *str, CURL *curl, const char *key, CURLINFO ci,
107 struct per_transfer *per, const struct writeoutvar *wovar)
108 {
109 if(wovar->id == VAR_NUM_HEADERS) {
110 fprintf(str, "\"%s\":%ld", key, per->num_headers);
111 return 1;
112 }
113 else {
114 long val = 0;
115 if(CURLE_OK == curl_easy_getinfo(curl, ci, &val)) {
116 fprintf(str, "\"%s\":%ld", key, val);
117 return 1;
118 }
119 }
120 return 0;
121 }
122
writeOffset(FILE * str,CURL * curl,const char * key,CURLINFO ci)123 static int writeOffset(FILE *str, CURL *curl, const char *key, CURLINFO ci)
124 {
125 curl_off_t val = 0;
126 if(CURLE_OK == curl_easy_getinfo(curl, ci, &val)) {
127 fprintf(str, "\"%s\":%" CURL_FORMAT_CURL_OFF_T, key, val);
128 return 1;
129 }
130 return 0;
131 }
132
writeFilename(FILE * str,const char * key,const char * filename)133 static int writeFilename(FILE *str, const char *key, const char *filename)
134 {
135 if(filename) {
136 fprintf(str, "\"%s\":\"", key);
137 jsonEscape(str, filename);
138 fprintf(str, "\"");
139 }
140 else {
141 fprintf(str, "\"%s\":null", key);
142 }
143 return 1;
144 }
145
writeVersion(FILE * str,CURL * curl,const char * key,CURLINFO ci)146 static int writeVersion(FILE *str, CURL *curl, const char *key, CURLINFO ci)
147 {
148 long version = 0;
149 if(CURLE_OK == curl_easy_getinfo(curl, ci, &version) &&
150 (version >= 0) &&
151 (version < (long)(sizeof(http_version)/sizeof(char *)))) {
152 fprintf(str, "\"%s\":\"%s\"", key, http_version[version]);
153 return 1;
154 }
155 return 0;
156 }
157
ourWriteOutJSON(const struct writeoutvar mappings[],CURL * curl,struct per_transfer * per,FILE * stream)158 void ourWriteOutJSON(const struct writeoutvar mappings[], CURL *curl,
159 struct per_transfer *per, FILE *stream)
160 {
161 int i;
162
163 fputs("{", stream);
164 for(i = 0; mappings[i].name != NULL; i++) {
165 const struct writeoutvar *wovar = &mappings[i];
166 const char *name = mappings[i].name;
167 CURLINFO cinfo = mappings[i].cinfo;
168 int ok = 0;
169
170 if(mappings[i].is_ctrl == 1) {
171 continue;
172 }
173
174 switch(mappings[i].jsontype) {
175 case JSON_STRING:
176 ok = writeString(stream, curl, name, cinfo);
177 break;
178 case JSON_LONG:
179 ok = writeLong(stream, curl, name, cinfo, per, wovar);
180 break;
181 case JSON_OFFSET:
182 ok = writeOffset(stream, curl, name, cinfo);
183 break;
184 case JSON_TIME:
185 ok = writeTime(stream, curl, name, cinfo);
186 break;
187 case JSON_FILENAME:
188 ok = writeFilename(stream, name, per->outs.filename);
189 break;
190 case JSON_VERSION:
191 ok = writeVersion(stream, curl, name, cinfo);
192 break;
193 default:
194 break;
195 }
196
197 if(ok) {
198 fputs(",", stream);
199 }
200 }
201
202 fprintf(stream, "\"curl_version\":\"%s\"}", curl_version());
203 }
204