Allow user to send chunked HTTP post request by calling the
input callback function on write watch until the user
indicate no more data  we send the 0 length chunk to
indicate end of request body.
---
 gweb/gweb.c |  209 ++++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 135 insertions(+), 74 deletions(-)

diff --git a/gweb/gweb.c b/gweb/gweb.c
index 295b93f..5c473f9 100644
--- a/gweb/gweb.c
+++ b/gweb/gweb.c
@@ -66,6 +66,8 @@ struct web_session {
        gsize receive_space;
        GString *current_header;
        gboolean header_done;
+       gboolean more_data;
+       gboolean request_started;
 
        GWebResult result;
 
@@ -313,6 +315,117 @@ static inline void call_result_func(struct web_session 
*session, guint16 status)
        session->result_func(&session->result, session->user_data);
 }
 
+static void get_pending_input_data(struct web_session *session)
+{
+       GString *buf;
+       gchar *str;
+       const guint8 *body;
+       gsize length;
+       gsize count, bytes_written;
+       GIOStatus status;
+
+       if (session->input_func != NULL)
+               session->more_data = session->input_func(&body, &length,
+                                                       session->user_data);
+       else {
+               session->more_data = FALSE;
+               return;
+       }
+
+       buf = g_string_new(NULL);
+
+       if (length > 0) {
+               g_string_append_printf(buf, "%x\r\n", length);
+               g_string_append_len(buf, (char *) body, length);
+               g_string_append(buf, "\r\n");
+       }
+       if (session->more_data == FALSE)
+               g_string_append(buf, "0\r\n\r\n");
+
+       count = buf->len;
+       str = g_string_free(buf, FALSE);
+       if (count > 0) {
+               status = g_io_channel_write_chars(session->transport_channel,
+                                       str, count, &bytes_written, NULL);
+
+       debug(session->web, "status %u bytes written %zu",
+                                       status, bytes_written);
+       }
+
+       g_free(str);
+}
+
+static void start_request(struct web_session *session)
+{
+       GString *buf;
+       gchar *str;
+       const guint8 *body;
+       gsize length;
+       gsize count, bytes_written;
+       GIOStatus status;
+
+       debug(session->web, "request %s from %s",
+                                       session->request, session->host);
+
+       buf = g_string_new(NULL);
+
+       if (session->content_type == NULL)
+               g_string_append_printf(buf, "GET %s HTTP/1.1\r\n",
+                                                       session->request);
+       else
+               g_string_append_printf(buf, "POST %s HTTP/1.1\r\n",
+                                                       session->request);
+       g_string_append_printf(buf, "Host: %s\r\n", session->host);
+       if (session->web->user_agent != NULL)
+               g_string_append_printf(buf, "User-Agent: %s\r\n",
+                                               session->web->user_agent);
+       if (session->web->accept_option != NULL)
+               g_string_append_printf(buf, "Accept: %s\r\n",
+                                               session->web->accept_option);
+       if (session->content_type != NULL) {
+               g_string_append_printf(buf, "Content-Type: %s\r\n",
+                                                       session->content_type);
+               if (session->input_func != NULL)
+                       session->more_data = session->input_func(&body, &length,
+                                                       session->user_data);
+               else
+                       length = 0;
+
+               if (session->more_data == FALSE)
+                       g_string_append_printf(buf, "Content-Length: %zu\r\n",
+                                                                       length);
+               else
+                       g_string_append(buf, "Transfer-Encoding: chunked\r\n");
+       }
+       if (session->web->close_connection == TRUE)
+               g_string_append(buf, "Connection: close\r\n");
+       g_string_append(buf, "\r\n");
+
+       if (session->content_type != NULL && length > 0) {
+               if (session->more_data == TRUE) {
+                       g_string_append_printf(buf, "%x\r\n", length);
+                       g_string_append_len(buf, (char *) body, length);
+                       g_string_append(buf, "\r\n");
+               } else
+                       g_string_append_len(buf, (char *) body, length);
+       }
+
+       count = buf->len;
+       str = g_string_free(buf, FALSE);
+
+       debug(session->web, "bytes to write %zu", count);
+
+       status = g_io_channel_write_chars(session->transport_channel,
+                                       str, count, &bytes_written, NULL);
+
+       debug(session->web, "status %u bytes written %zu",
+                                       status, bytes_written);
+
+       //printf("%s", str);
+
+       g_free(str);
+}
+
 static gboolean received_data(GIOChannel *channel, GIOCondition cond,
                                                        gpointer user_data)
 {
@@ -329,6 +442,19 @@ static gboolean received_data(GIOChannel *channel, 
GIOCondition cond,
                return FALSE;
        }
 
+       if (cond & G_IO_OUT) {
+               if (session->request_started == FALSE) {
+                       session->request_started = TRUE;
+                       start_request(session);
+                       return TRUE;
+               } else if (session->content_type != NULL &&
+                               session->more_data == TRUE)
+                       get_pending_input_data(session);
+       }
+
+       if ((cond & G_IO_IN) == FALSE)
+               return TRUE;
+
        status = g_io_channel_read_chars(channel,
                                (gchar *) session->receive_buffer,
                                session->receive_space - 1, &bytes_read, NULL);
@@ -398,7 +524,6 @@ static gboolean received_data(GIOChannel *channel, 
GIOCondition cond,
 
                g_string_truncate(session->current_header, 0);
        }
-
        return TRUE;
 }
 
@@ -416,11 +541,6 @@ static int connect_session_transport(struct web_session 
*session)
        sin.sin_port = htons(session->port);
        sin.sin_addr.s_addr = inet_addr(session->address);
 
-       if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
-               close(sk);
-               return -EIO;
-       }
-
        if (session->flags & SESSION_FLAG_USE_TLS)
                session->transport_channel = g_io_channel_gnutls_new(sk);
        else
@@ -431,15 +551,23 @@ static int connect_session_transport(struct web_session 
*session)
                return -ENOMEM;
        }
 
+       g_io_channel_set_flags(session->transport_channel,
+                                       G_IO_FLAG_NONBLOCK, NULL);
        g_io_channel_set_encoding(session->transport_channel, NULL, NULL);
        g_io_channel_set_buffered(session->transport_channel, FALSE);
 
        g_io_channel_set_close_on_unref(session->transport_channel, TRUE);
 
        session->transport_watch = g_io_add_watch(session->transport_channel,
-                               G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
+                       G_IO_OUT | G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
                                                received_data, session);
 
+       if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0 &&
+                                               errno != EINPROGRESS) {
+               close(sk);
+               return -EIO;
+       }
+
        return 0;
 }
 
@@ -457,69 +585,6 @@ static int create_transport(struct web_session *session)
        return 0;
 }
 
-static void start_request(struct web_session *session)
-{
-       GString *buf;
-       gchar *str;
-       const guint8 *body;
-       gsize length;
-       gsize count, bytes_written;
-       GIOStatus status;
-
-       debug(session->web, "request %s from %s",
-                                       session->request, session->host);
-
-       buf = g_string_new(NULL);
-
-       if (session->content_type == NULL)
-               g_string_append_printf(buf, "GET %s HTTP/1.1\r\n",
-                                                       session->request);
-       else
-               g_string_append_printf(buf, "POST %s HTTP/1.1\r\n",
-                                                       session->request);
-       g_string_append_printf(buf, "Host: %s\r\n", session->host);
-       if (session->web->user_agent != NULL)
-               g_string_append_printf(buf, "User-Agent: %s\r\n",
-                                               session->web->user_agent);
-       if (session->web->accept_option != NULL)
-               g_string_append_printf(buf, "Accept: %s\r\n",
-                                               session->web->accept_option);
-       if (session->content_type != NULL) {
-               g_string_append_printf(buf, "Content-Type: %s\r\n",
-                                               session->content_type);
-               if (session->input_func != NULL)
-                       session->input_func(&body, &length, session->user_data);
-               else
-                       length = 0;
-
-               g_string_append_printf(buf, "Content-Length: %zu\r\n", length);
-       }
-       if (session->web->close_connection == TRUE)
-               g_string_append(buf, "Connection: close\r\n");
-       g_string_append(buf, "\r\n");
-
-       count = buf->len;
-
-       if (session->content_type != NULL && length > 0) {
-               g_string_append_len(buf, (char *) body, length);
-               count += length;
-       }
-
-       str = g_string_free(buf, FALSE);
-
-       debug(session->web, "bytes to write %zu", count);
-
-       status = g_io_channel_write_chars(session->transport_channel,
-                                       str, count, &bytes_written, NULL);
-
-       debug(session->web, "status %u bytes written %zu",
-                                               status, bytes_written);
-
-       //printf("%s", str);
-
-       g_free(str);
-}
-
 static int parse_url(struct web_session *session, const char *url)
 {
        char *scheme, *host, *port, *path;
@@ -594,8 +659,6 @@ static void resolv_result(GResolvResultStatus status,
                call_result_func(session, 409);
                return;
        }
-
-       start_request(session);
 }
 
 static guint do_request(GWeb *web, const char *url,
@@ -657,8 +720,6 @@ static guint do_request(GWeb *web, const char *url,
                        free_session(session);
                        return 0;
                }
-
-               start_request(session);
        }
 
        web->session_list = g_list_append(web->session_list, session);
-- 
1.7.2.3

_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman

Reply via email to