Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Content-Type multipart/form-data is not serialized in proxy and recording mode #263

Closed
pmiossec opened this issue Apr 1, 2019 · 17 comments
Assignees
Labels

Comments

@pmiossec
Copy link

pmiossec commented Apr 1, 2019

In the last version of WireMock.Net.StandAlone ( Version="1.0.8"), when doing a Content-Type multipart/form-data POST request, the mapping generated doesn't contain the Matcher for the body (so that don't made it a valid mapping).

Note: I forward to another Wiremock instance and see the content of the body, so the content seems to be forwarded.

I get the generated mapping (Notice the empty "Body" key) :

{
  "Guid": "ba19b8f6-432e-4e4b-92e0-d51c372b4277",
  "Title": "",
  "Priority": 0,
  "Request": {
    "Path": {
      "Matchers": [
        {
          "Name": "WildcardMatcher",
          "Pattern": "/export/xxxxxx/upload",
          "IgnoreCase": false
        }
      ]
    },
    "Methods": [
      "POST"
    ],
    "Headers": [
      {
        "Name": "Content-Type",
        "Matchers": [
          {
            "Name": "WildcardMatcher",
            "Pattern": "multipart/form-data; boundary=\"31455f07-7487-400f-906e-9e1aefa04869\"",
            "IgnoreCase": true
          }
        ]
      },
      {
        "Name": "Host",
        "Matchers": [
          {
            "Name": "WildcardMatcher",
            "Pattern": "localhost:8080",
            "IgnoreCase": true
          }
        ]
      },
      {
        "Name": "Content-Length",
        "Matchers": [
          {
            "Name": "WildcardMatcher",
            "Pattern": "298",
            "IgnoreCase": true
          }
        ]
      }
    ],
    "Body": {}
  },
  "Response": {
    "StatusCode": 404,
    "BodyAsJson": {
      "Status": "No matching mapping found"
    },
    "UseTransformer": false,
    "Headers": {
      "Content-Type": "application/json",
      "Date": "Mon, 01 Apr 2019 10:09:04 GMT",
      "Server": "Kestrel",
      "Transfer-Encoding": "chunked"
    }
  }
}

I have the same behavior when doing the request through Postman or C# code...

If you want to test, you could reproduce with this code.

        public async Task<T> UploadFileFromPath<T>(string uri, string filePath, string filename = null)
        {
            if (!File.Exists(filePath))
            {
                throw new ArgumentException($"The file to upload '{filePath}' doesn't exist!");
            }

            using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            using (var form = new MultipartFormDataContent())
            using (var sc = new StreamContent(fs))
            {
                sc.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
                form.Add(sc, "file", filename ?? Path.GetFileName(filePath));
                var response = await _httpClient.PostAsync(uri, form).ConfigureAwait(false);
                response.EnsureSuccessStatusCode();
                return await HandleResponse<T>(response).ConfigureAwait(false);
            }
        }
@StefH
Copy link
Collaborator

StefH commented Apr 1, 2019

If possible, can you provide the full body (captured using fiddler for example)?

@pmiossec
Copy link
Author

pmiossec commented Apr 1, 2019

Body content obtained with fiddler:

POST http://localhost:8080/export/via-fiddler/upload HTTP/1.1
Content-Type: multipart/form-data; boundary="5aaf4468-6f12-49e4-ae28-88d5e18593ca"
Content-Length: 298
Host: localhost:8080

--5aaf4468-6f12-49e4-ae28-88d5e18593ca
Content-Type: application/json
Content-Disposition: form-data; name=file; filename=relationship_types.json; filename*=utf-8''relationship_types.json

[{"relationshipTypeId":1,"relationshipTypeCode":"Ownership"}]
--5aaf4468-6f12-49e4-ae28-88d5e18593ca--

@StefH
Copy link
Collaborator

StefH commented Apr 1, 2019

I checked, and this is actually by design.
Only full text or json body is saved on the mapping.

I left out Bytes / Multipart because I'm not sure which matcher to use.

@pmiossec
Copy link
Author

pmiossec commented Apr 1, 2019

I don't know what to do with this answer 😢

It seems to me that the content in sent in text so it should be possible to do some checks.
But what worries me much is that the body is empty and we could think that nothing was sent...

I don't know if we could not have a "No check" matcher so that we could have the value received serialized in the mapping file but ignored in the matching process. That way the developer could really see what have been sent.

Thanks for the answer.

@StefH
Copy link
Collaborator

StefH commented Apr 1, 2019

Sorry for my short answer. What I just meant to say is that up until your question, I did not really think it would be usefull / possible to save the body in case of Bytes or Multipart.

I think using the ExactObjectMatcher could be an option in this case. I'll take a look at the code.

@StefH
Copy link
Collaborator

StefH commented Apr 1, 2019

Using the ExactObjectMatcher would return the body in the mapping as:

Example:

"Body": {
  "Matcher": {
    "Name": "ExactObjectMatcher",
    "Pattern": "LS0xNjU4YTNjMi05NzhkLTQyNWUtOTZiMy04YzE1MTcxZDc1NWQNCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOA0KQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPXRlc3Q7IGZpbGVuYW1lPXRlc3QudHh0OyBmaWxlbmFtZSo9dXRmLTgnJ3Rlc3QudHh0DQoNCmRhdGENCi0tMTY1OGEzYzItOTc4ZC00MjVlLTk2YjMtOGMxNTE3MWQ3NTVkLS0NCg=="
   }
}

Would this be ok?

@StefH
Copy link
Collaborator

StefH commented Apr 2, 2019

Linked to PR - #264

@StefH
Copy link
Collaborator

StefH commented Apr 2, 2019

I can also build some logic to check if the data is a valid ASCII string, in that case I can change the detection from MultiPart logic and the code will automatically used the current string matchers...

In this case, the mapping would look like:

"Body": {
  "Matcher": {
    "Name": "ExactMatcher",
    "Pattern": "--cea0a92a-94b2-4c5c-b3d9-da77d4220113\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Disposition: form-data; name=test; filename=test.txt; filename*=utf-8''test.txt\r\n\r\ndata\r\n--cea0a92a-94b2-4c5c-b3d9-da77d4220113--\r\n"
  }
}

@pmiossec
Copy link
Author

pmiossec commented Apr 2, 2019

I'm really impress and appreciate this very quick PR 👍
But that didn't let me the time to answer your question 😢

Using the ExactObjectMatcher would return the body in the mapping as:
Would this be ok?

I don't think it will be very useful due to the multiparts boundaries that are by default auto generated and, so, varies and consequently, the ExactObjectMatcher will match nothing :(

I can also build some logic to check if the data is a valid ASCII string, in that case I can change the detection from MultiPart logic and the code will automatically used the current string matchers...

Something like that will indeed be much more valuable and will let the developer check for part of the string (without the boundaries, for example).

@StefH
Copy link
Collaborator

StefH commented Apr 2, 2019

Would the mapping in my proposal work for you?

"Body": {
  "Matcher": {
    "Name": "ExactMatcher",
    "Pattern": "--cea0a92a-94b2-4c5c-b3d9-da77d4220113\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Disposition: form-data; name=test; filename=test.txt; filename*=utf-8''test.txt\r\n\r\ndata\r\n--cea0a92a-94b2-4c5c-b3d9-da77d4220113--\r\n"
  }
}

@pmiossec
Copy link
Author

pmiossec commented Apr 2, 2019

I'm not very used to mapping file but will I be able to modified it to look like below and that will still work?

"Body": {
  "Matcher": {
    "Name": "WildcardMatcher",
    "Pattern": "--*\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Disposition: form-data; name=test; filename=test.txt; filename*=utf-8''test.txt\r\n\r\ndata\r\n--*--\r\n"
  }
}

If yes, 👍
Perhaps there is also a something looking like ContainsMatcher that return true if the body contains the string passed?

@StefH
Copy link
Collaborator

StefH commented Apr 2, 2019

You can indeed change the generated mapping to use the WildcardMatcher, this is essentially a contains-matcher if used correctly (in your example this is correct) ==> "*XXX*"

@StefH
Copy link
Collaborator

StefH commented Apr 2, 2019

@pmiossec
If you like, you can use this preview NuGet which includes this code.
https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net/1.0.12-ci-11179

@pmiossec
Copy link
Author

pmiossec commented Apr 2, 2019 via email

@StefH
Copy link
Collaborator

StefH commented Apr 4, 2019

@pmiossec Does that NuGet work correct for you?

@StefH StefH self-assigned this Apr 5, 2019
@StefH StefH added the bug label Apr 5, 2019
@pmiossec
Copy link
Author

pmiossec commented Apr 5, 2019

@StefH I have tested it and it is working as expected.

Thank you very much!

@StefH
Copy link
Collaborator

StefH commented Apr 5, 2019

Today a new official NuGet will be released.

@StefH StefH closed this as completed Apr 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants