From fa5bc0e044e48e10f03c29f378a8c0a5d276e753 Mon Sep 17 00:00:00 2001 From: Andrea Zagli Date: Sun, 21 Jun 2015 19:43:21 +0200 Subject: [PATCH] Redid ZakCgiMain::parse_stdin: now works also with binary files. --- src/main.c | 297 +++++++++++++++++++++++++++++++++++----------------- src/main.h | 2 + tests/env.c | 39 +++---- 3 files changed, 225 insertions(+), 113 deletions(-) diff --git a/src/main.c b/src/main.c index b79be44..1816586 100644 --- a/src/main.c +++ b/src/main.c @@ -219,6 +219,7 @@ gchar const gchar *env; guint l; + gsize bytesread; GError *error; GInputStream *istream; @@ -236,131 +237,237 @@ gchar ret = g_malloc0 (l + 1); istream = g_unix_input_stream_new (0, TRUE); - g_input_stream_read (istream, - ret, - l, - NULL, - &error); + g_input_stream_read_all (istream, + ret, + l, + &bytesread, + NULL, + &error); + if (l != bytesread) + { + syslog (LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), "error reading stdin: bytes read differ from content length"); + } if (error != NULL) { syslog (LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), "error reading stdin: %s", error->message); } + + syslog (LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), "stdin: %s", ret); } } return ret; } -GHashTable -*zak_cgi_main_parse_stdin (const gchar *buf, const gchar *boundary) +static gchar +*zak_cgi_main_read_line (const gchar *buf, guint l, guint *i, + gboolean no_new_line_but_null_terminated, + guint *bytesread) { - GHashTable *ht; - - gchar *_boundary; - - gchar **v_boundary; - guint l_v_boundary; + gchar *line; + guint line_start; + guint count; - guint i_v_boundary; - - ht = NULL; - - _boundary = g_strdup_printf ("--%s", boundary); - v_boundary = g_strsplit (buf, _boundary, -1); - if (v_boundary != NULL) + for (line_start = *i, count = 1; *i < l - 1; (*i)++, count++) { - gchar *eol; - gchar *deol; - - eol = g_strdup_printf ("%c%c", 13, 10); - deol = g_strdup_printf ("%s%s", eol, eol); - - ht = g_hash_table_new (g_str_hash, g_str_equal); - - l_v_boundary = g_strv_length (v_boundary); - for (i_v_boundary = 1; i_v_boundary < l_v_boundary - 1; i_v_boundary++) + if (buf[*i] == 13 && buf[*i + 1] == 10) { - gchar *first_line; - gchar *end_line; - gchar **v_content; - gchar **parts; - guint l_v_content; - guint i_v_content; - - gchar *param_name; - gchar *param_name_file; - gchar *param_value; + (*i)++; + count++; + break; + } + } - GValue *gval; + line = (gchar *)g_memdup (buf + line_start, count); + if (no_new_line_but_null_terminated) + { + line[count - 2] = '\0'; + } - end_line = g_strstr_len (v_boundary[i_v_boundary] + 2, -1, eol); - first_line = g_strndup (v_boundary[i_v_boundary], strlen (v_boundary[i_v_boundary]) - strlen (end_line)); + *bytesread = count; - v_content = g_strsplit (first_line, ";", -1); - l_v_content = g_strv_length (v_content); + (*i)++; - parts = g_strsplit (v_content[1], "=", 2); - param_name = g_strndup (parts[1] + 1, strlen (parts[1]) - 2); - param_name[strlen (parts[1]) - 2] = '\0'; - g_strfreev (parts); + return line; +} - if (l_v_content == 3) - { - parts = g_strsplit (v_content[2], "=", 2); - param_name_file = g_strndup (parts[1] + 1, strlen (parts[1]) - 2); - param_name_file[strlen (parts[1]) - 2] = '\0'; - g_strfreev (parts); - } +/** + * zak_cgi_main_parse_stdin: + * + * Returns: + */ +GHashTable +*zak_cgi_main_parse_stdin (const gchar *buf, const gchar *boundary) +{ + GHashTable *ht; - g_strfreev (v_content); - g_free (first_line); + const gchar *env; - end_line = g_strstr_len (v_boundary[i_v_boundary], -1, deol); - if (l_v_content == 3) - { - param_value = g_strndup (end_line + 4, strlen (end_line + 4) - 2); - param_value[ strlen (end_line + 4) - 2] = '\0'; - } - else - { - param_value = g_strdup (end_line + 4); - } + guint l; + guint i; + guint bytesread; - gval = g_new0 (GValue, 1); + gchar *_boundary; - if (l_v_content == 3) - { - GPtrArray *ar; + gchar *line; + gchar *content_disposition; + gchar *content_type; + gchar *tmp; - ar = g_ptr_array_new (); - g_ptr_array_add (ar, g_strdup (param_name_file)); - g_ptr_array_add (ar, g_strdup (param_value)); + ht = NULL; - g_value_init (gval, G_TYPE_PTR_ARRAY); - g_value_take_boxed (gval, ar); - } - else - { - g_value_init (gval, G_TYPE_STRING); - g_value_set_string (gval, g_strdup (param_value)); - } + env = g_getenv ("CONTENT_LENGTH"); + if (env != NULL) + { + l = strtol (env, NULL, 10); + if (l > 0) + { + ht = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_replace (ht, g_strdup (param_name), gval); + _boundary = g_strdup_printf ("--%s", boundary); - g_free (param_name); - g_free (param_value); - if (l_v_content == 3) + i = 0; + do { - g_free (param_name_file); - } + /* read line */ + line = zak_cgi_main_read_line (buf, l, &i, TRUE, &bytesread); + syslog (LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), "boundary: %s %d", line, bytesread); + if (g_strcmp0 (line, _boundary) == 0) + { + /* content-disposition */ + gchar **v_content; + gchar **parts; + guint l_v_content; + + gchar *param_name; + gchar *param_name_file; + gchar *param_value; + guint file_l; + + GValue *gval; + + content_disposition = zak_cgi_main_read_line (buf, l, &i, TRUE, &bytesread); + syslog (LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), "content_disposition: %s", content_disposition); + + v_content = g_strsplit (content_disposition, ";", -1); + l_v_content = g_strv_length (v_content); + + parts = g_strsplit (v_content[1], "=", 2); + param_name = g_strndup (parts[1] + 1, strlen (parts[1]) - 2); + param_name[strlen (parts[1]) - 2] = '\0'; + g_strfreev (parts); + + if (l_v_content == 3) + { + parts = g_strsplit (v_content[2], "=", 2); + param_name_file = g_strndup (parts[1] + 1, strlen (parts[1]) - 2); + param_name_file[strlen (parts[1]) - 2] = '\0'; + syslog (LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), "param_name_file: %s", param_name_file); + g_strfreev (parts); + + /* content-type */ + content_type = zak_cgi_main_read_line (buf, l, &i, TRUE, &bytesread); + syslog (LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), "content_type: %s", content_type); + g_free (content_type); + } + + g_strfreev (v_content); + g_free (content_disposition); + + /* empty */ + g_free (zak_cgi_main_read_line (buf, l, &i, TRUE, &bytesread)); + + if (l_v_content == 3) + { + param_value = (gchar *)g_malloc (1); + if (g_strcmp0 (param_name_file, "") != 0) + { + gboolean exit; + + exit = FALSE; + file_l = 0; + do + { + tmp = zak_cgi_main_read_line (buf, l, &i, FALSE, &bytesread); + syslog (LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), "tmp: %s %d", tmp, bytesread); + + if (memcmp (tmp, _boundary, strlen (_boundary)) == 0) + { + i -= bytesread; + exit = TRUE; + } + else + { + param_value = g_realloc (param_value, file_l + bytesread); + memmove (param_value + file_l, tmp, bytesread); + file_l += bytesread; + } + + g_free (tmp); + } while (!exit); + } + else + { + /* empty */ + g_free (zak_cgi_main_read_line (buf, l, &i, TRUE, &bytesread)); + + file_l = 3; + param_value[0] = '\0'; + } + } + else + { + param_value = zak_cgi_main_read_line (buf, l, &i, TRUE, &bytesread); + syslog (LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), "param_value: %s", param_value); + } + + gval = g_new0 (GValue, 1); + + if (l_v_content == 3) + { + GPtrArray *ar; + + ar = g_ptr_array_new (); + g_ptr_array_add (ar, g_strdup (param_name_file)); + g_ptr_array_add (ar, g_memdup (param_value, file_l - 2)); + g_ptr_array_add (ar, GSIZE_TO_POINTER (file_l - 2)); + + g_value_init (gval, G_TYPE_PTR_ARRAY); + g_value_take_boxed (gval, ar); + } + else + { + g_value_init (gval, G_TYPE_STRING); + g_value_set_string (gval, g_strdup (param_value)); + } + + g_hash_table_replace (ht, g_strdup (param_name), gval); + + g_free (param_name); + g_free (param_value); + if (l_v_content == 3) + { + g_free (param_name_file); + } + } + else + { + tmp = g_strdup_printf ("%s--", _boundary); + if (g_strcmp0 (line, tmp) == 0) + { + g_free (tmp); + break; + } + g_free (tmp); + } + + g_free (line); + } while (i < l); + + g_free (_boundary); } - - g_strfreev (v_boundary); - g_free (deol); - g_free (eol); } - g_free (_boundary); - + return ht; } diff --git a/src/main.h b/src/main.h index 0dd24d9..63e4c88 100644 --- a/src/main.h +++ b/src/main.h @@ -62,6 +62,8 @@ gchar *zak_cgi_main_get_stdin (void); GHashTable *zak_cgi_main_parse_stdin (const gchar *buf, const gchar *boundary); +GHashTable *zak_cgi_main_parse_stdin_bin (const gchar *buf, const gchar *boundary); + G_END_DECLS diff --git a/tests/env.c b/tests/env.c index acd40bd..6f5d512 100644 --- a/tests/env.c +++ b/tests/env.c @@ -40,7 +40,7 @@ main (int argc, char *argv[]) g_free (env); env = zak_cgi_main_get_stdin (); - syslog (LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), "stdin: %s", env); + /*syslog (LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), "stdin: %s", env);*/ if (env != NULL) { g_string_append_printf (str, @@ -75,23 +75,26 @@ main (int argc, char *argv[]) g_string_append_printf (str, "%s%s\n", (gchar *)key, (gchar *)g_ptr_array_index (ar, 0)); - /* save the file to tmp */ - GFile *gfile; - GFileIOStream *iostream; - GOutputStream *ostream; - - iostream = NULL; - gfile = g_file_new_tmp (g_strdup_printf ("cgi-XXXXXX-%s", (gchar *)g_ptr_array_index (ar, 0)), - &iostream, - NULL); - - ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream)); - g_output_stream_write (ostream, - (gchar *)g_ptr_array_index (ar, 1), - strlen ((gchar *)g_ptr_array_index (ar, 1)), - NULL, - NULL); - g_output_stream_close (ostream, NULL, NULL); + if (g_strcmp0 ((gchar *)g_ptr_array_index (ar, 0), "") != 0) + { + /* save the file to tmp */ + GFile *gfile; + GFileIOStream *iostream; + GOutputStream *ostream; + + iostream = NULL; + gfile = g_file_new_tmp (g_strdup_printf ("cgi-XXXXXX-%s", (gchar *)g_ptr_array_index (ar, 0)), + &iostream, + NULL); + + ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream)); + g_output_stream_write (ostream, + g_ptr_array_index (ar, 1), + GPOINTER_TO_SIZE (g_ptr_array_index (ar, 2)), + NULL, + NULL); + g_output_stream_close (ostream, NULL, NULL); + } } else { -- 2.49.0