]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
lib: move handling of `data->req.writer_stack` into Curl_client_write()
authorStefan Eissing <stefan@eissing.org>
Wed, 20 Sep 2023 09:59:16 +0000 (11:59 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 28 Sep 2023 08:00:13 +0000 (10:00 +0200)
- move definitions from content_encoding.h to sendf.h
- move create/cleanup/add code into sendf.c
- installed content_encoding writers will always be called
  on Curl_client_write(CLIENTWRITE_BODY)
- Curl_client_cleanup() frees writers and tempbuffers from
  paused transfers, irregardless of protocol

Closes #11908

lib/c-hyper.c
lib/content_encoding.c
lib/content_encoding.h
lib/http.c
lib/http_chunks.c
lib/multi.c
lib/sendf.c
lib/sendf.h
lib/transfer.c
lib/url.c

index c558955c9d4cbd9b815dd17af529def69c68717e..5726ff1cc3a0b565b446fc57e15fac368ede7e56 100644 (file)
@@ -246,11 +246,7 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
   if(0 == len)
     return HYPER_ITER_CONTINUE;
   Curl_debug(data, CURLINFO_DATA_IN, buf, len);
-  if(!data->set.http_ce_skip && k->writer_stack)
-    /* content-encoded data */
-    result = Curl_unencode_write(data, k->writer_stack, buf, len);
-  else
-    result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
+  result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
 
   if(result) {
     data->state.hresult = result;
index efbe7cb18d1e671ada16e496b6dceb9e1cda1138..be7c075e949855695b75b2b9309ef9e4c4f561eb 100644 (file)
@@ -280,9 +280,6 @@ static CURLcode deflate_init_writer(struct Curl_easy *data,
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
 
-  if(!writer->downstream)
-    return CURLE_WRITE_ERROR;
-
   /* Initialize zlib */
   z->zalloc = (alloc_func) zalloc_cb;
   z->zfree = (free_func) zfree_cb;
@@ -337,9 +334,6 @@ static CURLcode gzip_init_writer(struct Curl_easy *data,
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
 
-  if(!writer->downstream)
-    return CURLE_WRITE_ERROR;
-
   /* Initialize zlib */
   z->zalloc = (alloc_func) zalloc_cb;
   z->zfree = (free_func) zfree_cb;
@@ -647,9 +641,6 @@ static CURLcode brotli_init_writer(struct Curl_easy *data,
   struct brotli_writer *bp = (struct brotli_writer *) writer;
   (void) data;
 
-  if(!writer->downstream)
-    return CURLE_WRITE_ERROR;
-
   bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL);
   return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY;
 }
@@ -741,9 +732,6 @@ static CURLcode zstd_init_writer(struct Curl_easy *data,
 
   (void)data;
 
-  if(!writer->downstream)
-    return CURLE_WRITE_ERROR;
-
   zp->zds = ZSTD_createDStream();
   zp->decomp = NULL;
   return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
@@ -822,8 +810,9 @@ static const struct content_encoding zstd_encoding = {
 static CURLcode identity_init_writer(struct Curl_easy *data,
                                      struct contenc_writer *writer)
 {
-  (void) data;
-  return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
+  (void)data;
+  (void)writer;
+  return CURLE_OK;
 }
 
 static CURLcode identity_unencode_write(struct Curl_easy *data,
@@ -903,51 +892,13 @@ char *Curl_all_content_encodings(void)
 }
 
 
-/* Real client writer: no downstream. */
-static CURLcode client_init_writer(struct Curl_easy *data,
-                                   struct contenc_writer *writer)
-{
-  (void) data;
-  return writer->downstream? CURLE_WRITE_ERROR: CURLE_OK;
-}
-
-static CURLcode client_unencode_write(struct Curl_easy *data,
-                                      struct contenc_writer *writer,
-                                      const char *buf, size_t nbytes)
-{
-  struct SingleRequest *k = &data->req;
-
-  (void) writer;
-
-  if(!nbytes || k->ignorebody)
-    return CURLE_OK;
-
-  return Curl_client_write(data, CLIENTWRITE_BODY, (char *) buf, nbytes);
-}
-
-static void client_close_writer(struct Curl_easy *data,
-                                struct contenc_writer *writer)
-{
-  (void) data;
-  (void) writer;
-}
-
-static const struct content_encoding client_encoding = {
-  NULL,
-  NULL,
-  client_init_writer,
-  client_unencode_write,
-  client_close_writer,
-  sizeof(struct contenc_writer)
-};
-
-
 /* Deferred error dummy writer. */
 static CURLcode error_init_writer(struct Curl_easy *data,
                                   struct contenc_writer *writer)
 {
-  (void) data;
-  return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
+  (void)data;
+  (void)writer;
+  return CURLE_OK;
 }
 
 static CURLcode error_unencode_write(struct Curl_easy *data,
@@ -984,31 +935,6 @@ static const struct content_encoding error_encoding = {
   sizeof(struct contenc_writer)
 };
 
-/* Create an unencoding writer stage using the given handler. */
-static struct contenc_writer *
-new_unencoding_writer(struct Curl_easy *data,
-                      const struct content_encoding *handler,
-                      struct contenc_writer *downstream,
-                      int order)
-{
-  struct contenc_writer *writer;
-
-  DEBUGASSERT(handler->writersize >= sizeof(struct contenc_writer));
-  writer = (struct contenc_writer *) calloc(1, handler->writersize);
-
-  if(writer) {
-    writer->handler = handler;
-    writer->downstream = downstream;
-    writer->order = order;
-    if(handler->init_writer(data, writer)) {
-      free(writer);
-      writer = NULL;
-    }
-  }
-
-  return writer;
-}
-
 /* Write data using an unencoding writer stack. "nbytes" is not
    allowed to be 0. */
 CURLcode Curl_unencode_write(struct Curl_easy *data,
@@ -1017,23 +943,11 @@ CURLcode Curl_unencode_write(struct Curl_easy *data,
 {
   if(!nbytes)
     return CURLE_OK;
+  if(!writer)
+    return CURLE_WRITE_ERROR;
   return writer->handler->unencode_write(data, writer, buf, nbytes);
 }
 
-/* Close and clean-up the connection's writer stack. */
-void Curl_unencode_cleanup(struct Curl_easy *data)
-{
-  struct SingleRequest *k = &data->req;
-  struct contenc_writer *writer = k->writer_stack;
-
-  while(writer) {
-    k->writer_stack = writer->downstream;
-    writer->handler->close_writer(data, writer);
-    free(writer);
-    writer = k->writer_stack;
-  }
-}
-
 /* Find the content encoding by name. */
 static const struct content_encoding *find_encoding(const char *name,
                                                     size_t len)
@@ -1049,9 +963,6 @@ static const struct content_encoding *find_encoding(const char *name,
   return NULL;
 }
 
-/* allow no more than 5 "chained" compression steps */
-#define MAX_ENCODE_STACK 5
-
 /* Set-up the unencoding stack from the Content-Encoding header value.
  * See RFC 7231 section 3.1.2.2. */
 CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
@@ -1059,6 +970,7 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
 {
   struct SingleRequest *k = &data->req;
   unsigned int order = is_transfer? 2: 1;
+  CURLcode result;
 
   do {
     const char *name;
@@ -1085,41 +997,19 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
       if(is_transfer && !data->set.http_transfer_encoding)
         /* not requested, ignore */
         return CURLE_OK;
-      encoding = find_encoding(name, namelen);
-
-      if(!k->writer_stack) {
-        k->writer_stack = new_unencoding_writer(data, &client_encoding,
-                                                NULL, 0);
-
-        if(!k->writer_stack)
-          return CURLE_OUT_OF_MEMORY;
-      }
 
+      encoding = find_encoding(name, namelen);
       if(!encoding)
         encoding = &error_encoding;  /* Defer error at stack use. */
 
-      if(k->writer_stack_depth++ >= MAX_ENCODE_STACK) {
-        failf(data, "Reject response due to more than %u content encodings",
-              MAX_ENCODE_STACK);
-        return CURLE_BAD_CONTENT_ENCODING;
-      }
-      /* Stack the unencoding stage. */
-      if(order >= k->writer_stack->order) {
-        writer = new_unencoding_writer(data, encoding,
-                                       k->writer_stack, order);
-        if(!writer)
-          return CURLE_OUT_OF_MEMORY;
-        k->writer_stack = writer;
-      }
-      else {
-        struct contenc_writer *w = k->writer_stack;
-        while(w->downstream && order < w->downstream->order)
-          w = w->downstream;
-        writer = new_unencoding_writer(data, encoding,
-                                       w->downstream, order);
-        if(!writer)
-          return CURLE_OUT_OF_MEMORY;
-        w->downstream = writer;
+      result = Curl_client_create_writer(&writer, data, encoding, order);
+      if(result)
+        return result;
+
+      result = Curl_client_add_writer(data, writer);
+      if(result) {
+        Curl_client_free_writer(data, writer);
+        return result;
       }
     }
   } while(*enclist);
@@ -1149,11 +1039,6 @@ CURLcode Curl_unencode_write(struct Curl_easy *data,
   return CURLE_NOT_BUILT_IN;
 }
 
-void Curl_unencode_cleanup(struct Curl_easy *data)
-{
-  (void) data;
-}
-
 char *Curl_all_content_encodings(void)
 {
   return strdup(CONTENT_ENCODING_DEFAULT);  /* Satisfy caller. */
index 56e7f97f70491966ce2aea2def8b4a0586faf6e0..ef7930cb32cdd5d6854fa679411e028c36fe342a 100644 (file)
  ***************************************************************************/
 #include "curl_setup.h"
 
-struct contenc_writer {
-  const struct content_encoding *handler;  /* Encoding handler. */
-  struct contenc_writer *downstream;  /* Downstream writer. */
-  unsigned int order; /* Ordering within writer stack. */
-};
-
-/* Content encoding writer. */
-struct content_encoding {
-  const char *name;        /* Encoding name. */
-  const char *alias;       /* Encoding name alias. */
-  CURLcode (*init_writer)(struct Curl_easy *data,
-                          struct contenc_writer *writer);
-  CURLcode (*unencode_write)(struct Curl_easy *data,
-                             struct contenc_writer *writer,
-                             const char *buf, size_t nbytes);
-  void (*close_writer)(struct Curl_easy *data,
-                       struct contenc_writer *writer);
-  size_t writersize;
-};
+struct contenc_writer;
 
+char *Curl_all_content_encodings(void);
 
 CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
                                      const char *enclist, int is_transfer);
@@ -52,6 +35,5 @@ CURLcode Curl_unencode_write(struct Curl_easy *data,
                              struct contenc_writer *writer,
                              const char *buf, size_t nbytes);
 void Curl_unencode_cleanup(struct Curl_easy *data);
-char *Curl_all_content_encodings(void);
 
 #endif /* HEADER_CURL_CONTENT_ENCODING_H */
index cced2ef8e3885c2dbe62f8399e31ce30e420ae6b..40ef70df50c5c40fa077e9ae44a13456dbf141f5 100644 (file)
@@ -1602,8 +1602,6 @@ CURLcode Curl_http_done(struct Curl_easy *data,
   data->state.authhost.multipass = FALSE;
   data->state.authproxy.multipass = FALSE;
 
-  Curl_unencode_cleanup(data);
-
   /* set the proper values (possibly modified on POST) */
   conn->seek_func = data->set.seek_func; /* restore */
   conn->seek_client = data->set.seek_client; /* restore */
index bda00d38338771a5869de4c1156dce96c77ff649..2a401d14c13e591be10f25af1c45f1c1a5f679e5 100644 (file)
@@ -175,10 +175,7 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
 
       /* Write the data portion available */
       if(!data->set.http_te_skip && !k->ignorebody) {
-        if(!data->set.http_ce_skip && k->writer_stack)
-          result = Curl_unencode_write(data, k->writer_stack, datap, piece);
-        else
-          result = Curl_client_write(data, CLIENTWRITE_BODY, datap, piece);
+        result = Curl_client_write(data, CLIENTWRITE_BODY, datap, piece);
 
         if(result) {
           *extrap = result;
index 49be772a315330a47c7e3a14ea1efd8c6cf14aca..3170adcd7dd316f5703ab2208b8352339384ac92 100644 (file)
@@ -665,7 +665,6 @@ static CURLcode multi_done(struct Curl_easy *data,
 {
   CURLcode result;
   struct connectdata *conn = data->conn;
-  unsigned int i;
 
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   DEBUGF(infof(data, "multi_done[%s]: status: %d prem: %d done: %d",
@@ -721,12 +720,7 @@ static CURLcode multi_done(struct Curl_easy *data,
 
   Curl_safefree(data->state.ulbuf);
 
-  /* if the transfer was completed in a paused state there can be buffered
-     data left to free */
-  for(i = 0; i < data->state.tempcount; i++) {
-    Curl_dyn_free(&data->state.tempwrite[i].b);
-  }
-  data->state.tempcount = 0;
+  Curl_client_cleanup(data);
 
   CONNCACHE_LOCK(data);
   Curl_detach_connection(data);
index 9f30ffc8c872b956a0a84738df1190ce5a7e23a6..0482c5da4e2ce0bd79aa59b261df536d1ae64633 100644 (file)
@@ -40,6 +40,7 @@
 #include "sendf.h"
 #include "cfilters.h"
 #include "connect.h"
+#include "content_encoding.h"
 #include "vtls/vtls.h"
 #include "vssh/ssh.h"
 #include "easyif.h"
@@ -403,6 +404,14 @@ CURLcode Curl_client_write(struct Curl_easy *data,
   DEBUGASSERT(!(type & CLIENTWRITE_BODY) || (type == CLIENTWRITE_BODY));
   /* INFO is only INFO */
   DEBUGASSERT(!(type & CLIENTWRITE_INFO) || (type == CLIENTWRITE_INFO));
+
+  if(type == CLIENTWRITE_BODY) {
+    if(data->req.ignorebody)
+      return CURLE_OK;
+
+    if(data->req.writer_stack && !data->set.http_ce_skip)
+      return Curl_unencode_write(data, data->req.writer_stack, ptr, len);
+  }
   return chop_write(data, type, FALSE, ptr, len);
 }
 
@@ -438,6 +447,138 @@ CURLcode Curl_client_unpause(struct Curl_easy *data)
   return result;
 }
 
+void Curl_client_cleanup(struct Curl_easy *data)
+{
+  struct contenc_writer *writer = data->req.writer_stack;
+  size_t i;
+
+  while(writer) {
+    data->req.writer_stack = writer->downstream;
+    writer->handler->close_writer(data, writer);
+    free(writer);
+    writer = data->req.writer_stack;
+  }
+
+  for(i = 0; i < data->state.tempcount; i++) {
+    Curl_dyn_free(&data->state.tempwrite[i].b);
+  }
+  data->state.tempcount = 0;
+
+}
+
+/* Real client writer: no downstream. */
+static CURLcode client_cew_init(struct Curl_easy *data,
+                                struct contenc_writer *writer)
+{
+  (void) data;
+  (void)writer;
+  return CURLE_OK;
+}
+
+static CURLcode client_cew_write(struct Curl_easy *data,
+                                 struct contenc_writer *writer,
+                                 const char *buf, size_t nbytes)
+{
+  (void)writer;
+  if(!nbytes || data->req.ignorebody)
+    return CURLE_OK;
+  return chop_write(data, CLIENTWRITE_BODY, FALSE, (char *)buf, nbytes);
+}
+
+static void client_cew_close(struct Curl_easy *data,
+                             struct contenc_writer *writer)
+{
+  (void) data;
+  (void) writer;
+}
+
+static const struct content_encoding client_cew = {
+  NULL,
+  NULL,
+  client_cew_init,
+  client_cew_write,
+  client_cew_close,
+  sizeof(struct contenc_writer)
+};
+
+/* Create an unencoding writer stage using the given handler. */
+CURLcode Curl_client_create_writer(struct contenc_writer **pwriter,
+                                   struct Curl_easy *data,
+                                   const struct content_encoding *ce_handler,
+                                   int order)
+{
+  struct contenc_writer *writer;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+
+  DEBUGASSERT(ce_handler->writersize >= sizeof(struct contenc_writer));
+  writer = (struct contenc_writer *) calloc(1, ce_handler->writersize);
+  if(!writer)
+    goto out;
+
+  writer->handler = ce_handler;
+  writer->order = order;
+  result = ce_handler->init_writer(data, writer);
+
+out:
+  *pwriter = result? NULL : writer;
+  if(result)
+    free(writer);
+  return result;
+}
+
+void Curl_client_free_writer(struct Curl_easy *data,
+                             struct contenc_writer *writer)
+{
+  if(writer) {
+    writer->handler->close_writer(data, writer);
+    free(writer);
+  }
+}
+
+/* allow no more than 5 "chained" compression steps */
+#define MAX_ENCODE_STACK 5
+
+
+static CURLcode init_writer_stack(struct Curl_easy *data)
+{
+  DEBUGASSERT(!data->req.writer_stack);
+  return Curl_client_create_writer(&data->req.writer_stack,
+                                   data, &client_cew, 0);
+}
+
+CURLcode Curl_client_add_writer(struct Curl_easy *data,
+                                struct contenc_writer *writer)
+{
+  CURLcode result;
+
+  if(!data->req.writer_stack) {
+    result = init_writer_stack(data);
+    if(result)
+      return result;
+  }
+
+  if(data->req.writer_stack_depth++ >= MAX_ENCODE_STACK) {
+    failf(data, "Reject response due to more than %u content encodings",
+          MAX_ENCODE_STACK);
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Stack the unencoding stage. */
+  if(writer->order >= data->req.writer_stack->order) {
+    writer->downstream = data->req.writer_stack;
+    data->req.writer_stack = writer;
+  }
+  else {
+    struct contenc_writer *w = data->req.writer_stack;
+    while(w->downstream && writer->order < w->downstream->order)
+      w = w->downstream;
+    writer->downstream = w->downstream;
+    w->downstream = writer;
+  }
+  return CURLE_OK;
+}
+
+
 /*
  * Internal read-from-socket function. This is meant to deal with plain
  * sockets, SSL sockets and kerberos sockets.
index f55110f96308f898dd87ed5d23e850989f92090b..3fb07f64a995ba985d1ad471516849c38bf948c1 100644 (file)
@@ -54,6 +54,40 @@ CURLcode Curl_client_write(struct Curl_easy *data, int type, char *ptr,
                            size_t len) WARN_UNUSED_RESULT;
 
 CURLcode Curl_client_unpause(struct Curl_easy *data);
+void Curl_client_cleanup(struct Curl_easy *data);
+
+struct contenc_writer {
+  const struct content_encoding *handler;  /* Encoding handler. */
+  struct contenc_writer *downstream;  /* Downstream writer. */
+  unsigned int order; /* Ordering within writer stack. */
+};
+
+/* Content encoding writer. */
+struct content_encoding {
+  const char *name;        /* Encoding name. */
+  const char *alias;       /* Encoding name alias. */
+  CURLcode (*init_writer)(struct Curl_easy *data,
+                          struct contenc_writer *writer);
+  CURLcode (*unencode_write)(struct Curl_easy *data,
+                             struct contenc_writer *writer,
+                             const char *buf, size_t nbytes);
+  void (*close_writer)(struct Curl_easy *data,
+                       struct contenc_writer *writer);
+  size_t writersize;
+};
+
+
+CURLcode Curl_client_create_writer(struct contenc_writer **pwriter,
+                                   struct Curl_easy *data,
+                                   const struct content_encoding *ce_handler,
+                                   int order);
+
+void Curl_client_free_writer(struct Curl_easy *data,
+                             struct contenc_writer *writer);
+
+CURLcode Curl_client_add_writer(struct Curl_easy *data,
+                                struct contenc_writer *writer);
+
 
 /* internal read-function, does plain socket, SSL and krb4 */
 CURLcode Curl_read(struct Curl_easy *data, curl_socket_t sockfd,
index b9ce2b513158da32c7fcd917a287aa750a145dc4..92ce0dfd9a62e4d8a01dba30f62d43b2b87e944e 100644 (file)
@@ -700,19 +700,15 @@ static CURLcode readwrite_data(struct Curl_easy *data,
              in http_chunks.c.
              Make sure that ALL_CONTENT_ENCODINGS contains all the
              encodings handled here. */
-          if(data->set.http_ce_skip || !k->writer_stack) {
-            if(!k->ignorebody && nread) {
+          if(!k->ignorebody && nread) {
 #ifndef CURL_DISABLE_POP3
-              if(conn->handler->protocol & PROTO_FAMILY_POP3)
-                result = Curl_pop3_write(data, k->str, nread);
-              else
+            if(conn->handler->protocol & PROTO_FAMILY_POP3)
+              result = Curl_pop3_write(data, k->str, nread);
+            else
 #endif /* CURL_DISABLE_POP3 */
-                result = Curl_client_write(data, CLIENTWRITE_BODY, k->str,
-                                           nread);
-            }
+              result = Curl_client_write(data, CLIENTWRITE_BODY, k->str,
+                                         nread);
           }
-          else if(!k->ignorebody && nread)
-            result = Curl_unencode_write(data, k->writer_stack, k->str, nread);
         }
         k->badheader = HEADER_NORMAL; /* taken care of now */
 
index 6d60477779d7909c53a40db438a7477ef8776d8a..f9120ee03e856d0a278d1a2aa70c83598c36a4a4 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -2033,13 +2033,13 @@ void Curl_free_request_state(struct Curl_easy *data)
 {
   Curl_safefree(data->req.p.http);
   Curl_safefree(data->req.newurl);
-
 #ifndef CURL_DISABLE_DOH
   if(data->req.doh) {
     Curl_close(&data->req.doh->probe[0].easy);
     Curl_close(&data->req.doh->probe[1].easy);
   }
 #endif
+  Curl_client_cleanup(data);
 }