Whats Content-Type value within a HTTP-Request whe

2020-01-25 09:52发布

问题:

I need to extract uploads from http-trafic. How could do that? First of all, the request-method will be POST. Secondly, there will be a Content-Type header-field. I do not want to extract formular-data, but uploads like mail-attachements.

回答1:

The content type is per specification multipart/form-data.

This is a special content type which can be visualized as multiple sub-requests in one big request. Each of those sub-requests (one form-data element) has their own set of headers. The content type of the actual data is in there.

Here's an example how it look like with 1 normal field and 1 file field (in HTML terms, when using <input name="textfield"><input type="file" name="filefield">):

Content-Type: multipart/form-data;boundary=SOME_BOUNDARY

--SOME_BOUNDARY
content-disposition: form-data;name="textfield"
content-type: text/plain;charset=UTF-8

value of textfield here
--SOME_BOUNDARY
content-disposition: form-data;name="filefield";filename="some.ext"
content-type: application/octet-stream

binary file content here

--SOME_BOUNDARY--

As to parsing and extracting this data, practically every programming language has builtin/3rd party APIs for this. As you didn't tell anything about which one you're using, it's impossible to give a targeted answer. In case of for example Java, that would be either the 3rd party library Apache Commons FileUpload or when you're using Servlet 3.0, the API-provided request.getPart() method.



回答2:

If (and I by no means am saying this is the correct way) you just want to save data from a byte array, you should look at how to read the POST body at: Reading POST body with bottle.py Reading the data and then creating a new file should do the trick.



回答3:

Based on @BalusC s solution I made a little extension method for .NET's build in WebClient class which does not support Multipart upload out of the box.

Usage

Just mix string values and files (enclosed in #)

    public void UploadMultipart()
    {
        var fileName = "/some/existing/file.ext";
        using (var client = new WebClient())
        {
            var values = new NameValueCollection();
            values.Add("id", Guid.NewGuid().ToString());
            values.Add("name", Path.GetFileNameWithoutExtension(fileName));
            values.Add("file", $"#{fileName}#");

            var result = client.UploadMultipart(address, method, values);
            var content = client.Encoding.GetString(result);
        }
    }

Extension method

    public static byte[] UploadMultipart(this WebClient client,
        string address, string method, NameValueCollection values)
    {

        string boundary = DateTime.Now.Ticks.ToString("x");

        client.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);

        var sb = new StringBuilder()
            .AppendLine();

        foreach (var key in values.AllKeys)
        {
            var contentDispositon = $"form-data;name=\"{key}\"";
            var contentType = $"text/plain;charset={client.Encoding.WebName}";

            var value = values[key];

            if (value.StartsWith("#") && value.EndsWith("#"))
            {
                // if a value is enclosed in hashes we expect this to be a path to a file
                // file=#/path/to/file.ext#
                var fileName = value.Trim('#');
                var file = File.ReadAllBytes(fileName);
                value = client.Encoding.GetString(file);

                contentType = "application/octet-stream";
                contentDispositon = $"form-data;name=\"{key}\"filename=\"{Path.GetFileName(fileName)}\"";
            }

            sb.AppendLine($"--{boundary}")
              .AppendLine($"Content-Disposition: {contentDispositon}")
              .AppendLine($"Content-Type: {contentType}")
              .AppendLine()
              .AppendLine(value);
        }

        sb.AppendLine($"--{boundary}--");

        var data = client.Encoding.GetBytes(sb.ToString());

        return client.UploadData(address, method, data);

    }