240 likes | 374 Views
Web Basics. Willem Visser RW334. Overview. Basic Browser and Server Interaction Forms with actions, url encoding and handlers Parameters Having more than one handler GET versus POST Templates Jinja2 Validation and Escaping.
E N D
Web Basics Willem VisserRW334
Overview • Basic Browser and Server Interaction • Forms with actions, url encoding and handlers • Parameters • Having more than one handler • GET versus POST • Templates • Jinja2 • Validation and Escaping <thanks>Udacity CS253 is the inspiration for a lot of this content</thanks>
Forms with actions <form> <input name="q"> <input type="submit"> </form> <form action = "/foo"> <input name="q"> <input type="submit"> </form> <form action = ”http://www.google.com/search"> <input name="q"> <input type="submit"> </form>
Server side • How do we react to the “action”? import webapp2 class MainPage(webapp2.RequestHandler): defget(self): self.response.headers['Content-Type'] = 'text/plain' self.response.out.write('Hello, RW334 World!') app = webapp2.WSGIApplication([('/', MainPage)], debug=True) Main.py … handlers: - url: /.* script: main.app … app.yaml
Server Handler (1) • Lets first add the form to our web page import webapp2 form = """ <form action = "/foo"> <input name="q"> <input type="submit"> </form> """ class MainPage(webapp2.RequestHandler): defget(self): self.response.headers['Content-Type'] = 'text/plain' self.response.out.write(form) app = webapp2.WSGIApplication([('/', MainPage)], debug=True) Will this render the form?
Server Handler (2) • Default content type is HTML import webapp2 form = """ <form action = "/foo"> <input name="q"> <input type="submit"> </form> """ class MainPage(webapp2.RequestHandler): defget(self): #self.response.headers['Content-Type'] = 'text/plain' self.response.out.write(form) app = webapp2.WSGIApplication([('/', MainPage)], debug=True) Will this correctly submit?
Server Handler (3) • Add the FooPage handler whenever the “/foo” url is accessed on our server • Can get the “q” parameter from the GET request … class FooPage(webapp2.RequestHandler): def get(self): q = self.request.get("q") self.response.out.write("Thanks for %s" % q) app = webapp2.WSGIApplication( [('/', MainPage), ('/foo', FooPage)], debug=True)
Server Handler (4) class FooPage(webapp2.RequestHandler): defget(self): self.response.headers['Content-Type'] = 'text/plain' self.response.out.write(self.request) app = webapp2.WSGIApplication([('/', MainPage), ('/foo', FooPage)], debug=True) GET /foo?q=blah HTTP/1.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.8,af;q=0.6 Host: localhost:8080 Referer: http://localhost:8080/ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36 X-Appengine-Country: ZZ
GET versus POST … form = """ <form method = “post” action = "/foo"> <input name="q"> <input type="submit"> </form> """ class MainPage(webapp2.RequestHandler): def get(self): self.response.out.write(form) class FooPage(webapp2.RequestHandler): def get(self): q = self.request.get("q") self.response.out.write("Thanks for %s" % q) app = webapp2.WSGIApplication([('/', MainPage), ('/foo', FooPage)], debug=True) Will this correctly submit?
GET versus POST (2) … form = """ <form method = “post” action = "/foo"> <input name="q"> <input type="submit"> </form> """ class MainPage(webapp2.RequestHandler): def get(self): self.response.out.write(form) class FooPage(webapp2.RequestHandler): def post(self): q = self.request.get("q") self.response.out.write("Thanks for %s" % q) app = webapp2.WSGIApplication([('/', MainPage), ('/foo', FooPage)], debug=True) Where did the parameter go in url?
GET versus POST (3) • Parameter now part of the body of request POST /foo HTTP/1.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.8,af;q=0.6 Content-Length: 6 Content-Type: application/x-www-form-urlencoded Content_Length: 6 Content_Type: application/x-www-form-urlencoded Host: localhost:8080 Origin: http://localhost:8080 Referer: http://localhost:8080/ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36 X-Appengine-Country: ZZ q=blah
GET versus POST (4) • GET • Parameters in URL • Length restrictions • Used for fetching documents • OK to cache • Same request in succession should produce the same • Should not change the server • POST • Parameters in body • Used for updating (server) • No caching
Templates • Greatly simplify developing dynamic websites • Pass data variables to the page • Embed programming constructs in the page • Lots of options, we will use jinja2
First create your Template <!DOCTYPE html> <html> <head> <title>I'm using Templates!</title> </head> <body> I'm {{name}}, and I {{verb}} RW334! </body> </html> base.html … libraries: - name: jinja2 version: latest … app.yaml
Handler import os import webapp2 import jinja2 jinja_environment = jinja2.Environment(autoescape=True, loader=jinja2.FileSystemLoader(os.path.join(os.path.dirname(__file__), 'templates'))) class MainPage(webapp2.RequestHandler): defget(self): template_values = { 'name': 'Willem', 'verb': 'love' } template = jinja_environment.get_template('base.html') self.response.out.write(template.render(template_values)) app = webapp2.WSGIApplication([('/', MainPage)], debug=True)
Loops! <!DOCTYPE html> <html> <head> <title>I'm using Templates!</title> </head> <body> I'm {{name}}, and I {{verb}} RW334! Here are a few of my favourite things about the course: <ul> {% for item in favourites %} <li>{{ item }}</li> {% endfor %} </ul> </body> </html>
Handler … class MainPage(webapp2.RequestHandler): def get(self): template_values = { 'name': 'Willem', 'verb': 'love', 'favourites' : favourites } template = jinja_environment.get_template('base.html') self.response.out.write(template.render(template_values)) app = webapp2.WSGIApplication([('/', MainPage)], debug=True)
Validation • When you receive input it is important to validate it • Can happen on the client and the server • We will look at it on the server side here
Birthday <!DOCTYPE html> <html> <head> <title>Validation</title> </head> <body> <form method = "post"> What is your birthday? <br> <label> Month <input type = "text" name = "month" value="{{month}}”> </label> <label> Day <input type = "text" name = "day" value="{{day}}”> </label> <label> Year <input type = "text" name = "year" value = "{{year}}”> </label> <div style="color: red"> {{error}} </div> <br><br> <input type = "submit"> </form> </body> </html>
Handler with Validation class MainPage(webapp2.RequestHandler): defdisplayform(self, error = "", month = "", day = "", year = ""): values = dict([('error', error), ('month', month), ('day', day), ('year', year)]) template = jinja_environment.get_template('validation.html') self.response.out.write(template.render(values)) def get(self): self.displayform() def post(self): user_month = self.request.get("month") user_day = self.request.get("day") user_year = self.request.get("year") month = valid_month(user_month) day = valid_day(user_day) year = valid_year(user_year) if not(month and day and year): self.displayform("Not a valid date", user_month, user_day, user_year) else: self.response.out.write("Thanks for the valid birthday")
Escaping • What happens if we add this in a field • yaya”>oops! • We need to make sure HTML characters display as intended not mess with the “real” HTML • This is done by Escaping the HTML • Convert it to something harmless • Common cases • “ becomes " and & becomes & • > becomes > and < becomes <
Escaping Example • If we want to display this line in the browser • How do we display <html> in HTML? • By typing • How do we display <html> in HTML?
First Rule of Escaping NEVER ROLL YOUR OWN!
Escape Libs import cgi defescape_html(s): return cgi.escape(s,quote = True) class MainPage(webapp2.RequestHandler): defdisplayform(self, error = "", month = "", day = "", year = ""): values = dict([('error', error), ('month', escape_html(month)), ('day', escape_html(day)), ('year', escape_html(year))]) template = jinja_environment.get_template('validation.html') self.response.out.write(template.render(values)) OR jinja_environment = jinja2.Environment(autoescape=True, loader=jinja2.FileSystemLoader(os.path.join(os.path.dirname(__file__), 'templates')))