Forum Discussion

TestKeks's avatar
TestKeks
Occasional Contributor
7 years ago

Performing post request with content-type multipart/form-data (for binary file)

Hi,

 

in a script test, I would like to use the send method to send a binary file, namely a desktop screenshot, formatted in the content type "multipart/form-data". According to the JavaScript code example for the CreatePostRequest Method I wrote down the following:

 

 

function httpPostRequest()

{

  var address = "https://example.com/receiver";

 

  // Define the request body FormData-Object

  var requestBody = new FormData(Sys.Desktop.Picture());

 

  // Create the aqHttpRequest object

  var aqHttpRequest = aqHttp.CreatePostRequest(address, "", "");

 

  // Specify the Content-Type header value

  aqHttpRequest.SetHeader("Content-Type", "multipart/form-data");

 

  // Send the request, create the aqHttpResponse object

  var aqHttpResponse = aqHttpRequest.Send(requestBody);

 

  // Check the response:

  Log.Message(aqHttpResponse.StatusCode); // A status code

  Log.Message(aqHttpResponse.Text); // A body

}

 

But the JavaScript object FormData, which is to be generated in this code, is apparently not supported by TestComplete. The error "ReferenceError: FormData is not defined" appears. Or what am I doing wrong?

 

Is there any other way? Or do I have to build my own function to format the binary code according to the standard (see here)?

 

Thanks in advance for any hint and best regards

  • HKosova's avatar
    HKosova
    SmartBear Alumni (Retired)

    Hi TestKeks,

     

    File upload using multipart requests is tricky because the request body needs to be formatted with extra info - boundaries, Content-Disposition header, etc., as shown here.

     

    aqHttp does not have a built-in method to format multipart requests. You will need to either format the request body manually (add the boundaries, Content-... headers, etc. yourself), or use some external tool or library to send the request.

     

    Do you have curl? If yes, you could just shell out to curl:

    var url = "http://httpbin.org/post";
    var fileName = "C:\\my_image.png";
    var fieldName = "file"; // The name of the form field whose value is the file contents.
    // Check with the admins of the targer server or its docs
    // to learn what field name to use.

    var command = aqString.Format("curl \"%s\" -F \"%s=@%s\"", url, fieldName, fileName);
    // TC 12.0+ WshShell.Run(command, 0, true);
    // TC <= 11.x
    // Sys.OleObject("WScript.Shell").Run(command, 0, true);
    // TODO: check response status and content if needed

     

    Alternatively, if you have .NET Framework 4.5+, you can use its HttpClient and MultipartFormDataContent classes as shown in the following example. You need to add the System.Net.Http assembly to Tools > Current Project Properties > CLR Bridge to use this code.

    var url = "http://httpbin.org/post";
    var fileName = "C:\\my_image.png";
    var fieldName = "file"; // The name of the form field whose value is the file contents.
    // Check with the admins of the targer server or its docs
    // to learn what field name to use.
    // Read file contents as a byte array
    var fileData = dotNET.System_IO.File.ReadAllBytes(fileName);

    // Configure multipart request
    var httpClient = dotNET.System_Net_Http.HttpClient.zctor();
    var formData = dotNET.System_Net_Http.MultipartFormDataContent.zctor();
    formData.Add_3(dotNET.System_Net_Http.ByteArrayContent.zctor(fileData),
    fieldName,
    aqFileSystem.GetFileName(fileName));

    // Send the request and check the response
    var response = httpClient.PostAsync(url, formData).Result;
    if (response.IsSuccessStatusCode)
    {
    Log.Message("success!")
    }
    Log.Message("Status: " + response.StatusCode.value__); // e.g. 200 or 400
    Log.Message("Response contents - see Additional Info", response.Content.ReadAsStringAsync().Result);
    • TestKeks's avatar
      TestKeks
      Occasional Contributor

      Hi Helen,

       

      thanks for your reply. Our messages have crossed.

       
      As I wrote above, only those approaches that I can use for TestComplete tests on CrossBrowserTesting are useful to me. That's why I have already started to create the required multipart/form-data format myself (of course including the required headers and boundaries etc.). Outside of TestComplete, I have already succeeded in doing so. I now only need the correct method to integrate the binary image data into my post message.

      Thank you and best regards
  • AlexKaras's avatar
    AlexKaras
    Champion Level 3

    Hi,

     

    a) I am not sure that FormData is "JavaScript object" but not something provided by the browser (https://developer.mozilla.org/en-US/docs/Web/API/FormData);

    b) I am not sure that

    var requestBody = new FormData(Sys.Desktop.Picture());

    will work. According to the samples, you should first save .Desktop.Picture() to the file and use something like

    formData.append('image', <FullFileName>);

    then;

    c) If you don't need to use different files every time (and I am pretty sure that you don't), you may capture request that sends some small file using Fiddler or the tool like it and use captured data for the form content.

    • TestKeks's avatar
      TestKeks
      Occasional Contributor

      Hi AlexKaras,

       

      regarding a) and b) you may be right in principle.

       

      But either way, since the FormData object is not supported by TestComplete, the method formData.append() cannot work either. Because even if I try to initiate the FormData object empty ...

       

      var requestBody = new FormData();

       

      ... I get the same error.

       

      I did not quite understand what you mean by c). Maybe I should have mentioned that I need the routine for some web tests that have to run on CrossBrowserTesting devices. I wanted to avoid opening another browser tab for such actions in parallel to the tested web application. And of course, I can't access desktop applications on these devices at all - if that's necessary for such additional tools. Otherwise could you please outline the use of Fiddler in this context a little closer?

       

      Thank you and best regards

      • AlexKaras's avatar
        AlexKaras
        Champion Level 3

        Hi,

         

        > since the FormData object is not supported by TestComplete

        Depending on the scripting language of your test project, you may look for some third-party library/component that will provide such functionality and use it. However, there may be problems with deploying required components to the CrossBrowserTesting environment.

         

        > could you please outline the use of Fiddler in this context a little closer?

        The suggestion is based on the assumption that you don't need to send some specific file in your test but it is acceptable if the same file is sent every time.

        If this assumption is correct, then you may use Fiddler or any other request-capturing tool to capture the request that sends some small (for performance considerations) file. The captured request will provide you with the already properly encoded body part. So you may store it in some file or as a constant string in test code and use in the test.