]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
build: drop more forward function declarations
authorViktor Szakats <commit@vsz.me>
Wed, 14 Jan 2026 16:11:55 +0000 (17:11 +0100)
committerViktor Szakats <commit@vsz.me>
Wed, 14 Jan 2026 22:34:05 +0000 (23:34 +0100)
Most by moving functions around. Also delete unused ones.
Reducing their number from 83 to 33.

Remaining ones due to:
- circular dependencies.
- H3 code, that I did not attempt to update and likely the above applies.
- static declarations with attributes (`CURL_PRINTF`, `WARN_UNUSED_RESULT`).
- OS400 code.

Closes #20321

15 files changed:
lib/cf-h2-proxy.c
lib/cfilters.c
lib/conncache.c
lib/cw-out.c
lib/cw-pause.c
lib/http2.c
lib/mime.c
lib/rtsp.c
lib/sendf.c
lib/urlapi.c
lib/vtls/schannel.c
lib/vtls/vtls_scache.c
lib/vtls/wolfssl.c
src/tool_cb_dbg.c
src/tool_writeout.c

index 96fc7cd8f851cc19ee764dc8a3e79c01f1af8deb..f46a074afa765d2c7d0af68e46bb23d6d0b63550 100644 (file)
@@ -259,113 +259,6 @@ static int proxy_h2_client_new(struct Curl_cfilter *cf,
   return rc;
 }
 
-static ssize_t on_session_send(nghttp2_session *h2,
-                               const uint8_t *buf, size_t blen,
-                               int flags, void *userp);
-static int proxy_h2_on_frame_recv(nghttp2_session *session,
-                                  const nghttp2_frame *frame,
-                                  void *userp);
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-static int proxy_h2_on_frame_send(nghttp2_session *session,
-                                  const nghttp2_frame *frame,
-                                  void *userp);
-#endif
-static int proxy_h2_on_stream_close(nghttp2_session *session,
-                                    int32_t stream_id,
-                                    uint32_t error_code, void *userp);
-static int proxy_h2_on_header(nghttp2_session *session,
-                              const nghttp2_frame *frame,
-                              const uint8_t *name, size_t namelen,
-                              const uint8_t *value, size_t valuelen,
-                              uint8_t flags,
-                              void *userp);
-static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
-                                int32_t stream_id,
-                                const uint8_t *mem, size_t len, void *userp);
-
-/*
- * Initialize the cfilter context
- */
-static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
-                                     struct Curl_easy *data)
-{
-  struct cf_h2_proxy_ctx *ctx = cf->ctx;
-  CURLcode result = CURLE_OUT_OF_MEMORY;
-  nghttp2_session_callbacks *cbs = NULL;
-  int rc;
-
-  DEBUGASSERT(!ctx->h2);
-  memset(&ctx->tunnel, 0, sizeof(ctx->tunnel));
-
-  Curl_bufq_init(&ctx->inbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_RECV_CHUNKS);
-  Curl_bufq_init(&ctx->outbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_SEND_CHUNKS);
-
-  if(tunnel_stream_init(cf, &ctx->tunnel))
-    goto out;
-
-  rc = nghttp2_session_callbacks_new(&cbs);
-  if(rc) {
-    failf(data, "Could not initialize nghttp2 callbacks");
-    goto out;
-  }
-
-  nghttp2_session_callbacks_set_send_callback(cbs, on_session_send);
-  nghttp2_session_callbacks_set_on_frame_recv_callback(
-    cbs, proxy_h2_on_frame_recv);
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-  nghttp2_session_callbacks_set_on_frame_send_callback(cbs,
-                                                       proxy_h2_on_frame_send);
-#endif
-  nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
-    cbs, tunnel_recv_callback);
-  nghttp2_session_callbacks_set_on_stream_close_callback(
-    cbs, proxy_h2_on_stream_close);
-  nghttp2_session_callbacks_set_on_header_callback(cbs, proxy_h2_on_header);
-
-  /* The nghttp2 session is not yet setup, do it */
-  rc = proxy_h2_client_new(cf, cbs);
-  if(rc) {
-    failf(data, "Could not initialize nghttp2");
-    goto out;
-  }
-
-  {
-    nghttp2_settings_entry iv[3];
-
-    iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
-    iv[0].value = Curl_multi_max_concurrent_streams(data->multi);
-    iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
-    iv[1].value = H2_TUNNEL_WINDOW_SIZE;
-    iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
-    iv[2].value = 0;
-    rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE, iv, 3);
-    if(rc) {
-      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
-            nghttp2_strerror(rc), rc);
-      result = CURLE_HTTP2;
-      goto out;
-    }
-  }
-
-  rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0,
-                                             PROXY_HTTP2_HUGE_WINDOW_SIZE);
-  if(rc) {
-    failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
-          nghttp2_strerror(rc), rc);
-    result = CURLE_HTTP2;
-    goto out;
-  }
-
-  /* all set, traffic will be send on connect */
-  result = CURLE_OK;
-
-out:
-  if(cbs)
-    nghttp2_session_callbacks_del(cbs);
-  CURL_TRC_CF(data, cf, "[0] init proxy ctx -> %d", result);
-  return result;
-}
-
 static int proxy_h2_should_close_session(struct cf_h2_proxy_ctx *ctx)
 {
   return !nghttp2_session_want_read(ctx->h2) &&
@@ -1051,6 +944,89 @@ out:
   return result;
 }
 
+/*
+ * Initialize the cfilter context
+ */
+static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  nghttp2_session_callbacks *cbs = NULL;
+  int rc;
+
+  DEBUGASSERT(!ctx->h2);
+  memset(&ctx->tunnel, 0, sizeof(ctx->tunnel));
+
+  Curl_bufq_init(&ctx->inbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_RECV_CHUNKS);
+  Curl_bufq_init(&ctx->outbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_SEND_CHUNKS);
+
+  if(tunnel_stream_init(cf, &ctx->tunnel))
+    goto out;
+
+  rc = nghttp2_session_callbacks_new(&cbs);
+  if(rc) {
+    failf(data, "Could not initialize nghttp2 callbacks");
+    goto out;
+  }
+
+  nghttp2_session_callbacks_set_send_callback(cbs, on_session_send);
+  nghttp2_session_callbacks_set_on_frame_recv_callback(
+    cbs, proxy_h2_on_frame_recv);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  nghttp2_session_callbacks_set_on_frame_send_callback(cbs,
+                                                       proxy_h2_on_frame_send);
+#endif
+  nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
+    cbs, tunnel_recv_callback);
+  nghttp2_session_callbacks_set_on_stream_close_callback(
+    cbs, proxy_h2_on_stream_close);
+  nghttp2_session_callbacks_set_on_header_callback(cbs, proxy_h2_on_header);
+
+  /* The nghttp2 session is not yet setup, do it */
+  rc = proxy_h2_client_new(cf, cbs);
+  if(rc) {
+    failf(data, "Could not initialize nghttp2");
+    goto out;
+  }
+
+  {
+    nghttp2_settings_entry iv[3];
+
+    iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
+    iv[0].value = Curl_multi_max_concurrent_streams(data->multi);
+    iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
+    iv[1].value = H2_TUNNEL_WINDOW_SIZE;
+    iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
+    iv[2].value = 0;
+    rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE, iv, 3);
+    if(rc) {
+      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
+            nghttp2_strerror(rc), rc);
+      result = CURLE_HTTP2;
+      goto out;
+    }
+  }
+
+  rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0,
+                                             PROXY_HTTP2_HUGE_WINDOW_SIZE);
+  if(rc) {
+    failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
+          nghttp2_strerror(rc), rc);
+    result = CURLE_HTTP2;
+    goto out;
+  }
+
+  /* all set, traffic will be send on connect */
+  result = CURLE_OK;
+
+out:
+  if(cbs)
+    nghttp2_session_callbacks_del(cbs);
+  CURL_TRC_CF(data, cf, "[0] init proxy ctx -> %d", result);
+  return result;
+}
+
 static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf,
                                     struct Curl_easy *data,
                                     bool *done)
index 8a6a163067fe9837aed614de0a501276aec4b588..76c24e7a68bafaff89c12a73377187d58e06ec49 100644 (file)
@@ -33,9 +33,6 @@
 #include "select.h"
 #include "curlx/strparse.h"
 
-static void cf_cntrl_update_info(struct Curl_easy *data,
-                                 struct connectdata *conn);
-
 #ifdef UNITTESTS
 /* used by unit2600.c */
 void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -55,9 +52,6 @@ CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
   return CURLE_OK;
 }
 
-static void conn_report_connect_stats(struct Curl_cfilter *cf,
-                                      struct Curl_easy *data);
-
 CURLcode Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
                                     struct Curl_easy *data,
                                     struct easy_pollset *ps)
@@ -451,6 +445,51 @@ static CURLcode cf_verboseconnect(struct Curl_easy *data,
 }
 #endif
 
+static CURLcode cf_cntrl_all(struct connectdata *conn,
+                             struct Curl_easy *data,
+                             bool ignore_result,
+                             int event, int arg1, void *arg2)
+{
+  CURLcode result = CURLE_OK;
+  size_t i;
+
+  for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) {
+    result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
+                                event, arg1, arg2);
+    if(!ignore_result && result)
+      break;
+  }
+  return result;
+}
+
+static void cf_cntrl_update_info(struct Curl_easy *data,
+                                 struct connectdata *conn)
+{
+  cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
+}
+
+/**
+ * Update connection statistics
+ */
+static void conn_report_connect_stats(struct Curl_cfilter *cf,
+                                      struct Curl_easy *data)
+{
+  if(cf) {
+    struct curltime connected;
+    struct curltime appconnected;
+
+    memset(&connected, 0, sizeof(connected));
+    cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
+    if(connected.tv_sec || connected.tv_usec)
+      Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
+
+    memset(&appconnected, 0, sizeof(appconnected));
+    cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
+    if(appconnected.tv_sec || appconnected.tv_usec)
+      Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
+  }
+}
+
 CURLcode Curl_conn_connect(struct Curl_easy *data,
                            int sockindex,
                            bool blocking,
@@ -922,23 +961,6 @@ Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex)
   return cf ? cf_get_remote_addr(cf, data) : NULL;
 }
 
-static CURLcode cf_cntrl_all(struct connectdata *conn,
-                             struct Curl_easy *data,
-                             bool ignore_result,
-                             int event, int arg1, void *arg2)
-{
-  CURLcode result = CURLE_OK;
-  size_t i;
-
-  for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) {
-    result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
-                                event, arg1, arg2);
-    if(!ignore_result && result)
-      break;
-  }
-  return result;
-}
-
 CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
 {
   return cf_cntrl_all(data->conn, data, FALSE, CF_CTRL_DATA_SETUP, 0, NULL);
@@ -976,34 +998,6 @@ CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause)
                       CF_CTRL_DATA_PAUSE, do_pause, NULL);
 }
 
-static void cf_cntrl_update_info(struct Curl_easy *data,
-                                 struct connectdata *conn)
-{
-  cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
-}
-
-/**
- * Update connection statistics
- */
-static void conn_report_connect_stats(struct Curl_cfilter *cf,
-                                      struct Curl_easy *data)
-{
-  if(cf) {
-    struct curltime connected;
-    struct curltime appconnected;
-
-    memset(&connected, 0, sizeof(connected));
-    cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
-    if(connected.tv_sec || connected.tv_usec)
-      Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
-
-    memset(&appconnected, 0, sizeof(appconnected));
-    cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
-    if(appconnected.tv_sec || appconnected.tv_usec)
-      Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
-  }
-}
-
 bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
                         bool *input_pending)
 {
index f19d061ca3a39695f8a935cdc170f0f7865aa689..983224722a3be8e1913451ad04f21e493468b57f 100644 (file)
@@ -69,11 +69,6 @@ struct cpool_bundle {
   char dest[1]; /* destination of bundle, allocated to keep dest_len bytes */
 };
 
-static void cpool_discard_conn(struct cpool *cpool,
-                               struct Curl_easy *data,
-                               struct connectdata *conn,
-                               bool aborted);
-
 static struct cpool_bundle *cpool_bundle_create(const char *dest)
 {
   struct cpool_bundle *bundle;
@@ -189,6 +184,53 @@ static void cpool_remove_conn(struct cpool *cpool,
   }
 }
 
+static void cpool_discard_conn(struct cpool *cpool,
+                               struct Curl_easy *data,
+                               struct connectdata *conn,
+                               bool aborted)
+{
+  bool done = FALSE;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(!data->conn);
+  DEBUGASSERT(cpool);
+  DEBUGASSERT(!conn->bits.in_cpool);
+
+  /*
+   * If this connection is not marked to force-close, leave it open if there
+   * are other users of it
+   */
+  if(CONN_INUSE(conn) && !aborted) {
+    CURL_TRC_M(data, "[CPOOL] not discarding #%" FMT_OFF_T
+               " still in use by %u transfers", conn->connection_id,
+               conn->attached_xfers);
+    return;
+  }
+
+  /* treat the connection as aborted in CONNECT_ONLY situations, we do
+   * not know what the APP did with it. */
+  if(conn->connect_only)
+    aborted = TRUE;
+  conn->bits.aborted = aborted;
+
+  /* We do not shutdown dead connections. The term 'dead' can be misleading
+   * here, as we also mark errored connections/transfers as 'dead'.
+   * If we do a shutdown for an aborted transfer, the server might think
+   * it was successful otherwise (for example an ftps: upload). This is
+   * not what we want. */
+  if(aborted)
+    done = TRUE;
+  if(!done) {
+    /* Attempt to shutdown the connection right away. */
+    Curl_cshutdn_run_once(cpool->idata, conn, &done);
+  }
+
+  if(done || !data->multi)
+    Curl_cshutdn_terminate(cpool->idata, conn, FALSE);
+  else
+    Curl_cshutdn_add(&data->multi->cshutdn, conn, cpool->num_conn);
+}
+
 void Curl_cpool_destroy(struct cpool *cpool)
 {
   if(cpool && cpool->initialised && cpool->idata) {
@@ -592,53 +634,6 @@ bool Curl_cpool_find(struct Curl_easy *data,
   return result;
 }
 
-static void cpool_discard_conn(struct cpool *cpool,
-                               struct Curl_easy *data,
-                               struct connectdata *conn,
-                               bool aborted)
-{
-  bool done = FALSE;
-
-  DEBUGASSERT(data);
-  DEBUGASSERT(!data->conn);
-  DEBUGASSERT(cpool);
-  DEBUGASSERT(!conn->bits.in_cpool);
-
-  /*
-   * If this connection is not marked to force-close, leave it open if there
-   * are other users of it
-   */
-  if(CONN_INUSE(conn) && !aborted) {
-    CURL_TRC_M(data, "[CPOOL] not discarding #%" FMT_OFF_T
-               " still in use by %u transfers", conn->connection_id,
-               conn->attached_xfers);
-    return;
-  }
-
-  /* treat the connection as aborted in CONNECT_ONLY situations, we do
-   * not know what the APP did with it. */
-  if(conn->connect_only)
-    aborted = TRUE;
-  conn->bits.aborted = aborted;
-
-  /* We do not shutdown dead connections. The term 'dead' can be misleading
-   * here, as we also mark errored connections/transfers as 'dead'.
-   * If we do a shutdown for an aborted transfer, the server might think
-   * it was successful otherwise (for example an ftps: upload). This is
-   * not what we want. */
-  if(aborted)
-    done = TRUE;
-  if(!done) {
-    /* Attempt to shutdown the connection right away. */
-    Curl_cshutdn_run_once(cpool->idata, conn, &done);
-  }
-
-  if(done || !data->multi)
-    Curl_cshutdn_terminate(cpool->idata, conn, FALSE);
-  else
-    Curl_cshutdn_add(&data->multi->cshutdn, conn, cpool->num_conn);
-}
-
 void Curl_conn_terminate(struct Curl_easy *data,
                          struct connectdata *conn,
                          bool aborted)
index 69fb344fde8ea2c68a7885c2786ad8041f98fb96..786d7509cd89e47134da6e9070809969fc5a1041 100644 (file)
@@ -101,22 +101,6 @@ struct cw_out_ctx {
   BIT(errored);
 };
 
-static CURLcode cw_out_write(struct Curl_easy *data,
-                             struct Curl_cwriter *writer, int type,
-                             const char *buf, size_t nbytes);
-static void cw_out_close(struct Curl_easy *data, struct Curl_cwriter *writer);
-static CURLcode cw_out_init(struct Curl_easy *data,
-                            struct Curl_cwriter *writer);
-
-const struct Curl_cwtype Curl_cwt_out = {
-  "cw-out",
-  NULL,
-  cw_out_init,
-  cw_out_write,
-  cw_out_close,
-  sizeof(struct cw_out_ctx)
-};
-
 static CURLcode cw_out_init(struct Curl_easy *data,
                             struct Curl_cwriter *writer)
 {
@@ -455,6 +439,15 @@ static CURLcode cw_out_write(struct Curl_easy *data,
   return CURLE_OK;
 }
 
+const struct Curl_cwtype Curl_cwt_out = {
+  "cw-out",
+  NULL,
+  cw_out_init,
+  cw_out_write,
+  cw_out_close,
+  sizeof(struct cw_out_ctx)
+};
+
 bool Curl_cw_out_is_paused(struct Curl_easy *data)
 {
   struct Curl_cwriter *cw_out;
index 481b9fb27db8fe768b93c82e6850ae5c59c2dcdf..2489a330a03ba8fc94808f4b142ea54f43723272 100644 (file)
@@ -70,23 +70,6 @@ struct cw_pause_ctx {
   size_t buf_total;
 };
 
-static CURLcode cw_pause_write(struct Curl_easy *data,
-                               struct Curl_cwriter *writer, int type,
-                               const char *buf, size_t nbytes);
-static void cw_pause_close(struct Curl_easy *data,
-                           struct Curl_cwriter *writer);
-static CURLcode cw_pause_init(struct Curl_easy *data,
-                              struct Curl_cwriter *writer);
-
-const struct Curl_cwtype Curl_cwt_pause = {
-  "cw-pause",
-  NULL,
-  cw_pause_init,
-  cw_pause_write,
-  cw_pause_close,
-  sizeof(struct cw_pause_ctx)
-};
-
 static CURLcode cw_pause_init(struct Curl_easy *data,
                               struct Curl_cwriter *writer)
 {
@@ -220,6 +203,15 @@ static CURLcode cw_pause_write(struct Curl_easy *data,
   return result;
 }
 
+const struct Curl_cwtype Curl_cwt_pause = {
+  "cw-pause",
+  NULL,
+  cw_pause_init,
+  cw_pause_write,
+  cw_pause_close,
+  sizeof(struct cw_pause_ctx)
+};
+
 CURLcode Curl_cw_pause_flush(struct Curl_easy *data)
 {
   struct Curl_cwriter *cw_pause;
index f1c9fb59d66d50259d04428967cb8627ebbe8f75..3520b544a416583ce2040259b3260c6de6c01ec8 100644 (file)
@@ -124,7 +124,59 @@ struct cf_h2_ctx {
 #undef CF_CTX_CALL_DATA
 #define CF_CTX_CALL_DATA(cf) ((struct cf_h2_ctx *)(cf)->ctx)->call_data
 
-static void h2_stream_hash_free(unsigned int id, void *stream);
+/**
+ * All about the H2 internals of a stream
+ */
+struct h2_stream_ctx {
+  struct bufq sendbuf; /* request buffer */
+  struct h1_req_parser h1; /* parsing the request */
+  struct dynhds resp_trailers; /* response trailer fields */
+  size_t resp_hds_len; /* amount of response header bytes in recvbuf */
+  curl_off_t nrcvd_data;  /* number of DATA bytes received */
+
+  char **push_headers;       /* allocated array */
+  size_t push_headers_used;  /* number of entries filled in */
+  size_t push_headers_alloc; /* number of entries allocated */
+
+  int status_code; /* HTTP response status code */
+  uint32_t error; /* stream error code */
+  CURLcode xfer_result; /* Result of writing out response */
+  int32_t local_window_size; /* the local recv window size */
+  int32_t id; /* HTTP/2 protocol identifier for stream */
+  BIT(resp_hds_complete); /* we have a complete, final response */
+  BIT(closed); /* TRUE on stream close */
+  BIT(reset);  /* TRUE on stream reset */
+  BIT(close_handled); /* TRUE if stream closure is handled by libcurl */
+  BIT(bodystarted);
+  BIT(body_eos);    /* the complete body has been added to `sendbuf` and
+                     * is being/has been processed from there. */
+  BIT(write_paused);  /* stream write is paused */
+};
+
+static void free_push_headers(struct h2_stream_ctx *stream)
+{
+  size_t i;
+  for(i = 0; i < stream->push_headers_used; i++)
+    curlx_free(stream->push_headers[i]);
+  Curl_safefree(stream->push_headers);
+  stream->push_headers_used = 0;
+}
+
+static void h2_stream_ctx_free(struct h2_stream_ctx *stream)
+{
+  Curl_bufq_free(&stream->sendbuf);
+  Curl_h1_req_parse_free(&stream->h1);
+  Curl_dynhds_free(&stream->resp_trailers);
+  free_push_headers(stream);
+  curlx_free(stream);
+}
+
+static void h2_stream_hash_free(unsigned int id, void *stream)
+{
+  (void)id;
+  DEBUGASSERT(stream);
+  h2_stream_ctx_free((struct h2_stream_ctx *)stream);
+}
 
 static void cf_h2_ctx_init(struct cf_h2_ctx *ctx, bool via_h1_upgrade)
 {
@@ -212,41 +264,6 @@ static CURLcode cf_h2_update_settings(struct cf_h2_ctx *ctx,
   return CURLE_OK;
 }
 
-static CURLcode nw_out_flush(struct Curl_cfilter *cf,
-                             struct Curl_easy *data);
-
-static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
-                                   struct Curl_easy *data);
-
-/**
- * All about the H2 internals of a stream
- */
-struct h2_stream_ctx {
-  struct bufq sendbuf; /* request buffer */
-  struct h1_req_parser h1; /* parsing the request */
-  struct dynhds resp_trailers; /* response trailer fields */
-  size_t resp_hds_len; /* amount of response header bytes in recvbuf */
-  curl_off_t nrcvd_data;  /* number of DATA bytes received */
-
-  char **push_headers;       /* allocated array */
-  size_t push_headers_used;  /* number of entries filled in */
-  size_t push_headers_alloc; /* number of entries allocated */
-
-  int status_code; /* HTTP response status code */
-  uint32_t error; /* stream error code */
-  CURLcode xfer_result; /* Result of writing out response */
-  int32_t local_window_size; /* the local recv window size */
-  int32_t id; /* HTTP/2 protocol identifier for stream */
-  BIT(resp_hds_complete); /* we have a complete, final response */
-  BIT(closed); /* TRUE on stream close */
-  BIT(reset);  /* TRUE on stream reset */
-  BIT(close_handled); /* TRUE if stream closure is handled by libcurl */
-  BIT(bodystarted);
-  BIT(body_eos);    /* the complete body has been added to `sendbuf` and
-                     * is being/has been processed from there. */
-  BIT(write_paused);  /* stream write is paused */
-};
-
 #define H2_STREAM_CTX(ctx, data)                                        \
   ((struct h2_stream_ctx *)(                                            \
     data? Curl_uint32_hash_get(&(ctx)->streams, (data)->mid) : NULL))
@@ -275,31 +292,6 @@ static struct h2_stream_ctx *h2_stream_ctx_create(struct cf_h2_ctx *ctx)
   return stream;
 }
 
-static void free_push_headers(struct h2_stream_ctx *stream)
-{
-  size_t i;
-  for(i = 0; i < stream->push_headers_used; i++)
-    curlx_free(stream->push_headers[i]);
-  Curl_safefree(stream->push_headers);
-  stream->push_headers_used = 0;
-}
-
-static void h2_stream_ctx_free(struct h2_stream_ctx *stream)
-{
-  Curl_bufq_free(&stream->sendbuf);
-  Curl_h1_req_parse_free(&stream->h1);
-  Curl_dynhds_free(&stream->resp_trailers);
-  free_push_headers(stream);
-  curlx_free(stream);
-}
-
-static void h2_stream_hash_free(unsigned int id, void *stream)
-{
-  (void)id;
-  DEBUGASSERT(stream);
-  h2_stream_ctx_free((struct h2_stream_ctx *)stream);
-}
-
 #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
 static int32_t cf_h2_get_desired_local_win(struct Curl_cfilter *cf,
                                            struct Curl_easy *data)
@@ -406,6 +398,29 @@ static CURLcode http2_data_setup(struct Curl_cfilter *cf,
   return CURLE_OK;
 }
 
+static CURLcode nw_out_flush(struct Curl_cfilter *cf,
+                             struct Curl_easy *data)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  size_t nwritten;
+  CURLcode result;
+
+  if(Curl_bufq_is_empty(&ctx->outbufq))
+    return CURLE_OK;
+
+  result = Curl_cf_send_bufq(cf->next, data, &ctx->outbufq, NULL, 0,
+                             &nwritten);
+  if(result) {
+    if(result == CURLE_AGAIN) {
+      CURL_TRC_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN",
+                  Curl_bufq_len(&ctx->outbufq));
+      ctx->nw_out_blocked = 1;
+    }
+    return result;
+  }
+  return Curl_bufq_is_empty(&ctx->outbufq) ? CURLE_OK : CURLE_AGAIN;
+}
+
 static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
   struct cf_h2_ctx *ctx = cf->ctx;
@@ -464,154 +479,6 @@ static int h2_client_new(struct Curl_cfilter *cf,
   return rc;
 }
 
-static ssize_t send_callback(nghttp2_session *h2,
-                             const uint8_t *mem, size_t length, int flags,
-                             void *userp);
-static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
-                         void *userp);
-static int cf_h2_on_invalid_frame_recv(nghttp2_session *session,
-                                       const nghttp2_frame *frame,
-                                       int lib_error_code,
-                                       void *user_data);
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame,
-                         void *userp);
-#endif
-static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
-                              int32_t stream_id,
-                              const uint8_t *mem, size_t len, void *userp);
-static int on_stream_close(nghttp2_session *session, int32_t stream_id,
-                           uint32_t error_code, void *userp);
-static int on_begin_headers(nghttp2_session *session,
-                            const nghttp2_frame *frame, void *userp);
-static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
-                     const uint8_t *name, size_t namelen,
-                     const uint8_t *value, size_t valuelen,
-                     uint8_t flags,
-                     void *userp);
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-static int error_callback(nghttp2_session *session, const char *msg,
-                          size_t len, void *userp);
-#endif
-static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf,
-                               struct Curl_easy *data)
-{
-  struct cf_h2_ctx *ctx = cf->ctx;
-  struct h2_stream_ctx *stream;
-  CURLcode result = CURLE_OUT_OF_MEMORY;
-  int rc;
-  nghttp2_session_callbacks *cbs = NULL;
-
-  DEBUGASSERT(!ctx->h2);
-  DEBUGASSERT(ctx->initialized);
-
-  rc = nghttp2_session_callbacks_new(&cbs);
-  if(rc) {
-    failf(data, "Could not initialize nghttp2 callbacks");
-    goto out;
-  }
-
-  nghttp2_session_callbacks_set_send_callback(cbs, send_callback);
-  nghttp2_session_callbacks_set_on_frame_recv_callback(cbs, on_frame_recv);
-  nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(cbs,
-    cf_h2_on_invalid_frame_recv);
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-  nghttp2_session_callbacks_set_on_frame_send_callback(cbs, on_frame_send);
-#endif
-  nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
-    cbs, on_data_chunk_recv);
-  nghttp2_session_callbacks_set_on_stream_close_callback(cbs, on_stream_close);
-  nghttp2_session_callbacks_set_on_begin_headers_callback(
-    cbs, on_begin_headers);
-  nghttp2_session_callbacks_set_on_header_callback(cbs, on_header);
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-  nghttp2_session_callbacks_set_error_callback(cbs, error_callback);
-#endif
-
-  /* The nghttp2 session is not yet setup, do it */
-  rc = h2_client_new(cf, cbs);
-  if(rc) {
-    failf(data, "Could not initialize nghttp2");
-    goto out;
-  }
-  ctx->max_concurrent_streams = DEFAULT_MAX_CONCURRENT_STREAMS;
-
-  if(ctx->via_h1_upgrade) {
-    /* HTTP/1.1 Upgrade issued. H2 Settings have already been submitted
-     * in the H1 request and we upgrade from there. This stream
-     * is opened implicitly as #1. */
-    uint8_t binsettings[H2_BINSETTINGS_LEN];
-    ssize_t rclen;
-    size_t binlen; /* length of the binsettings data */
-
-    rclen = populate_binsettings(binsettings, data);
-
-    if(!curlx_sztouz(rclen, &binlen) || !binlen) {
-      failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
-      result = CURLE_FAILED_INIT;
-      goto out;
-    }
-
-    result = http2_data_setup(cf, data, &stream);
-    if(result)
-      goto out;
-    DEBUGASSERT(stream);
-    stream->id = 1;
-    /* queue SETTINGS frame (again) */
-    rc = nghttp2_session_upgrade2(ctx->h2, binsettings, binlen,
-                                  data->state.httpreq == HTTPREQ_HEAD,
-                                  NULL);
-    if(rc) {
-      failf(data, "nghttp2_session_upgrade2() failed: %s(%d)",
-            nghttp2_strerror(rc), rc);
-      result = CURLE_HTTP2;
-      goto out;
-    }
-
-    rc = nghttp2_session_set_stream_user_data(ctx->h2, stream->id,
-                                              data);
-    if(rc) {
-      infof(data, "http/2: failed to set user_data for stream %u",
-            stream->id);
-      DEBUGASSERT(0);
-    }
-    CURL_TRC_CF(data, cf, "created session via Upgrade");
-  }
-  else {
-    nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
-    size_t ivlen;
-
-    ivlen = populate_settings(iv, data, ctx);
-    rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE,
-                                 iv, ivlen);
-    if(rc) {
-      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
-            nghttp2_strerror(rc), rc);
-      result = CURLE_HTTP2;
-      goto out;
-    }
-  }
-
-  rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0,
-                                             HTTP2_HUGE_WINDOW_SIZE);
-  if(rc) {
-    failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
-          nghttp2_strerror(rc), rc);
-    result = CURLE_HTTP2;
-    goto out;
-  }
-
-  /* all set, traffic will be send on connect */
-  result = CURLE_OK;
-  CURL_TRC_CF(data, cf, "[0] created h2 session%s",
-              ctx->via_h1_upgrade ? " (via h1 upgrade)" : "");
-
-out:
-  if(cbs)
-    nghttp2_session_callbacks_del(cbs);
-  return result;
-}
-
 /*
  * Returns nonzero if current HTTP/2 session should be closed.
  */
@@ -738,29 +605,6 @@ void Curl_http2_ver(char *p, size_t len)
   (void)curl_msnprintf(p, len, "nghttp2/%s", h2->version_str);
 }
 
-static CURLcode nw_out_flush(struct Curl_cfilter *cf,
-                             struct Curl_easy *data)
-{
-  struct cf_h2_ctx *ctx = cf->ctx;
-  size_t nwritten;
-  CURLcode result;
-
-  if(Curl_bufq_is_empty(&ctx->outbufq))
-    return CURLE_OK;
-
-  result = Curl_cf_send_bufq(cf->next, data, &ctx->outbufq, NULL, 0,
-                             &nwritten);
-  if(result) {
-    if(result == CURLE_AGAIN) {
-      CURL_TRC_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN",
-                  Curl_bufq_len(&ctx->outbufq));
-      ctx->nw_out_blocked = 1;
-    }
-    return result;
-  }
-  return Curl_bufq_is_empty(&ctx->outbufq) ? CURLE_OK : CURLE_AGAIN;
-}
-
 /*
  * The implementation of nghttp2_send_callback type. Here we write |data| with
  * size |length| to the network and return the number of bytes actually
@@ -2533,6 +2377,125 @@ static CURLcode cf_h2_adjust_pollset(struct Curl_cfilter *cf,
   return result;
 }
 
+static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf,
+                               struct Curl_easy *data)
+{
+  struct cf_h2_ctx *ctx = cf->ctx;
+  struct h2_stream_ctx *stream;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  int rc;
+  nghttp2_session_callbacks *cbs = NULL;
+
+  DEBUGASSERT(!ctx->h2);
+  DEBUGASSERT(ctx->initialized);
+
+  rc = nghttp2_session_callbacks_new(&cbs);
+  if(rc) {
+    failf(data, "Could not initialize nghttp2 callbacks");
+    goto out;
+  }
+
+  nghttp2_session_callbacks_set_send_callback(cbs, send_callback);
+  nghttp2_session_callbacks_set_on_frame_recv_callback(cbs, on_frame_recv);
+  nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(cbs,
+    cf_h2_on_invalid_frame_recv);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  nghttp2_session_callbacks_set_on_frame_send_callback(cbs, on_frame_send);
+#endif
+  nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
+    cbs, on_data_chunk_recv);
+  nghttp2_session_callbacks_set_on_stream_close_callback(cbs, on_stream_close);
+  nghttp2_session_callbacks_set_on_begin_headers_callback(
+    cbs, on_begin_headers);
+  nghttp2_session_callbacks_set_on_header_callback(cbs, on_header);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  nghttp2_session_callbacks_set_error_callback(cbs, error_callback);
+#endif
+
+  /* The nghttp2 session is not yet setup, do it */
+  rc = h2_client_new(cf, cbs);
+  if(rc) {
+    failf(data, "Could not initialize nghttp2");
+    goto out;
+  }
+  ctx->max_concurrent_streams = DEFAULT_MAX_CONCURRENT_STREAMS;
+
+  if(ctx->via_h1_upgrade) {
+    /* HTTP/1.1 Upgrade issued. H2 Settings have already been submitted
+     * in the H1 request and we upgrade from there. This stream
+     * is opened implicitly as #1. */
+    uint8_t binsettings[H2_BINSETTINGS_LEN];
+    ssize_t rclen;
+    size_t binlen; /* length of the binsettings data */
+
+    rclen = populate_binsettings(binsettings, data);
+
+    if(!curlx_sztouz(rclen, &binlen) || !binlen) {
+      failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
+      result = CURLE_FAILED_INIT;
+      goto out;
+    }
+
+    result = http2_data_setup(cf, data, &stream);
+    if(result)
+      goto out;
+    DEBUGASSERT(stream);
+    stream->id = 1;
+    /* queue SETTINGS frame (again) */
+    rc = nghttp2_session_upgrade2(ctx->h2, binsettings, binlen,
+                                  data->state.httpreq == HTTPREQ_HEAD,
+                                  NULL);
+    if(rc) {
+      failf(data, "nghttp2_session_upgrade2() failed: %s(%d)",
+            nghttp2_strerror(rc), rc);
+      result = CURLE_HTTP2;
+      goto out;
+    }
+
+    rc = nghttp2_session_set_stream_user_data(ctx->h2, stream->id,
+                                              data);
+    if(rc) {
+      infof(data, "http/2: failed to set user_data for stream %u",
+            stream->id);
+      DEBUGASSERT(0);
+    }
+    CURL_TRC_CF(data, cf, "created session via Upgrade");
+  }
+  else {
+    nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
+    size_t ivlen;
+
+    ivlen = populate_settings(iv, data, ctx);
+    rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE,
+                                 iv, ivlen);
+    if(rc) {
+      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
+            nghttp2_strerror(rc), rc);
+      result = CURLE_HTTP2;
+      goto out;
+    }
+  }
+
+  rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0,
+                                             HTTP2_HUGE_WINDOW_SIZE);
+  if(rc) {
+    failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
+          nghttp2_strerror(rc), rc);
+    result = CURLE_HTTP2;
+    goto out;
+  }
+
+  /* all set, traffic will be send on connect */
+  result = CURLE_OK;
+  CURL_TRC_CF(data, cf, "[0] created h2 session%s",
+              ctx->via_h1_upgrade ? " (via h1 upgrade)" : "");
+
+out:
+  if(cbs)
+    nghttp2_session_callbacks_del(cbs);
+  return result;
+}
+
 static CURLcode cf_h2_connect(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               bool *done)
index 493924a567e59ba6693dee49c32f1772dd4d337e..f34e4f91d36a75b6bf24c99afa2f20db53ec965a 100644 (file)
@@ -53,30 +53,8 @@ struct Curl_easy;
 
 static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
                                  void *instream, bool *hasread);
-
-/* Encoders. */
-static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
-                               curl_mimepart *part);
-static curl_off_t encoder_nop_size(curl_mimepart *part);
-static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
-                                curl_mimepart *part);
-static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
-                                  curl_mimepart *part);
-static curl_off_t encoder_base64_size(curl_mimepart *part);
-static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
-                              curl_mimepart *part);
-static curl_off_t encoder_qp_size(curl_mimepart *part);
 static curl_off_t mime_size(curl_mimepart *part);
 
-static const struct mime_encoder encoders[] = {
-  { "binary", encoder_nop_read, encoder_nop_size },
-  { "8bit", encoder_nop_read, encoder_nop_size },
-  { "7bit", encoder_7bit_read, encoder_nop_size },
-  { "base64", encoder_base64_read, encoder_base64_size },
-  { "quoted-printable", encoder_qp_read, encoder_qp_size },
-  { ZERO_NULL, ZERO_NULL, ZERO_NULL }
-};
-
 /* Quoted-printable character class table.
  *
  * We cannot rely on ctype functions since quoted-printable input data
@@ -1435,6 +1413,15 @@ CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
   return CURLE_OK;
 }
 
+static const struct mime_encoder encoders[] = {
+  { "binary", encoder_nop_read, encoder_nop_size },
+  { "8bit", encoder_nop_read, encoder_nop_size },
+  { "7bit", encoder_7bit_read, encoder_nop_size },
+  { "base64", encoder_base64_read, encoder_base64_size },
+  { "quoted-printable", encoder_qp_read, encoder_qp_size },
+  { ZERO_NULL, ZERO_NULL, ZERO_NULL }
+};
+
 /* Set mime data transfer encoder. */
 CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
 {
index 09b01f176b4194ceee0b08da10cba06dba7de10f..c3711caf049e3183aff0555994c37dfacc6f2206 100644 (file)
@@ -73,31 +73,6 @@ struct RTSP {
 #define RTP_PKT_LENGTH(p) ((((unsigned int)((unsigned char)((p)[2]))) << 8) | \
                             ((unsigned int)((unsigned char)((p)[3]))))
 
-/*
- * Parse and write out an RTSP response.
- * @param data     the transfer
- * @param conn     the connection
- * @param buf      data read from connection
- * @param blen     amount of data in buf
- * @param is_eos   TRUE iff this is the last write
- * @param readmore out, TRUE iff complete buf was consumed and more data
- *                 is needed
- */
-static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
-                                    const char *buf,
-                                    size_t blen,
-                                    bool is_eos);
-static CURLcode rtsp_rtp_write_resp_hd(struct Curl_easy *data,
-                                       const char *buf,
-                                       size_t blen,
-                                       bool is_eos);
-
-static CURLcode rtsp_setup_connection(struct Curl_easy *data,
-                                      struct connectdata *conn);
-static uint32_t rtsp_conncheck(struct Curl_easy *data,
-                               struct connectdata *check,
-                               uint32_t checks_to_perform);
-
 /* this returns the socket to wait for in the DO and DOING state for the multi
    interface and then we are always _sending_ a request and thus we wait for
    the single socket to become writable only */
@@ -108,11 +83,6 @@ static CURLcode rtsp_do_pollset(struct Curl_easy *data,
   return Curl_pollset_add_out(data, ps, data->conn->sock[FIRSTSOCKET]);
 }
 
-static CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr,
-                                 size_t len);
-static CURLcode rtsp_parse_transport(struct Curl_easy *data,
-                                     const char *transport);
-
 #define MAX_RTP_BUFFERSIZE 1000000 /* arbitrary */
 
 static void rtsp_easy_dtor(void *key, size_t klen, void *entry)
@@ -649,6 +619,48 @@ static CURLcode rtp_write_body_junk(struct Curl_easy *data,
   return CURLE_OK;
 }
 
+static CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr,
+                                 size_t len)
+{
+  size_t wrote;
+  curl_write_callback writeit;
+  void *user_ptr;
+
+  if(len == 0) {
+    failf(data, "Cannot write a 0 size RTP packet.");
+    return CURLE_WRITE_ERROR;
+  }
+
+  /* If the user has configured CURLOPT_INTERLEAVEFUNCTION then use that
+     function and any configured CURLOPT_INTERLEAVEDATA to write out the RTP
+     data. Otherwise, use the CURLOPT_WRITEFUNCTION with the CURLOPT_WRITEDATA
+     pointer to write out the RTP data. */
+  if(data->set.fwrite_rtp) {
+    writeit = data->set.fwrite_rtp;
+    user_ptr = data->set.rtp_out;
+  }
+  else {
+    writeit = data->set.fwrite_func;
+    user_ptr = data->set.out;
+  }
+
+  Curl_set_in_callback(data, TRUE);
+  wrote = writeit((char *)CURL_UNCONST(ptr), 1, len, user_ptr);
+  Curl_set_in_callback(data, FALSE);
+
+  if(CURL_WRITEFUNC_PAUSE == wrote) {
+    failf(data, "Cannot pause RTP");
+    return CURLE_WRITE_ERROR;
+  }
+
+  if(wrote != len) {
+    failf(data, "Failed writing RTP data");
+    return CURLE_WRITE_ERROR;
+  }
+
+  return CURLE_OK;
+}
+
 static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
                                 struct rtsp_conn *rtspc,
                                 const char *buf,
@@ -812,6 +824,16 @@ out:
   return result;
 }
 
+/*
+ * Parse and write out an RTSP response.
+ * @param data     the transfer
+ * @param conn     the connection
+ * @param buf      data read from connection
+ * @param blen     amount of data in buf
+ * @param is_eos   TRUE iff this is the last write
+ * @param readmore out, TRUE iff complete buf was consumed and more data
+ *                 is needed
+ */
 static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
                                     const char *buf,
                                     size_t blen,
@@ -908,45 +930,46 @@ static CURLcode rtsp_rtp_write_resp_hd(struct Curl_easy *data,
   return rtsp_rtp_write_resp(data, buf, blen, is_eos);
 }
 
-static CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr,
-                                 size_t len)
+static CURLcode rtsp_parse_transport(struct Curl_easy *data,
+                                     const char *transport)
 {
-  size_t wrote;
-  curl_write_callback writeit;
-  void *user_ptr;
-
-  if(len == 0) {
-    failf(data, "Cannot write a 0 size RTP packet.");
-    return CURLE_WRITE_ERROR;
-  }
-
-  /* If the user has configured CURLOPT_INTERLEAVEFUNCTION then use that
-     function and any configured CURLOPT_INTERLEAVEDATA to write out the RTP
-     data. Otherwise, use the CURLOPT_WRITEFUNCTION with the CURLOPT_WRITEDATA
-     pointer to write out the RTP data. */
-  if(data->set.fwrite_rtp) {
-    writeit = data->set.fwrite_rtp;
-    user_ptr = data->set.rtp_out;
-  }
-  else {
-    writeit = data->set.fwrite_func;
-    user_ptr = data->set.out;
-  }
-
-  Curl_set_in_callback(data, TRUE);
-  wrote = writeit((char *)CURL_UNCONST(ptr), 1, len, user_ptr);
-  Curl_set_in_callback(data, FALSE);
-
-  if(CURL_WRITEFUNC_PAUSE == wrote) {
-    failf(data, "Cannot pause RTP");
-    return CURLE_WRITE_ERROR;
-  }
-
-  if(wrote != len) {
-    failf(data, "Failed writing RTP data");
-    return CURLE_WRITE_ERROR;
+  /* If we receive multiple Transport response-headers, the interleaved
+     channels of each response header is recorded and used together for
+     subsequent data validity checks.*/
+  /* e.g.: ' RTP/AVP/TCP;unicast;interleaved=5-6' */
+  const char *start, *end;
+  start = transport;
+  while(start && *start) {
+    curlx_str_passblanks(&start);
+    end = strchr(start, ';');
+    if(checkprefix("interleaved=", start)) {
+      curl_off_t chan1, chan2, chan;
+      const char *p = start + 12;
+      if(!curlx_str_number(&p, &chan1, 255)) {
+        unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;
+        chan2 = chan1;
+        if(!curlx_str_single(&p, '-')) {
+          if(curlx_str_number(&p, &chan2, 255)) {
+            infof(data, "Unable to read the interleaved parameter from "
+                  "Transport header: [%s]", transport);
+            chan2 = chan1;
+          }
+        }
+        for(chan = chan1; chan <= chan2; chan++) {
+          int idx = (int)chan / 8;
+          int off = (int)chan % 8;
+          rtp_channel_mask[idx] |= (unsigned char)(1 << off);
+        }
+      }
+      else {
+        infof(data, "Unable to read the interleaved parameter from "
+              "Transport header: [%s]", transport);
+      }
+      break;
+    }
+    /* skip to next parameter */
+    start = (!end) ? end : (end + 1);
   }
-
   return CURLE_OK;
 }
 
@@ -1019,49 +1042,6 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
   return CURLE_OK;
 }
 
-static CURLcode rtsp_parse_transport(struct Curl_easy *data,
-                                     const char *transport)
-{
-  /* If we receive multiple Transport response-headers, the interleaved
-     channels of each response header is recorded and used together for
-     subsequent data validity checks.*/
-  /* e.g.: ' RTP/AVP/TCP;unicast;interleaved=5-6' */
-  const char *start, *end;
-  start = transport;
-  while(start && *start) {
-    curlx_str_passblanks(&start);
-    end = strchr(start, ';');
-    if(checkprefix("interleaved=", start)) {
-      curl_off_t chan1, chan2, chan;
-      const char *p = start + 12;
-      if(!curlx_str_number(&p, &chan1, 255)) {
-        unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;
-        chan2 = chan1;
-        if(!curlx_str_single(&p, '-')) {
-          if(curlx_str_number(&p, &chan2, 255)) {
-            infof(data, "Unable to read the interleaved parameter from "
-                  "Transport header: [%s]", transport);
-            chan2 = chan1;
-          }
-        }
-        for(chan = chan1; chan <= chan2; chan++) {
-          int idx = (int)chan / 8;
-          int off = (int)chan % 8;
-          rtp_channel_mask[idx] |= (unsigned char)(1 << off);
-        }
-      }
-      else {
-        infof(data, "Unable to read the interleaved parameter from "
-              "Transport header: [%s]", transport);
-      }
-      break;
-    }
-    /* skip to next parameter */
-    start = (!end) ? end : (end + 1);
-  }
-  return CURLE_OK;
-}
-
 /*
  * RTSP handler interface.
  */
index 680cd11356560ed6ee027db4e64fa9d321835689..402f9499f684579ea810b0f64fa78bf8fb8e7406 100644 (file)
 #include "strerror.h"
 #include "progress.h"
 
-
-static CURLcode do_init_writer_stack(struct Curl_easy *data);
-
-/* Curl_client_write() sends data to the write callback(s)
-
-   The bit pattern defines to what "streams" to write to. Body and/or header.
-   The defines are in sendf.h of course.
- */
-CURLcode Curl_client_write(struct Curl_easy *data,
-                           int type, const char *buf, size_t blen)
-{
-  CURLcode result;
-
-  /* it is one of those, at least */
-  DEBUGASSERT(type &
-              (CLIENTWRITE_BODY | CLIENTWRITE_HEADER | CLIENTWRITE_INFO));
-  /* BODY is only BODY (with optional EOS) */
-  DEBUGASSERT(!(type & CLIENTWRITE_BODY) ||
-              ((type & ~(CLIENTWRITE_BODY | CLIENTWRITE_EOS)) == 0));
-  /* INFO is only INFO (with optional EOS) */
-  DEBUGASSERT(!(type & CLIENTWRITE_INFO) ||
-              ((type & ~(CLIENTWRITE_INFO | CLIENTWRITE_EOS)) == 0));
-
-  if(!data->req.writer_stack) {
-    result = do_init_writer_stack(data);
-    if(result)
-      return result;
-    DEBUGASSERT(data->req.writer_stack);
-  }
-
-  result = Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
-  CURL_TRC_WRITE(data, "client_write(type=%x, len=%zu) -> %d",
-                 type, blen, result);
-  return result;
-}
-
 static void cl_reset_writer(struct Curl_easy *data)
 {
   struct Curl_cwriter *writer = data->req.writer_stack;
@@ -206,6 +170,7 @@ struct cw_download_ctx {
   struct Curl_cwriter super;
   BIT(started_response);
 };
+
 /* Download client writer in phase CURL_CW_PROTOCOL that
  * sees the "real" download body data. */
 static CURLcode cw_download_write(struct Curl_easy *data,
@@ -351,6 +316,84 @@ static const struct Curl_cwtype cw_raw = {
   sizeof(struct Curl_cwriter)
 };
 
+static CURLcode do_init_writer_stack(struct Curl_easy *data)
+{
+  struct Curl_cwriter *writer;
+  CURLcode result;
+
+  DEBUGASSERT(!data->req.writer_stack);
+  result = Curl_cwriter_create(&data->req.writer_stack,
+                               data, &Curl_cwt_out, CURL_CW_CLIENT);
+  if(result)
+    return result;
+
+  /* This places the "pause" writer behind the "download" writer that
+   * is added below. Meaning the "download" can do checks on content length
+   * and other things *before* write outs are buffered for paused transfers. */
+  result = Curl_cwriter_create(&writer, data, &Curl_cwt_pause,
+                               CURL_CW_PROTOCOL);
+  if(!result) {
+    result = Curl_cwriter_add(data, writer);
+    if(result)
+      Curl_cwriter_free(data, writer);
+  }
+  if(result)
+    return result;
+
+  result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
+  if(!result) {
+    result = Curl_cwriter_add(data, writer);
+    if(result)
+      Curl_cwriter_free(data, writer);
+  }
+  if(result)
+    return result;
+
+  result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
+  if(!result) {
+    result = Curl_cwriter_add(data, writer);
+    if(result)
+      Curl_cwriter_free(data, writer);
+  }
+  if(result)
+    return result;
+
+  return result;
+}
+
+/* Curl_client_write() sends data to the write callback(s)
+
+   The bit pattern defines to what "streams" to write to. Body and/or header.
+   The defines are in sendf.h of course.
+ */
+CURLcode Curl_client_write(struct Curl_easy *data,
+                           int type, const char *buf, size_t blen)
+{
+  CURLcode result;
+
+  /* it is one of those, at least */
+  DEBUGASSERT(type &
+              (CLIENTWRITE_BODY | CLIENTWRITE_HEADER | CLIENTWRITE_INFO));
+  /* BODY is only BODY (with optional EOS) */
+  DEBUGASSERT(!(type & CLIENTWRITE_BODY) ||
+              ((type & ~(CLIENTWRITE_BODY | CLIENTWRITE_EOS)) == 0));
+  /* INFO is only INFO (with optional EOS) */
+  DEBUGASSERT(!(type & CLIENTWRITE_INFO) ||
+              ((type & ~(CLIENTWRITE_INFO | CLIENTWRITE_EOS)) == 0));
+
+  if(!data->req.writer_stack) {
+    result = do_init_writer_stack(data);
+    if(result)
+      return result;
+    DEBUGASSERT(data->req.writer_stack);
+  }
+
+  result = Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
+  CURL_TRC_WRITE(data, "client_write(type=%x, len=%zu) -> %d",
+                 type, blen, result);
+  return result;
+}
+
 /* Create an unencoding writer stage using the given handler. */
 CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
                              struct Curl_easy *data,
@@ -400,51 +443,6 @@ size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase)
   return n;
 }
 
-static CURLcode do_init_writer_stack(struct Curl_easy *data)
-{
-  struct Curl_cwriter *writer;
-  CURLcode result;
-
-  DEBUGASSERT(!data->req.writer_stack);
-  result = Curl_cwriter_create(&data->req.writer_stack,
-                               data, &Curl_cwt_out, CURL_CW_CLIENT);
-  if(result)
-    return result;
-
-  /* This places the "pause" writer behind the "download" writer that
-   * is added below. Meaning the "download" can do checks on content length
-   * and other things *before* write outs are buffered for paused transfers. */
-  result = Curl_cwriter_create(&writer, data, &Curl_cwt_pause,
-                               CURL_CW_PROTOCOL);
-  if(!result) {
-    result = Curl_cwriter_add(data, writer);
-    if(result)
-      Curl_cwriter_free(data, writer);
-  }
-  if(result)
-    return result;
-
-  result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
-  if(!result) {
-    result = Curl_cwriter_add(data, writer);
-    if(result)
-      Curl_cwriter_free(data, writer);
-  }
-  if(result)
-    return result;
-
-  result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
-  if(!result) {
-    result = Curl_cwriter_add(data, writer);
-    if(result)
-      Curl_cwriter_free(data, writer);
-  }
-  if(result)
-    return result;
-
-  return result;
-}
-
 CURLcode Curl_cwriter_add(struct Curl_easy *data,
                           struct Curl_cwriter *writer)
 {
index a67cf7a05fbc580c4d2eeed0e3f417c812a9f189..c7c48ed79892994078875566513230eb5c9ca001 100644 (file)
@@ -83,9 +83,6 @@ struct Curl_URL {
 
 #define DEFAULT_SCHEME "https"
 
-static CURLUcode parseurl_and_replace(const char *url, CURLU *u,
-                                      unsigned int flags);
-
 static void free_urlhandle(struct Curl_URL *u)
 {
   curlx_free(u->scheme);
@@ -222,81 +219,6 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
   return 0;
 }
 
-/*
- * Concatenate a relative URL onto a base URL making it absolute.
- */
-static CURLUcode redirect_url(const char *base, const char *relurl,
-                              CURLU *u, unsigned int flags)
-{
-  struct dynbuf urlbuf;
-  bool host_changed = FALSE;
-  const char *useurl = relurl;
-  const char *cutoff = NULL;
-  size_t prelen;
-  CURLUcode uc;
-
-  /* protsep points to the start of the hostname, after [scheme]:// */
-  const char *protsep = base + strlen(u->scheme) + 3;
-  DEBUGASSERT(base && relurl && u); /* all set here */
-  if(!base)
-    return CURLUE_MALFORMED_INPUT; /* should never happen */
-
-  /* handle different relative URL types */
-  switch(relurl[0]) {
-  case '/':
-    if(relurl[1] == '/') {
-      /* protocol-relative URL: //example.com/path */
-      cutoff = protsep;
-      useurl = &relurl[2];
-      host_changed = TRUE;
-    }
-    else
-      /* absolute /path */
-      cutoff = strchr(protsep, '/');
-    break;
-
-  case '#':
-    /* fragment-only change */
-    if(u->fragment)
-      cutoff = strchr(protsep, '#');
-    break;
-
-  default:
-    /* path or query-only change */
-    if(u->query && u->query[0])
-      /* remove existing query */
-      cutoff = strchr(protsep, '?');
-    else if(u->fragment && u->fragment[0])
-      /* Remove existing fragment */
-      cutoff = strchr(protsep, '#');
-
-    if(relurl[0] != '?') {
-      /* append a relative path after the last slash */
-      cutoff = memrchr(protsep, '/',
-                       cutoff ? (size_t)(cutoff - protsep) : strlen(protsep));
-      if(cutoff)
-        cutoff++; /* truncate after last slash */
-    }
-    break;
-  }
-
-  prelen = cutoff ? (size_t)(cutoff - base) : strlen(base);
-
-  /* build new URL */
-  curlx_dyn_init(&urlbuf, CURL_MAX_INPUT_LENGTH);
-
-  if(!curlx_dyn_addn(&urlbuf, base, prelen) &&
-     !urlencode_str(&urlbuf, useurl, strlen(useurl), !host_changed, FALSE)) {
-    uc = parseurl_and_replace(curlx_dyn_ptr(&urlbuf), u,
-                              flags & ~CURLU_PATH_AS_IS);
-  }
-  else
-    uc = CURLUE_OUT_OF_MEMORY;
-
-  curlx_dyn_free(&urlbuf);
-  return uc;
-}
-
 /* scan for byte values <= 31, 127 and sometimes space */
 CURLUcode Curl_junkscan(const char *url, size_t *urllen, bool allowspace)
 {
@@ -1286,6 +1208,81 @@ static CURLUcode parseurl_and_replace(const char *url, CURLU *u,
   return result;
 }
 
+/*
+ * Concatenate a relative URL onto a base URL making it absolute.
+ */
+static CURLUcode redirect_url(const char *base, const char *relurl,
+                              CURLU *u, unsigned int flags)
+{
+  struct dynbuf urlbuf;
+  bool host_changed = FALSE;
+  const char *useurl = relurl;
+  const char *cutoff = NULL;
+  size_t prelen;
+  CURLUcode uc;
+
+  /* protsep points to the start of the hostname, after [scheme]:// */
+  const char *protsep = base + strlen(u->scheme) + 3;
+  DEBUGASSERT(base && relurl && u); /* all set here */
+  if(!base)
+    return CURLUE_MALFORMED_INPUT; /* should never happen */
+
+  /* handle different relative URL types */
+  switch(relurl[0]) {
+  case '/':
+    if(relurl[1] == '/') {
+      /* protocol-relative URL: //example.com/path */
+      cutoff = protsep;
+      useurl = &relurl[2];
+      host_changed = TRUE;
+    }
+    else
+      /* absolute /path */
+      cutoff = strchr(protsep, '/');
+    break;
+
+  case '#':
+    /* fragment-only change */
+    if(u->fragment)
+      cutoff = strchr(protsep, '#');
+    break;
+
+  default:
+    /* path or query-only change */
+    if(u->query && u->query[0])
+      /* remove existing query */
+      cutoff = strchr(protsep, '?');
+    else if(u->fragment && u->fragment[0])
+      /* Remove existing fragment */
+      cutoff = strchr(protsep, '#');
+
+    if(relurl[0] != '?') {
+      /* append a relative path after the last slash */
+      cutoff = memrchr(protsep, '/',
+                       cutoff ? (size_t)(cutoff - protsep) : strlen(protsep));
+      if(cutoff)
+        cutoff++; /* truncate after last slash */
+    }
+    break;
+  }
+
+  prelen = cutoff ? (size_t)(cutoff - base) : strlen(base);
+
+  /* build new URL */
+  curlx_dyn_init(&urlbuf, CURL_MAX_INPUT_LENGTH);
+
+  if(!curlx_dyn_addn(&urlbuf, base, prelen) &&
+     !urlencode_str(&urlbuf, useurl, strlen(useurl), !host_changed, FALSE)) {
+    uc = parseurl_and_replace(curlx_dyn_ptr(&urlbuf), u,
+                              flags & ~CURLU_PATH_AS_IS);
+  }
+  else
+    uc = CURLUE_OUT_OF_MEMORY;
+
+  curlx_dyn_free(&urlbuf);
+  return uc;
+}
+
 /*
  */
 CURLU *curl_url(void)
index 891dfc4e73c45309a54de726eb6f82b025c42cb3..64509fd4cef6df7733f56dd904541fb7fb39945a 100644 (file)
 static bool s_win_has_alpn;
 #endif
 
-static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
-                                             struct Curl_easy *data,
-                                             const char *pinnedpubkey);
-
 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
                           void *BufDataPtr, unsigned long BufByteSize)
 {
@@ -1115,6 +1111,74 @@ static CURLcode schannel_error(struct Curl_easy *data,
   }
 }
 
+static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
+                                             struct Curl_easy *data,
+                                             const char *pinnedpubkey)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+  struct schannel_ssl_backend_data *backend =
+    (struct schannel_ssl_backend_data *)connssl->backend;
+  CERT_CONTEXT *pCertContextServer = NULL;
+
+  /* Result is returned to caller */
+  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+  DEBUGASSERT(backend);
+
+  /* if a path was not specified, do not pin */
+  if(!pinnedpubkey)
+    return CURLE_OK;
+
+  do {
+    SECURITY_STATUS sspi_status;
+    const char *x509_der;
+    DWORD x509_der_len;
+    struct Curl_X509certificate x509_parsed;
+    struct Curl_asn1Element *pubkey;
+
+    sspi_status =
+      Curl_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
+                                       SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+                                       &pCertContextServer);
+
+    if((sspi_status != SEC_E_OK) || !pCertContextServer) {
+      char buffer[STRERROR_LEN];
+      failf(data, "schannel: Failed to read remote certificate context: %s",
+            Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+      break; /* failed */
+    }
+
+    if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
+         (pCertContextServer->cbCertEncoded > 0)))
+      break;
+
+    x509_der = (const char *)pCertContextServer->pbCertEncoded;
+    x509_der_len = pCertContextServer->cbCertEncoded;
+    memset(&x509_parsed, 0, sizeof(x509_parsed));
+    if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
+      break;
+
+    pubkey = &x509_parsed.subjectPublicKeyInfo;
+    if(!pubkey->header || pubkey->end <= pubkey->header) {
+      failf(data, "SSL: failed retrieving public key from server certificate");
+      break;
+    }
+
+    result = Curl_pin_peer_pubkey(data,
+                                  pinnedpubkey,
+                                  (const unsigned char *)pubkey->header,
+                                  (size_t)(pubkey->end - pubkey->header));
+    if(result) {
+      failf(data, "SSL: public key does not match pinned public key");
+    }
+  } while(0);
+
+  if(pCertContextServer)
+    CertFreeCertificateContext(pCertContextServer);
+
+  return result;
+}
+
 static CURLcode schannel_connect_step2(struct Curl_cfilter *cf,
                                        struct Curl_easy *data)
 {
@@ -2580,74 +2644,6 @@ static CURLcode schannel_random(struct Curl_easy *data,
   return Curl_win32_random(entropy, length);
 }
 
-static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
-                                             struct Curl_easy *data,
-                                             const char *pinnedpubkey)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct schannel_ssl_backend_data *backend =
-    (struct schannel_ssl_backend_data *)connssl->backend;
-  CERT_CONTEXT *pCertContextServer = NULL;
-
-  /* Result is returned to caller */
-  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
-
-  DEBUGASSERT(backend);
-
-  /* if a path was not specified, do not pin */
-  if(!pinnedpubkey)
-    return CURLE_OK;
-
-  do {
-    SECURITY_STATUS sspi_status;
-    const char *x509_der;
-    DWORD x509_der_len;
-    struct Curl_X509certificate x509_parsed;
-    struct Curl_asn1Element *pubkey;
-
-    sspi_status =
-      Curl_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
-                                       SECPKG_ATTR_REMOTE_CERT_CONTEXT,
-                                       &pCertContextServer);
-
-    if((sspi_status != SEC_E_OK) || !pCertContextServer) {
-      char buffer[STRERROR_LEN];
-      failf(data, "schannel: Failed to read remote certificate context: %s",
-            Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
-      break; /* failed */
-    }
-
-    if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
-         (pCertContextServer->cbCertEncoded > 0)))
-      break;
-
-    x509_der = (const char *)pCertContextServer->pbCertEncoded;
-    x509_der_len = pCertContextServer->cbCertEncoded;
-    memset(&x509_parsed, 0, sizeof(x509_parsed));
-    if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
-      break;
-
-    pubkey = &x509_parsed.subjectPublicKeyInfo;
-    if(!pubkey->header || pubkey->end <= pubkey->header) {
-      failf(data, "SSL: failed retrieving public key from server certificate");
-      break;
-    }
-
-    result = Curl_pin_peer_pubkey(data,
-                                  pinnedpubkey,
-                                  (const unsigned char *)pubkey->header,
-                                  (size_t)(pubkey->end - pubkey->header));
-    if(result) {
-      failf(data, "SSL: public key does not match pinned public key");
-    }
-  } while(0);
-
-  if(pCertContextServer)
-    CertFreeCertificateContext(pCertContextServer);
-
-  return result;
-}
-
 static void schannel_checksum(const unsigned char *input,
                               size_t inputlen,
                               unsigned char *checksum,
index df04ec7e00f0dbee591a42ecb5646204476416c6..0149b51869d7b42c41bfed6c81f6bc5d32921445 100644 (file)
@@ -46,8 +46,6 @@
 #include "../rand.h"
 
 
-static bool cf_ssl_peer_key_is_global(const char *peer_key);
-
 /* a peer+tls-config we cache sessions for */
 struct Curl_ssl_scache_peer {
   char *ssl_peer_key;      /* id for peer + relevant TLS configuration */
@@ -69,6 +67,235 @@ struct Curl_ssl_scache_peer {
 
 #define GOOD_SCACHE(x) ((x) && (x)->magic == CURL_SCACHE_MAGIC)
 
+static CURLcode cf_ssl_peer_key_add_path(struct dynbuf *buf,
+                                         const char *name,
+                                         const char *path,
+                                         bool *is_local)
+{
+  if(path && path[0]) {
+    /* We try to add absolute paths, so that the session key can stay
+     * valid when used in another process with different CWD. However,
+     * when a path does not exist, this does not work. Then, we add
+     * the path as is. */
+#ifdef _WIN32
+    char abspath[_MAX_PATH];
+    if(_fullpath(abspath, path, _MAX_PATH))
+      return curlx_dyn_addf(buf, ":%s-%s", name, abspath);
+    *is_local = TRUE;
+#elif defined(HAVE_REALPATH)
+    if(path[0] != '/') {
+      char *abspath = realpath(path, NULL);
+      if(abspath) {
+        CURLcode r = curlx_dyn_addf(buf, ":%s-%s", name, abspath);
+        /* !checksrc! disable BANNEDFUNC 1 */
+        free(abspath); /* allocated by libc, free without memdebug */
+        return r;
+      }
+      *is_local = TRUE;
+    }
+#endif
+    return curlx_dyn_addf(buf, ":%s-%s", name, path);
+  }
+  return CURLE_OK;
+}
+
+static CURLcode cf_ssl_peer_key_add_hash(struct dynbuf *buf,
+                                         const char *name,
+                                         struct curl_blob *blob)
+{
+  CURLcode r = CURLE_OK;
+  if(blob && blob->len) {
+    unsigned char hash[CURL_SHA256_DIGEST_LENGTH];
+    size_t i;
+
+    r = curlx_dyn_addf(buf, ":%s-", name);
+    if(r)
+      goto out;
+    r = Curl_sha256it(hash, blob->data, blob->len);
+    if(r)
+      goto out;
+    for(i = 0; i < CURL_SHA256_DIGEST_LENGTH; ++i) {
+      r = curlx_dyn_addf(buf, "%02x", hash[i]);
+      if(r)
+        goto out;
+    }
+  }
+out:
+  return r;
+}
+
+#define CURL_SSLS_LOCAL_SUFFIX     ":L"
+#define CURL_SSLS_GLOBAL_SUFFIX    ":G"
+
+static bool cf_ssl_peer_key_is_global(const char *peer_key)
+{
+  size_t len = peer_key ? strlen(peer_key) : 0;
+  return (len > 2) &&
+         (peer_key[len - 1] == 'G') &&
+         (peer_key[len - 2] == ':');
+}
+
+CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
+                                const struct ssl_peer *peer,
+                                const char *tls_id,
+                                char **ppeer_key)
+{
+  struct ssl_primary_config *ssl = Curl_ssl_cf_get_primary_config(cf);
+  struct dynbuf buf;
+  size_t key_len;
+  bool is_local = FALSE;
+  CURLcode r;
+
+  *ppeer_key = NULL;
+  curlx_dyn_init(&buf, 10 * 1024);
+
+  r = curlx_dyn_addf(&buf, "%s:%d", peer->hostname, peer->port);
+  if(r)
+    goto out;
+
+  switch(peer->transport) {
+  case TRNSPRT_TCP:
+    break;
+  case TRNSPRT_UDP:
+    r = curlx_dyn_add(&buf, ":UDP");
+    break;
+  case TRNSPRT_QUIC:
+    r = curlx_dyn_add(&buf, ":QUIC");
+    break;
+  case TRNSPRT_UNIX:
+    r = curlx_dyn_add(&buf, ":UNIX");
+    break;
+  default:
+    r = curlx_dyn_addf(&buf, ":TRNSPRT-%d", peer->transport);
+    break;
+  }
+  if(r)
+    goto out;
+
+  if(!ssl->verifypeer) {
+    r = curlx_dyn_add(&buf, ":NO-VRFY-PEER");
+    if(r)
+      goto out;
+  }
+  if(!ssl->verifyhost) {
+    r = curlx_dyn_add(&buf, ":NO-VRFY-HOST");
+    if(r)
+      goto out;
+  }
+  if(ssl->verifystatus) {
+    r = curlx_dyn_add(&buf, ":VRFY-STATUS");
+    if(r)
+      goto out;
+  }
+  if(!ssl->verifypeer || !ssl->verifyhost) {
+    if(cf->conn->bits.conn_to_host) {
+      r = curlx_dyn_addf(&buf, ":CHOST-%s", cf->conn->conn_to_host.name);
+      if(r)
+        goto out;
+    }
+    if(cf->conn->bits.conn_to_port) {
+      r = curlx_dyn_addf(&buf, ":CPORT-%d", cf->conn->conn_to_port);
+      if(r)
+        goto out;
+    }
+  }
+
+  if(ssl->version || ssl->version_max) {
+    r = curlx_dyn_addf(&buf, ":TLSVER-%d-%d", ssl->version,
+                       (ssl->version_max >> 16));
+    if(r)
+      goto out;
+  }
+  if(ssl->ssl_options) {
+    r = curlx_dyn_addf(&buf, ":TLSOPT-%x", ssl->ssl_options);
+    if(r)
+      goto out;
+  }
+  if(ssl->cipher_list) {
+    r = curlx_dyn_addf(&buf, ":CIPHER-%s", ssl->cipher_list);
+    if(r)
+      goto out;
+  }
+  if(ssl->cipher_list13) {
+    r = curlx_dyn_addf(&buf, ":CIPHER13-%s", ssl->cipher_list13);
+    if(r)
+      goto out;
+  }
+  if(ssl->curves) {
+    r = curlx_dyn_addf(&buf, ":CURVES-%s", ssl->curves);
+    if(r)
+      goto out;
+  }
+  if(ssl->verifypeer) {
+    r = cf_ssl_peer_key_add_path(&buf, "CA", ssl->CAfile, &is_local);
+    if(r)
+      goto out;
+    r = cf_ssl_peer_key_add_path(&buf, "CApath", ssl->CApath, &is_local);
+    if(r)
+      goto out;
+    r = cf_ssl_peer_key_add_path(&buf, "CRL", ssl->CRLfile, &is_local);
+    if(r)
+      goto out;
+    r = cf_ssl_peer_key_add_path(&buf, "Issuer", ssl->issuercert, &is_local);
+    if(r)
+      goto out;
+    if(ssl->cert_blob) {
+      r = cf_ssl_peer_key_add_hash(&buf, "CertBlob", ssl->cert_blob);
+      if(r)
+        goto out;
+    }
+    if(ssl->ca_info_blob) {
+      r = cf_ssl_peer_key_add_hash(&buf, "CAInfoBlob", ssl->ca_info_blob);
+      if(r)
+        goto out;
+    }
+    if(ssl->issuercert_blob) {
+      r = cf_ssl_peer_key_add_hash(&buf, "IssuerBlob", ssl->issuercert_blob);
+      if(r)
+        goto out;
+    }
+  }
+  if(ssl->pinned_key && ssl->pinned_key[0]) {
+    r = curlx_dyn_addf(&buf, ":Pinned-%s", ssl->pinned_key);
+    if(r)
+      goto out;
+  }
+
+  if(ssl->clientcert && ssl->clientcert[0]) {
+    r = curlx_dyn_add(&buf, ":CCERT");
+    if(r)
+      goto out;
+  }
+#ifdef USE_TLS_SRP
+  if(ssl->username || ssl->password) {
+    r = curlx_dyn_add(&buf, ":SRP-AUTH");
+    if(r)
+      goto out;
+  }
+#endif
+
+  if(!tls_id || !tls_id[0]) {
+    r = CURLE_FAILED_INIT;
+    goto out;
+  }
+  r = curlx_dyn_addf(&buf, ":IMPL-%s", tls_id);
+  if(r)
+    goto out;
+
+  r = curlx_dyn_addf(&buf, is_local ?
+                     CURL_SSLS_LOCAL_SUFFIX : CURL_SSLS_GLOBAL_SUFFIX);
+  if(r)
+    goto out;
+
+  *ppeer_key = curlx_dyn_take(&buf, &key_len);
+  /* we just added printable char, and dynbuf always null-terminates, no need
+   * to track length */
+
+out:
+  curlx_dyn_free(&buf);
+  return r;
+}
+
 struct Curl_ssl_scache {
   unsigned int magic;
   struct Curl_ssl_scache_peer *peers;
@@ -368,235 +595,6 @@ void Curl_ssl_scache_unlock(struct Curl_easy *data)
     Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
 }
 
-static CURLcode cf_ssl_peer_key_add_path(struct dynbuf *buf,
-                                         const char *name,
-                                         const char *path,
-                                         bool *is_local)
-{
-  if(path && path[0]) {
-    /* We try to add absolute paths, so that the session key can stay
-     * valid when used in another process with different CWD. However,
-     * when a path does not exist, this does not work. Then, we add
-     * the path as is. */
-#ifdef _WIN32
-    char abspath[_MAX_PATH];
-    if(_fullpath(abspath, path, _MAX_PATH))
-      return curlx_dyn_addf(buf, ":%s-%s", name, abspath);
-    *is_local = TRUE;
-#elif defined(HAVE_REALPATH)
-    if(path[0] != '/') {
-      char *abspath = realpath(path, NULL);
-      if(abspath) {
-        CURLcode r = curlx_dyn_addf(buf, ":%s-%s", name, abspath);
-        /* !checksrc! disable BANNEDFUNC 1 */
-        free(abspath); /* allocated by libc, free without memdebug */
-        return r;
-      }
-      *is_local = TRUE;
-    }
-#endif
-    return curlx_dyn_addf(buf, ":%s-%s", name, path);
-  }
-  return CURLE_OK;
-}
-
-static CURLcode cf_ssl_peer_key_add_hash(struct dynbuf *buf,
-                                         const char *name,
-                                         struct curl_blob *blob)
-{
-  CURLcode r = CURLE_OK;
-  if(blob && blob->len) {
-    unsigned char hash[CURL_SHA256_DIGEST_LENGTH];
-    size_t i;
-
-    r = curlx_dyn_addf(buf, ":%s-", name);
-    if(r)
-      goto out;
-    r = Curl_sha256it(hash, blob->data, blob->len);
-    if(r)
-      goto out;
-    for(i = 0; i < CURL_SHA256_DIGEST_LENGTH; ++i) {
-      r = curlx_dyn_addf(buf, "%02x", hash[i]);
-      if(r)
-        goto out;
-    }
-  }
-out:
-  return r;
-}
-
-#define CURL_SSLS_LOCAL_SUFFIX     ":L"
-#define CURL_SSLS_GLOBAL_SUFFIX    ":G"
-
-static bool cf_ssl_peer_key_is_global(const char *peer_key)
-{
-  size_t len = peer_key ? strlen(peer_key) : 0;
-  return (len > 2) &&
-         (peer_key[len - 1] == 'G') &&
-         (peer_key[len - 2] == ':');
-}
-
-CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
-                                const struct ssl_peer *peer,
-                                const char *tls_id,
-                                char **ppeer_key)
-{
-  struct ssl_primary_config *ssl = Curl_ssl_cf_get_primary_config(cf);
-  struct dynbuf buf;
-  size_t key_len;
-  bool is_local = FALSE;
-  CURLcode r;
-
-  *ppeer_key = NULL;
-  curlx_dyn_init(&buf, 10 * 1024);
-
-  r = curlx_dyn_addf(&buf, "%s:%d", peer->hostname, peer->port);
-  if(r)
-    goto out;
-
-  switch(peer->transport) {
-  case TRNSPRT_TCP:
-    break;
-  case TRNSPRT_UDP:
-    r = curlx_dyn_add(&buf, ":UDP");
-    break;
-  case TRNSPRT_QUIC:
-    r = curlx_dyn_add(&buf, ":QUIC");
-    break;
-  case TRNSPRT_UNIX:
-    r = curlx_dyn_add(&buf, ":UNIX");
-    break;
-  default:
-    r = curlx_dyn_addf(&buf, ":TRNSPRT-%d", peer->transport);
-    break;
-  }
-  if(r)
-    goto out;
-
-  if(!ssl->verifypeer) {
-    r = curlx_dyn_add(&buf, ":NO-VRFY-PEER");
-    if(r)
-      goto out;
-  }
-  if(!ssl->verifyhost) {
-    r = curlx_dyn_add(&buf, ":NO-VRFY-HOST");
-    if(r)
-      goto out;
-  }
-  if(ssl->verifystatus) {
-    r = curlx_dyn_add(&buf, ":VRFY-STATUS");
-    if(r)
-      goto out;
-  }
-  if(!ssl->verifypeer || !ssl->verifyhost) {
-    if(cf->conn->bits.conn_to_host) {
-      r = curlx_dyn_addf(&buf, ":CHOST-%s", cf->conn->conn_to_host.name);
-      if(r)
-        goto out;
-    }
-    if(cf->conn->bits.conn_to_port) {
-      r = curlx_dyn_addf(&buf, ":CPORT-%d", cf->conn->conn_to_port);
-      if(r)
-        goto out;
-    }
-  }
-
-  if(ssl->version || ssl->version_max) {
-    r = curlx_dyn_addf(&buf, ":TLSVER-%d-%d", ssl->version,
-                       (ssl->version_max >> 16));
-    if(r)
-      goto out;
-  }
-  if(ssl->ssl_options) {
-    r = curlx_dyn_addf(&buf, ":TLSOPT-%x", ssl->ssl_options);
-    if(r)
-      goto out;
-  }
-  if(ssl->cipher_list) {
-    r = curlx_dyn_addf(&buf, ":CIPHER-%s", ssl->cipher_list);
-    if(r)
-      goto out;
-  }
-  if(ssl->cipher_list13) {
-    r = curlx_dyn_addf(&buf, ":CIPHER13-%s", ssl->cipher_list13);
-    if(r)
-      goto out;
-  }
-  if(ssl->curves) {
-    r = curlx_dyn_addf(&buf, ":CURVES-%s", ssl->curves);
-    if(r)
-      goto out;
-  }
-  if(ssl->verifypeer) {
-    r = cf_ssl_peer_key_add_path(&buf, "CA", ssl->CAfile, &is_local);
-    if(r)
-      goto out;
-    r = cf_ssl_peer_key_add_path(&buf, "CApath", ssl->CApath, &is_local);
-    if(r)
-      goto out;
-    r = cf_ssl_peer_key_add_path(&buf, "CRL", ssl->CRLfile, &is_local);
-    if(r)
-      goto out;
-    r = cf_ssl_peer_key_add_path(&buf, "Issuer", ssl->issuercert, &is_local);
-    if(r)
-      goto out;
-    if(ssl->cert_blob) {
-      r = cf_ssl_peer_key_add_hash(&buf, "CertBlob", ssl->cert_blob);
-      if(r)
-        goto out;
-    }
-    if(ssl->ca_info_blob) {
-      r = cf_ssl_peer_key_add_hash(&buf, "CAInfoBlob", ssl->ca_info_blob);
-      if(r)
-        goto out;
-    }
-    if(ssl->issuercert_blob) {
-      r = cf_ssl_peer_key_add_hash(&buf, "IssuerBlob", ssl->issuercert_blob);
-      if(r)
-        goto out;
-    }
-  }
-  if(ssl->pinned_key && ssl->pinned_key[0]) {
-    r = curlx_dyn_addf(&buf, ":Pinned-%s", ssl->pinned_key);
-    if(r)
-      goto out;
-  }
-
-  if(ssl->clientcert && ssl->clientcert[0]) {
-    r = curlx_dyn_add(&buf, ":CCERT");
-    if(r)
-      goto out;
-  }
-#ifdef USE_TLS_SRP
-  if(ssl->username || ssl->password) {
-    r = curlx_dyn_add(&buf, ":SRP-AUTH");
-    if(r)
-      goto out;
-  }
-#endif
-
-  if(!tls_id || !tls_id[0]) {
-    r = CURLE_FAILED_INIT;
-    goto out;
-  }
-  r = curlx_dyn_addf(&buf, ":IMPL-%s", tls_id);
-  if(r)
-    goto out;
-
-  r = curlx_dyn_addf(&buf, is_local ?
-                     CURL_SSLS_LOCAL_SUFFIX : CURL_SSLS_GLOBAL_SUFFIX);
-  if(r)
-    goto out;
-
-  *ppeer_key = curlx_dyn_take(&buf, &key_len);
-  /* we just added printable char, and dynbuf always null-terminates, no need
-   * to track length */
-
-out:
-  curlx_dyn_free(&buf);
-  return r;
-}
-
 static bool cf_ssl_scache_match_auth(struct Curl_ssl_scache_peer *peer,
                                      struct ssl_primary_config *conn_config)
 {
index 34dfd331ae276e56a2603f1d15e36288a0375997..80272ea3648138616cb13989bf4210afc21ded74 100644 (file)
 #undef USE_BIO_CHAIN
 #endif
 
-static CURLcode wssl_connect(struct Curl_cfilter *cf,
-                             struct Curl_easy *data,
-                             bool *done);
-
 #ifdef OPENSSL_EXTRA
 /*
  * Availability note:
index 6a566c30b097593bad9b1b1582780ef31743890a..0c8568ff62ff8a6c0931089b3d96e0762455612a 100644 (file)
 #include "tool_util.h"
 #include "toolx/tool_time.h"
 
-static void dump(const char *timebuf, const char *idsbuf, const char *text,
-                 FILE *stream, const unsigned char *ptr, size_t size,
-                 trace tracetype, curl_infotype infotype);
-
 /*
  * Return the formatted HH:MM:SS for the tv_sec given.
  */
@@ -69,6 +65,60 @@ static void log_line_start(FILE *log, const char *timebuf,
     fputs(s_infotype[type], log);
 }
 
+static void dump(const char *timebuf, const char *idsbuf, const char *text,
+                 FILE *stream, const unsigned char *ptr, size_t size,
+                 trace tracetype, curl_infotype infotype)
+{
+  size_t i;
+  size_t c;
+
+  unsigned int width = 0x10;
+
+  if(tracetype == TRACE_ASCII)
+    /* without the hex output, we can fit more on screen */
+    width = 0x40;
+
+  curl_mfprintf(stream, "%s%s%s, %zu bytes (0x%zx)\n", timebuf, idsbuf,
+                text, size, size);
+
+  for(i = 0; i < size; i += width) {
+
+    curl_mfprintf(stream, "%04zx: ", i);
+
+    if(tracetype == TRACE_BIN) {
+      /* hex not disabled, show it */
+      for(c = 0; c < width; c++)
+        if(i + c < size)
+          curl_mfprintf(stream, "%02x ", ptr[i + c]);
+        else
+          fputs("   ", stream);
+    }
+
+    for(c = 0; (c < width) && (i + c < size); c++) {
+      /* check for 0D0A; if found, skip past and start a new line of output */
+      if((tracetype == TRACE_ASCII) &&
+         (i + c + 1 < size) && (ptr[i + c] == 0x0D) &&
+         (ptr[i + c + 1] == 0x0A)) {
+        i += (c + 2 - width);
+        break;
+      }
+      (void)infotype;
+      curl_mfprintf(stream, "%c",
+                    ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x7F)) ?
+                    ptr[i + c] : UNPRINTABLE_CHAR);
+      /* check again for 0D0A, to avoid an extra \n if it is at width */
+      if((tracetype == TRACE_ASCII) &&
+         (i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) &&
+         (ptr[i + c + 2] == 0x0A)) {
+        i += (c + 3 - width);
+        break;
+      }
+    }
+    fputc('\n', stream); /* newline */
+  }
+  fflush(stream);
+}
+
 #define TRC_IDS_FORMAT_IDS_1  "[%" CURL_FORMAT_CURL_OFF_T "-x] "
 #define TRC_IDS_FORMAT_IDS_2  "[%" CURL_FORMAT_CURL_OFF_T "-%" \
                                    CURL_FORMAT_CURL_OFF_T "] "
@@ -230,57 +280,3 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
        global->tracetype, type);
   return 0;
 }
-
-static void dump(const char *timebuf, const char *idsbuf, const char *text,
-                 FILE *stream, const unsigned char *ptr, size_t size,
-                 trace tracetype, curl_infotype infotype)
-{
-  size_t i;
-  size_t c;
-
-  unsigned int width = 0x10;
-
-  if(tracetype == TRACE_ASCII)
-    /* without the hex output, we can fit more on screen */
-    width = 0x40;
-
-  curl_mfprintf(stream, "%s%s%s, %zu bytes (0x%zx)\n", timebuf, idsbuf,
-                text, size, size);
-
-  for(i = 0; i < size; i += width) {
-
-    curl_mfprintf(stream, "%04zx: ", i);
-
-    if(tracetype == TRACE_BIN) {
-      /* hex not disabled, show it */
-      for(c = 0; c < width; c++)
-        if(i + c < size)
-          curl_mfprintf(stream, "%02x ", ptr[i + c]);
-        else
-          fputs("   ", stream);
-    }
-
-    for(c = 0; (c < width) && (i + c < size); c++) {
-      /* check for 0D0A; if found, skip past and start a new line of output */
-      if((tracetype == TRACE_ASCII) &&
-         (i + c + 1 < size) && (ptr[i + c] == 0x0D) &&
-         (ptr[i + c + 1] == 0x0A)) {
-        i += (c + 2 - width);
-        break;
-      }
-      (void)infotype;
-      curl_mfprintf(stream, "%c",
-                    ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x7F)) ?
-                    ptr[i + c] : UNPRINTABLE_CHAR);
-      /* check again for 0D0A, to avoid an extra \n if it is at width */
-      if((tracetype == TRACE_ASCII) &&
-         (i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) &&
-         (ptr[i + c + 2] == 0x0A)) {
-        i += (c + 3 - width);
-        break;
-      }
-    }
-    fputc('\n', stream); /* newline */
-  }
-  fflush(stream);
-}
index 25c9622312bbc5b7cec2eeb698fdde016c1ea525..2ade080a1813282516c12dcfb285d10c9c4d23fd 100644 (file)
 #include "tool_writeout.h"
 #include "tool_writeout_json.h"
 
-static int writeTime(FILE *stream, const struct writeoutvar *wovar,
-                     struct per_transfer *per, CURLcode per_result,
-                     bool use_json);
-
-static int writeString(FILE *stream, const struct writeoutvar *wovar,
-                       struct per_transfer *per, CURLcode per_result,
-                       bool use_json);
-
-static int writeLong(FILE *stream, const struct writeoutvar *wovar,
-                     struct per_transfer *per, CURLcode per_result,
-                     bool use_json);
-
-static int writeOffset(FILE *stream, const struct writeoutvar *wovar,
-                       struct per_transfer *per, CURLcode per_result,
-                       bool use_json);
-
 struct httpmap {
   const char *str;
   int num;
@@ -57,103 +41,6 @@ static const struct httpmap http_version[] = {
   { NULL, 0 } /* end of list */
 };
 
-/* The designated write function should be the same as the CURLINFO return type
-   with exceptions special cased in the respective function. For example,
-   http_version uses CURLINFO_HTTP_VERSION which returns the version as a long,
-   however it is output as a string and therefore is handled in writeString.
-
-   Yes: "http_version": "1.1"
-   No:  "http_version": 1.1
-
-   Variable names MUST be in alphabetical order.
-   */
-static const struct writeoutvar variables[] = {
-  { "certs", VAR_CERT, CURLINFO_NONE, writeString },
-  { "conn_id", VAR_CONN_ID, CURLINFO_CONN_ID, writeOffset },
-  { "content_type", VAR_CONTENT_TYPE, CURLINFO_CONTENT_TYPE, writeString },
-  { "errormsg", VAR_ERRORMSG, CURLINFO_NONE, writeString },
-  { "exitcode", VAR_EXITCODE, CURLINFO_NONE, writeLong },
-  { "filename_effective", VAR_EFFECTIVE_FILENAME, CURLINFO_NONE, writeString },
-  { "ftp_entry_path", VAR_FTP_ENTRY_PATH, CURLINFO_FTP_ENTRY_PATH,
-    writeString },
-  { "header_json", VAR_HEADER_JSON, CURLINFO_NONE, NULL },
-  { "http_code", VAR_HTTP_CODE, CURLINFO_RESPONSE_CODE, writeLong },
-  { "http_connect", VAR_HTTP_CODE_PROXY, CURLINFO_HTTP_CONNECTCODE,
-    writeLong },
-  { "http_version", VAR_HTTP_VERSION, CURLINFO_HTTP_VERSION, writeString },
-  { "json", VAR_JSON, CURLINFO_NONE, NULL },
-  { "local_ip", VAR_LOCAL_IP, CURLINFO_LOCAL_IP, writeString },
-  { "local_port", VAR_LOCAL_PORT, CURLINFO_LOCAL_PORT, writeLong },
-  { "method", VAR_EFFECTIVE_METHOD, CURLINFO_EFFECTIVE_METHOD, writeString },
-  { "num_certs", VAR_NUM_CERTS, CURLINFO_NONE, writeLong },
-  { "num_connects", VAR_NUM_CONNECTS, CURLINFO_NUM_CONNECTS, writeLong },
-  { "num_headers", VAR_NUM_HEADERS, CURLINFO_NONE, writeLong },
-  { "num_redirects", VAR_REDIRECT_COUNT, CURLINFO_REDIRECT_COUNT, writeLong },
-  { "num_retries", VAR_NUM_RETRY, CURLINFO_NONE, writeLong },
-  { "onerror", VAR_ONERROR, CURLINFO_NONE, NULL },
-  { "proxy_ssl_verify_result", VAR_PROXY_SSL_VERIFY_RESULT,
-    CURLINFO_PROXY_SSL_VERIFYRESULT, writeLong },
-  { "proxy_used", VAR_PROXY_USED, CURLINFO_USED_PROXY, writeLong },
-  { "redirect_url", VAR_REDIRECT_URL, CURLINFO_REDIRECT_URL, writeString },
-  { "referer", VAR_REFERER, CURLINFO_REFERER, writeString },
-  { "remote_ip", VAR_PRIMARY_IP, CURLINFO_PRIMARY_IP, writeString },
-  { "remote_port", VAR_PRIMARY_PORT, CURLINFO_PRIMARY_PORT, writeLong },
-  { "response_code", VAR_HTTP_CODE, CURLINFO_RESPONSE_CODE, writeLong },
-  { "scheme", VAR_SCHEME, CURLINFO_SCHEME, writeString },
-  { "size_download", VAR_SIZE_DOWNLOAD, CURLINFO_SIZE_DOWNLOAD_T,
-    writeOffset },
-  { "size_header", VAR_HEADER_SIZE, CURLINFO_HEADER_SIZE, writeLong },
-  { "size_request", VAR_REQUEST_SIZE, CURLINFO_REQUEST_SIZE, writeLong },
-  { "size_upload", VAR_SIZE_UPLOAD, CURLINFO_SIZE_UPLOAD_T, writeOffset },
-  { "speed_download", VAR_SPEED_DOWNLOAD, CURLINFO_SPEED_DOWNLOAD_T,
-    writeOffset },
-  { "speed_upload", VAR_SPEED_UPLOAD, CURLINFO_SPEED_UPLOAD_T, writeOffset },
-  { "ssl_verify_result", VAR_SSL_VERIFY_RESULT, CURLINFO_SSL_VERIFYRESULT,
-    writeLong },
-  { "stderr", VAR_STDERR, CURLINFO_NONE, NULL },
-  { "stdout", VAR_STDOUT, CURLINFO_NONE, NULL },
-  { "time_appconnect", VAR_APPCONNECT_TIME, CURLINFO_APPCONNECT_TIME_T,
-    writeTime },
-  { "time_connect", VAR_CONNECT_TIME, CURLINFO_CONNECT_TIME_T, writeTime },
-  { "time_namelookup", VAR_NAMELOOKUP_TIME, CURLINFO_NAMELOOKUP_TIME_T,
-    writeTime },
-  { "time_posttransfer", VAR_POSTTRANSFER_TIME, CURLINFO_POSTTRANSFER_TIME_T,
-    writeTime },
-  { "time_pretransfer", VAR_PRETRANSFER_TIME, CURLINFO_PRETRANSFER_TIME_T,
-    writeTime },
-  { "time_queue", VAR_QUEUE_TIME, CURLINFO_QUEUE_TIME_T, writeTime },
-  { "time_redirect", VAR_REDIRECT_TIME, CURLINFO_REDIRECT_TIME_T, writeTime },
-  { "time_starttransfer", VAR_STARTTRANSFER_TIME,
-    CURLINFO_STARTTRANSFER_TIME_T, writeTime },
-  { "time_total", VAR_TOTAL_TIME, CURLINFO_TOTAL_TIME_T, writeTime },
-  { "tls_earlydata", VAR_TLS_EARLYDATA_SENT, CURLINFO_EARLYDATA_SENT_T,
-    writeOffset },
-  { "url", VAR_INPUT_URL, CURLINFO_NONE, writeString },
-  { "url.fragment", VAR_INPUT_URLFRAGMENT, CURLINFO_NONE, writeString },
-  { "url.host", VAR_INPUT_URLHOST, CURLINFO_NONE, writeString },
-  { "url.options", VAR_INPUT_URLOPTIONS, CURLINFO_NONE, writeString },
-  { "url.password", VAR_INPUT_URLPASSWORD, CURLINFO_NONE, writeString },
-  { "url.path", VAR_INPUT_URLPATH, CURLINFO_NONE, writeString },
-  { "url.port", VAR_INPUT_URLPORT, CURLINFO_NONE, writeString },
-  { "url.query", VAR_INPUT_URLQUERY, CURLINFO_NONE, writeString },
-  { "url.scheme", VAR_INPUT_URLSCHEME, CURLINFO_NONE, writeString },
-  { "url.user", VAR_INPUT_URLUSER, CURLINFO_NONE, writeString },
-  { "url.zoneid", VAR_INPUT_URLZONEID, CURLINFO_NONE, writeString },
-  { "url_effective", VAR_EFFECTIVE_URL, CURLINFO_EFFECTIVE_URL, writeString },
-  { "urle.fragment", VAR_INPUT_URLEFRAGMENT, CURLINFO_NONE, writeString },
-  { "urle.host", VAR_INPUT_URLEHOST, CURLINFO_NONE, writeString },
-  { "urle.options", VAR_INPUT_URLEOPTIONS, CURLINFO_NONE, writeString },
-  { "urle.password", VAR_INPUT_URLEPASSWORD, CURLINFO_NONE, writeString },
-  { "urle.path", VAR_INPUT_URLEPATH, CURLINFO_NONE, writeString },
-  { "urle.port", VAR_INPUT_URLEPORT, CURLINFO_NONE, writeString },
-  { "urle.query", VAR_INPUT_URLEQUERY, CURLINFO_NONE, writeString },
-  { "urle.scheme", VAR_INPUT_URLESCHEME, CURLINFO_NONE, writeString },
-  { "urle.user", VAR_INPUT_URLEUSER, CURLINFO_NONE, writeString },
-  { "urle.zoneid", VAR_INPUT_URLEZONEID, CURLINFO_NONE, writeString },
-  { "urlnum", VAR_URLNUM, CURLINFO_NONE, writeOffset },
-  { "xfer_id", VAR_EASY_ID, CURLINFO_XFER_ID, writeOffset }
-};
-
 static int writeTime(FILE *stream, const struct writeoutvar *wovar,
                      struct per_transfer *per, CURLcode per_result,
                      bool use_json)
@@ -530,13 +417,102 @@ static int writeOffset(FILE *stream, const struct writeoutvar *wovar,
   return 1; /* return 1 if anything was written */
 }
 
-static int matchvar(const void *m1, const void *m2)
-{
-  const struct writeoutvar *v1 = m1;
-  const struct writeoutvar *v2 = m2;
+/* The designated write function should be the same as the CURLINFO return type
+   with exceptions special cased in the respective function. For example,
+   http_version uses CURLINFO_HTTP_VERSION which returns the version as a long,
+   however it is output as a string and therefore is handled in writeString.
 
-  return strcmp(v1->name, v2->name);
-}
+   Yes: "http_version": "1.1"
+   No:  "http_version": 1.1
+
+   Variable names MUST be in alphabetical order.
+   */
+static const struct writeoutvar variables[] = {
+  { "certs", VAR_CERT, CURLINFO_NONE, writeString },
+  { "conn_id", VAR_CONN_ID, CURLINFO_CONN_ID, writeOffset },
+  { "content_type", VAR_CONTENT_TYPE, CURLINFO_CONTENT_TYPE, writeString },
+  { "errormsg", VAR_ERRORMSG, CURLINFO_NONE, writeString },
+  { "exitcode", VAR_EXITCODE, CURLINFO_NONE, writeLong },
+  { "filename_effective", VAR_EFFECTIVE_FILENAME, CURLINFO_NONE, writeString },
+  { "ftp_entry_path", VAR_FTP_ENTRY_PATH, CURLINFO_FTP_ENTRY_PATH,
+    writeString },
+  { "header_json", VAR_HEADER_JSON, CURLINFO_NONE, NULL },
+  { "http_code", VAR_HTTP_CODE, CURLINFO_RESPONSE_CODE, writeLong },
+  { "http_connect", VAR_HTTP_CODE_PROXY, CURLINFO_HTTP_CONNECTCODE,
+    writeLong },
+  { "http_version", VAR_HTTP_VERSION, CURLINFO_HTTP_VERSION, writeString },
+  { "json", VAR_JSON, CURLINFO_NONE, NULL },
+  { "local_ip", VAR_LOCAL_IP, CURLINFO_LOCAL_IP, writeString },
+  { "local_port", VAR_LOCAL_PORT, CURLINFO_LOCAL_PORT, writeLong },
+  { "method", VAR_EFFECTIVE_METHOD, CURLINFO_EFFECTIVE_METHOD, writeString },
+  { "num_certs", VAR_NUM_CERTS, CURLINFO_NONE, writeLong },
+  { "num_connects", VAR_NUM_CONNECTS, CURLINFO_NUM_CONNECTS, writeLong },
+  { "num_headers", VAR_NUM_HEADERS, CURLINFO_NONE, writeLong },
+  { "num_redirects", VAR_REDIRECT_COUNT, CURLINFO_REDIRECT_COUNT, writeLong },
+  { "num_retries", VAR_NUM_RETRY, CURLINFO_NONE, writeLong },
+  { "onerror", VAR_ONERROR, CURLINFO_NONE, NULL },
+  { "proxy_ssl_verify_result", VAR_PROXY_SSL_VERIFY_RESULT,
+    CURLINFO_PROXY_SSL_VERIFYRESULT, writeLong },
+  { "proxy_used", VAR_PROXY_USED, CURLINFO_USED_PROXY, writeLong },
+  { "redirect_url", VAR_REDIRECT_URL, CURLINFO_REDIRECT_URL, writeString },
+  { "referer", VAR_REFERER, CURLINFO_REFERER, writeString },
+  { "remote_ip", VAR_PRIMARY_IP, CURLINFO_PRIMARY_IP, writeString },
+  { "remote_port", VAR_PRIMARY_PORT, CURLINFO_PRIMARY_PORT, writeLong },
+  { "response_code", VAR_HTTP_CODE, CURLINFO_RESPONSE_CODE, writeLong },
+  { "scheme", VAR_SCHEME, CURLINFO_SCHEME, writeString },
+  { "size_download", VAR_SIZE_DOWNLOAD, CURLINFO_SIZE_DOWNLOAD_T,
+    writeOffset },
+  { "size_header", VAR_HEADER_SIZE, CURLINFO_HEADER_SIZE, writeLong },
+  { "size_request", VAR_REQUEST_SIZE, CURLINFO_REQUEST_SIZE, writeLong },
+  { "size_upload", VAR_SIZE_UPLOAD, CURLINFO_SIZE_UPLOAD_T, writeOffset },
+  { "speed_download", VAR_SPEED_DOWNLOAD, CURLINFO_SPEED_DOWNLOAD_T,
+    writeOffset },
+  { "speed_upload", VAR_SPEED_UPLOAD, CURLINFO_SPEED_UPLOAD_T, writeOffset },
+  { "ssl_verify_result", VAR_SSL_VERIFY_RESULT, CURLINFO_SSL_VERIFYRESULT,
+    writeLong },
+  { "stderr", VAR_STDERR, CURLINFO_NONE, NULL },
+  { "stdout", VAR_STDOUT, CURLINFO_NONE, NULL },
+  { "time_appconnect", VAR_APPCONNECT_TIME, CURLINFO_APPCONNECT_TIME_T,
+    writeTime },
+  { "time_connect", VAR_CONNECT_TIME, CURLINFO_CONNECT_TIME_T, writeTime },
+  { "time_namelookup", VAR_NAMELOOKUP_TIME, CURLINFO_NAMELOOKUP_TIME_T,
+    writeTime },
+  { "time_posttransfer", VAR_POSTTRANSFER_TIME, CURLINFO_POSTTRANSFER_TIME_T,
+    writeTime },
+  { "time_pretransfer", VAR_PRETRANSFER_TIME, CURLINFO_PRETRANSFER_TIME_T,
+    writeTime },
+  { "time_queue", VAR_QUEUE_TIME, CURLINFO_QUEUE_TIME_T, writeTime },
+  { "time_redirect", VAR_REDIRECT_TIME, CURLINFO_REDIRECT_TIME_T, writeTime },
+  { "time_starttransfer", VAR_STARTTRANSFER_TIME,
+    CURLINFO_STARTTRANSFER_TIME_T, writeTime },
+  { "time_total", VAR_TOTAL_TIME, CURLINFO_TOTAL_TIME_T, writeTime },
+  { "tls_earlydata", VAR_TLS_EARLYDATA_SENT, CURLINFO_EARLYDATA_SENT_T,
+    writeOffset },
+  { "url", VAR_INPUT_URL, CURLINFO_NONE, writeString },
+  { "url.fragment", VAR_INPUT_URLFRAGMENT, CURLINFO_NONE, writeString },
+  { "url.host", VAR_INPUT_URLHOST, CURLINFO_NONE, writeString },
+  { "url.options", VAR_INPUT_URLOPTIONS, CURLINFO_NONE, writeString },
+  { "url.password", VAR_INPUT_URLPASSWORD, CURLINFO_NONE, writeString },
+  { "url.path", VAR_INPUT_URLPATH, CURLINFO_NONE, writeString },
+  { "url.port", VAR_INPUT_URLPORT, CURLINFO_NONE, writeString },
+  { "url.query", VAR_INPUT_URLQUERY, CURLINFO_NONE, writeString },
+  { "url.scheme", VAR_INPUT_URLSCHEME, CURLINFO_NONE, writeString },
+  { "url.user", VAR_INPUT_URLUSER, CURLINFO_NONE, writeString },
+  { "url.zoneid", VAR_INPUT_URLZONEID, CURLINFO_NONE, writeString },
+  { "url_effective", VAR_EFFECTIVE_URL, CURLINFO_EFFECTIVE_URL, writeString },
+  { "urle.fragment", VAR_INPUT_URLEFRAGMENT, CURLINFO_NONE, writeString },
+  { "urle.host", VAR_INPUT_URLEHOST, CURLINFO_NONE, writeString },
+  { "urle.options", VAR_INPUT_URLEOPTIONS, CURLINFO_NONE, writeString },
+  { "urle.password", VAR_INPUT_URLEPASSWORD, CURLINFO_NONE, writeString },
+  { "urle.path", VAR_INPUT_URLEPATH, CURLINFO_NONE, writeString },
+  { "urle.port", VAR_INPUT_URLEPORT, CURLINFO_NONE, writeString },
+  { "urle.query", VAR_INPUT_URLEQUERY, CURLINFO_NONE, writeString },
+  { "urle.scheme", VAR_INPUT_URLESCHEME, CURLINFO_NONE, writeString },
+  { "urle.user", VAR_INPUT_URLEUSER, CURLINFO_NONE, writeString },
+  { "urle.zoneid", VAR_INPUT_URLEZONEID, CURLINFO_NONE, writeString },
+  { "urlnum", VAR_URLNUM, CURLINFO_NONE, writeOffset },
+  { "xfer_id", VAR_EASY_ID, CURLINFO_XFER_ID, writeOffset }
+};
 
 #define MAX_WRITEOUT_NAME_LENGTH 24
 
@@ -720,6 +696,14 @@ static void output_header(struct per_transfer *per,
   *pptr = ptr;
 }
 
+static int matchvar(const void *m1, const void *m2)
+{
+  const struct writeoutvar *v1 = m1;
+  const struct writeoutvar *v2 = m2;
+
+  return strcmp(v1->name, v2->name);
+}
+
 void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
                  CURLcode per_result)
 {