Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

A Simple Way to Upload Files Using Mongoose

DZone's Guide to

A Simple Way to Upload Files Using Mongoose

Mongoose is a free, open-source, embeddable, simple, generic "C" server program. It's really easy to modify and extend. Here's how you can upload files with it.

· Web Dev Zone
Free Resource

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

Do you want to upload files of any size simply and joyously? You definitely need Mongoose.

Here’s How You Do It, Step by Step

First of all, we need a web page with an "Upload button", it might be something like this:

<html><body>Upload example
<form method="POST" action="upload ectype="multipart/form-data">
<input type="file" name="file" /> 
<br/> <input type="submit" value="Upload"/>
</form></body></html>

Now, we need to implement an event handler. It is usually the Mongoose event handler. Here is how it begins:

static void handle_upload(struct mg_connection *nc, int ev, void *p) {
  struct file_writer_data *data = (struct file_writer_data *) nc->user_data;
  struct mg_http_multipart_part *mp = (struct mg_http_multipart_part*)p;

Take a look at the mg_http_multipart_part structure. It contains useful information about the uploading process.

In the handler, we need to take care of the following events:

  • MG_EV_HTTP_PART_BEGIN: new incoming data request, we can do some preparation here. For example, we can open the file.
case MG_EV_HTTP_PART_BEGIN:
  .....
  data = calloc(1, sizeof(struct file_writer_data));
  /* We use temp file, but it is possible to use real file name;
     mp->file_name contains it */
  data->fp = tmpfile();  
        data->bytes_written = 0;
  ....     
  • MG_EV_HTTP_PART_DATA: data continues, mp contains pointer to data and its length. Writing to file here.
    case MG_EV_HTTP_PART_DATA: 
    ...
    fwrite(mp->data.p, 1, mp->data.len, data->fp
    .... 
  • MG_EV_HTTP_PART_END: data finished, time to close file.
case MG_EV_HTTP_PART_END:  
  ....
  fclose(data->fp);
  ....

Let’s put it all together:

static void handle_upload(struct mg_connection *nc, int ev, void *p) {
  struct file_writer_data *data = 
     (struct file_writer_data *) nc->user_data;
  struct mg_http_multipart_part *mp = 
     (struct mg_http_multipart_part*)p;

  switch (ev) {
    case MG_EV_HTTP_PART_BEGIN: {
      if (data == NULL) {
        data = calloc(1, sizeof(struct file_writer_data));
        data->fp = tmpfile();
        data->bytes_written = 0;

        if (data->fp == NULL) {
          mg_printf(nc, "%s",
                    "HTTP/1.1 500 Failed to open a file\r\n"
                    "Content-Length: 0\r\n\r\n");
          nc->flags |= MG_F_SEND_AND_CLOSE;
          return;
        }
        nc->user_data = (void *) data;
      }
      break;
    }
    case MG_EV_HTTP_PART_DATA: {
      if (fwrite(mp->data.p, 1, 
           mp->data.len, data->fp) != mp->data.len) {
        mg_printf(nc, "%s",
                  "HTTP/1.1 500 Failed to write to a file\r\n"
                  "Content-Length: 0\r\n\r\n");
        nc->flags |= MG_F_SEND_AND_CLOSE;
        return;
      }
      data->bytes_written += mp->data.len;
      break;
    }
    case MG_EV_HTTP_PART_END: {
      mg_printf(nc,
                "HTTP/1.1 200 OK\r\n"
                "Content-Type: text/plain\r\n"
                "Connection: close\r\n\r\n"
                "Written %ld of POST data to a temp file\n\n",
                (long) ftell(data->fp));
      nc->flags |= MG_F_SEND_AND_CLOSE;
      fclose(data->fp);
      free(data);
      nc->user_data = NULL;
      break;
    }
  }
}

Don't forget to establish the listening connection:

  nc = mg_bind(&mgr, "1234", ev_handler);

And, register the HTTP endpoint (this is optional):

  mg_register_http_endpoint(nc, "/upload", handle_upload);

That's basically it. Mongoose will handle the rest.

Two More Things You Need to Know

You can use the same approach for uploading files to embedded devices. Mongoose parses a multipart request on the fly and issues events as we described earlier without waiting for the entire request to be buffered. So, you can upload gigabyte files, even if your device has only a few kilobytes of memory.  

And, Mongoose can do even more for you. If all you need is to save an uploaded file into a file system (not, let’s say, program a flash chip), you can usemg_file_upload_handler helper function. In this case, event handler shapes to:

void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
  switch (ev) {
    ...
    case MG_EV_HTTP_PART_BEGIN:
    case MG_EV_HTTP_PART_DATA:
    case MG_EV_HTTP_PART_END:
      mg_file_upload_handler(nc, ev, ev_data, upload_fname);
      break;
   }
 }

This is really simple.

You can download the full source code here.

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:
file i/o operations ,http server ,mongoose ,tutorial

Published at DZone with permission of Alexander Alashkin, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}