16

What im doing

Im trying to get my hands dirty with python and im making a very simple http server so i can send commands to my arduino via serial. Im validating the commands as i sgould and everything works as it ahould be.

The concept

Im using the HTTP server in order to recieve POST requests from remote computers and smartphones and execute code with my arduino via Serial. It has few cool features like users and user permission levels.

The problem

I would like to give feedback when a request arrives. Specificaly JSON feedback with the outcome of the execution like error, notes and success. Im thinking to make a dictionary in python and add whatever i want to send back the the frontend then enclode it in json and send it as a response. (Something like php's json_encode() which takes an array and outputs json)

The code

import SimpleHTTPServer
import SocketServer
import logging
import cgi
import time
import sys

class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):

def do_GET(self):
    logging.warning("======= GET STARTED =======")
    logging.warning(self.headers)
    SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)

def do_POST(self):
    form = cgi.FieldStorage(
        fp=self.rfile,
        headers=self.headers,
        environ={'REQUEST_METHOD':'POST',
                 'CONTENT_TYPE':self.headers['Content-Type'],
                 })

    if self.check_auth(username, passcode):
        self.send_response(200)
        self.send_header('Content-Type', 'application/json')
        self.end_headers()
    else:
        print cur_time + "failed to login " + form.list[0].name + form.list[0].value
        self.send_response(500)
        self.send_header('Content-Type', 'application/json')
        self.end_headers()

SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
Handler = ServerHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
httpd.serve_forever()

I've tried to minimize the code so you can see the clear HTTP part.

As you can see im sending the headers and the response type (200 for successful login and 500 for unsuccessful login)

Objectives i need to accomplish

The complet code as a gist: https://gist.github.com/FlevasGR/1170d2ea47d851bfe024

I know this might not be the best you you've ever seens in your life but its my first time writing in Python :)

1 Answer 1

9

The json module of Python's standard library offers exactly the functionality you're asking for. import json at the top of your module and json.dumps(whatever) to get the json string to send in the response.

As a side note, failing authorization is most definitely not a 500 error: 500 means "server error" and the server is making absolutely no error in rejecting unauthorized users!-) Use a 403 ("forbidden") or other security-related 400-code to reject unauthorized users -- see http://en.wikipedia.org/wiki/HTTP_403 and more generally http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error for more.

This latter bit isn't what you're asking about, but maintaining semantic integrity of HTTP status codes is important -- it's violated often enough on the web today to give headaches to maintainers of HTTP clients, servers, proxies, caches, &c... let's make their life easier, not harder, by sticking to the standards!)

Sign up to request clarification or add additional context in comments.

5 Comments

Hello Alex, thanks for your reply. Indeed its perfect! Just what i wanted, but do you have any clue on how to push it back to the user?
@ZisakisZavitsanakis, SimpleHTTPRequestHandler is designed to "serve files from the current directory and below", per docs.python.org/2/library/simplehttpserver.html. Still, you're subclassing it and overriding methods, so what you're using is essentially docs.python.org/2/library/basehttpserver.html -- thus you can just write to self.wfile after the end_headers call.
Hmmmm so basicaly i need to push a file instead of a string. What if i write the encoded dictionary into a temp file and push that? An then overwrite it on every request
@ZisakisZavitsanakis, just self.wfile.write(result) after the end_headers call -- much, much better than messing with actual on-disk files. These are "file-like objects" (the other one is self.rfile to get the body of the request) and it's better to let Python's standard library do the work for you. BTW, nowadays WSGI is the recommended way to make Python HTTP servers -- see docs.python.org/2/library/wsgiref.html#module-wsgiref and the first example in particular.
I did it and it almost worked but instead of getting only the json response im also getting html like this: {"lights2": 2, "lights1": 2, "tv1": 4, "tv2": 4}HTTP/1.0 200 OK Server: SimpleHTTP/0.6 Python/2.7.8 Date: Fri, 30 Jan 2015 17:10:46 GMT Content-type: text/html; charset=mbcs Content-Length: 318 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html> <title>Directory listing for /</title> <body> <h2>Directory listing for /</h2> <hr> <ul> <li><a href=".idea/">.idea/</a> <li><a href="main.py">main.py</a> <li><a href="out.json">out.json</a> <li><a href="users.xml">users.xml</a>

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.