python simulation is used to realize POST request to submit images

  • 2020-06-12 10:01:18
  • OfStack

This paper mainly introduces how to use python simulation to realize POST request to submit pictures. Please share it for your reference and study. Let's have a look at the detailed introduction below:

Using requests to simulate HTTP requests would have been a very easy thing to do, such as uploading a picture, a few lines of code:


import requests
files = {'attachment_file': ('1.png', open('1.png', 'rb'), 'image/png', {})}
values = {'next':"http://www.xxxx.com/xxxx"}
r = requests.post('http://www.xxxx.com/upload', files=files, data=values) #  successful 
r = requests.post('http://www.xxxx.com/upload', files=files, data=values) #  failure 
r = requests.post('http://www.xxxx.com/upload', files=files, data=values) #  failure 
r = requests.post('http://www.xxxx.com/upload', files=files, data=values) #  failure 
r = requests.post('http://www.xxxx.com/upload', files=files, data=values) #  failure 
...

However, I ran into a big hole when Debugging an django program today -- in order to be lazy, I executed the above code directly in ipython. The first commit was normal, but the second commit failed to pass the form verification.

The code for the validation section is simple:


......
form = AttachmentForm(request.POST, request.FILES)
if form.is_valid():
 form.save(request, obj)
 messages.success(request,_('Your attachment was uploaded.'))
 return HttpResponseRedirect(next)
......

What the hell! ? Why only the first successful submission?? All the rest failed?? Had to step 1 to follow up the step to django source, found the problem django/forms/fields py file:


def to_python(self, data):
 if data in validators.EMPTY_VALUES:
 return None
 # UploadedFile objects should have name and size attributes.
 try:
 file_name = data.name
 file_size = data.size
 except AttributeError:
 raise ValidationError(self.error_messages['invalid'])
 if self.max_length is not None and len(file_name) > self.max_length:
 error_values = {'max': self.max_length, 'length': len(file_name)}
 raise ValidationError(self.error_messages['max_length'] % error_values)
 if not file_name:
 raise ValidationError(self.error_messages['invalid'])
 if not self.allow_empty_file and not file_size:
 raise ValidationError(self.error_messages['empty'])
 return data

At the first execution, the cut was normal, and this data was the file type of InMemoryUploadFile, name and size were the name and size of the image we uploaded, and the second execution of THE post request was found data.size It's zero? ! No wonder it just started if not self.allow_empty_file and not file_size这 A judged exception!

So the heart of the problem is not in the part of django that validates the form, but in the part that sends the request. But the part of the code that sends the request is pretty simple, right? The request packets issued by requests in the normal case and the error case are output, and the difference is found:


# normal 
In [28]: r = requests.post('http://www.xxxx.com/upload', files=files, data=values)
In [29]: r.request.body
# An error condition 
In [33]: r = requests.post('http://www.xxxx.com/upload', files=files, data=values)
In [34]: r.request.body
Out[34]: '--155322d3e780432bb06e58135e041c8f\r\nContent-Disposition: form-data; name="next"\r\n\r\nhttp://www.xxxx.com/upload\r\n--155322d3e780432bb06e58135e041c8f\r\nContent-Disposition: form-data; name="attachment_file"; filename="1.png"\r\nContent-Type: image/png\r\n\r\n\r\n--155322d3e780432bb06e58135e041c8f--\r\n'

No output in the normal case, the error case looks like the output in the normal case, right? Isn't that scientific?

Combined with the above two points, I have a vague feeling that the problem lies in the construction of data. The key lies in files = {'attachment_file': ('1.png', open('1.png', 'rb') , 'image/png', {})} First of all, it is necessary to pay special attention to the variable types such as dictionary and list, which are passed as parameters of the function. Second, the open function opens 1 file, so where is the file closed?

With this doubt in mind, I rewrote the code as follows:


fl = open('1.png','rb')
files = {'attachment_file': ('1.png', fl, 'image/png', {})}
r1 = requests.post('http://www.xxxx.com/upload', files=files, data=values)
fl.close()
fl = open('1.png','rb')
files = {'attachment_file': ('1.png', fl, 'image/png', {})}
r2 = requests.post('http://www.xxxx.com/upload', files=files, data=values)

Then execute again, as expected successfully uploaded 2 pictures. Normally, you wouldn't open a picture and upload it, but that's why you get such an interesting problem. The processing code for the files object in requests is in the models.py file for interested readers to debug.

In addition, the requests call cannot include Chinese in the file name of the upload, or it cannot be verified by the django form, which I won't go into here.

conclusion


Related articles: