2

Here's the form my web server is serving upon a GET request (plus the contents of the memory list). I'm trying to make it so that when the message is submitted, it is appended to memory. Form is as follows:

form = ''' <!DOCTYPE html><html><head><title>Server</title></head><body>
           <form action="/basic-server.py" method="post">
           <label>Message <input name="message" type="text" /></label>
           </form>
           </body></html> '''

memory = []

Now here is the content of my POST method using BasicHTTPRequestHandler:

def do_POST(self):

    length = int(self.headers.get('Content-Length'))
    postvars = parse.parse_qs(self.rfile.read(length))
    memory.append(postvars["message"])

    self.send_response(303)
    self.send_header('Location', '/')
    self.end_headers()

It throws a KeyError for 'message'. The thing that confuses me about this is that if I remove that line and print out postvars, it looks like a dictionary with a "message" key containing the message I type in on the form.

If I use memory.append(postvars) and input 'test' the application works and appends the following dictionary: {b'message': [b'test']}. What's with the 'b' characters? If I use [b'message'] as a key, it works, but returns [b'test'] to memory instead of simply test.

Matt Cook
  • 149
  • 1
  • 1
  • 9
  • Can you add the output of `print(postvars)` when placed directly before or at the point where `memory.append(postvars["message"])` is to the post? – 3D1T0R Jul 27 '17 at 06:01
  • @3D1T0R If I use `memory.append(postvars)` and input 'test' the application works and appends the following dictionary: `{b'message': [b'test']}`. What's with the 'b' characters? If I use `[b'message']` as a key, it works, but returns `[b'test']` to memory instead of simply `test`. Thanks for the help! – Matt Cook Jul 27 '17 at 14:12
  • That information should be [edit]ed into the post. Sorry I didn't get back to you sooner, but it looks like Matt Cook's got you covered in [his answer](https://stackoverflow.com/questions/45341464/keyerror-in-do-post-procedure-but-key-exists#45355547) – 3D1T0R Jul 27 '17 at 21:43
  • @3D1T0R Yep, I figured it out eventually. Your response actually helped me to test and debug it, so thank you! I'll put that stuff in the main post now. – Matt Cook Jul 27 '17 at 22:38

1 Answers1

2

The Fix

You need to decode the information pushed through the post request.

Before

postvars = parse.parse_qs(self.rfile.read(length))

should become...

After

postvars = parse.parse_qs(self.rfile.read(length).decode())

Explanation

In the original code, postvars is a dictionary of byte literals instead of string literals. Here is a good explanation of this.

So in before, postvars == [{b'message': [b'Post Message']}], meaning the key and value are both byte literals. You can't use the string ['message'] as a key because the key is a byte instance, not a string instance. The key here is [b'message'].

In after, postvars becomes [{'message': ['Test']}] - the key and value are now decoded into string instances as expected.

Matt Cook
  • 149
  • 1
  • 1
  • 9