gustavonihei commented on a change in pull request #695:
URL: 
https://github.com/apache/incubator-nuttx-apps/pull/695#discussion_r628554049



##########
File path: netutils/webclient/webclient.c
##########
@@ -674,225 +693,336 @@ int webclient_perform(FAR struct webclient_context *ctx)
 
   /* Initialize the state structure */
 
-  ws = calloc(1, sizeof(struct wget_s));
-  if (!ws)
+  if (ctx->ws == NULL)
     {
-      return -errno;
-    }
+      ws = calloc(1, sizeof(struct wget_s));
+      if (!ws)
+        {
+          return -errno;
+        }
 
-  ws->buffer = ctx->buffer;
-  ws->buflen = ctx->buflen;
+      ws->buffer = ctx->buffer;
+      ws->buflen = ctx->buflen;
 
-  /* Parse the hostname (with optional port number) and filename
-   * from the URL.
-   */
+      /* Parse the hostname (with optional port number) and filename
+       * from the URL.
+       */
 
-  ret = parseurl(ctx->url, ws);
-  if (ret != 0)
-    {
-      nwarn("WARNING: Malformed URL: %s\n", ctx->url);
-      free(ws);
-      return ret;
+      ret = parseurl(ctx->url, ws);
+      if (ret != 0)
+        {
+          nwarn("WARNING: Malformed URL: %s\n", ctx->url);
+          free(ws);
+          return ret;
+        }
+
+      ws->state = WEBCLIENT_STATE_SOCKET;
+      ctx->ws = ws;
     }
 
+  ws = ctx->ws;
+
   ninfo("hostname='%s' filename='%s'\n", ws->hostname, ws->filename);
 
   /* The following sequence may repeat indefinitely if we are redirected */
 
+  conn = &ws->conn;
   do
     {
-      if (!strcmp(ws->scheme, "https") && tls_ops != NULL)
-        {
-          conn.tls = true;
-        }
-      else if (!strcmp(ws->scheme, "http"))
+      if (ws->state == WEBCLIENT_STATE_SOCKET)
         {
-          conn.tls = false;
-        }
-      else
-        {
-          nerr("ERROR: unsupported scheme: %s\n", ws->scheme);
-          free(ws);
-          return -ENOTSUP;
-        }
-
-      /* Re-initialize portions of the state structure that could have
-       * been left from the previous time through the loop and should not
-       * persist with the new connection.
-       */
-
-      ws->httpstatus = HTTPSTATUS_NONE;
-      ws->offset     = 0;
-      ws->datend     = 0;
-      ws->ndx        = 0;
-
-      if (conn.tls)
-        {
-          char port_str[sizeof("65535")];
-
-#if defined(CONFIG_WEBCLIENT_NET_LOCAL)
-          if (ctx->unix_socket_path != NULL)
+          if (!strcmp(ws->scheme, "https") && tls_ops != NULL)
+            {
+              conn->tls = true;
+            }
+          else if (!strcmp(ws->scheme, "http"))
             {
-              nerr("ERROR: TLS on AF_LOCAL socket is not implemented\n");
+              conn->tls = false;
+            }
+          else
+            {
+              nerr("ERROR: unsupported scheme: %s\n", ws->scheme);
               free(ws);
               return -ENOTSUP;
             }
-#endif
 
-          snprintf(port_str, sizeof(port_str), "%u", ws->port);
-          ret = tls_ops->connect(tls_ctx, ws->hostname, port_str,
-                                 CONFIG_WEBCLIENT_TIMEOUT, &conn.tls_conn);
-        }
-      else
-        {
-#if defined(CONFIG_WEBCLIENT_NET_LOCAL)
-          struct sockaddr_un server_un;
-#endif
-          struct sockaddr_in server_in;
-          int domain;
-          const struct sockaddr *server_address;
-          socklen_t server_address_len;
+          /* Re-initialize portions of the state structure that could have
+           * been left from the previous time through the loop and should not
+           * persist with the new connection.
+           */
 
-#if defined(CONFIG_WEBCLIENT_NET_LOCAL)
-          if (ctx->unix_socket_path != NULL)
-            {
-              domain = PF_LOCAL;
+          ws->httpstatus = HTTPSTATUS_NONE;
+          ws->offset     = 0;
+          ws->datend     = 0;
+          ws->ndx        = 0;
+          ws->redirected = 0;
 
-              memset(&server_un, 0, sizeof(server_un));
-              server_un.sun_family = AF_LOCAL;
-              strncpy(server_un.sun_path, ctx->unix_socket_path,
-                      sizeof(server_un.sun_path));
-#if !defined(__NuttX__) && !defined(__linux__)
-              server_un.sun_len = SUN_LEN(&server_un);
+          if (conn->tls)
+            {
+#if defined(CONFIG_WEBCLIENT_NET_LOCAL)
+              if (ctx->unix_socket_path != NULL)
+                {
+                  nerr("ERROR: TLS on AF_LOCAL socket is not implemented\n");
+                  free(ws);
+                  return -ENOTSUP;
+                }
 #endif
-              server_address = (const struct sockaddr *)&server_un;
-              server_address_len = sizeof(server_un);
             }
           else
-#endif
             {
-              domain = PF_INET;
+              int domain;
+
+#if defined(CONFIG_WEBCLIENT_NET_LOCAL)
+              if (ctx->unix_socket_path != NULL)
+                {
+                  domain = PF_LOCAL;
+                }
+              else
+#endif
+                {
+                  domain = PF_INET;
+                }
 
-              /* Get the server address from the host name */
+              /* Create a socket */
 
-              server_in.sin_family = AF_INET;
-              server_in.sin_port   = htons(ws->port);
-              ret = wget_gethostip(ws->hostname, &server_in.sin_addr);
-              if (ret < 0)
+              conn->sockfd = socket(domain, SOCK_STREAM, 0);
+              if (conn->sockfd < 0)
                 {
-                  /* Could not resolve host (or malformed IP address) */
+                  ret = -errno;
+                  nerr("ERROR: socket failed: %d\n", errno);
+                  goto errout_with_errno;
+                }
 
-                  nwarn("WARNING: Failed to resolve hostname\n");
-                  free(ws);
-                  return -EHOSTUNREACH;
+              ws->need_conn_close = true;
+
+              if ((ctx->flags & WEBCLIENT_FLAG_NON_BLOCKING) != 0)
+                {
+                  int flags = fcntl(conn->sockfd, F_GETFL, 0);
+                  ret = fcntl(conn->sockfd, F_SETFL, flags | O_NONBLOCK);
+                  if (ret == -1)
+                    {
+                      ret = -errno;
+                      nerr("ERROR: F_SETFL failed: %d\n", ret);
+                      goto errout_with_errno;
+                    }
                 }
+              else
+                {
+                  /* Set send and receive timeout values */
 
-              server_address = (const struct sockaddr *)&server_in;
-              server_address_len = sizeof(struct sockaddr_in);
+                  tv.tv_sec  = CONFIG_WEBCLIENT_TIMEOUT;
+                  tv.tv_usec = 0;
+
+                  setsockopt(conn->sockfd, SOL_SOCKET, SO_RCVTIMEO,
+                             (FAR const void *)&tv, sizeof(struct timeval));
+                  setsockopt(conn->sockfd, SOL_SOCKET, SO_SNDTIMEO,
+                             (FAR const void *)&tv, sizeof(struct timeval));
+                }
             }
 
-          /* Create a socket */
+          ws->state = WEBCLIENT_STATE_CONNECT;
+        }
 
-          conn.sockfd = socket(domain, SOCK_STREAM, 0);
-          if (conn.sockfd < 0)
+      if (ws->state == WEBCLIENT_STATE_CONNECT)
+        {
+          if (conn->tls)
             {
-              /* socket failed.  It will set the errno appropriately */
+              char port_str[sizeof("65535")];
 
-              nerr("ERROR: socket failed: %d\n", errno);
-              free(ws);
-              return -errno;
+#if defined(CONFIG_WEBCLIENT_NET_LOCAL)
+              if (ctx->unix_socket_path != NULL)
+                {
+                  nerr("ERROR: TLS on AF_LOCAL socket is not implemented\n");
+                  free(ws);
+                  return -ENOTSUP;
+                }
+#endif
+
+              snprintf(port_str, sizeof(port_str), "%u", ws->port);
+              ret = tls_ops->connect(tls_ctx, ws->hostname, port_str,
+                                     CONFIG_WEBCLIENT_TIMEOUT,
+                                     &conn->tls_conn);
+              if (ret == 0)
+                {
+                  ws->need_conn_close = true;
+                }
             }
+          else
+            {
+#if defined(CONFIG_WEBCLIENT_NET_LOCAL)
+              struct sockaddr_un server_un;
+#endif
+              struct sockaddr_in server_in;
+              const struct sockaddr *server_address;
+              socklen_t server_address_len;
+
+#if defined(CONFIG_WEBCLIENT_NET_LOCAL)
+              if (ctx->unix_socket_path != NULL)
+                {
+                  memset(&server_un, 0, sizeof(server_un));
+                  server_un.sun_family = AF_LOCAL;
+                  strncpy(server_un.sun_path, ctx->unix_socket_path,
+                          sizeof(server_un.sun_path));
+#if !defined(__NuttX__) && !defined(__linux__)
+                  server_un.sun_len = SUN_LEN(&server_un);
+#endif
+                  server_address = (const struct sockaddr *)&server_un;
+                  server_address_len = sizeof(server_un);
+                }
+              else
+#endif
+                {
+                  /* Get the server address from the host name */
 
-          /* Set send and receive timeout values */
+                  server_in.sin_family = AF_INET;
+                  server_in.sin_port   = htons(ws->port);
+                  ret = wget_gethostip(ws->hostname, &server_in.sin_addr);
+                  if (ret < 0)
+                    {
+                      /* Could not resolve host (or malformed IP address) */
 
-          tv.tv_sec  = CONFIG_WEBCLIENT_TIMEOUT;
-          tv.tv_usec = 0;
+                      nwarn("WARNING: Failed to resolve hostname\n");
+                      free(ws);

Review comment:
       ```suggestion
                         free(ws);
                         ctx->ws = NULL;
   ```
   To avoid use-after-free errors, the freed pointer should be nullified.
   ```




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to