【问题标题】:Reading CGI POST data the most efficient way读取 CGI POST 数据最有效的方法
【发布时间】:2010-07-14 02:07:47
【问题描述】:

我非常需要一种方法来挖掘潜在的大量 CGI 提供的 POST 数据。

读取 GET 数据没什么大不了的,因为我可以根据需要随时重新请求 QUERY_STRING 环境变量,但使用通过 stdin 提供的 POST 数据。我只能读取一次,并且必须将其存储在某个地方。

我当前的方法包括读取临时文件中的全部 POST 数据,该文件将在程序退出时删除并扫描它以找到我想要找到的键。 在 GET 解析方法中,我可以只在 QUERY_STRING 上使用 strtok(),因为 GET 数据的限制非常低,因此可以安全地在 RAM 中获取,但 POST 数据可以是从空到“name=Bob”到 4 Gigabye 电影的任何内容文件。

所以,这是我目前的方法:

int get_post_data(const char *s_key, char *target, size_t target_size)
{
   FILE *tmp;
   int ret_val = -1;

   /* postdata_temp = global variable containing the temporary file name */
   if ((tmp = fopen(postdata_tempfile, "r")) == NULL)
      return -1;
   else
   {
      char *buffer = NULL;
      char *temp_buffer = NULL;
      int buffer_size;
      int i;

      if ((buffer = malloc(BUFFER_SIZE)) == NULL)
         return -1;

      memset(buffer, 0, sizeof(BUFFER_SIZE));
      buffer_size = BUFFER_SIZE;

      for (i = 0;; i++)
      {
         int c = fgetc(tmp);

         if ((c == '&') || feof(tmp))
         {
            char *key = strtok(buffer, "=");
            char *val = strtok(NULL, "");            

            if (key)
            {
               if (strcmp(s_key, key) == 0)
               {
                  if (val)
                  {
                     strncpy(target, val, target_size);
                     ret_val = strlen(val);
                  }
                  else
                  {
                     target = NULL;
                     ret_val = 0;
                  }

                  break;
               }
            }

            if (feof(tmp))
               break;

            memset(buffer, 0, buffer_size);
            i = -1; /* because it will be 0 when the fgetc() is called the 
                     * next time */
         }
         else
         {
            if (!(i < buffer_size))
            {
               buffer_size += BUFFER_SIZE;

               if ((temp_buffer = realloc(buffer, buffer_size)) == NULL)
               {
                  free(temp_buffer);
                  free(buffer);
                  target = NULL;

                  return -1;
               }
               else
                  buffer = temp_buffer;
            }

            buffer[i] = c;
         }

      }

      free(buffer);

      // printf("Final buffer size: %d<br />\n", buffer_size);
   }

   fclose(tmp);

   return ret_val;
}

这确实有效,我可以调用get_post_data("user_password", pass, sizeof(pass));,检查返回值(0 = 数据长度),但它似乎过于肥胖。我的意思是.. 我想搜索的每个 POST 参数的巨大 IO 开销只是为了不让我的 RAM 中的整个字符串用于可能上传的大文件?

Stackoverflow 是怎么想的?

【问题讨论】:

    标签: c parsing post cgi storage


    【解决方案1】:

    如果您想避免将大文件加载到 RAM 中,您可以使用内存映射文件 - 不可移植,但这是正确的做法。如果您的平台是 POSIX,您可以为此使用 mmap()

    顺便说一句,我没有完全阅读或测试您的代码,但我想知道使用strtok() 是否正确,因为它会破坏数据。如果您的数据可能是二进制文件,我还想知道使用 str...() 函数,但我不知道 CGI 部分是如何工作的,所以您可能就在那里。

    【讨论】:

    • 数据以“key=value”的形式到达,我使用strtok() 分割键和值。在实践中只有值是二进制的,并且将不加修改地传递给调用者:)
    • @LukeN:这些有帮助吗?
    【解决方案2】:

    我认为拒绝大于设定限制(例如 2MB)的 POST 请求会更容易。

    这样:

    • 您有一个可管理大小的数据块可供使用。
    • 您可以防止恶意 4GB POST 请求。

    【讨论】:

    • 我尽量不限制我的程序可以接受的内容。在这种特殊情况下(文本文章),2 MB 就足够了,但我编写模块的方式使我能够在任何情况下使用它们,例如文件上传,其中 2 MB 是杯水车薪。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-24
    • 1970-01-01
    • 2018-07-21
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多