Abdallah Safieddine
Abdallah Safieddine

Reputation: 125

C# how to handle multipart file uploaded from android to C#

I'm uploading excel file from android to C# the request from android is arriving to c# server(I don't want to use asp.net).

I've built from scratch a simple HTTPServe, I do't how to handle multipart data upload in c# that's my code :

Request.cs:

  class Request
{

    public String type { get; set; }
    public String url { get; set; }

    public String host { get; set; }

    private Request(String type,String url,String host)
    {
        this.type = type;

        this.url = url;

        this.host = host;
    }


    public static Request GetRequest(String request)
    {
        if (String.IsNullOrEmpty(request))
            return null;

        String[] tokens = request.Split(' ');      

        String type = tokens[0];

        String url = tokens[1];

        String host = tokens[4];




        return new Request(type, url, host);



    }
}

Response.cs: class Response {

    private Byte[] data = null;

    private String status;

    private String mime;


    private Response(String status,String mime,Byte[] data)
    {
        this.status = status;
        this.data = data;
        this.mime = mime;

    }


    public static Response From(Request request)
    {

        Console.WriteLine(request.type);
        if (request == null)
            return MakeNullRequest();



        if (request.type.Equals("POST"))
        {
            return UploadCompleteResponse(request);

        }

        return MakeFromExcel();

    }




    private static Response UploadCompleteResponse(Request request)
    {   //Handling the multipart request here but I don't know how that is a simple example 
        Console.WriteLine("uploaded!!");
        byte[] bytes = Encoding.ASCII.GetBytes("uploaded!!");

        return new Response("ok 200","text/plain",bytes);


    }



    //private static Response MakeFromFile(FileInfo f)
    //{
    //  // to do later 
    //    //return new Response("200 ok", "text/html", d);
    //}



    //Retruning an excel file response  
    private static Response MakeFromExcel()
    {
        String file = Environment.CurrentDirectory + HTTPServer.EXCEL_DIR+"brains.xlsx";
        Console.WriteLine(file);
        FileInfo info = new FileInfo(file);
        if (info.Exists)
        {
            FileStream fs = info.OpenRead();
            BinaryReader read = new BinaryReader(fs);
            Byte[] d = new Byte[fs.Length];
            read.Read(d, 0, d.Length);
            fs.Close();
            return new Response("200 ok", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", d);
        }

        return PageNotFound();


    }

    private static Response MakeNullRequest()
    {

        String file = Environment.CurrentDirectory+HTTPServer.MSG_DIR +"400.html";
        Console.WriteLine(file);
        FileInfo info = new FileInfo(file);
        FileStream fs=info.OpenRead();
        BinaryReader read=new BinaryReader(fs);
        Byte[] d = new Byte[fs.Length];
        read.Read(d, 0, d.Length);

        fs.Close();
        return new Response("400 Bad Request", "text/html", d);
    }


    private static Response PageNotFound()
    {

        String file = Environment.CurrentDirectory + HTTPServer.MSG_DIR + "400.html";
        FileInfo info = new FileInfo(file);
        FileStream fs = info.OpenRead();
        BinaryReader read = new BinaryReader(fs);
        Byte[] d = new Byte[fs.Length];
        read.Read(d, 0, d.Length);
        return new Response("404 Not Found", "text/html", d);
    }

    public void Post(NetworkStream stream)
    {
        StreamWriter writer = new StreamWriter(stream);

        writer.WriteLine(String.Format("{0} {1}\r\nServer: {2}\r\nContent-Type: {3}\r\nAccept-Ranges: 255 bytes\r\nContent-Length: {4}\r\n", HTTPServer.VERSION
            , status, HTTPServer.NAME, mime, data.Length));
        writer.Flush();
        stream.Write(data, 0, data.Length);
        stream.Flush();
        stream.Close();

    }
}

In the above code I used more than one type of response You can access and the request fields by increasing the size of the token array.

HTTServer.cs:

    class HTTPServer
{
    public const String MSG_DIR = "\\root\\msg\\";
    public const String EXCEL_DIR = "\\root\\excel\\";
    public const String WEB_DIR = "\\root\\web\\";
    public const String VERSION = "HTTP/1.1";
    public const String NAME = "Thecode007 HTTP SERVER v 1.0";
    private bool running = false;

    private TcpListener listener;



    public HTTPServer(int port)
    {
        listener = new TcpListener(IPAddress.Any,port);
    }


    public void Start() {

        Thread serverThread = new Thread(new ThreadStart(Run));

        serverThread.Start();

    }


    private void Run()
    {

        running = true;

        listener.Start();

        while (running)
        {

            Console.WriteLine("Waiting for connection...");
            TcpClient client = listener.AcceptTcpClient();

            HandleClient(client);

              Console.WriteLine("Client connected!");





        }

        running = false;

         listener.Stop();
    }

    private void HandleClient(TcpClient client)
    {
        StreamReader reader = new StreamReader(client.GetStream());

        String msg = "";

        while (reader.Peek() != -1)
        {

            msg += reader.ReadLine()+"\n";

        }



        Console.WriteLine(msg);


        Request req = Request.GetRequest(msg);

        Response resp = Response.From(req);


        resp.Post(client.GetStream());
    }



}

And here is the main method:

class Program
{
    static void Main(string[] args)
    {


        Console.WriteLine("Starting Serving on port 9000");

        HTTPServer server = new HTTPServer(9000);

        server.Start();

        Console.ReadLine();
    }
}

Upvotes: 2

Views: 626

Answers (2)

Abdallah Safieddine
Abdallah Safieddine

Reputation: 125

Response.cs:

 class Response
   {

    private Byte[] data = null;

    private String status;

    private String mime;


    private Response(String status,String mime,Byte[] data)
    {
        this.status = status;
        this.data = data;
        this.mime = mime;

    }


    public static Response From(Request request)
    {


        if (request == null)
            return MakeNullRequest();



        if (request.type.Equals("POST"))
        {
            return UploadCompleteResponse(request);

        }

        return MakeFromExcel();

    }




    private static Response UploadCompleteResponse(Request request)
    {  //I added on the rquest array the datapart which contains data
       String data=request.data;


        byte[] bytes = Encoding.ASCII.GetBytes("uploaded!!");

        return new Response("ok 200","text/plain",bytes);


    }



    //private static Response MakeFromFile(FileInfo f)
    //{
    //  // to do later 
    //    //return new Response("200 ok", "text/html", d);
    //}



    //Retruning an excel file response  
    private static Response MakeFromExcel()
    {
        String file = Environment.CurrentDirectory + HTTPServer.EXCEL_DIR+"brains.xlsx";
        Console.WriteLine(file);
        FileInfo info = new FileInfo(file);
        if (info.Exists)
        {
            FileStream fs = info.OpenRead();
            BinaryReader read = new BinaryReader(fs);
            Byte[] d = new Byte[fs.Length];
            read.Read(d, 0, d.Length);
            fs.Close();
            return new Response("200 ok", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", d);
        }

        return PageNotFound();


    }

    private static Response MakeNullRequest()
    {

        String file = Environment.CurrentDirectory+HTTPServer.MSG_DIR +"400.html";
        Console.WriteLine(file);
        FileInfo info = new FileInfo(file);
        FileStream fs=info.OpenRead();
        BinaryReader read=new BinaryReader(fs);
        Byte[] d = new Byte[fs.Length];
        read.Read(d, 0, d.Length);

        fs.Close();
        return new Response("400 Bad Request", "text/html", d);
    }


    private static Response PageNotFound()
    {

        String file = Environment.CurrentDirectory + HTTPServer.MSG_DIR + "400.html";
        FileInfo info = new FileInfo(file);
        FileStream fs = info.OpenRead();
        BinaryReader read = new BinaryReader(fs);
        Byte[] d = new Byte[fs.Length];
        read.Read(d, 0, d.Length);
        return new Response("404 Not Found", "text/html", d);
    }

    public void Post(NetworkStream stream)
    {

        try
        {
               StreamWriter writer = new StreamWriter(stream);

        writer.WriteLine(String.Format("{0} {1}\r\nServer: {2}\r\nContent-Type: {3}\r\nAccept-Ranges: 255 bytes\r\nContent-Length: {4}\r\n", HTTPServer.VERSION
            , status, HTTPServer.NAME, mime, data.Length));
        writer.Flush();
        stream.Write(data, 0, data.Length);
        stream.Flush();

        stream.Close();

        }catch(Exception  ex){


        }




    }
}

Request.cs:

    class Request
{

    public String type { get; set; }
    public String url { get; set; }

    public String host { get; set; }


    public String data { get; set; }




    private Request(String type,String url,String host)
    {
        this.type = type;

        this.url = url;

        this.host = host;
    }

    private Request(String type, String url, String host,String data)
    {
        this.type = type;

        this.url = url;

        this.host = host;

        this.data = data;
    }


    public static Request GetRequest(String request)
    {
        if (String.IsNullOrEmpty(request))
            return null;

        String[] tokens = request.Split(' ');      

        String type = tokens[0];

        String url = tokens[1];

        String host = tokens[4];
        String data = "N/A";
        if (tokens.Length >= 9)
        {
            data = tokens[8];



        }

        return new Request(type, url, host, data);



    }
}

Secondly my android client was excpecting a response which is responsbody type not a plain text thats why the data was never sent....

Upvotes: 0

Neil
Neil

Reputation: 1633

Disclaimer: You should never write a HTTP server directly with TcpClient for any production work. There are far too many specifications to be accounted for and C# has these built in to any Asp.Net web server you use.

That being said, for an exercise this is a matter of parsing the request in a specific way. You should be able to reference these questions to learn more about the details of multipart boundary:

Essentially, you will have to read a header from the http headers (Content-Type), and parse the value of boundary= to determine what is separating the key/value pairs of the multipart form in the request body. Once you've got the boundary you will have to parse the body of the request into the real key/value pairs of the form. From there, the contents of the uploaded file will be the value of whatever key the form submits it as.

Read more on the official W3 spec

Upvotes: 2

Related Questions