1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2012, 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 http://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 _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
25#include <curl/mprintf.h>
26
27#include "tool_cfgable.h"
28#include "tool_writeout.h"
29
30#include "memdebug.h" /* keep this as LAST include */
31
32typedef enum {
33  VAR_NONE,       /* must be the first */
34  VAR_TOTAL_TIME,
35  VAR_NAMELOOKUP_TIME,
36  VAR_CONNECT_TIME,
37  VAR_APPCONNECT_TIME,
38  VAR_PRETRANSFER_TIME,
39  VAR_STARTTRANSFER_TIME,
40  VAR_SIZE_DOWNLOAD,
41  VAR_SIZE_UPLOAD,
42  VAR_SPEED_DOWNLOAD,
43  VAR_SPEED_UPLOAD,
44  VAR_HTTP_CODE,
45  VAR_HTTP_CODE_PROXY,
46  VAR_HEADER_SIZE,
47  VAR_REQUEST_SIZE,
48  VAR_EFFECTIVE_URL,
49  VAR_CONTENT_TYPE,
50  VAR_NUM_CONNECTS,
51  VAR_REDIRECT_TIME,
52  VAR_REDIRECT_COUNT,
53  VAR_FTP_ENTRY_PATH,
54  VAR_REDIRECT_URL,
55  VAR_SSL_VERIFY_RESULT,
56  VAR_EFFECTIVE_FILENAME,
57  VAR_PRIMARY_IP,
58  VAR_PRIMARY_PORT,
59  VAR_LOCAL_IP,
60  VAR_LOCAL_PORT,
61  VAR_NUM_OF_VARS /* must be the last */
62} replaceid;
63
64struct variable {
65  const char *name;
66  replaceid id;
67};
68
69
70static const struct variable replacements[]={
71  {"url_effective", VAR_EFFECTIVE_URL},
72  {"http_code", VAR_HTTP_CODE},
73  {"response_code", VAR_HTTP_CODE},
74  {"http_connect", VAR_HTTP_CODE_PROXY},
75  {"time_total", VAR_TOTAL_TIME},
76  {"time_namelookup", VAR_NAMELOOKUP_TIME},
77  {"time_connect", VAR_CONNECT_TIME},
78  {"time_appconnect", VAR_APPCONNECT_TIME},
79  {"time_pretransfer", VAR_PRETRANSFER_TIME},
80  {"time_starttransfer", VAR_STARTTRANSFER_TIME},
81  {"size_header", VAR_HEADER_SIZE},
82  {"size_request", VAR_REQUEST_SIZE},
83  {"size_download", VAR_SIZE_DOWNLOAD},
84  {"size_upload", VAR_SIZE_UPLOAD},
85  {"speed_download", VAR_SPEED_DOWNLOAD},
86  {"speed_upload", VAR_SPEED_UPLOAD},
87  {"content_type", VAR_CONTENT_TYPE},
88  {"num_connects", VAR_NUM_CONNECTS},
89  {"time_redirect", VAR_REDIRECT_TIME},
90  {"num_redirects", VAR_REDIRECT_COUNT},
91  {"ftp_entry_path", VAR_FTP_ENTRY_PATH},
92  {"redirect_url", VAR_REDIRECT_URL},
93  {"ssl_verify_result", VAR_SSL_VERIFY_RESULT},
94  {"filename_effective", VAR_EFFECTIVE_FILENAME},
95  {"remote_ip", VAR_PRIMARY_IP},
96  {"remote_port", VAR_PRIMARY_PORT},
97  {"local_ip", VAR_LOCAL_IP},
98  {"local_port", VAR_LOCAL_PORT},
99  {NULL, VAR_NONE}
100};
101
102void ourWriteOut(CURL *curl, struct OutStruct *outs, const char *writeinfo)
103{
104  FILE *stream = stdout;
105  const char *ptr = writeinfo;
106  char *stringp;
107  long longinfo;
108  double doubleinfo;
109
110  while(ptr && *ptr) {
111    if('%' == *ptr) {
112      if('%' == ptr[1]) {
113        /* an escaped %-letter */
114        fputc('%', stream);
115        ptr += 2;
116      }
117      else {
118        /* this is meant as a variable to output */
119        char *end;
120        char keepit;
121        int i;
122        if(('{' == ptr[1]) && ((end = strchr(ptr, '}')) != NULL)) {
123          bool match = FALSE;
124          ptr += 2; /* pass the % and the { */
125          keepit = *end;
126          *end = 0; /* zero terminate */
127          for(i = 0; replacements[i].name; i++) {
128            if(curl_strequal(ptr, replacements[i].name)) {
129              match = TRUE;
130              switch(replacements[i].id) {
131              case VAR_EFFECTIVE_URL:
132                if((CURLE_OK ==
133                    curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &stringp))
134                   && stringp)
135                  fputs(stringp, stream);
136                break;
137              case VAR_HTTP_CODE:
138                if(CURLE_OK ==
139                   curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &longinfo))
140                  fprintf(stream, "%03ld", longinfo);
141                break;
142              case VAR_HTTP_CODE_PROXY:
143                if(CURLE_OK ==
144                   curl_easy_getinfo(curl, CURLINFO_HTTP_CONNECTCODE,
145                                     &longinfo))
146                  fprintf(stream, "%03ld", longinfo);
147                break;
148              case VAR_HEADER_SIZE:
149                if(CURLE_OK ==
150                   curl_easy_getinfo(curl, CURLINFO_HEADER_SIZE, &longinfo))
151                  fprintf(stream, "%ld", longinfo);
152                break;
153              case VAR_REQUEST_SIZE:
154                if(CURLE_OK ==
155                   curl_easy_getinfo(curl, CURLINFO_REQUEST_SIZE, &longinfo))
156                  fprintf(stream, "%ld", longinfo);
157                break;
158              case VAR_NUM_CONNECTS:
159                if(CURLE_OK ==
160                   curl_easy_getinfo(curl, CURLINFO_NUM_CONNECTS, &longinfo))
161                  fprintf(stream, "%ld", longinfo);
162                break;
163              case VAR_REDIRECT_COUNT:
164                if(CURLE_OK ==
165                   curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &longinfo))
166                  fprintf(stream, "%ld", longinfo);
167                break;
168              case VAR_REDIRECT_TIME:
169                if(CURLE_OK ==
170                   curl_easy_getinfo(curl, CURLINFO_REDIRECT_TIME,
171                                     &doubleinfo))
172                  fprintf(stream, "%.3f", doubleinfo);
173                break;
174              case VAR_TOTAL_TIME:
175                if(CURLE_OK ==
176                   curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &doubleinfo))
177                  fprintf(stream, "%.3f", doubleinfo);
178                break;
179              case VAR_NAMELOOKUP_TIME:
180                if(CURLE_OK ==
181                   curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME,
182                                     &doubleinfo))
183                  fprintf(stream, "%.3f", doubleinfo);
184                break;
185              case VAR_CONNECT_TIME:
186                if(CURLE_OK ==
187                   curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &doubleinfo))
188                  fprintf(stream, "%.3f", doubleinfo);
189                break;
190              case VAR_APPCONNECT_TIME:
191                if(CURLE_OK ==
192                   curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME,
193                                     &doubleinfo))
194                  fprintf(stream, "%.3f", doubleinfo);
195                break;
196              case VAR_PRETRANSFER_TIME:
197                if(CURLE_OK ==
198                   curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME,
199                                     &doubleinfo))
200                  fprintf(stream, "%.3f", doubleinfo);
201                break;
202              case VAR_STARTTRANSFER_TIME:
203                if(CURLE_OK ==
204                   curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME,
205                                     &doubleinfo))
206                  fprintf(stream, "%.3f", doubleinfo);
207                break;
208              case VAR_SIZE_UPLOAD:
209                if(CURLE_OK ==
210                   curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD, &doubleinfo))
211                  fprintf(stream, "%.0f", doubleinfo);
212                break;
213              case VAR_SIZE_DOWNLOAD:
214                if(CURLE_OK ==
215                   curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD,
216                                     &doubleinfo))
217                  fprintf(stream, "%.0f", doubleinfo);
218                break;
219              case VAR_SPEED_DOWNLOAD:
220                if(CURLE_OK ==
221                   curl_easy_getinfo(curl, CURLINFO_SPEED_DOWNLOAD,
222                                     &doubleinfo))
223                  fprintf(stream, "%.3f", doubleinfo);
224                break;
225              case VAR_SPEED_UPLOAD:
226                if(CURLE_OK ==
227                   curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &doubleinfo))
228                  fprintf(stream, "%.3f", doubleinfo);
229                break;
230              case VAR_CONTENT_TYPE:
231                if((CURLE_OK ==
232                    curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &stringp))
233                   && stringp)
234                  fputs(stringp, stream);
235                break;
236              case VAR_FTP_ENTRY_PATH:
237                if((CURLE_OK ==
238                    curl_easy_getinfo(curl, CURLINFO_FTP_ENTRY_PATH, &stringp))
239                   && stringp)
240                  fputs(stringp, stream);
241                break;
242              case VAR_REDIRECT_URL:
243                if((CURLE_OK ==
244                    curl_easy_getinfo(curl, CURLINFO_REDIRECT_URL, &stringp))
245                   && stringp)
246                  fputs(stringp, stream);
247                break;
248              case VAR_SSL_VERIFY_RESULT:
249                if(CURLE_OK ==
250                   curl_easy_getinfo(curl, CURLINFO_SSL_VERIFYRESULT,
251                                     &longinfo))
252                  fprintf(stream, "%ld", longinfo);
253                break;
254              case VAR_EFFECTIVE_FILENAME:
255                if(outs->filename)
256                  fprintf(stream, "%s", outs->filename);
257                break;
258              case VAR_PRIMARY_IP:
259                if(CURLE_OK ==
260                   curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP,
261                                     &stringp))
262                  fprintf(stream, "%s", stringp);
263                break;
264              case VAR_PRIMARY_PORT:
265                if(CURLE_OK ==
266                   curl_easy_getinfo(curl, CURLINFO_PRIMARY_PORT,
267                                     &longinfo))
268                  fprintf(stream, "%ld", longinfo);
269                break;
270              case VAR_LOCAL_IP:
271                if(CURLE_OK ==
272                   curl_easy_getinfo(curl, CURLINFO_LOCAL_IP,
273                                     &stringp))
274                  fprintf(stream, "%s", stringp);
275                break;
276              case VAR_LOCAL_PORT:
277                if(CURLE_OK ==
278                   curl_easy_getinfo(curl, CURLINFO_LOCAL_PORT,
279                                     &longinfo))
280                  fprintf(stream, "%ld", longinfo);
281                break;
282              default:
283                break;
284              }
285              break;
286            }
287          }
288          if(!match) {
289            fprintf(stderr, "curl: unknown --write-out variable: '%s'\n", ptr);
290          }
291          ptr = end + 1; /* pass the end */
292          *end = keepit;
293        }
294        else {
295          /* illegal syntax, then just output the characters that are used */
296          fputc('%', stream);
297          fputc(ptr[1], stream);
298          ptr += 2;
299        }
300      }
301    }
302    else if('\\' == *ptr) {
303      switch(ptr[1]) {
304      case 'r':
305        fputc('\r', stream);
306        break;
307      case 'n':
308        fputc('\n', stream);
309        break;
310      case 't':
311        fputc('\t', stream);
312        break;
313      default:
314        /* unknown, just output this */
315        fputc(*ptr, stream);
316        fputc(ptr[1], stream);
317        break;
318      }
319      ptr += 2;
320    }
321    else {
322      fputc(*ptr, stream);
323      ptr++;
324    }
325  }
326
327}
328