def run(): # Create web server application app = tinyweb.webserver() # Add our resources app.add_resource(CustomersList, '/customers') app.add_resource(Customer, '/customers/<user_id>') app.run(host='0.0.0.0', port=8081)
def setUp(self): self.srv = webserver() self.tempfn = '__tmp.html' self.ctype = None self.max_age = 2592000 with open(self.tempfn, 'wb') as f: f.write('someContent blah blah')
def testUrlFinderParameterized(self): srv = webserver() # Add few routes srv.add_route('/', 0) srv.add_route('/<user_name>', 1) srv.add_route('/a/<id>', 2) # Check first url (non param) rq = request(mockReader([])) rq.path = b'/' f, args = srv._find_url_handler(rq) self.assertEqual(f, 0) # Check second url rq.path = b'/user1' f, args = srv._find_url_handler(rq) self.assertEqual(f, 1) self.assertEqual(args['_param_name'], 'user_name') self.assertEqual(rq._param, 'user1') # Check third url rq.path = b'/a/123456' f, args = srv._find_url_handler(rq) self.assertEqual(f, 2) self.assertEqual(args['_param_name'], 'id') self.assertEqual(rq._param, '123456') # When param is empty and there is no non param endpoint rq.path = b'/a/' f, args = srv._find_url_handler(rq) self.assertEqual(f, 2) self.assertEqual(rq._param, '')
def setup_modules(self): # Base config self.config = SimpleConfig() self.config.add_param('configured', False) self.config.add_param( 'hostname', 'neopixel_{:s}'.format(platform.utils.mac_last_digits())) # Setup remote logging self.rlogging = RemoteLogging(self.config) # MQTT self.mqtt = tinymqtt.MQTTClient('neopixelctrl-{:s}'.format( platform.utils.mac_last_digits()), config=self.config) # DNS self.dns = tinydns.Server(ttl=10) # Modules self.ambi = AmbientLightAnalogSensor(self.config, self.mqtt, machine.ADC(0)) self.setupbtn = SetupButton(self.config, machine.Pin(setup_btn_pin)) self.status = StatusLed(self.config, machine.Pin(status_led_pin)) # WebServer self.web = tinyweb.webserver(max_concurrency=1, debug=True) # LED strip handler (+ associated web routes) self.neo = NeopixelStrip(machine.Pin(neopixel_pin), self.config, self.web, self.mqtt, self.loop)
def setUp(self): self.srv = webserver() self.srv.conns[id(1)] = None self.srv.add_resource(ResourceGetPost, '/') self.srv.add_resource(ResourceGetParam, '/param/<user_id>') self.srv.add_resource(ResourceGetArgs, '/args', arg1=1, arg2=2) self.srv.add_resource(ResourceNegative, '/negative')
def setup_modules(self): # Base config self.config = SimpleConfig() self.config.add_param('configured', False) self.config.add_param('hostname', 'wifiswitch_{:s}'.format(mac_last_digits())) # Setup remote logging self.rlogging = RemoteLogging(self.config) # MQTT self.mqtt = tinymqtt.MQTTClient('wifiswitch-{:s}'.format( mac_last_digits()), server='192.168.1.1', port=3883, config=self.config) # Modules self.status = StatusLed(self.config, machine.Pin(status_led_pin)) # self.setupbtn = SetupButton(self.config, machine.Pin(setup_btn_pin)) # WebServer self.web = tinyweb.webserver(debug=True) # Relays self.relays = [] for num, pin in enumerate(relays_pins): self.relays.append( Relay(num + 1, machine.Pin(pin), self.config, self.web, self.mqtt)) # Binary Sensors (user GPIO - currently only GPIO) self.binary_sensors = [] for num, pin in enumerate(binary_sensor_pins): pname = 'mqtt_binary_sensor{}_status'.format(num + 1) self.config.add_param(pname, 'binary_sensor{}'.format(num + 1)) self.binary_sensors.append( BinarySensor(machine.Pin(pin), self.config, self.mqtt, pname))
def testMalformedRequest(self): """Verify that malformed request generates proper response""" rdr = mockReader(['GET /\r\n', HDR('Host: blah.com'), HDRE]) wrt = mockWriter() srv = webserver() run_generator(srv._handler(rdr, wrt)) exp = ['HTTP/1.0 400 Bad Request\r\n', '\r\n'] self.assertEqual(wrt.history, exp) # Connection must be closed self.assertTrue(wrt.closed)
def testStartHTML(self): """Verify that request.start_html() works well""" srv = webserver() srv.add_route('/', self.hello_world_handler) rdr = mockReader(['GET / HTTP/1.1\r\n', HDR('Host: blah.com'), HDRE]) wrt = mockWriter() # "Send" request run_generator(srv._handler(rdr, wrt)) # Ensure that proper response "sent" self.assertEqual(wrt.history, self.hello_world_history) self.assertTrue(wrt.closed)
def startServer(self): self.server = tinyweb.webserver() self.server.add_route('/', self.app, methods=["GET"]) self.server.add_route('/execute', self.execute, methods=['POST'], save_headers=['Content-Length', 'Content-Type']) self.server.add_route('/static/<loc>', self.static, methods=['GET']) self.toggleServerStatusLED() self.server.run(self.address, self.port)
def setUp(self): self.dummy_called = False self.data = {} # "Register" one connection into map for dedicated decor server server_for_decorators.conns[id(1)] = None self.hello_world_history = ['HTTP/1.0 200 MSG\r\n' + 'Content-Type: text/html\r\n\r\n', '<html><h1>Hello world</h1></html>'] # Create one more server - to simplify bunch of tests self.srv = webserver() self.srv.conns[id(1)] = None
def testUrlFinderNegative(self): srv = webserver() # empty URL is not allowed with self.assertRaises(ValueError): srv.add_route('', 1) # Query string is not allowed with self.assertRaises(ValueError): srv.add_route('/?a=a', 1) # Duplicate urls srv.add_route('/duppp', 1) with self.assertRaises(ValueError): srv.add_route('/duppp', 1)
def testRequestBodyJson(self): """JSON encoded POST body""" srv = webserver() srv.add_route('/', self.dummy_post_handler, methods=['POST']) rdr = mockReader([ 'POST / HTTP/1.1\r\n', HDR('Content-Type: application/json'), HDR('Content-Length: 10'), HDRE, '{"a": "b"}' ]) wrt = mockWriter() run_generator(srv._handler(rdr, wrt)) # Check parsed POST body self.assertEqual(self.data, {'a': 'b'})
def testRequestBodyUnknownType(self): """Unknow HTTP body test - empty dict expected""" srv = webserver() srv.add_route('/', self.dummy_post_handler, methods=['POST']) rdr = mockReader([ 'POST / HTTP/1.1\r\n', HDR('Host: blah.com'), HDR('Content-Length: 5'), HDRE, '12345' ]) wrt = mockWriter() run_generator(srv._handler(rdr, wrt)) # Check extracted POST body self.assertEqual(self.data, {})
def testRequestBodyNegative(self): """Regular HTML form""" srv = webserver() srv.add_route('/', self.dummy_post_handler, methods=['POST']) rdr = mockReader([ 'POST / HTTP/1.1\r\n', HDR('Content-Type: application/json'), HDR('Content-Length: 9'), HDRE, 'some junk' ]) wrt = mockWriter() run_generator(srv._handler(rdr, wrt)) # payload broken - HTTP 400 expected self.assertEqual(wrt.history, ['HTTP/1.0 400 Bad Request\r\n', '\r\n'])
def testRequestBodyUrlencoded(self): """Regular HTML form""" srv = webserver() srv.add_route('/', self.dummy_post_handler, methods=['POST']) rdr = mockReader([ 'POST / HTTP/1.1\r\n', HDR('Content-Type: application/x-www-form-urlencoded; charset=UTF-8' ), HDR('Content-Length: 10'), HDRE, 'a=b&c=%20d' ]) wrt = mockWriter() run_generator(srv._handler(rdr, wrt)) # Check parsed POST body self.assertEqual(self.data, {'a': 'b', 'c': ' d'})
def run(): # Create web server application app = tinyweb.webserver() # Add our resources @app.route('/') @app.route('/index.html') async def index(req, resp): # Just send file await resp.send_file('/index.html') app.add_resource(CustomersList, '/customers') app.add_resource(Customer, '/customers/<user_id>') app.add_resource(lightShow, '/light') app.run(host='0.0.0.0', port=8081, loop_forever=False)
def testRequestLargeBody(self): """Max Body size check""" srv = webserver() srv.add_route('/', self.dummy_post_handler, methods=['POST'], max_body_size=5) rdr = mockReader([ 'POST / HTTP/1.1\r\n', HDR('Content-Type: application/json'), HDR('Content-Length: 9'), HDRE, 'some junk' ]) wrt = mockWriter() run_generator(srv._handler(rdr, wrt)) # payload broken - HTTP 400 expected self.assertEqual(wrt.history, ['HTTP/1.0 413 Payload Too Large\r\n', '\r\n'])
def testRouteParameterized(self): """Verify that route with params works fine""" srv = webserver() srv.add_route('/db/<user_name>', self.route_parameterized_handler) rdr = mockReader( ['GET /db/user1 HTTP/1.1\r\n', HDR('Host: junk.com'), HDRE]) wrt = mockWriter() # "Send" request run_generator(srv._handler(rdr, wrt)) # Ensure that proper response "sent" expected = [ 'HTTP/1.0 200 OK\r\n', 'Content-Type: text/html\r\n\r\n', '<html>Hello, user1</html>' ] self.assertEqual(wrt.history, expected) self.assertTrue(wrt.closed)
def testAutoOptionsMethod(self): """Test auto implementation of OPTIONS method""" srv = webserver() srv.add_route('/', self.hello_world_handler, methods=['POST', 'PUT', 'DELETE']) srv.add_route('/disabled', self.hello_world_handler, auto_method_options=False) rdr = mockReader(['OPTIONS / HTTP/1.0\r\n', HDRE]) wrt = mockWriter() run_generator(srv._handler(rdr, wrt)) exp = [ 'HTTP/1.0 200 OK\r\n', 'Access-Control-Allow-Headers: *\r\n' 'Access-Control-Allow-Origin: *\r\n' 'Access-Control-Allow-Methods: POST PUT DELETE\r\n\r\n' ] self.assertEqual(wrt.history, exp) self.assertTrue(wrt.closed)
def testCatchAllDecorator(self): # A fresh server for the catchall handler server_for_catchall_decorator = webserver() # Catchall decorator and handler @server_for_catchall_decorator.catchall() async def route_for_catchall_decorator(req, resp): await resp.start_html() await resp.send('my404') rdr = mockReader(['GET /this/is/an/invalid/url HTTP/1.1\r\n', HDRE]) wrt = mockWriter() server_for_catchall_decorator.conns[id(1)] = None run_coro(server_for_catchall_decorator._handler(rdr, wrt)) expected = ['HTTP/1.0 200 MSG\r\n' + 'Content-Type: text/html\r\n\r\n', 'my404'] self.assertEqual(wrt.history, expected) self.assertTrue(wrt.closed)
def testUrlFinderExplicit(self): urls = [('/', 1), ('/%20', 2), ('/a/b', 3), ('/aac', 5)] junk = ['//', '', '/a', '/aa', '/a/fhhfhfhfhfhf'] # Create server, add routes srv = webserver() for u in urls: srv.add_route(u[0], u[1]) # Search them all for u in urls: # Create mock request object with "pre-parsed" url path rq = request(mockReader([])) rq.path = u[0].encode() f, args = srv._find_url_handler(rq) self.assertEqual(u[1], f) # Some simple negative cases for j in junk: rq = request(mockReader([])) rq.path = j.encode() f, args = srv._find_url_handler(rq) self.assertIsNone(f) self.assertIsNone(args)
def testDisallowedMethod(self): """Verify that server respects allowed methods""" srv = webserver() srv.add_route('/', self.hello_world_handler) srv.add_route('/post_only', self.dummy_handler, methods=['POST']) rdr = mockReader(['GET / HTTP/1.0\r\n', HDRE]) # "Send" GET request, by default GET is enabled wrt = mockWriter() run_generator(srv._handler(rdr, wrt)) self.assertEqual(wrt.history, self.hello_world_history) self.assertTrue(wrt.closed) # "Send" GET request to POST only location self.dummy_called = False rdr = mockReader(['GET /post_only HTTP/1.1\r\n', HDRE]) wrt = mockWriter() run_generator(srv._handler(rdr, wrt)) # Hanlder should not be called - method not allowed self.assertFalse(self.dummy_called) exp = ['HTTP/1.0 405 Method Not Allowed\r\n', '\r\n'] self.assertEqual(wrt.history, exp) # Connection must be closed self.assertTrue(wrt.closed)
def testParseHeadersOnOff(self): """Verify parameter parse_headers works""" srv = webserver() srv.add_route('/parse', self.dummy_handler, parse_headers=True) srv.add_route('/noparse', self.dummy_handler, parse_headers=False) rdr = mockReader([ 'GET /noparse HTTP/1.1\r\n', HDR('Host: blah.com'), HDR('Header1: lalalla'), HDR('Junk: junk.com'), HDRE ]) # "Send" request with parsing off wrt = mockWriter() run_generator(srv._handler(rdr, wrt)) self.assertTrue(self.dummy_called) # Check for headers self.assertEqual(self.dummy_req.headers, {}) self.assertTrue(wrt.closed) # "Send" request with parsing on rdr = mockReader([ 'GET /parse HTTP/1.1\r\n', HDR('Host: blah.com'), HDR('Header1: lalalla'), HDR('Junk: junk.com'), HDRE ]) wrt = mockWriter() run_generator(srv._handler(rdr, wrt)) self.assertTrue(self.dummy_called) # Check for headers hdrs = { b'Junk': b'junk.com', b'Host': b'blah.com', b'Header1': b'lalalla' } self.assertEqual(self.dummy_req.headers, hdrs) self.assertTrue(wrt.closed)
def setUp(self): self.srv = webserver() self.srv.add_resource(ResourceGetPost, '/') self.srv.add_resource(ResourceGetParam, '/param/<user_id>')
from tinyweb import webserver from tinyweb.server import HTTPException from radio.tuner import device app = webserver() @app.resource('/status', method='GET') def status(params): status = { 'state': device.state, 'volume': device.volume, 'frequency': device.frequency, 'stereo': device.stereo, 'mute': device.mute } return (status, 200) @app.resource('/mute', method='PUT') def mute(params): try: device.mute = int(params.get('value')) except ValueError: raise HTTPException(400) return ('', 202) @app.resource('/volume', method='PUT') def volume(params): try:
def testUrlFinderNegative(self): srv = webserver() # empty URL is not allowed with self.assertRaises(ValueError): srv.add_route('', 1) # Query string is not allowed with self.assertRaises(ValueError): srv.add_route('/?a=a', 1) # Duplicate urls srv.add_route('/duppp', 1) with self.assertRaises(ValueError): srv.add_route('/duppp', 1) # We want to test decorator @server.route as well server_for_decorators = webserver() @server_for_decorators.route('/uid/<user_id>') @server_for_decorators.route('/uid2/<user_id>') async def route_for_decorator(req, resp, user_id): await resp.start_html() await resp.send('YO, {}'.format(user_id)) class ServerFull(unittest.TestCase): def setUp(self): self.dummy_called = False self.data = {} # "Register" one connection into map for dedicated decor server
def main(): # Some ports requires to allocate extra mem for exceptions if hasattr(micropython, 'alloc_emergency_exception_buf'): micropython.alloc_emergency_exception_buf(100) loop = asyncio.get_event_loop() logging.basicConfig(level=logging.DEBUG) # Base config config = SimpleConfig() config.add_param('configured', False) wsetup = WifiSetup(config) # MQTT mqtt = tinymqtt.MQTTClient('LEDcontroller-{}'.format( platform.utils.mac_last_digits()), config=config) # DNS dns = tinydns.Server(ttl=10) # WebServer web = tinyweb.webserver() # Enable REST API for config & wifi web.add_resource(config, '/config') web.add_resource(wsetup, '/wifi') # Create LED strip handler WhiteLedStrip(machine.Pin(green_pin), config, web, mqtt, loop) # Peripheral modules setupbtn = SetupButton(config, None) # Other web routes @web.route('/') async def index(req, resp): if config.configured: await resp.redirect('/dashboard') else: await resp.redirect('/setup') @web.route('/dashboard') async def page_dashboard(req, resp): await resp.send_file('dashboard_all.html.gz', content_encoding='gzip', content_type='text/html') @web.route('/setup') async def page_setup(req, resp): await resp.send_file('setup_all.html.gz', content_encoding='gzip', content_type='text/html') # Setup AP parameters ap_if = network.WLAN(network.AP_IF) essid = b'LedCtrl-%s' % platform.utils.mac_last_digits() ap_if.active(True) ap_if.config(essid=essid, authmode=network.AUTH_WPA_WPA2_PSK, password=b'ledledled') ap_if.ifconfig(('192.168.168.1', '255.255.255.0', '192.168.168.1', '192.168.168.1')) ap_if.active(False) # Captive portal platform.utils.captiveportal.enable(web, dns, '192.168.168.1') # Load configuration try: config.load() except Exception as e: log.warning('Config load failed: {}'.format(e)) pass # Main loop try: wport = 80 dport = 53 if platform.utils.is_emulator(): wport = 8080 dport = 5335 # Start services dns.run(host='0.0.0.0', port=dport, loop=loop) web.run(host='0.0.0.0', port=wport, loop_forever=False, loop=loop) mqtt.run(loop) setupbtn.run(loop) # Run main loop loop.run_forever() except KeyboardInterrupt as e: if platform.utils.is_emulator(): for s in [web, dns, mqtt]: s.shutdown() loop.run_until_complete(shutdown_wait()) else: raise except Exception as e: log.exc(e, "Unhandled exception")
#!/usr/bin/env micropython """ MIT license (C) Konstantin Belyalov 2017-2018 """ import tinyweb # Create web server application app = tinyweb.webserver() # Index page @app.route('/') def index(request, response): # Start HTTP response with content-type text/html yield from response.start_html() # Send actual HTML page yield from response.send('<html><body><h1>Hello, world!</h1></html>\n') # Another one, more complicated page @app.route('/table') def table(request, response): # Start HTTP response with content-type text/html yield from response.start_html() yield from response.send('<html><body><h1>Simple table</h1>' '<table border=1 width=400>' '<tr><td>Name</td><td>Some Value</td></tr>') for i in range(10): yield from response.send('<tr><td>Name{}</td><td>Value{}</td></tr>'.format(i, i))
await client.connect(loop) # n=0 #sreader = uasyncio.StreamReader(sys.stdin) n = 0 while True: res = await sreader.readline() await client.publish(PUB_TOPIC, res, qos=1) await uasyncio.sleep(0) gc.collect() loop.create_task(mqtt_main(client)) app = tinyweb.webserver(external_loop=loop, debug=True) # Index page @app.route('/') async def index(request, response): global wifi wifi.active(True) # Start HTTP response with content-type text/html ssids = sorted(ssid.decode('utf-8') for ssid, *_ in wifi.scan()[:10]) gc.collect() await response.start_html() # Send actual HTML page await response.send(""" <html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />