18

I am trying to upload an image in django rest using multipart/form-data in a PUT request and Pillow:

class ABC(APIView):
    parser_classes = (MultiPartParser,)
    def put(self, request):
        a = Image()
        a.image_url = request.data["image"]
        a.save()

class Image(models.Model):
      image_url = models.ImageField(upload_to='static/bills', blank=True)

I make a request which is a PUT request and a multipart/form-data. I end up getting a response code of 400 with the message:

{
  "detail": "Multipart form parse error - Invalid boundary in multipart: None"
}

Somehow this has broken just now. It was working fine when I wrote it the first time. Since then I have added few settings configuration for CORS requests like:

CORS_ORIGIN_ALLOW_ALL = True

CORS_ALLOW_HEADERS = (
    'x-requested-with',
    'content-type',
    'accept',
    'origin',
    'authorization',
    'x-csrftoken',
    'token',
    'x-device-id',
    'x-device-type',
    'x-push-id',
    'dataserviceversion',
    'maxdataserviceversion'
)
CORS_ALLOW_METHODS = (
        'GET',
        'POST',
        'PUT',
        'PATCH',
        'DELETE',
        'OPTIONS'
    )

Any ideas?

OPTIONS Request response:

Access-Control-Allow-Headers → x-requested-with, content-type, accept, origin, authorization, x-csrftoken, token, x-device-id, x-device-type, x-push-id, dataserviceversion, maxdataserviceversion
    Access-Control-Allow-Methods → GET, POST, PUT, PATCH, DELETE, OPTIONS
    Access-Control-Allow-Origin → *
    Access-Control-Max-Age → 86400
    Allow → GET, POST, DELETE, HEAD, OPTIONS
    Content-Type → application/json
    Date → Fri, 21 Aug 2015 06:23:28 GMT
    Server → WSGIServer/0.1 Python/2.7.6
    Vary → Accept
    X-Frame-Options → SAMEORIGIN
Varun Jain
  • 1,901
  • 7
  • 33
  • 66
  • Can you add the browser request as caught in sniffer? – Skarlinski Aug 16 '15 at 23:23
  • Don't have sniffer. I am using postman to make this request. – Varun Jain Aug 17 '15 at 06:13
  • 2
    Can you send an `OPTIONS` request to the same URL and check what is the response? For a valid CORS service, the response should be an empty `200 OK` response with headers like `Access-Control-Allow-Methods, Access-Control-Allow-Origin` etc.. – psiyumm Aug 17 '15 at 12:30
  • So request headers + form data from postman – Skarlinski Aug 17 '15 at 17:46
  • The error you are receiving signals that the content-type header of the request is missing the `boundary` parameter. Can you check the headers of the request? – Andrea Corbellini Aug 20 '15 at 18:41
  • @Skarlinski I updated the question with the response to options parameters – Varun Jain Aug 21 '15 at 06:24
  • Not sure what you are saying or asking for? – Varun Jain Aug 21 '15 at 07:11
  • You really need to show the code you use to generate the request. Hopefully [my answer](http://stackoverflow.com/a/32142213/838992) will allow you to resolve for yourself, but if not, we need to see the request generating code to work out why `boundary` is missing from the `content-type` header. – J Richard Snape Aug 21 '15 at 13:59
  • 1
    After searching a lot for a solution, I found that removing the `content-type` header from the request solves this problem. – Iqbal Jan 27 '16 at 09:16

3 Answers3

32

Removing the content-type from the headers resolves this.

Varun Jain
  • 1,901
  • 7
  • 33
  • 66
  • 1
    If you are using POSTMAN, there is a section where you can view the code for the request in different languages. This acts as a clue. – Varun Jain May 25 '16 at 08:26
  • worked for me too! thanks man, but one question: do you know why it worked? – Khaled Al-Ansari Jul 19 '16 at 10:14
  • 1
    Just happened to me. Postman will automatically add the Content-Type header with boundary if you choose 'form data' for the body. But if you specify your own Content-Type header without boundary, then Postman will not overwrite the header you give it, or maybe the header is doubled and the server only reads the first Content Type header encountered. – andho Apr 12 '17 at 15:20
  • How to remove the content-type from the headers ? – Rajiv Sharma Aug 08 '17 at 04:33
  • OMG you save me! Thanks – seuling Feb 05 '20 at 18:22
3

Your error is telling you that the boundary for your multipart/form-data content of your request is invalid - in particular that is is None. This, by design, returns a 400 ("Bad Request") response code. The Error is raised here in the django code.

To enter that code branch with boundary equal to None means that the boundary option is not specified in the content-type header of your request.

boundary must be specified when using multipart/form-data in content-type as specified in RFC2046 (referred to by RFC2388) - in particular section 5.1.1

The Content-Type field for multipart entities requires one parameter, "boundary".

You say it has worked before, so you should check the code that you are using to make the request - something must have changed to mean that the boundary is not specified in the content-type.

N.B. I presume the request is code-generated, as <form method="put"> is invalid HTML and so a request generated by a browser given that HTML would be a GET rather than a PUT.

Community
  • 1
  • 1
J Richard Snape
  • 20,116
  • 5
  • 51
  • 79
  • Can you share the curl request I should be using for this kind of request? I am not too familiar with it and having doubts about the api just confuses me about the curl request. – Varun Jain Aug 21 '15 at 14:21
  • 1
    Something like `curl -v -XPUT -H "Content-Type: multipart/form-data; boundary=----------------------------4ebf00fbcf09" --data-binary @test.jpg http://` should work, where the string following `boundary=` is arbitrary, but should not occur in the data that follows. I'm assuming your image data is in a file called `"test.jpg"`, but you could equally put the raw data there. – J Richard Snape Aug 21 '15 at 14:43
  • I'm not familiar with postman, so can't really comment on how to generate the request via that tool. If the above `curl` works, I can copy it into the answer to make it complete. – J Richard Snape Aug 21 '15 at 14:44
  • Hmmm - not sure that CURL command will work actually. The [man page](http://curl.haxx.se/docs/manpage.html) seems to indicate that 1) you should use [`-F`](http://curl.haxx.se/docs/manpage.html#-F) not [`--data-binary`](http://curl.haxx.se/docs/manpage.html#-d) to get content type `multipart/form-data` 2) these will be compiled into a `POST` request. I'm not sure whether `-X PUT` overrides this, but I suspect not (haven't got an environment to easily test right now). Using `PUT` rather than `POST` seems a little unusual - is there a reason you're doing that? – J Richard Snape Aug 22 '15 at 06:33
  • Hi @VarunJain Wondering whether you've got this working / whether this answer helps you. I wouldn't want your bounty to go to waste - if you're still struggling maybe I can help you debug a bit more... :) – J Richard Snape Aug 23 '15 at 22:27
  • Hi, I haven't. Still struggling with this. – Varun Jain Aug 24 '15 at 13:09
  • @varunjain Ok, so what is issue? Does my answer and comment make sense to you given your symptoms? Is it you Can't get a curl request to work? Same error? Bounty will just disappear in 3 hours, let's try to sort so you can award :) – J Richard Snape Aug 24 '15 at 15:54
1

You will typically want to use both FormParser and MultiPartParser together in order to fully support HTML form data.

Vinod
  • 549
  • 3
  • 8