Witold Filipczyk <[EMAIL PROTECTED]> writes:

> On Mon, May 12, 2008 at 12:14:52AM +0300, Kalle Olavi Niemitalo wrote:
>> - The code is duplicated between src/protocol/file/cgi.c and
>>   src/protocol/http/http.c.  This may be the best way but it
>>   looks a bit annoying.
>
> I have no idea how to make it better.

How about the following?  I did not test this yet.

1008: Merge POST data sending of HTTP and local CGI.

To reduce code duplication, src/protocol/file/cgi.c no longer parses
connection->uri->post on its own but rather calls the new function
http_read_post_data(), provided by src/protocol/http/http.c.  The same
code is now also used for POST requests that do not include files.

---
commit bd3745a8558bbebdbbe9d4195e095fd14adce24b
tree 05d3fab7c7e99630303bb8c6c73ec6519a7fa6e6
parent 181486696b58d0284fe64a8cadba0720ece87543
author Kalle Olavi Niemitalo <[EMAIL PROTECTED]> Sun, 18 May 2008 22:27:18 +0300
committer Kalle Olavi Niemitalo <[EMAIL PROTECTED]> Sun, 18 May 2008 22:34:16 
+0300

 src/protocol/file/cgi.c  |  151 +++---------------------------
 src/protocol/http/http.c |  230 ++++++++++++++++++++++++++--------------------
 src/protocol/http/http.h |    3 -
 3 files changed, 146 insertions(+), 238 deletions(-)

diff --git a/src/protocol/file/cgi.c b/src/protocol/file/cgi.c
index ac16335..f7cb873 100644
--- a/src/protocol/file/cgi.c
+++ b/src/protocol/file/cgi.c
@@ -82,161 +82,42 @@ close_pipe_and_read(struct socket *data_socket)
 
 
 #define POST_BUFFER_SIZE 4096
-#define BIG_READ 65536
-static void send_files2(struct socket *socket);
 
 static void
-send_files(struct socket *socket)
+send_more_post_data(struct socket *socket)
 {
        struct connection *conn = socket->conn;
        struct http_connection_info *http = conn->info;
-       unsigned char *post = http->post_data;
        unsigned char buffer[POST_BUFFER_SIZE];
-       unsigned char *file = strchr(post, FILE_CHAR);
-       struct string data;
-       int n = 0;
-       int finish = 0;
-
-       if (!init_string(&data)) {
-               abort_connection(conn, S_OUT_OF_MEM);
-               return;
-       }
-
-       if (!file) {
-               finish = 1;
-               file = strchr(post, '\0');
-       }
-
-       while (post < file) {
-               int h1, h2;
-
-               h1 = unhx(post[0]);
-               assertm(h1 >= 0 && h1 < 16, "h1 in the POST buffer is %d 
(%d/%c)", h1, post[0], post[0]);
-               if_assert_failed h1 = 0;
-
-               h2 = unhx(post[1]);
-               assertm(h2 >= 0 && h2 < 16, "h2 in the POST buffer is %d 
(%d/%c)", h2, post[1], post[1]);
-               if_assert_failed h2 = 0;
-
-               buffer[n++] = (h1<<4) + h2;
-               post += 2;
-               if (n == POST_BUFFER_SIZE) {
-                       add_bytes_to_string(&data, buffer, n);
-                       n = 0;
-               }
-       }
-       if (n) add_bytes_to_string(&data, buffer, n);
-
-       if (finish) {
-               write_to_socket(socket, data.source, data.length, S_SENT,
-                       close_pipe_and_read);
-       } else {
-               unsigned char *end = strchr(file + 1, FILE_CHAR);
-
-               assert(end);
-               *end = '\0';
-               conn->post_fd = open(file + 1, O_RDONLY);
-               *end = FILE_CHAR;
-               if (conn->post_fd < 0) {
-                       int errno_from_open = errno;
-
-                       done_string(&data);
-                       abort_connection(conn, -errno_from_open);
-                       return;
-               }
-               http->post_data = end + 1;
-               socket->state = SOCKET_END_ONCLOSE;
-               write_to_socket(socket, data.source, data.length, S_TRANS,
-                               send_files2);
-       }
-       done_string(&data);
-}
-
-static void
-send_files2(struct socket *socket)
-{
-       struct connection *conn = socket->conn;
-       unsigned char buffer[BIG_READ];
-       int n = safe_read(conn->post_fd, buffer, BIG_READ);
-
-       if (n > 0) {
-               socket->state = SOCKET_END_ONCLOSE;
-               write_to_socket(socket, buffer, n, S_TRANS,
-                       send_files2);
-       } else {
-               close(conn->post_fd);
-               conn->post_fd = -1;
-               send_files(socket);
+       int got;
+
+       got = http_read_post_data(socket, buffer, POST_BUFFER_SIZE);
+       if (got < 0) {
+               abort_connection(conn, -errno);
+       } else if (got > 0) {
+               write_to_socket(socket, buffer, got, S_TRANS,
+                               send_more_post_data);
+               http->uploaded += got;
+       } else {                /* got == 0, meaning end of data */
+               close_pipe_and_read(socket);
        }
 }
 
+#undef POST_BUFFER_SIZE
 
 static void
 send_post_data(struct connection *conn)
 {
+       struct http_connection_info *http = conn->info;
        unsigned char *post = conn->uri->post;
        unsigned char *postend;
-       unsigned char buffer[POST_BUFFER_SIZE];
-       struct string data;
-       int n = 0;
 
        postend = strchr(post, '\n');
        if (postend) post = postend + 1;
 
-       if (post) {
-               unsigned char *file = strchr(post, FILE_CHAR);
-
-               if (file) {
-                       struct http_connection_info *http = conn->info;
-
-                       http->post_data = post;
-                       send_files(conn->data_socket);
-                       return;
-               }
-       }
-
-
-       if (!init_string(&data)) {
-               abort_connection(conn, S_OUT_OF_MEM);
-               return;
-       }
-
-       /* FIXME: Code duplication with protocol/http/http.c! --witekfl */
-       while (post[0] && post[1]) {
-               int h1, h2;
-
-               h1 = unhx(post[0]);
-               assert(h1 >= 0 && h1 < 16);
-               if_assert_failed h1 = 0;
-
-               h2 = unhx(post[1]);
-               assert(h2 >= 0 && h2 < 16);
-               if_assert_failed h2 = 0;
-
-               buffer[n++] = (h1<<4) + h2;
-               post += 2;
-               if (n == POST_BUFFER_SIZE) {
-                       add_bytes_to_string(&data, buffer, n);
-                       n = 0;
-               }
-       }
-       if (n)
-               add_bytes_to_string(&data, buffer, n);
-
-
-       /* If we're submitting a form whose controls do not have
-        * names, then the POST has a Content-Type but empty data,
-        * and an assertion would fail in write_to_socket.  */
-       if (data.length)
-               write_to_socket(conn->data_socket, data.source, data.length,
-                               S_SENT, close_pipe_and_read);
-       else
-               close_pipe_and_read(conn->data_socket);
-
-       done_string(&data);
+       http->post_data = post;
+       send_more_post_data(conn->data_socket);
 }
-#undef POST_BUFFER_SIZE
-#undef BIG_READ
 
 static void
 send_request(struct connection *conn)
diff --git a/src/protocol/http/http.c b/src/protocol/http/http.c
index 3dcf83b..d68ad7d 100644
--- a/src/protocol/http/http.c
+++ b/src/protocol/http/http.c
@@ -613,94 +613,151 @@ post_length(unsigned char *post_data, unsigned int 
*count)
 #define POST_BUFFER_SIZE 4096
 #define BIG_READ 655360
 
-static void send_files2(struct socket *socket);
-
-static void
-send_files(struct socket *socket)
+static int
+http_read_post_data_inline(struct socket *socket,
+                          unsigned char buffer[], int max)
 {
-       struct connection *conn = socket->conn;
-       struct http_connection_info *http = conn->info;
+       struct connection *const conn = socket->conn;
+       struct http_connection_info *const http = conn->info;
        unsigned char *post = http->post_data;
-       unsigned char buffer[POST_BUFFER_SIZE];
-       unsigned char *file = strchr(post, FILE_CHAR);
-       struct string data;
-       int n = 0;
-       int finish = 0;
+       unsigned char *end = strchr(post, FILE_CHAR);
+       int total = 0;
 
-       if (!init_string(&data)) {
-               http_end_request(conn, S_OUT_OF_MEM, 0);
-               return;
-       }
+       assert(conn->post_fd < 0);
+       if_assert_failed { errno = EINVAL; return -1; }
 
-       if (!file) {
-               finish = 1;
-               file = strchr(post, '\0');
-       }
+       if (!end)
+               end = strchr(post, '\0');
 
-       while (post < file) {
+       while (post < end && total < max) {
                int h1, h2;
 
                h1 = unhx(post[0]);
                assertm(h1 >= 0 && h1 < 16, "h1 in the POST buffer is %d 
(%d/%c)", h1, post[0], post[0]);
                if_assert_failed h1 = 0;
 
-               h2 = unhx(post[1]);
-               assertm(h2 >= 0 && h2 < 16, "h2 in the POST buffer is %d 
(%d/%c)", h2, post[1], post[1]);
+               h2 = unhx(post[0]);
+               assertm(h2 >= 0 && h2 < 16, "h2 in the POST buffer is %d 
(%d/%c)", h2, post[0], post[0]);
                if_assert_failed h2 = 0;
 
-               buffer[n++] = (h1<<4) + h2;
+               buffer[total++] = (h1<<4) + h2;
                post += 2;
-               if (n == POST_BUFFER_SIZE) {
-                       add_bytes_to_string(&data, buffer, n);
-                       n = 0;
-               }
        }
-       if (n) add_bytes_to_string(&data, buffer, n);
+       if (post != end || *end != FILE_CHAR) {
+               http->post_data = post;
+               return total;
+       }
+
+       end = strchr(post + 1, FILE_CHAR);
+       assert(end);
+       *end = '\0';
+       conn->post_fd = open(post + 1, O_RDONLY);
+       /* Be careful not to change errno here.  */
+       *end = FILE_CHAR;
+       if (conn->post_fd < 0) {
+               http->post_data = post;
+               if (total > 0)
+                       return total; /* retry the open on the next call */
+               else
+                       return -1; /* caller gets errno from open() */
+       }
+       http->post_data = end + 1;
+       return total;
+}
 
-       if (finish) {
-               http->uploaded += data.length;
-               request_from_socket(socket, data.source, data.length, S_SENT,
-                   SOCKET_END_ONCLOSE, http_got_header);
-       } else {
-               unsigned char *end = strchr(file + 1, FILE_CHAR);
+static int
+http_read_post_data_fd(struct socket *socket,
+                      unsigned char buffer[], int max)
+{
+       struct connection *const conn = socket->conn;
+       int ret;
 
-               assert(end);
-               *end = '\0';
-               conn->post_fd = open(file + 1, O_RDONLY);
-               *end = FILE_CHAR;
-               if (conn->post_fd < 0) {
-                       int errno_from_open = errno;
+       /* safe_read() would set errno = EBADF anyway, but check this
+        * explicitly to make any such bugs easier to detect.  */
+       assert(conn->post_fd >= 0);
+       if_assert_failed { errno = EBADF; return -1; }
 
-                       done_string(&data);
-                       http_end_request(conn, -errno_from_open, 0);
-                       return;
+       ret = safe_read(conn->post_fd, buffer, max);
+       if (ret <= 0) {
+               const int errno_from_read = errno;
+
+               close(conn->post_fd);
+               conn->post_fd = -1;
+
+               errno = errno_from_read;
+       }
+       return ret;
+}
+
+/** Read data from socket->conn->uri->post or from the files to which
+ * it refers.
+ *
+ * @return >0 if read that many bytes; 0 if EOF; -1 on error and set
+ * errno.  */
+int
+http_read_post_data(struct socket *socket,
+                   unsigned char buffer[], int max)
+{
+       struct connection *const conn = socket->conn;
+       int total = 0;
+
+       while (total < max) {
+               int chunk;
+               int post_fd = conn->post_fd;
+
+               if (post_fd < 0)
+                       chunk = http_read_post_data_inline(socket,
+                                                          buffer + total,
+                                                          max - total);
+               else
+                       chunk = http_read_post_data_fd(socket,
+                                                      buffer + total,
+                                                      max - total);
+               /* Be careful not to change errno here.  */
+
+               if (chunk == 0 && conn->post_fd == post_fd)
+                       return total; /* EOF */
+               if (chunk < 0) {
+                       /* If some data has already been successfully
+                        * read to buffer[], tell the caller about
+                        * that and forget about the error.  The next
+                        * http_read_post_data() call will retry the
+                        * operation that failed.  */
+                       if (total != 0)
+                               return total;
+                       else
+                               return chunk; /* caller gets errno from above */
                }
-               http->post_data = end + 1;
-               socket->state = SOCKET_END_ONCLOSE;
-               http->uploaded += data.length;
-               write_to_socket(socket, data.source, data.length, S_TRANS,
-                               send_files2);
+               total += chunk;
        }
-       done_string(&data);
+       return total;
 }
 
 static void
-send_files2(struct socket *socket)
+send_more_post_data(struct socket *socket)
 {
        struct connection *conn = socket->conn;
        struct http_connection_info *http = conn->info;
-       unsigned char buffer[BIG_READ];
-       int n = safe_read(conn->post_fd, buffer, BIG_READ);
-
-       if (n > 0) {
+       unsigned char buffer[POST_BUFFER_SIZE];
+       int got;
+
+       got = http_read_post_data(socket, buffer, POST_BUFFER_SIZE);
+       if (got < 0) {
+               http_end_request(conn, -errno, 0);
+       } else if (got > 0) {
+               write_to_socket(socket, buffer, got, S_TRANS,
+                               send_more_post_data);
+               http->uploaded += got;
+       } else {                /* got == 0, meaning end of data */
+               /* Can't use request_from_socket() because there's no
+                * more data to write.  */
+               struct read_buffer *rb = alloc_read_buffer(socket);
+               
                socket->state = SOCKET_END_ONCLOSE;
-               http->uploaded += n;
-               write_to_socket(socket, buffer, n, S_TRANS,
-                       send_files2);
-       } else {
-               close(conn->post_fd);
-               conn->post_fd = -1;
-               send_files(socket);
+               if (rb)
+                       read_from_socket(socket, rb, S_SENT, http_got_header);
+               else
+                       http_end_request(conn, S_OUT_OF_MEM, 0);
        }
 }
 
@@ -1084,53 +1141,22 @@ http_send_header(struct socket *socket)
 
        add_crlf_to_string(&header);
 
-       if (files) {
-               assert(!use_connect && post_data);
-               assert(conn->post_fd == -1);
-               http->post_data = post_data;
-               socket->state = SOCKET_END_ONCLOSE;
-               if (!conn->upload_progress)
-                       conn->upload_progress = init_progress(0);
-               write_to_socket(socket, header.source, header.length, S_TRANS,
-                       send_files);
-               done_string(&header);
-               return;
-       }
        /* CONNECT: Any POST data is for the origin server only.
         * This was already checked above and post_data is NULL
         * in that case.  Verified with an assertion below.  */
        if (post_data) {
-               unsigned char *post = post_data;
-               unsigned char buffer[POST_BUFFER_SIZE];
-               int n = 0;
-
                assert(!use_connect); /* see comment above */
+               assert(conn->post_fd == -1);
 
-               while (post[0] && post[1]) {
-                       int h1, h2;
-
-                       h1 = unhx(post[0]);
-                       assertm(h1 >= 0 && h1 < 16, "h1 in the POST buffer is 
%d (%d/%c)", h1, post[0], post[0]);
-                       if_assert_failed h1 = 0;
-
-                       h2 = unhx(post[1]);
-                       assertm(h2 >= 0 && h2 < 16, "h2 in the POST buffer is 
%d (%d/%c)", h2, post[1], post[1]);
-                       if_assert_failed h2 = 0;
-
-                       buffer[n++] = (h1<<4) + h2;
-                       post += 2;
-                       if (n == POST_BUFFER_SIZE) {
-                               add_bytes_to_string(&header, buffer, n);
-                               n = 0;
-                       }
-               }
-
-               if (n)
-                       add_bytes_to_string(&header, buffer, n);
-       }
-
-       request_from_socket(socket, header.source, header.length, S_SENT,
-                           SOCKET_END_ONCLOSE, http_got_header);
+               http->post_data = post_data;
+               socket->state = SOCKET_END_ONCLOSE;
+               if (!conn->upload_progress && files)
+                       conn->upload_progress = init_progress(0);
+               write_to_socket(socket, header.source, header.length, S_TRANS,
+                               send_more_post_data);
+       } else
+               request_from_socket(socket, header.source, header.length, 
S_SENT,
+                                   SOCKET_END_ONCLOSE, http_got_header);
        done_string(&header);
 }
 
diff --git a/src/protocol/http/http.h b/src/protocol/http/http.h
index c2950d9..305acaf 100644
--- a/src/protocol/http/http.h
+++ b/src/protocol/http/http.h
@@ -40,7 +40,8 @@ struct http_connection_info {
        unsigned char *post_data;
 };
 
-
+int http_read_post_data(struct socket *socket,
+                       unsigned char buffer[], int max);
 
 extern struct module http_protocol_module;
 

Attachment: pgpsrLYoBEjNf.pgp
Description: PGP signature

_______________________________________________
elinks-dev mailing list
elinks-dev@linuxfromscratch.org
http://linuxfromscratch.org/mailman/listinfo/elinks-dev

Reply via email to