Web Architectures - Stellenbosch University

Download Report

Transcript Web Architectures - Stellenbosch University

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
<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”?
Main.py
import webapp2
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, RW334 World!')
app.yaml
app = webapp2.WSGIApplication([('/', MainPage)], debug=True)
…
handlers:
- url: /.*
script: main.app
…
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):
def get(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):
def get(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):
def get(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
app.yaml
base.html
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>
…
libraries:
- name: jinja2
version: latest
…
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):
def get(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):
def displayform(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 &quot and & becomes &amp
– > becomes &gt and < becomes &lt
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 &lthtml&gt in HTML?
First Rule of Escaping
NEVER ROLL YOUR OWN!
Escape Libs
import cgi
def escape_html(s):
return cgi.escape(s,quote = True)
class MainPage(webapp2.RequestHandler):
def displayform(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')))