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#define ENABLE_CURLX_PRINTF
2613498266Sopenharmony_ci/* use our own printf() functions */
2713498266Sopenharmony_ci#include "curlx.h"
2813498266Sopenharmony_ci#include "tool_cfgable.h"
2913498266Sopenharmony_ci#include "tool_writeout.h"
3013498266Sopenharmony_ci#include "tool_writeout_json.h"
3113498266Sopenharmony_ci#include "dynbuf.h"
3213498266Sopenharmony_ci
3313498266Sopenharmony_ci#include "memdebug.h" /* keep this as LAST include */
3413498266Sopenharmony_ci
3513498266Sopenharmony_cistatic int writeTime(FILE *stream, const struct writeoutvar *wovar,
3613498266Sopenharmony_ci                     struct per_transfer *per, CURLcode per_result,
3713498266Sopenharmony_ci                     bool use_json);
3813498266Sopenharmony_ci
3913498266Sopenharmony_cistatic int writeString(FILE *stream, const struct writeoutvar *wovar,
4013498266Sopenharmony_ci                       struct per_transfer *per, CURLcode per_result,
4113498266Sopenharmony_ci                       bool use_json);
4213498266Sopenharmony_ci
4313498266Sopenharmony_cistatic int writeLong(FILE *stream, const struct writeoutvar *wovar,
4413498266Sopenharmony_ci                     struct per_transfer *per, CURLcode per_result,
4513498266Sopenharmony_ci                     bool use_json);
4613498266Sopenharmony_ci
4713498266Sopenharmony_cistatic int writeOffset(FILE *stream, const struct writeoutvar *wovar,
4813498266Sopenharmony_ci                       struct per_transfer *per, CURLcode per_result,
4913498266Sopenharmony_ci                       bool use_json);
5013498266Sopenharmony_ci
5113498266Sopenharmony_cistruct httpmap {
5213498266Sopenharmony_ci  const char *str;
5313498266Sopenharmony_ci  int num;
5413498266Sopenharmony_ci};
5513498266Sopenharmony_ci
5613498266Sopenharmony_cistatic const struct httpmap http_version[] = {
5713498266Sopenharmony_ci  { "0",   CURL_HTTP_VERSION_NONE},
5813498266Sopenharmony_ci  { "1",   CURL_HTTP_VERSION_1_0},
5913498266Sopenharmony_ci  { "1.1", CURL_HTTP_VERSION_1_1},
6013498266Sopenharmony_ci  { "2",   CURL_HTTP_VERSION_2},
6113498266Sopenharmony_ci  { "3",   CURL_HTTP_VERSION_3},
6213498266Sopenharmony_ci  { NULL, 0} /* end of list */
6313498266Sopenharmony_ci};
6413498266Sopenharmony_ci
6513498266Sopenharmony_ci/* The designated write function should be the same as the CURLINFO return type
6613498266Sopenharmony_ci   with exceptions special cased in the respective function. For example,
6713498266Sopenharmony_ci   http_version uses CURLINFO_HTTP_VERSION which returns the version as a long,
6813498266Sopenharmony_ci   however it is output as a string and therefore is handled in writeString.
6913498266Sopenharmony_ci
7013498266Sopenharmony_ci   Yes: "http_version": "1.1"
7113498266Sopenharmony_ci   No:  "http_version": 1.1
7213498266Sopenharmony_ci
7313498266Sopenharmony_ci   Variable names should be in alphabetical order.
7413498266Sopenharmony_ci   */
7513498266Sopenharmony_cistatic const struct writeoutvar variables[] = {
7613498266Sopenharmony_ci  {"certs", VAR_CERT, CURLINFO_NONE, writeString},
7713498266Sopenharmony_ci  {"content_type", VAR_CONTENT_TYPE, CURLINFO_CONTENT_TYPE, writeString},
7813498266Sopenharmony_ci  {"conn_id", VAR_CONN_ID, CURLINFO_CONN_ID, writeOffset},
7913498266Sopenharmony_ci  {"errormsg", VAR_ERRORMSG, CURLINFO_NONE, writeString},
8013498266Sopenharmony_ci  {"exitcode", VAR_EXITCODE, CURLINFO_NONE, writeLong},
8113498266Sopenharmony_ci  {"filename_effective", VAR_EFFECTIVE_FILENAME, CURLINFO_NONE, writeString},
8213498266Sopenharmony_ci  {"ftp_entry_path", VAR_FTP_ENTRY_PATH, CURLINFO_FTP_ENTRY_PATH, writeString},
8313498266Sopenharmony_ci  {"header_json", VAR_HEADER_JSON, CURLINFO_NONE, NULL},
8413498266Sopenharmony_ci  {"http_code", VAR_HTTP_CODE, CURLINFO_RESPONSE_CODE, writeLong},
8513498266Sopenharmony_ci  {"http_connect", VAR_HTTP_CODE_PROXY, CURLINFO_HTTP_CONNECTCODE, writeLong},
8613498266Sopenharmony_ci  {"http_version", VAR_HTTP_VERSION, CURLINFO_HTTP_VERSION, writeString},
8713498266Sopenharmony_ci  {"json", VAR_JSON, CURLINFO_NONE, NULL},
8813498266Sopenharmony_ci  {"local_ip", VAR_LOCAL_IP, CURLINFO_LOCAL_IP, writeString},
8913498266Sopenharmony_ci  {"local_port", VAR_LOCAL_PORT, CURLINFO_LOCAL_PORT, writeLong},
9013498266Sopenharmony_ci  {"method", VAR_EFFECTIVE_METHOD, CURLINFO_EFFECTIVE_METHOD, writeString},
9113498266Sopenharmony_ci  {"num_certs", VAR_NUM_CERTS, CURLINFO_NONE, writeLong},
9213498266Sopenharmony_ci  {"num_connects", VAR_NUM_CONNECTS, CURLINFO_NUM_CONNECTS, writeLong},
9313498266Sopenharmony_ci  {"num_headers", VAR_NUM_HEADERS, CURLINFO_NONE, writeLong},
9413498266Sopenharmony_ci  {"num_redirects", VAR_REDIRECT_COUNT, CURLINFO_REDIRECT_COUNT, writeLong},
9513498266Sopenharmony_ci  {"onerror", VAR_ONERROR, CURLINFO_NONE, NULL},
9613498266Sopenharmony_ci  {"proxy_ssl_verify_result", VAR_PROXY_SSL_VERIFY_RESULT,
9713498266Sopenharmony_ci   CURLINFO_PROXY_SSL_VERIFYRESULT, writeLong},
9813498266Sopenharmony_ci  {"redirect_url", VAR_REDIRECT_URL, CURLINFO_REDIRECT_URL, writeString},
9913498266Sopenharmony_ci  {"referer", VAR_REFERER, CURLINFO_REFERER, writeString},
10013498266Sopenharmony_ci  {"remote_ip", VAR_PRIMARY_IP, CURLINFO_PRIMARY_IP, writeString},
10113498266Sopenharmony_ci  {"remote_port", VAR_PRIMARY_PORT, CURLINFO_PRIMARY_PORT, writeLong},
10213498266Sopenharmony_ci  {"response_code", VAR_HTTP_CODE, CURLINFO_RESPONSE_CODE, writeLong},
10313498266Sopenharmony_ci  {"scheme", VAR_SCHEME, CURLINFO_SCHEME, writeString},
10413498266Sopenharmony_ci  {"size_download", VAR_SIZE_DOWNLOAD, CURLINFO_SIZE_DOWNLOAD_T, writeOffset},
10513498266Sopenharmony_ci  {"size_header", VAR_HEADER_SIZE, CURLINFO_HEADER_SIZE, writeLong},
10613498266Sopenharmony_ci  {"size_request", VAR_REQUEST_SIZE, CURLINFO_REQUEST_SIZE, writeLong},
10713498266Sopenharmony_ci  {"size_upload", VAR_SIZE_UPLOAD, CURLINFO_SIZE_UPLOAD_T, writeOffset},
10813498266Sopenharmony_ci  {"speed_download", VAR_SPEED_DOWNLOAD, CURLINFO_SPEED_DOWNLOAD_T,
10913498266Sopenharmony_ci   writeOffset},
11013498266Sopenharmony_ci  {"speed_upload", VAR_SPEED_UPLOAD, CURLINFO_SPEED_UPLOAD_T, writeOffset},
11113498266Sopenharmony_ci  {"ssl_verify_result", VAR_SSL_VERIFY_RESULT, CURLINFO_SSL_VERIFYRESULT,
11213498266Sopenharmony_ci   writeLong},
11313498266Sopenharmony_ci  {"stderr", VAR_STDERR, CURLINFO_NONE, NULL},
11413498266Sopenharmony_ci  {"stdout", VAR_STDOUT, CURLINFO_NONE, NULL},
11513498266Sopenharmony_ci  {"time_appconnect", VAR_APPCONNECT_TIME, CURLINFO_APPCONNECT_TIME_T,
11613498266Sopenharmony_ci   writeTime},
11713498266Sopenharmony_ci  {"time_connect", VAR_CONNECT_TIME, CURLINFO_CONNECT_TIME_T, writeTime},
11813498266Sopenharmony_ci  {"time_namelookup", VAR_NAMELOOKUP_TIME, CURLINFO_NAMELOOKUP_TIME_T,
11913498266Sopenharmony_ci   writeTime},
12013498266Sopenharmony_ci  {"time_pretransfer", VAR_PRETRANSFER_TIME, CURLINFO_PRETRANSFER_TIME_T,
12113498266Sopenharmony_ci   writeTime},
12213498266Sopenharmony_ci  {"time_redirect", VAR_REDIRECT_TIME, CURLINFO_REDIRECT_TIME_T, writeTime},
12313498266Sopenharmony_ci  {"time_starttransfer", VAR_STARTTRANSFER_TIME, CURLINFO_STARTTRANSFER_TIME_T,
12413498266Sopenharmony_ci   writeTime},
12513498266Sopenharmony_ci  {"time_total", VAR_TOTAL_TIME, CURLINFO_TOTAL_TIME_T, writeTime},
12613498266Sopenharmony_ci  {"url", VAR_INPUT_URL, CURLINFO_NONE, writeString},
12713498266Sopenharmony_ci  {"url.scheme", VAR_INPUT_URLSCHEME, CURLINFO_NONE, writeString},
12813498266Sopenharmony_ci  {"url.user", VAR_INPUT_URLUSER, CURLINFO_NONE, writeString},
12913498266Sopenharmony_ci  {"url.password", VAR_INPUT_URLPASSWORD, CURLINFO_NONE, writeString},
13013498266Sopenharmony_ci  {"url.options", VAR_INPUT_URLOPTIONS, CURLINFO_NONE, writeString},
13113498266Sopenharmony_ci  {"url.host", VAR_INPUT_URLHOST, CURLINFO_NONE, writeString},
13213498266Sopenharmony_ci  {"url.port", VAR_INPUT_URLPORT, CURLINFO_NONE, writeString},
13313498266Sopenharmony_ci  {"url.path", VAR_INPUT_URLPATH, CURLINFO_NONE, writeString},
13413498266Sopenharmony_ci  {"url.query", VAR_INPUT_URLQUERY, CURLINFO_NONE, writeString},
13513498266Sopenharmony_ci  {"url.fragment", VAR_INPUT_URLFRAGMENT, CURLINFO_NONE, writeString},
13613498266Sopenharmony_ci  {"url.zoneid", VAR_INPUT_URLZONEID, CURLINFO_NONE, writeString},
13713498266Sopenharmony_ci  {"urle.scheme", VAR_INPUT_URLESCHEME, CURLINFO_NONE, writeString},
13813498266Sopenharmony_ci  {"urle.user", VAR_INPUT_URLEUSER, CURLINFO_NONE, writeString},
13913498266Sopenharmony_ci  {"urle.password", VAR_INPUT_URLEPASSWORD, CURLINFO_NONE, writeString},
14013498266Sopenharmony_ci  {"urle.options", VAR_INPUT_URLEOPTIONS, CURLINFO_NONE, writeString},
14113498266Sopenharmony_ci  {"urle.host", VAR_INPUT_URLEHOST, CURLINFO_NONE, writeString},
14213498266Sopenharmony_ci  {"urle.port", VAR_INPUT_URLEPORT, CURLINFO_NONE, writeString},
14313498266Sopenharmony_ci  {"urle.path", VAR_INPUT_URLEPATH, CURLINFO_NONE, writeString},
14413498266Sopenharmony_ci  {"urle.query", VAR_INPUT_URLEQUERY, CURLINFO_NONE, writeString},
14513498266Sopenharmony_ci  {"urle.fragment", VAR_INPUT_URLEFRAGMENT, CURLINFO_NONE, writeString},
14613498266Sopenharmony_ci  {"urle.zoneid", VAR_INPUT_URLEZONEID, CURLINFO_NONE, writeString},
14713498266Sopenharmony_ci  {"url_effective", VAR_EFFECTIVE_URL, CURLINFO_EFFECTIVE_URL, writeString},
14813498266Sopenharmony_ci  {"urlnum", VAR_URLNUM, CURLINFO_NONE, writeLong},
14913498266Sopenharmony_ci  {"xfer_id", VAR_EASY_ID, CURLINFO_XFER_ID, writeOffset},
15013498266Sopenharmony_ci  {NULL, VAR_NONE, CURLINFO_NONE, NULL}
15113498266Sopenharmony_ci};
15213498266Sopenharmony_ci
15313498266Sopenharmony_cistatic int writeTime(FILE *stream, const struct writeoutvar *wovar,
15413498266Sopenharmony_ci                     struct per_transfer *per, CURLcode per_result,
15513498266Sopenharmony_ci                     bool use_json)
15613498266Sopenharmony_ci{
15713498266Sopenharmony_ci  bool valid = false;
15813498266Sopenharmony_ci  curl_off_t us = 0;
15913498266Sopenharmony_ci
16013498266Sopenharmony_ci  (void)per;
16113498266Sopenharmony_ci  (void)per_result;
16213498266Sopenharmony_ci  DEBUGASSERT(wovar->writefunc == writeTime);
16313498266Sopenharmony_ci
16413498266Sopenharmony_ci  if(wovar->ci) {
16513498266Sopenharmony_ci    if(!curl_easy_getinfo(per->curl, wovar->ci, &us))
16613498266Sopenharmony_ci      valid = true;
16713498266Sopenharmony_ci  }
16813498266Sopenharmony_ci  else {
16913498266Sopenharmony_ci    DEBUGASSERT(0);
17013498266Sopenharmony_ci  }
17113498266Sopenharmony_ci
17213498266Sopenharmony_ci  if(valid) {
17313498266Sopenharmony_ci    curl_off_t secs = us / 1000000;
17413498266Sopenharmony_ci    us %= 1000000;
17513498266Sopenharmony_ci
17613498266Sopenharmony_ci    if(use_json)
17713498266Sopenharmony_ci      fprintf(stream, "\"%s\":", wovar->name);
17813498266Sopenharmony_ci
17913498266Sopenharmony_ci    fprintf(stream, "%" CURL_FORMAT_CURL_OFF_TU
18013498266Sopenharmony_ci            ".%06" CURL_FORMAT_CURL_OFF_TU, secs, us);
18113498266Sopenharmony_ci  }
18213498266Sopenharmony_ci  else {
18313498266Sopenharmony_ci    if(use_json)
18413498266Sopenharmony_ci      fprintf(stream, "\"%s\":null", wovar->name);
18513498266Sopenharmony_ci  }
18613498266Sopenharmony_ci
18713498266Sopenharmony_ci  return 1; /* return 1 if anything was written */
18813498266Sopenharmony_ci}
18913498266Sopenharmony_ci
19013498266Sopenharmony_cistatic int urlpart(struct per_transfer *per, writeoutid vid,
19113498266Sopenharmony_ci                   const char **contentp)
19213498266Sopenharmony_ci{
19313498266Sopenharmony_ci  CURLU *uh = curl_url();
19413498266Sopenharmony_ci  int rc = 0;
19513498266Sopenharmony_ci  if(uh) {
19613498266Sopenharmony_ci    CURLUPart cpart = CURLUPART_HOST;
19713498266Sopenharmony_ci    char *part = NULL;
19813498266Sopenharmony_ci    const char *url = NULL;
19913498266Sopenharmony_ci
20013498266Sopenharmony_ci    if(vid >= VAR_INPUT_URLEHOST) {
20113498266Sopenharmony_ci      if(curl_easy_getinfo(per->curl, CURLINFO_EFFECTIVE_URL, &url))
20213498266Sopenharmony_ci        rc = 5;
20313498266Sopenharmony_ci    }
20413498266Sopenharmony_ci    else
20513498266Sopenharmony_ci      url = per->this_url;
20613498266Sopenharmony_ci
20713498266Sopenharmony_ci    if(!rc) {
20813498266Sopenharmony_ci      switch(vid) {
20913498266Sopenharmony_ci      case VAR_INPUT_URLSCHEME:
21013498266Sopenharmony_ci      case VAR_INPUT_URLESCHEME:
21113498266Sopenharmony_ci        cpart = CURLUPART_SCHEME;
21213498266Sopenharmony_ci        break;
21313498266Sopenharmony_ci      case VAR_INPUT_URLUSER:
21413498266Sopenharmony_ci      case VAR_INPUT_URLEUSER:
21513498266Sopenharmony_ci        cpart = CURLUPART_USER;
21613498266Sopenharmony_ci        break;
21713498266Sopenharmony_ci      case VAR_INPUT_URLPASSWORD:
21813498266Sopenharmony_ci      case VAR_INPUT_URLEPASSWORD:
21913498266Sopenharmony_ci        cpart = CURLUPART_PASSWORD;
22013498266Sopenharmony_ci        break;
22113498266Sopenharmony_ci      case VAR_INPUT_URLOPTIONS:
22213498266Sopenharmony_ci      case VAR_INPUT_URLEOPTIONS:
22313498266Sopenharmony_ci        cpart = CURLUPART_OPTIONS;
22413498266Sopenharmony_ci        break;
22513498266Sopenharmony_ci      case VAR_INPUT_URLHOST:
22613498266Sopenharmony_ci      case VAR_INPUT_URLEHOST:
22713498266Sopenharmony_ci        cpart = CURLUPART_HOST;
22813498266Sopenharmony_ci        break;
22913498266Sopenharmony_ci      case VAR_INPUT_URLPORT:
23013498266Sopenharmony_ci      case VAR_INPUT_URLEPORT:
23113498266Sopenharmony_ci        cpart = CURLUPART_PORT;
23213498266Sopenharmony_ci        break;
23313498266Sopenharmony_ci      case VAR_INPUT_URLPATH:
23413498266Sopenharmony_ci      case VAR_INPUT_URLEPATH:
23513498266Sopenharmony_ci        cpart = CURLUPART_PATH;
23613498266Sopenharmony_ci        break;
23713498266Sopenharmony_ci      case VAR_INPUT_URLQUERY:
23813498266Sopenharmony_ci      case VAR_INPUT_URLEQUERY:
23913498266Sopenharmony_ci        cpart = CURLUPART_QUERY;
24013498266Sopenharmony_ci        break;
24113498266Sopenharmony_ci      case VAR_INPUT_URLFRAGMENT:
24213498266Sopenharmony_ci      case VAR_INPUT_URLEFRAGMENT:
24313498266Sopenharmony_ci        cpart = CURLUPART_FRAGMENT;
24413498266Sopenharmony_ci        break;
24513498266Sopenharmony_ci      case VAR_INPUT_URLZONEID:
24613498266Sopenharmony_ci      case VAR_INPUT_URLEZONEID:
24713498266Sopenharmony_ci        cpart = CURLUPART_ZONEID;
24813498266Sopenharmony_ci        break;
24913498266Sopenharmony_ci      default:
25013498266Sopenharmony_ci        /* not implemented */
25113498266Sopenharmony_ci        rc = 4;
25213498266Sopenharmony_ci        break;
25313498266Sopenharmony_ci      }
25413498266Sopenharmony_ci    }
25513498266Sopenharmony_ci    if(!rc && curl_url_set(uh, CURLUPART_URL, url,
25613498266Sopenharmony_ci                           CURLU_GUESS_SCHEME|CURLU_NON_SUPPORT_SCHEME))
25713498266Sopenharmony_ci      rc = 2;
25813498266Sopenharmony_ci
25913498266Sopenharmony_ci    if(!rc && curl_url_get(uh, cpart, &part, CURLU_DEFAULT_PORT))
26013498266Sopenharmony_ci      rc = 3;
26113498266Sopenharmony_ci
26213498266Sopenharmony_ci    if(!rc && part)
26313498266Sopenharmony_ci      *contentp = part;
26413498266Sopenharmony_ci    curl_url_cleanup(uh);
26513498266Sopenharmony_ci  }
26613498266Sopenharmony_ci  else
26713498266Sopenharmony_ci    return 1;
26813498266Sopenharmony_ci  return rc;
26913498266Sopenharmony_ci}
27013498266Sopenharmony_ci
27113498266Sopenharmony_cistatic int writeString(FILE *stream, const struct writeoutvar *wovar,
27213498266Sopenharmony_ci                       struct per_transfer *per, CURLcode per_result,
27313498266Sopenharmony_ci                       bool use_json)
27413498266Sopenharmony_ci{
27513498266Sopenharmony_ci  bool valid = false;
27613498266Sopenharmony_ci  const char *strinfo = NULL;
27713498266Sopenharmony_ci  const char *freestr = NULL;
27813498266Sopenharmony_ci  struct dynbuf buf;
27913498266Sopenharmony_ci  curlx_dyn_init(&buf, 256*1024);
28013498266Sopenharmony_ci
28113498266Sopenharmony_ci  DEBUGASSERT(wovar->writefunc == writeString);
28213498266Sopenharmony_ci
28313498266Sopenharmony_ci  if(wovar->ci) {
28413498266Sopenharmony_ci    if(wovar->ci == CURLINFO_HTTP_VERSION) {
28513498266Sopenharmony_ci      long version = 0;
28613498266Sopenharmony_ci      if(!curl_easy_getinfo(per->curl, CURLINFO_HTTP_VERSION, &version)) {
28713498266Sopenharmony_ci        const struct httpmap *m = &http_version[0];
28813498266Sopenharmony_ci        while(m->str) {
28913498266Sopenharmony_ci          if(m->num == version) {
29013498266Sopenharmony_ci            strinfo = m->str;
29113498266Sopenharmony_ci            valid = true;
29213498266Sopenharmony_ci            break;
29313498266Sopenharmony_ci          }
29413498266Sopenharmony_ci          m++;
29513498266Sopenharmony_ci        }
29613498266Sopenharmony_ci      }
29713498266Sopenharmony_ci    }
29813498266Sopenharmony_ci    else {
29913498266Sopenharmony_ci      if(!curl_easy_getinfo(per->curl, wovar->ci, &strinfo) && strinfo)
30013498266Sopenharmony_ci        valid = true;
30113498266Sopenharmony_ci    }
30213498266Sopenharmony_ci  }
30313498266Sopenharmony_ci  else {
30413498266Sopenharmony_ci    switch(wovar->id) {
30513498266Sopenharmony_ci    case VAR_CERT:
30613498266Sopenharmony_ci      if(per->certinfo) {
30713498266Sopenharmony_ci        int i;
30813498266Sopenharmony_ci        bool error = FALSE;
30913498266Sopenharmony_ci        for(i = 0; (i < per->certinfo->num_of_certs) && !error; i++) {
31013498266Sopenharmony_ci          struct curl_slist *slist;
31113498266Sopenharmony_ci
31213498266Sopenharmony_ci          for(slist = per->certinfo->certinfo[i]; slist; slist = slist->next) {
31313498266Sopenharmony_ci            size_t len;
31413498266Sopenharmony_ci            if(curl_strnequal(slist->data, "cert:", 5)) {
31513498266Sopenharmony_ci              if(curlx_dyn_add(&buf, &slist->data[5])) {
31613498266Sopenharmony_ci                error = TRUE;
31713498266Sopenharmony_ci                break;
31813498266Sopenharmony_ci              }
31913498266Sopenharmony_ci            }
32013498266Sopenharmony_ci            else {
32113498266Sopenharmony_ci              if(curlx_dyn_add(&buf, slist->data)) {
32213498266Sopenharmony_ci                error = TRUE;
32313498266Sopenharmony_ci                break;
32413498266Sopenharmony_ci              }
32513498266Sopenharmony_ci            }
32613498266Sopenharmony_ci            len = curlx_dyn_len(&buf);
32713498266Sopenharmony_ci            if(len) {
32813498266Sopenharmony_ci              char *ptr = curlx_dyn_ptr(&buf);
32913498266Sopenharmony_ci              if(ptr[len -1] != '\n') {
33013498266Sopenharmony_ci                /* add a newline to make things look better */
33113498266Sopenharmony_ci                if(curlx_dyn_addn(&buf, "\n", 1)) {
33213498266Sopenharmony_ci                  error = TRUE;
33313498266Sopenharmony_ci                  break;
33413498266Sopenharmony_ci                }
33513498266Sopenharmony_ci              }
33613498266Sopenharmony_ci            }
33713498266Sopenharmony_ci          }
33813498266Sopenharmony_ci        }
33913498266Sopenharmony_ci        if(!error) {
34013498266Sopenharmony_ci          strinfo = curlx_dyn_ptr(&buf);
34113498266Sopenharmony_ci          if(!strinfo)
34213498266Sopenharmony_ci            /* maybe not a TLS protocol */
34313498266Sopenharmony_ci            strinfo = "";
34413498266Sopenharmony_ci          valid = true;
34513498266Sopenharmony_ci        }
34613498266Sopenharmony_ci      }
34713498266Sopenharmony_ci      else
34813498266Sopenharmony_ci        strinfo = ""; /* no cert info */
34913498266Sopenharmony_ci      break;
35013498266Sopenharmony_ci    case VAR_ERRORMSG:
35113498266Sopenharmony_ci      if(per_result) {
35213498266Sopenharmony_ci        strinfo = (per->errorbuffer && per->errorbuffer[0]) ?
35313498266Sopenharmony_ci          per->errorbuffer : curl_easy_strerror(per_result);
35413498266Sopenharmony_ci        valid = true;
35513498266Sopenharmony_ci      }
35613498266Sopenharmony_ci      break;
35713498266Sopenharmony_ci    case VAR_EFFECTIVE_FILENAME:
35813498266Sopenharmony_ci      if(per->outs.filename) {
35913498266Sopenharmony_ci        strinfo = per->outs.filename;
36013498266Sopenharmony_ci        valid = true;
36113498266Sopenharmony_ci      }
36213498266Sopenharmony_ci      break;
36313498266Sopenharmony_ci    case VAR_INPUT_URL:
36413498266Sopenharmony_ci      if(per->this_url) {
36513498266Sopenharmony_ci        strinfo = per->this_url;
36613498266Sopenharmony_ci        valid = true;
36713498266Sopenharmony_ci      }
36813498266Sopenharmony_ci      break;
36913498266Sopenharmony_ci    case VAR_INPUT_URLSCHEME:
37013498266Sopenharmony_ci    case VAR_INPUT_URLUSER:
37113498266Sopenharmony_ci    case VAR_INPUT_URLPASSWORD:
37213498266Sopenharmony_ci    case VAR_INPUT_URLOPTIONS:
37313498266Sopenharmony_ci    case VAR_INPUT_URLHOST:
37413498266Sopenharmony_ci    case VAR_INPUT_URLPORT:
37513498266Sopenharmony_ci    case VAR_INPUT_URLPATH:
37613498266Sopenharmony_ci    case VAR_INPUT_URLQUERY:
37713498266Sopenharmony_ci    case VAR_INPUT_URLFRAGMENT:
37813498266Sopenharmony_ci    case VAR_INPUT_URLZONEID:
37913498266Sopenharmony_ci    case VAR_INPUT_URLESCHEME:
38013498266Sopenharmony_ci    case VAR_INPUT_URLEUSER:
38113498266Sopenharmony_ci    case VAR_INPUT_URLEPASSWORD:
38213498266Sopenharmony_ci    case VAR_INPUT_URLEOPTIONS:
38313498266Sopenharmony_ci    case VAR_INPUT_URLEHOST:
38413498266Sopenharmony_ci    case VAR_INPUT_URLEPORT:
38513498266Sopenharmony_ci    case VAR_INPUT_URLEPATH:
38613498266Sopenharmony_ci    case VAR_INPUT_URLEQUERY:
38713498266Sopenharmony_ci    case VAR_INPUT_URLEFRAGMENT:
38813498266Sopenharmony_ci    case VAR_INPUT_URLEZONEID:
38913498266Sopenharmony_ci      if(per->this_url) {
39013498266Sopenharmony_ci        if(!urlpart(per, wovar->id, &strinfo)) {
39113498266Sopenharmony_ci          freestr = strinfo;
39213498266Sopenharmony_ci          valid = true;
39313498266Sopenharmony_ci        }
39413498266Sopenharmony_ci      }
39513498266Sopenharmony_ci      break;
39613498266Sopenharmony_ci    default:
39713498266Sopenharmony_ci      DEBUGASSERT(0);
39813498266Sopenharmony_ci      break;
39913498266Sopenharmony_ci    }
40013498266Sopenharmony_ci  }
40113498266Sopenharmony_ci
40213498266Sopenharmony_ci  if(valid) {
40313498266Sopenharmony_ci    DEBUGASSERT(strinfo);
40413498266Sopenharmony_ci    if(use_json) {
40513498266Sopenharmony_ci      fprintf(stream, "\"%s\":", wovar->name);
40613498266Sopenharmony_ci      jsonWriteString(stream, strinfo, FALSE);
40713498266Sopenharmony_ci    }
40813498266Sopenharmony_ci    else
40913498266Sopenharmony_ci      fputs(strinfo, stream);
41013498266Sopenharmony_ci  }
41113498266Sopenharmony_ci  else {
41213498266Sopenharmony_ci    if(use_json)
41313498266Sopenharmony_ci      fprintf(stream, "\"%s\":null", wovar->name);
41413498266Sopenharmony_ci  }
41513498266Sopenharmony_ci  curl_free((char *)freestr);
41613498266Sopenharmony_ci
41713498266Sopenharmony_ci  curlx_dyn_free(&buf);
41813498266Sopenharmony_ci  return 1; /* return 1 if anything was written */
41913498266Sopenharmony_ci}
42013498266Sopenharmony_ci
42113498266Sopenharmony_cistatic int writeLong(FILE *stream, const struct writeoutvar *wovar,
42213498266Sopenharmony_ci                     struct per_transfer *per, CURLcode per_result,
42313498266Sopenharmony_ci                     bool use_json)
42413498266Sopenharmony_ci{
42513498266Sopenharmony_ci  bool valid = false;
42613498266Sopenharmony_ci  long longinfo = 0;
42713498266Sopenharmony_ci
42813498266Sopenharmony_ci  DEBUGASSERT(wovar->writefunc == writeLong);
42913498266Sopenharmony_ci
43013498266Sopenharmony_ci  if(wovar->ci) {
43113498266Sopenharmony_ci    if(!curl_easy_getinfo(per->curl, wovar->ci, &longinfo))
43213498266Sopenharmony_ci      valid = true;
43313498266Sopenharmony_ci  }
43413498266Sopenharmony_ci  else {
43513498266Sopenharmony_ci    switch(wovar->id) {
43613498266Sopenharmony_ci    case VAR_NUM_CERTS:
43713498266Sopenharmony_ci      longinfo = per->certinfo ? per->certinfo->num_of_certs : 0;
43813498266Sopenharmony_ci      valid = true;
43913498266Sopenharmony_ci      break;
44013498266Sopenharmony_ci    case VAR_NUM_HEADERS:
44113498266Sopenharmony_ci      longinfo = per->num_headers;
44213498266Sopenharmony_ci      valid = true;
44313498266Sopenharmony_ci      break;
44413498266Sopenharmony_ci    case VAR_EXITCODE:
44513498266Sopenharmony_ci      longinfo = per_result;
44613498266Sopenharmony_ci      valid = true;
44713498266Sopenharmony_ci      break;
44813498266Sopenharmony_ci    case VAR_URLNUM:
44913498266Sopenharmony_ci      if(per->urlnum <= INT_MAX) {
45013498266Sopenharmony_ci        longinfo = (long)per->urlnum;
45113498266Sopenharmony_ci        valid = true;
45213498266Sopenharmony_ci      }
45313498266Sopenharmony_ci      break;
45413498266Sopenharmony_ci    default:
45513498266Sopenharmony_ci      DEBUGASSERT(0);
45613498266Sopenharmony_ci      break;
45713498266Sopenharmony_ci    }
45813498266Sopenharmony_ci  }
45913498266Sopenharmony_ci
46013498266Sopenharmony_ci  if(valid) {
46113498266Sopenharmony_ci    if(use_json)
46213498266Sopenharmony_ci      fprintf(stream, "\"%s\":%ld", wovar->name, longinfo);
46313498266Sopenharmony_ci    else {
46413498266Sopenharmony_ci      if(wovar->id == VAR_HTTP_CODE || wovar->id == VAR_HTTP_CODE_PROXY)
46513498266Sopenharmony_ci        fprintf(stream, "%03ld", longinfo);
46613498266Sopenharmony_ci      else
46713498266Sopenharmony_ci        fprintf(stream, "%ld", longinfo);
46813498266Sopenharmony_ci    }
46913498266Sopenharmony_ci  }
47013498266Sopenharmony_ci  else {
47113498266Sopenharmony_ci    if(use_json)
47213498266Sopenharmony_ci      fprintf(stream, "\"%s\":null", wovar->name);
47313498266Sopenharmony_ci  }
47413498266Sopenharmony_ci
47513498266Sopenharmony_ci  return 1; /* return 1 if anything was written */
47613498266Sopenharmony_ci}
47713498266Sopenharmony_ci
47813498266Sopenharmony_cistatic int writeOffset(FILE *stream, const struct writeoutvar *wovar,
47913498266Sopenharmony_ci                       struct per_transfer *per, CURLcode per_result,
48013498266Sopenharmony_ci                       bool use_json)
48113498266Sopenharmony_ci{
48213498266Sopenharmony_ci  bool valid = false;
48313498266Sopenharmony_ci  curl_off_t offinfo = 0;
48413498266Sopenharmony_ci
48513498266Sopenharmony_ci  (void)per;
48613498266Sopenharmony_ci  (void)per_result;
48713498266Sopenharmony_ci  DEBUGASSERT(wovar->writefunc == writeOffset);
48813498266Sopenharmony_ci
48913498266Sopenharmony_ci  if(wovar->ci) {
49013498266Sopenharmony_ci    if(!curl_easy_getinfo(per->curl, wovar->ci, &offinfo))
49113498266Sopenharmony_ci      valid = true;
49213498266Sopenharmony_ci  }
49313498266Sopenharmony_ci  else {
49413498266Sopenharmony_ci    DEBUGASSERT(0);
49513498266Sopenharmony_ci  }
49613498266Sopenharmony_ci
49713498266Sopenharmony_ci  if(valid) {
49813498266Sopenharmony_ci    if(use_json)
49913498266Sopenharmony_ci      fprintf(stream, "\"%s\":", wovar->name);
50013498266Sopenharmony_ci
50113498266Sopenharmony_ci    fprintf(stream, "%" CURL_FORMAT_CURL_OFF_T, offinfo);
50213498266Sopenharmony_ci  }
50313498266Sopenharmony_ci  else {
50413498266Sopenharmony_ci    if(use_json)
50513498266Sopenharmony_ci      fprintf(stream, "\"%s\":null", wovar->name);
50613498266Sopenharmony_ci  }
50713498266Sopenharmony_ci
50813498266Sopenharmony_ci  return 1; /* return 1 if anything was written */
50913498266Sopenharmony_ci}
51013498266Sopenharmony_ci
51113498266Sopenharmony_civoid ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
51213498266Sopenharmony_ci                 CURLcode per_result)
51313498266Sopenharmony_ci{
51413498266Sopenharmony_ci  FILE *stream = stdout;
51513498266Sopenharmony_ci  const char *writeinfo = config->writeout;
51613498266Sopenharmony_ci  const char *ptr = writeinfo;
51713498266Sopenharmony_ci  bool done = FALSE;
51813498266Sopenharmony_ci  struct curl_certinfo *certinfo;
51913498266Sopenharmony_ci  CURLcode res = curl_easy_getinfo(per->curl, CURLINFO_CERTINFO, &certinfo);
52013498266Sopenharmony_ci  bool fclose_stream = FALSE;
52113498266Sopenharmony_ci
52213498266Sopenharmony_ci  if(!writeinfo)
52313498266Sopenharmony_ci    return;
52413498266Sopenharmony_ci
52513498266Sopenharmony_ci  if(!res && certinfo)
52613498266Sopenharmony_ci    per->certinfo = certinfo;
52713498266Sopenharmony_ci
52813498266Sopenharmony_ci  while(ptr && *ptr && !done) {
52913498266Sopenharmony_ci    if('%' == *ptr && ptr[1]) {
53013498266Sopenharmony_ci      if('%' == ptr[1]) {
53113498266Sopenharmony_ci        /* an escaped %-letter */
53213498266Sopenharmony_ci        fputc('%', stream);
53313498266Sopenharmony_ci        ptr += 2;
53413498266Sopenharmony_ci      }
53513498266Sopenharmony_ci      else {
53613498266Sopenharmony_ci        /* this is meant as a variable to output */
53713498266Sopenharmony_ci        char *end;
53813498266Sopenharmony_ci        size_t vlen;
53913498266Sopenharmony_ci        if('{' == ptr[1]) {
54013498266Sopenharmony_ci          int i;
54113498266Sopenharmony_ci          bool match = FALSE;
54213498266Sopenharmony_ci          end = strchr(ptr, '}');
54313498266Sopenharmony_ci          ptr += 2; /* pass the % and the { */
54413498266Sopenharmony_ci          if(!end) {
54513498266Sopenharmony_ci            fputs("%{", stream);
54613498266Sopenharmony_ci            continue;
54713498266Sopenharmony_ci          }
54813498266Sopenharmony_ci          vlen = end - ptr;
54913498266Sopenharmony_ci          for(i = 0; variables[i].name; i++) {
55013498266Sopenharmony_ci            if((strlen(variables[i].name) == vlen) &&
55113498266Sopenharmony_ci               curl_strnequal(ptr, variables[i].name, vlen)) {
55213498266Sopenharmony_ci              match = TRUE;
55313498266Sopenharmony_ci              switch(variables[i].id) {
55413498266Sopenharmony_ci              case VAR_ONERROR:
55513498266Sopenharmony_ci                if(per_result == CURLE_OK)
55613498266Sopenharmony_ci                  /* this isn't error so skip the rest */
55713498266Sopenharmony_ci                  done = TRUE;
55813498266Sopenharmony_ci                break;
55913498266Sopenharmony_ci              case VAR_STDOUT:
56013498266Sopenharmony_ci                if(fclose_stream)
56113498266Sopenharmony_ci                  fclose(stream);
56213498266Sopenharmony_ci                fclose_stream = FALSE;
56313498266Sopenharmony_ci                stream = stdout;
56413498266Sopenharmony_ci                break;
56513498266Sopenharmony_ci              case VAR_STDERR:
56613498266Sopenharmony_ci                if(fclose_stream)
56713498266Sopenharmony_ci                  fclose(stream);
56813498266Sopenharmony_ci                fclose_stream = FALSE;
56913498266Sopenharmony_ci                stream = tool_stderr;
57013498266Sopenharmony_ci                break;
57113498266Sopenharmony_ci              case VAR_JSON:
57213498266Sopenharmony_ci                ourWriteOutJSON(stream, variables, per, per_result);
57313498266Sopenharmony_ci                break;
57413498266Sopenharmony_ci              case VAR_HEADER_JSON:
57513498266Sopenharmony_ci                headerJSON(stream, per);
57613498266Sopenharmony_ci                break;
57713498266Sopenharmony_ci              default:
57813498266Sopenharmony_ci                (void)variables[i].writefunc(stream, &variables[i],
57913498266Sopenharmony_ci                                             per, per_result, false);
58013498266Sopenharmony_ci                break;
58113498266Sopenharmony_ci              }
58213498266Sopenharmony_ci              break;
58313498266Sopenharmony_ci            }
58413498266Sopenharmony_ci          }
58513498266Sopenharmony_ci          if(!match) {
58613498266Sopenharmony_ci            fprintf(tool_stderr,
58713498266Sopenharmony_ci                    "curl: unknown --write-out variable: '%.*s'\n",
58813498266Sopenharmony_ci                    (int)vlen, ptr);
58913498266Sopenharmony_ci          }
59013498266Sopenharmony_ci          ptr = end + 1; /* pass the end */
59113498266Sopenharmony_ci        }
59213498266Sopenharmony_ci        else if(!strncmp("header{", &ptr[1], 7)) {
59313498266Sopenharmony_ci          ptr += 8;
59413498266Sopenharmony_ci          end = strchr(ptr, '}');
59513498266Sopenharmony_ci          if(end) {
59613498266Sopenharmony_ci            char hname[256]; /* holds the longest header field name */
59713498266Sopenharmony_ci            struct curl_header *header;
59813498266Sopenharmony_ci            vlen = end - ptr;
59913498266Sopenharmony_ci            if(vlen < sizeof(hname)) {
60013498266Sopenharmony_ci              memcpy(hname, ptr, vlen);
60113498266Sopenharmony_ci              hname[vlen] = 0;
60213498266Sopenharmony_ci              if(CURLHE_OK == curl_easy_header(per->curl, hname, 0,
60313498266Sopenharmony_ci                                               CURLH_HEADER, -1, &header))
60413498266Sopenharmony_ci                fputs(header->value, stream);
60513498266Sopenharmony_ci            }
60613498266Sopenharmony_ci            ptr = end + 1;
60713498266Sopenharmony_ci          }
60813498266Sopenharmony_ci          else
60913498266Sopenharmony_ci            fputs("%header{", stream);
61013498266Sopenharmony_ci        }
61113498266Sopenharmony_ci        else if(!strncmp("output{", &ptr[1], 7)) {
61213498266Sopenharmony_ci          bool append = FALSE;
61313498266Sopenharmony_ci          ptr += 8;
61413498266Sopenharmony_ci          if((ptr[0] == '>') && (ptr[1] == '>')) {
61513498266Sopenharmony_ci            append = TRUE;
61613498266Sopenharmony_ci            ptr += 2;
61713498266Sopenharmony_ci          }
61813498266Sopenharmony_ci          end = strchr(ptr, '}');
61913498266Sopenharmony_ci          if(end) {
62013498266Sopenharmony_ci            char fname[512]; /* holds the longest file name */
62113498266Sopenharmony_ci            size_t flen = end - ptr;
62213498266Sopenharmony_ci            if(flen < sizeof(fname)) {
62313498266Sopenharmony_ci              FILE *stream2;
62413498266Sopenharmony_ci              memcpy(fname, ptr, flen);
62513498266Sopenharmony_ci              fname[flen] = 0;
62613498266Sopenharmony_ci              stream2 = fopen(fname, append? FOPEN_APPENDTEXT :
62713498266Sopenharmony_ci                              FOPEN_WRITETEXT);
62813498266Sopenharmony_ci              if(stream2) {
62913498266Sopenharmony_ci                /* only change if the open worked */
63013498266Sopenharmony_ci                if(fclose_stream)
63113498266Sopenharmony_ci                  fclose(stream);
63213498266Sopenharmony_ci                stream = stream2;
63313498266Sopenharmony_ci                fclose_stream = TRUE;
63413498266Sopenharmony_ci              }
63513498266Sopenharmony_ci            }
63613498266Sopenharmony_ci            ptr = end + 1;
63713498266Sopenharmony_ci          }
63813498266Sopenharmony_ci          else
63913498266Sopenharmony_ci            fputs("%output{", stream);
64013498266Sopenharmony_ci        }
64113498266Sopenharmony_ci        else {
64213498266Sopenharmony_ci          /* illegal syntax, then just output the characters that are used */
64313498266Sopenharmony_ci          fputc('%', stream);
64413498266Sopenharmony_ci          fputc(ptr[1], stream);
64513498266Sopenharmony_ci          ptr += 2;
64613498266Sopenharmony_ci        }
64713498266Sopenharmony_ci      }
64813498266Sopenharmony_ci    }
64913498266Sopenharmony_ci    else if('\\' == *ptr && ptr[1]) {
65013498266Sopenharmony_ci      switch(ptr[1]) {
65113498266Sopenharmony_ci      case 'r':
65213498266Sopenharmony_ci        fputc('\r', stream);
65313498266Sopenharmony_ci        break;
65413498266Sopenharmony_ci      case 'n':
65513498266Sopenharmony_ci        fputc('\n', stream);
65613498266Sopenharmony_ci        break;
65713498266Sopenharmony_ci      case 't':
65813498266Sopenharmony_ci        fputc('\t', stream);
65913498266Sopenharmony_ci        break;
66013498266Sopenharmony_ci      default:
66113498266Sopenharmony_ci        /* unknown, just output this */
66213498266Sopenharmony_ci        fputc(*ptr, stream);
66313498266Sopenharmony_ci        fputc(ptr[1], stream);
66413498266Sopenharmony_ci        break;
66513498266Sopenharmony_ci      }
66613498266Sopenharmony_ci      ptr += 2;
66713498266Sopenharmony_ci    }
66813498266Sopenharmony_ci    else {
66913498266Sopenharmony_ci      fputc(*ptr, stream);
67013498266Sopenharmony_ci      ptr++;
67113498266Sopenharmony_ci    }
67213498266Sopenharmony_ci  }
67313498266Sopenharmony_ci  if(fclose_stream)
67413498266Sopenharmony_ci    fclose(stream);
67513498266Sopenharmony_ci}
676