1

So, I know the sever code works, as this site is currently in production and working fine. I, on the other hand, have developed a test script to unit test the API. I'm trying, using the HTTP POST method, to send a PDF file over to the nginx -> gunicorn -> flask app environment of the server.

The server gets the attachments with:

@app.route('<ObjectId:_id>/attachments', methods=['POST'])
@csrf.exempt
@opportunity_owner_required
@auth.login_required
@nocache
def upload_attachment(_id):
    upload = request.files.get('file')
    if not upload:
        abort(400, "Missing attached file.")

and I try and pass the pdf file to the server with:

def test_add_opportunity_attachment(self):
    files = {'file': ("mozilla.pdf", open('%s/mozilla.pdf' % PATHTOFILE, 'rb'))}
    headers = {'Content-Type': 'application/pdf', "enctype": "multipart/form-data", "Content-Disposition":"attachment;filename=mozilla.pdf"}
    r=self.session.post(self.formatURL('/attachments'), headers=headers, files=files)
    assert r.status_code == 200

But I always get the status 400.

When using ngrep to follow the output, I do see what appears to be the encoded form of the PDF being passed across the network, but the server cannot see it.

Please note: Some of the information is missing, due to the proprietary nature of it. But all the functions used within the test function work fine. formatURL formats it as expected and the urls do match.

8
  • 1
    Try removing your custom headers. I think by setting those you're over-writing the correct ones that requests will generate for you. Commented Apr 15, 2013 at 15:24
  • @sigmavirus24 Tried that also, no success. Commented Apr 15, 2013 at 15:29
  • Your authentication is attached to the session I assume. formatURL is returning a valid url I hope. I don't have time to look up flask's documentation now, but someone else might know better about the files attribute. Since in a multipart/form-data request there could be multiple files, are you sure .get('file') is correct? Commented Apr 15, 2013 at 15:32
  • @sigmavirus24 The server is correct, and formatURL returns the right url, yes. The object is being sent in as {'file': (filename, fileref)} so .get('file') /should/ be pulling out the tuple with the filename and fileref. Commented Apr 15, 2013 at 15:35
  • 1
    I don't see anything in your test_add_opportunity_attachment method that deals with logging in, but upload_attachment has @auth.login_required. Is the login information part of the missing information you mentioned? Commented Apr 15, 2013 at 16:59

1 Answer 1

1

So this issue was a little more obscure than I thought. Some back-end logic on the server, saves the file into a directory and then continues on to the @app.route() for the URL location. There were some missing permissions on my local copy, so when it tried to save the PDF file the upload would fail.

Another issue, was as noted above by sigmavirus24, the custom headers were not setting correctly, so the final version, that works, looked like:

def test_add_opportunity_attachment(self):
    payload = {"title": "Testing upload title", "description": "Testing upload description"}
    file_contents = open('%s/mozilla.pdf' % PATHTOFILE, 'rb')
    files = {'file': ('mozilla.pdf', file_contents)}
    r=self.session.post(self.formatURL('/attachments'), files=files, data=payload)
    if r.status_code != 200:
        assert r.status_code == 409 #Successful, but no duplicates allowed.
Sign up to request clarification or add additional context in comments.

1 Comment

Glad to have been of some assistance. I never consider file permissions on the local machine because you always assume there shouldn't be an issue with those. Cheers!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.