Search code examples
pythonjinja2cherrypyformshttp-post

CherryPy - 400 error, Multiple values for parameters from HTML form


I'm working on a web application in Python using CherryPy. I have a form on a page meant for editing your user profile, so the default values of things get filled in when you load the page. This uses Jinja2 for templating, so whether you're editing or creating a profile, a variable gets passed to the page telling it so.

<form method="post">
    <span class="left">
        <span id="prof-art" class="prof-art" style="background-image: url( {{ '/assets/profile-art/'+(prof.prof_id|string)+'.jpg' if prof.prof_id else '/static/img/new-user.jpg' }} );"></span>
        <span class="prof-name"><input type="text" name="name" placeholder="Name" autocomplete="off" {{ 'value="'+prof.name+'"' if prof.name }}></span>
        <span class="prof-loc"><input type="text" name="loc" placeholder="Location" autocomplete="off" {{ 'value="'+prof.location+'"' if prof.location }}></span>
        <span class="prof-url">example.com/u/<input type="text" name="url" autocomplete="off" {{ 'value="'+prof.url+'"' if prof.url }}></span>
        <span class="prof-bio"><textarea name="bio" placeholder="Add a description of yourself here. Markdown is supported." autocomplete="off">{{ prof.bio or '' }}</textarea></span>
        <span class="prof-img"><input type="file" name="img" id="imgInp"></span>
    </span>
    <button type="submit" class="blue-btn a prof-save">
        {% if editing %}<i class="fa fa-wrench"></i> Update
        {% else %}<i class="fa fa-plus-square"></i> Create
    {% endif %}</button>
</form>

When submitted, the code will process the data you gave and either save it or create it, depending on if you're editing it or creating your profile.

However, none of that's really important, as the HTTPError happens before my code is even processed.

Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/cherrypy/_cprequest.py", line 670, in respond
    response.body = self.handler()
  File "/Library/Python/2.7/site-packages/cherrypy/lib/encoding.py", line 217, in __call__
    self.body = self.oldhandler(*args, **kwargs)
  File "/Library/Python/2.7/site-packages/cherrypy/_cpdispatch.py", line 67, in __call__
    raise sys.exc_info()[1]
HTTPError: (400, 'Multiple values for parameters: url')

What's up with this? Why is just the URL field doing this? Even if I remove the value tag from the template it will do this. I can't find anything that can be causing this - there's ONE url field in the form, so why does it think there are 2? It seems it has to be happening when it's submitted, because nothing in my CherryPy server even runs before the error pops up.

Update: I wrote up a quick Python web server that prints out all the data in the request I send it. By changing the action attribute to that server's address I was able to inspect the POST variables passed along by the form. Turns out it may not even be the HTML form's fault, but CherryPy's.

POST Variables: {'url': 'dfghdfgdf', 'loc': 'fghjdfg', 'name': 'dfghdfgdf', 'btc': '', 'bio': 'srffghmn+dfghdfgh'}

Solution

  • The problem is that you are setting a positional argument on the method and sending another value on the form.

    For what I could see the form does not specify an action url, so it will use the current one. I guess you are doing something like this:

    class Root:
    
        @cherrypy.expose
        def u(self, url='', mode='', *args, **post):
             pass
    

    And submitting the form while on the URL: /u/SOMETHING, the SOMETHING is duplicating the meaning of the url parameter, given that is positional on the signature and also is passed as an argument on the form submission.