This project is read-only.

How to decode multipart/form-data

Sep 8, 2008 at 7:10 AM
Hi,

what is the easiest way to decode multipart/form-data, as generated by this form (file upload):

<form method='POST' enctype='multipart/form-data' action='http://localhost:11111/bitmap'>
Bitmap: <input type='file' name='file'/><br/>
Optional name: <input type='text' name='name'/><br/>
<br/>
<input type='submit' value='Upload'/>
</form>

I made some guesses and tried to use a FormDecoderProvider,

FormDecoderProvider fdp = new FormDecoderProvider();
request.DecodeBody(fdp);

but fdp.Count == 0.
Sep 8, 2008 at 7:24 AM
It should already have been done for you:

HttpFile file = Request.Form.GetFile("name");

The FormDecoderProvider is just a Provider (it check the request content type to see which decoder to use), which do not have any decoders in it from start.
To use it, you have to add one or more providers into it:

            FormDecoderProvider fdp = new FormDecoderProvider();
            fdp.Add(new MultipartDecoder());
            Request.DecodeBody(fdp);

This is done automatically by the HttpServer class if none have been previously added.
Sep 8, 2008 at 9:01 AM
Thanks, I missed the request.Form parameter.

But now I get an exception from request.Form.ContainsFile("file")

{"Cannot request information from instance HttpForm.EmptyForm."}

What does this mean? Am I missing something?
Sep 8, 2008 at 12:37 PM
As mentioned the webserver adds the different standard decoders itself but only if no other decoders are added so make sure you do not add any decoders yourself.
When a http request is recieved the decoders are iterated in FormDecoderProvider line 45, if you break there you should be able to see the decoders parsing the request if the mime-type is parsable.

If no decoder can parse the request the Request.Form is set to an EmptyForm instance which is your case, this shouldn't happen if the MultipartDecoder is added.
If you can please make sure the decoder is added or if you could post the exact usage of the webserver code so we can test it ourselves.

Hope this helps
Sep 9, 2008 at 8:34 AM
I figured out that svn change set 14119 corresponds to beta1 and downloaded the source. It would be helpful if you could tag your configurations in subversion.

I put breakpoints in FormDecoderProvider.Decode, but this metod is never called.

Is there a way to attach files to a forum post? I couldn't find any, so here is the code I use. I stripped it down to the essentials for the purpose of testing file upload. It is a console application.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net;
using HttpServer;
using HttpServer.FormDecoders;
using HttpListener = HttpServer.HttpListener;

namespace VirtualFinger
{
    class Program
    {
        private static bool running = true;

        private HttpListener listener;

        static void Main(string[] args)
        {
            int port = 11111;
            Program p = new Program(port);
            while (running)
            {
                Thread.Sleep(1000);
            }
        }

        public Program(int port)
        {
            listener = new HttpListener(IPAddress.Any, port);
            listener.RequestHandler += OnRequest;
            listener.Start(5);

            System.Console.WriteLine("VirtualFinger is listening on port " + port + ".");
        }

        private void OnRequest(HttpClientContext client, HttpRequest request)
        {
            // Log to std out
            foreach (String part in request.UriParts)
            {
                System.Console.Write(part + " ");
            }
            System.Console.WriteLine(request.Method);

            // Handle requests
            String response = "ok";

            if (request.Method.Equals("POST"))
            {
                if (request.UriParts.Length == 1 && request.UriParts[0].Equals("finger"))
                {
                    if (request.Form.ContainsFile("file")) //&& request.Param.Contains("name"))
                    {
                        System.Console.WriteLine(request.Form.GetFile("file"));
                        System.Console.WriteLine(request.Param["name"]);
                    }
                }
            }
            else
            {
                client.Respond(HttpHelper.HTTP11, HttpStatusCode.NotFound, request.Uri.AbsoluteUri, "");
                return;
            }

            client.Respond(response);
        }
    }
}

Another question. What do you suggest that I do to keep the application running while listening to incoming requests. Now I have a busy loop. A semaphore would be better, but is there some standard way to do it?

Sep 24, 2008 at 12:10 PM
I added the code that you suggested above

                    FormDecoderProvider fdp = new FormDecoderProvider();
                    fdp.Add(new MultipartDecoder());
                    request.DecodeBody(fdp);

and this solved the problem. Decoders are not added by default when using HttpListener.

Sep 24, 2008 at 1:11 PM
Good that you found a solution.

About keeping the server running:
In development I use a Console.ReadLine() at the end of the Main method.
In production, I run my server as a NT (windows) service.
Oct 24, 2008 at 8:10 AM
About keeping the server running:
I now wait on a semaphore in Main().

using System.Threading;

private static Semaphore terminate;

terminate = new Semaphore(0, 1);
Program p = new Program(port);
terminate.WaitOne();

In Program, I can do the following to exit the application:

terminate.Release(1);

Oct 24, 2008 at 8:27 AM
Read this article if you do not want to use any GUI but keep the server running in the background:
http://www.codeproject.com/KB/system/WindowsService.aspx