Presenter: James Huang Date: Sept. 29, 2014 1 HTTP and WWW Bottle Web Framework Request Routing Sending Static Files Handling HTML <Form> HTTP Errors and Redirects Cookies Templates Plugins Demo 2 World Wide Web (WWW) uses Hypertext Transfer Protocol (HTTP) as a standard for web client and web server to communicate. HTTP uses a request-response computing model. ◦ A server listens for clients’ connection over TCP. ◦ A client (e.g. web browser) sends a request message to server. ◦ The server sends back a status line followed by a response message. HTTP is a stateless protocol. ◦ Web applications often use cookies to maintain states. 3 An HTTP client specifies request methods to distinguish different types of actions to be performed on the server. GET ◦ Retrieves data from the server ◦ Should not have other effect on the server POST ◦ Requests that the server accepts the data enclosed in the request ◦ Used to submit a form, upload a file, etc. 4 An HTTP session is a sequence of requestresponse transactions. Web Client 1. GET /index.html HTTP/1.1 Host: www.example.com 2. HTTP/1.0 200 OK Date: Mon, 29 Sep 2014 03:50:21 GMT Server: WSGIServer/0.1 Python/2.7.2 Content-Length: 32 Content-Type: text/html; charset=UTF-8 Web Server <html> <body> Hello World. </body> </html> 5 Bottle is a web server that allows developers to write web applications in Python. It is easy to install and use. ◦ Implemented in Python ◦ Has no dependency on any external libraries Writing web application for Bottle is simple. ◦ A web application consists of callback functions that are called by Bottle to handle HTTP requests. ◦ Bottle handles errors and exceptions automatically. 6 hello.py: # A simple web application Imports Bottle web framework from bottle import run, route Links ‘/’ to home() @route('/') def home(): return '<html><body>Hello World.</body></html>‘ run(host='localhost', port=8080, debug=True) Starts web server on port 8080 7 URLs are linked to callback functions with route() decorator. URL contains wildcards, dynamic route, can be used to match more than one URL. @route(‘/hello/<name>’) def hello(name): return greet(name) More than one route can be used for a single callback function. @route(‘/’) @route(‘/hello/<name>’) def hello(name=‘Stranger’): return greet(name) 8 A simple wildcard (e.g. <name>) matches one or more characters up to the next slash (‘/’). ◦ E.g. ‘/hello/<name>’ matches ‘/hello/bob’, but not ‘/hello’ or ‘/hello/john/smith’. Each wildcard passes the matched part of URL as a keyword argument to the callback function. Filters can be used to match specific wildcards and converts matched part of URL. ◦ :int – matches digits only and converts the value to integer ◦ :path – matches more than one path segment ◦ :re – matches with a regular expression 9 A web application needs to have a callback to handle which files to serve to a client. ◦ Bottle does not automatically serve files to client. Bottle provides static_file() helper function. match URL with from bottle import static_file @route('/images/<filename:re:.*\.png>') regular expression def send_image(filename): return static_file(filename, root='/path/to/image/files', mimetype='image/png') match URL with path @route('/html/<filepath:path>') def server_static(filepath): return static_file(filepath, root='/path/to/your/html/files') 10 HTML usually specify to use POST request method to send form data. Bottle’s route decorator applies to GET request method by default. A web application can specify request method as an argument of route decorator. ◦ E.g. @route(‘/login’, method=‘POST’) Bottle also provides different decorators to handle different request methods: @get, @post, etc. as shortcuts. The value of an Input field of a form can be retrieved with request object. 11 from bottle import get, post, request # or route @get('/login') # or @route('/login') login() is called when user browse to /login def login(): return ''' <form action="/login" method="post"> Username: <input name="username" type="text" /> Password: <input name="password" type="password" /> <input value="Login" type="submit" /> </form> ''' @post('/login') # or @route('/login', method='POST') def do_login(): do_login() is called when user username = request.forms.get('username') submit the form password = request.forms.get('password') if check_login(username, password): request is used to retrieve return "<p>Your login information wasobject correct.</p>" the value of an input field else: return "<p>Login failed.</p>" 12 The abort() function is used to generate an HTTP error page. from bottle import route, abort @route('/restricted') def restricted(): abort(401, "Sorry, access denied.") The redirect() function redirects a client to a different URL. from bottle import redirect @route('/wrong/url') def wrong(): redirect("/right/url") 13 A cookie stores site-specific text information in a web browser’s profile. A web application creates a new cookie with Response.set_cookie(), access a cookie with Request.get_cookie(). @route('/hello') def hello_again(): if request.get_cookie("visited"): return "Welcome back! Nice to see you again" else: response.set_cookie("visited", "yes") return "Hello there! Nice to meet you" 14 A cookie can be controlled with different settings. ◦ max_age: maximum age in seconds ◦ expires: the timestamp when the cookie expires ◦ secure: limit the cookie to HTTPS connections These settings can be specified as keyword arguments to Response.set_cookie(). Cookie expires at the end of a browser session, unless max_age or expires is set. 15 Bottle provide a convenient way to generate web page from templates. Here is an example template: %if name == 'World': <h1>Hello {{name}}!</h1> <p>This is a test.</p> %else: <h1>Hello {{name.title()}}!</h1> <p>How are you?</p> %end Python-like syntax A web application uses templates with template() function. @route('/hello/<name>') def hello(name): return template('hello_template', name=name) hello_template.tpl 16 Bottle supports third-party plugins: ◦ Bottle-Sqlite: SQLite3 database plugin ◦ Bottle-Redis: Redis database plugin ◦ Bottle-Flash: flash plugin from bottle import route, install, template from bottle_sqlite import SQLitePlugin install(SQLitePlugin(dbfile='/tmp/test.db')) @route('/show/<post_id:int>') def show(db, post_id): SQLitePlugin detects the use of db and creates a new database connection. c = db.execute('SELECT title, content FROM posts WHERE id = ?', (post_id,)) row = c.fetchone() return template('show_post', title=row['title'], text=row['content']) 17 Thank you! contact: z.huang@utoronto.ca 18