| iMatix home page
| << | < | > | >>
SFL Logo SFL
Version 2.11

 

http_multipart_decode

#include "sflhttp.h"
DESCR *
http_multipart_decode (const char *mime_file, const char *store_path,
                       const char *local_format)

Synopsis

Parses a multipart-encoded file (as received by a web server as POST data) and returns a HTTP-encoded string containing the field data, in the format: "name=value&name=value&name=value...". For each field that refers to an uploaded file (INPUT field with type FILE), creates a temporary file holding the data. The name of this temporary file is put into a generated variable, whose name is built by using the local format string (ex: '%s_tmp'). The actual uploaded file is stored in a temporary file whose name is generated by the SFL get tmp file name() function. So, data for a file upload field called "doc" will be stored in a temporary file called (eg) "temp1234.tmp", and a field "doc_tmp" will be added, with the value "temp1234.tmp". The HTTP-encoded string is returned as a DESCR block, which you can decode using http query2strt(), passing the descriptor data. You must free the descriptor using mem_free() when you're finished with it.

Source Code - (sflhttp.c)

{
    FILE
        *f_source,
        *f_tmp = NULL;
    char
        *tmp_name = NULL,
        *p_head,
        *p_data,
        *p_next,
        *buffer;
    int
        offset,
        read_size,
        rest_read_size;
    static char
        separator [80 + 1];
    static int
        sep_size;
    SYMTAB
        *table,
        *header_tab;
    qbyte
        tmp_index = 1;
    DESCR
        *descr = NULL;

    ASSERT (local_format);

    if (strstr (local_format, "%s") == NULL)
        return (NULL);

    buffer = mem_alloc (MULTI_BUFFER_SIZE + REST_BUFFER_SIZE + 1);
    if (buffer == NULL)
        return (NULL);

    table = sym create table ();
    if (table == NULL)
      {
        mem_free (buffer);
        return (NULL);
      }

    header_tab = sym create table ();
    if (header_tab == NULL)
      {
        mem_free (buffer);
        sym delete table (table);
        return (NULL);
      }

    f_source = fopen (mime_file, "rb");
    if (f_source == NULL)
      {
        mem_free (buffer);
        sym delete table (table);
        sym delete table (header_tab);
        return (NULL);
      }

    memset (separator, 0, sizeof (separator));
    separator [0] = 0x0D;
    separator [1] = 0x0A;
    fgets (&separator [2], 78, f_source);
    strconvch (&separator [2] , '\r', '\0');
    strconvch (&separator [2] , '\n', '\0');
    sep_size  = strlen (separator);

    read_size = fread (buffer, 1, MULTI_BUFFER_SIZE, f_source);
    p_next = buffer;
    while (read_size > 0)
      {
        sym empty table (header_tab);
        p_head = p_next;
        p_data = (char *) memfind ((byte *) p_head,
                          MULTI_BUFFER_SIZE + REST_BUFFER_SIZE - (p_head - buffer),
                          (byte *) "\r\n\r\n", 4, FALSE);
        if (p_data)
          {
            *p_data = '\0';
            p_data += 4;
          }
        if (p_head)
          {
            multipart_decode_header (p_head, header_tab);
            if (sym lookup symbol (header_tab, "filename") != NULL)
              {
                if (f_tmp != NULL)
                  {
                    ASSERT (tmp_name != NULL);
                    fclose (f_tmp);
                    f_tmp = NULL;
                    if (get file size (tmp_name) == 0)
                        file delete (tmp_name);
                  }
                tmp_name = get tmp file name (store_path, &tmp_index, "tmp");
                f_tmp = fopen (tmp_name, "wb");
              }
          }
        p_next = (char *) memfind ((byte *) p_data,
                          /*  read_size                                      */
                          MULTI_BUFFER_SIZE + REST_BUFFER_SIZE - (p_data - buffer),
                          (byte *) separator, sep_size, FALSE);

        if (p_next != NULL)
          {
            /*  The next attribute-value pair was found                      */
            *p_next = '\0';
            save_multipart_header (table, header_tab, p_data, tmp_name,
                                   local_format);
            if (f_tmp)
              {
                /* Special case:
                   The next attribute value is found AND "f_tmp" is opened.
                   That means that the download file is completely in the
                   buffer and so we can save it to disk.
                 */
                fwrite (p_data, p_next - p_data, 1, f_tmp);
                fclose (f_tmp);
                f_tmp = NULL;
                if (get file size (tmp_name) == 0)
                    file delete (tmp_name);

                /* Now we need to check the buffer.  If the buffer is full
                   then we must read the rest of "f_source". The rest will
                   be written into the the buffer at REST_BUFFER_SIZE.
                 */
                if (read_size == MULTI_BUFFER_SIZE)
                    rest_read_size = fread (&buffer [MULTI_BUFFER_SIZE], 1,
                                            REST_BUFFER_SIZE, f_source);
              }
            p_next += sep_size;

            /*  Found end of file marker                                     */
            if (*p_next == '-' && *(p_next + 1) == '-')
              {
                if (f_tmp)
                  {
                    fclose (f_tmp);
                    f_tmp = NULL;
                    if (get file size (tmp_name) == 0)
                        file delete (tmp_name);
                  }
                break;
              }
            else
                while (*p_next == '\r' || *p_next == '\n')
                    p_next++;
          }
        else
          {
            if (f_tmp)
                fwrite (p_data, &buffer [read_size - sep_size ] - p_data,
                        1, f_tmp);
            offset = 0;
            while (read_size > 0 && p_next == NULL)
              {
                memmove (buffer, &buffer [read_size - sep_size + offset ],
                                 sep_size);
                read_size = fread (&buffer [sep_size], 1,
                                   MULTI_BUFFER_SIZE - sep_size, f_source);
                p_next = (char *) memfind ((byte *) buffer,
                                  read_size + sep_size,
                                  (byte *) separator, sep_size, FALSE);
                if (p_next != NULL)
                  {
                    /*  We need to test if the buffer is large enough.  If
                        not, we use the additional buffer size starting at
                        position REST_BUFFER_SIZE.
                     */
                    if (read_size == (MULTI_BUFFER_SIZE - sep_size))
                      {
                        /* Attach the rest of the file */
                        rest_read_size = fread (&buffer [MULTI_BUFFER_SIZE], 1,
                                                REST_BUFFER_SIZE, f_source);
                      }

                    *p_next = '\0';
                    save_multipart_header (table, header_tab,
                                           p_data, tmp_name, local_format);
                    if (f_tmp)
                      {
                        fwrite (buffer, p_next - buffer, 1, f_tmp);
                        fclose (f_tmp);
                        f_tmp = NULL;
                        if (get file size (tmp_name) == 0)
                            file delete (tmp_name);
                      }
                    p_next += sep_size;

                   /*  Found end of file marker                              */
                   if (*p_next == '-' && *(p_next + 1) == '-')
                     {
                       read_size = 0;
                       break;
                     }
                   else
                       while (*p_next == '\r' || *p_next == '\n')
                           p_next++;
                   read_size += sep_size;
                  }
                else
                  {
                    /*  We did not find the next separator, so we write the
                        file and continue.
                     */
                    if (f_tmp)
                        fwrite (buffer, read_size, 1, f_tmp);
                    offset = sep_size;
                  }

              }
          }
      }
    if (f_tmp)
      {
        fclose (f_tmp);
        if (get file size (tmp_name) == 0)
            file delete (tmp_name);
      }
    sym delete table (header_tab);
    fclose (f_source);
    mem_free (buffer);

    descr = http_multipart2url (table);
    sym delete table (table);

    return (descr);
}

| << | < | > | >> iMatix Copyright © 1996-2000 iMatix Corporation