Sending a Multipart Form Request to a Node server

Hello!

Not really sure if this is the right place to post this question, but here goes nothing.

I’ve been working on an app that lets you create models within Unity, and i’ve got everything working except my interface with the web marketplace.

I need to be able to send these files into my Node server in order to do a number of things but i am stuck on a step that i thought would be simple:

I can’t actually get the data to go through without the stream ending unexpectedly, or there being no data transferred on the other end (despite the Content-Length clearly growing and shrinking depending on what i add.)

Here is my code from Unity:

IEnumerator UploadFileToServer()
    {
        List<IMultipartFormSection> Data = new List<IMultipartFormSection>();
        Data.Add(new MultipartFormDataSection("SomeField", "SomeData"));
        Data.Add(new MultipartFormDataSection("SomeMoreFields", "SomeMOREData"));
        Data.Add(new MultipartFormFileSection("FuckinFile", UnityWebRequest.GenerateBoundary()));

        UnityWebRequest request = UnityWebRequest.Post(EndPoint, Data);

        yield return request.Send();

        if (request.isError)
        {
            Debug.Log("Error " + request.error);
        }
        else
        {
            Debug.Log("Form upload complete!");
            foreach (KeyValuePair<string, string> stuff in request.GetResponseHeaders())
            {
                Debug.Log("Got response header: key: " + stuff.Key + " val: " + stuff.Value);
            }
        }
    }

And once i send that through, i hit node:

At first, i used “Multiparty” which kept getting “Stream ended unexpectedly”
Heres the code for that:

exports.PostNewModelUnity = function (req, res) {

    console.log("Got new post from unity, parsing...");
    var form = new multiparty.Form();

    //console.log(req.method);
    console.log(util.inspect(req.headers));
    console.log(util.inspect(req.body));

    form.parse(req, function (err, fields, files) {
        if (err) {
            console.log("Errored parsing req from unity: " + err);
        } else {
            console.log("Succesfully got post from Unity");
            console.log(fields);
            console.log(files);
            util.inspect({
                fields: fields,
                files: files
            });
            res.end("Got some request");
        }
    });
}

Afterwards, i tried using “Multer” but i just don’t seem to have any data within the body, or the files field after trying to parse it with the “Any()” command, i tried “Array(), Fields(), None(), etc…” to no avail.

exports.PostNewModelUnity = function (req, res,next) {

    console.log("Got new post from unity, parsing...");
   
    console.log(util.inspect(req.headers));
    console.log("body");
    console.log(util.inspect(req.body));
    console.log("files");
    console.log(util.inspect(req.files));
}

I’ve been trying different options, so many that i don’t even know where to begin, and i kind of gave up for a month or two before getting back into it last night.

There was this post

And i tried doing what this dude did, to no avail. It changed from “stream ended unexpectedly” to “Content-Type missing boundary”…

Please give me a hand, my app is totally halted until i can get this working, and i am completely friggen lost.

PS. If i posted in the wrong section, please let me know so i can repost.

Thanks,

  • Sol.

I’m no specialist, but have you tried uploading raw data via UnityWebRequest.Put? Maybe that will do the job.

1 Like

How big is the data you try to send?

It’s model files so it’s variable. Depends on the size the user wanted to. But we’re probably going to restrict model uploaded to around 30 megs max for now cause we have like no money to invest into this (however, we’re uploading these onto sketchfab so we dont have to host it, so we’ll see. the thing we need to upload is mostly to do with other users remixing each others content which i hope will be fairly light weight data).

I just did this instead and with about a day of hitting my head against the wall i was able to do this.

Dont think it’s super efficient in the way im outputting the data from our stuff (it’s not streamed, just one chunk) so it’ll probably have to be looked at further down the line, but for now, and as a demo with a little amount of users im sure it’ll be fine.

Thank you!

Have you tried using WWWForm?

I have a similar issue with unity using UnityWebRequest.Post.

byte[] bytesArchivo = File.ReadAllBytes(fullPath);
            List<IMultipartFormSection> camposFormulario = new List<IMultipartFormSection>();
  camposFormulario.Add(new MultipartFormDataSection("field1", "value1"));
            camposFormulario.Add(new MultipartFormDataSection("field2", "value2"));
            camposFormulario.Add(new MultipartFormDataSection("field3", "value3"));
            camposFormulario.Add(new MultipartFormDataSection("field4", "value4"));
            camposFormulario.Add(new MultipartFormDataSection("field5", "value5"));
            camposFormulario.Add(new MultipartFormDataSection("field6", "value6"));
            string nom = Path.GetFileName(fullPath);
            camposFormulario.Add(new MultipartFormFileSection("archivo", bytesArchivo, nom, "application/pdf"));
Debug.Log(nom);
            UnityWebRequest www = new UnityWebRequest();
            www = UnityWebRequest.Post(url, camposFormulario);
www.downloadHandler = new DownloadHandlerBuffer();

I tried using WWWForm.
I get this Error: Generic/unknown HTTP error.
Same post using postman It’s working. Using WWWForm without the line camposFormulario.AddBinaryData("archivo", bytesArchivo, nom, "application/pdf"); It’s working. But I need Upload files with the form. Please, I need help with this issue. I spent a lot days working on this.
I found this https://stackoverflow.com/questions/49835903/generic-unknown-http-error-when-uploading-files-to-a-remote-form

Anyway I am trying to resolve this using UnityWebRequest

You need to read the file (File.ReadAllBytes()) and add it as as binary data.

My code has always been there, but I never wrote about it. My mistake. I added the snippet of code.

byte[] bytesArchivo = File.ReadAllBytes(fullPath);

Have you tried looking into the HTTP traffix using Fiddler or similar tool?

Yes, I did. Thanks for your reply.
The attached file: TCP stream from Wireshark.

Isn’t this a server response at the end of the file you attached?

Yes, but in Unity I get this Error: Generic/unknown HTTP error.
And that is not a normal flow. Using HTTP client from .NET is working, using postman It’s working, using the code with wwwForm and without the field of binary data, It’s working. That is not normal behavior. The request doesn’t reach the PHP file in the server. I deleted all restrictions from .htaccess files. Maybe the server is blocking request from Unity because the server believes that something is wrong in this aspects:

cross website scripting

bad user agents

SQL injection

trojans

session hijacking

other exploits

But I don’t know why others request from unity are working. I have right configuration files permission 644 and 755 in Folders. Topics are taken from https://www.namecheap.com/support/knowledgebase/article.aspx/9542/22/what-is-modsecurity-and-why-do-we-need-it

Solved. Thanks for your help. The issue was with ModSecurity. ModSecurity triggered one rule with a right request. If anyone else has the same issue contact to your hosting provider. Explain the problem. In my case, this link was useful https://www.namecheap.com/support/knowledgebase/article.aspx/9542/22/what-is-modsecurity-and-why-do-we-need-it.

PD: I don’t know. why only that specific code triggered the rule in ModSecurity? In other requests were working right. The issue was only when binary data was added in that specific way.

is there another approach for uploading a 200mb file or more? In mobile, reading all the bytes and having them in memory doesn’t sound like the way to go, but I’m not finding any other alternatives

There is UploadHandlerFile. You’d have to save entire upload content (body of HTTP message) to file first.