CS/COE 1520 Jarrett Billingsley Flask CS/COE 1520 Jarrett Billingsley
Today: Server-side programming concepts Flask
Server-side programming
server needs to "answer the phone" How can I help you today? from now on we'll focus on the other side of the connection. Server Browser Request server needs to "answer the phone" and then… do something Response and send a page back.
it also does stuff on top of the application layer… Remember this? it might help to know where we'll be working. this is where server-side programming happens. the server software decodes requests, encodes responses, and manages sessions with the client. the OS does this. these are handled by the networking hardware. it also does stuff on top of the application layer… - ok, it gets a little fuzzy there around the transport/network layers. - some things might be software, some might be hardware - some things might be done in the kernel, some things in userspace - regardless, unless you're doing extremely high-scale stuff, you're not likely to need to dip below those top few layers.
Ports (part of TCP/UDP) one server can have multiple capabilities. to access a particular capability, you use the server's IP address and a port number. 93.184.216.34 22 SSH there are some well-known port numbers for common things. 80 HTTP port numbers range from 0 to 65535. 443 HTTPS written as an address, we put a colon between the IP address and port: 93.184.216.34:80 - it's like calling a number and then dialing an extension to get to a particular phone - port 8080 is sometimes used as a fallback for when port 80 is blocked or something - port 666 is what the original Doom uses for netplay ;o
Sockets Client Browser Client OS Server software Server OS 80 the OS abstracts network connections with sockets. socket! Client Browser Client OS connect with TCP to 93.184.216.34:80 socket! Server software Server OS 80 the Berkeley Sockets interface is the typical way to use sockets. they present a very file-like interface. - you can look up the Berkeley Sockets docs – though most languages other than C provide a nicer library around them.
the OS makes a new socket for each client. Waiting for a call the server tells the OS, "I'll wait for connections on this port." now, whenever a client connects on port 80, the software gets notified! I'm listening on port 80. the OS makes a new socket for each client. Server software Server OS socket! 80 Client 1 a port can support many connections, not just one. it's a logical address, not physical. socket! 80 Client 2 socket! 80 Client 3 - there are limits, of course, but it's not unusual for a server to handle hundreds or thousands of clients at once.
And now that we're finally talking… now the server finally gets the client's request. it's an HTTP request! and all the server is required to do is send a response. what happens in between… is up to you! so to summarize: the server listens on a port the client connects to that port with a socket the server OS creates a socket for that connection the server software is notified of the connection the server software reads the request and responds the connection is closed! and this is the step that Flask focuses on.
NEVER. TRUST. THE CLIENT. Oh, and one more thing when developing server-side software… NEVER. TRUST. THE CLIENT.
Flask Basics
What is it? Server software Flask Your code! a framework for writing server software it eliminates much of the boilerplate, so you just write the cool bits Server software Flask setting up sockets Your code! spawning threads rendering pages decoding requests encoding responses logins using databases maintaining sessions the actual logic of your app a bunch of useful functionality - if you haven't done framework-style programming before, it's a lot like GUI programming - you don't write the main loop; you just fill in the important functionality - callbacks! callbacks everywhere!
How do you get it? it's easy to install with pip, Python's package manager. on the command line, pip install flask once it's installed, you use it like a library. you're also given the flask command-line tool. see the Flask docs on the various ways you can run your server! - there'll be more detailed instructions laterrrr, don't worryyyyyy - and you can just look at the Flask docs too
Looking at a simple example this is what's in fl1_hello.py: this creates a Flask object. it's sort of our gateway into the library. from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!" if __name__ == "__main__": app.run() this decorator associates hello() with the root directory of the server. and when you run this file, this starts a server on localhost.
The call is coming from inside the house sockets are an abstraction, and can connect anywhere… including to your own computer! localhost, whose IP is 127.0.0.1, means "the current computer." Your Browser Your OS connect with TCP to 127.0.0.1:5000 in this case, the OS is using sockets as a form of IPC – inter-process communication. python fl1_hello.py 5000 - ehhhh? 449? ehhhhhhhh??????????? - why is 449 not a prereq of this course, again? this is super useful for doing server development. you can serve and test on the same machine, no internet needed!
Routes http://example.com/some/path.html remember the path part of a URL: this doesn't have to be a literal file path. http://example.com/some/path.html a Flask route associates a path with a function. when that path gets a request, the function is called. let's look at fl2_hello_foo.py, which has multiple routes. note that /funny redirects us to /bar instead.
Trailing slash or no? http://example.com/contact in that example, /foo has no trailing slash, while /bar/ does. why? well, it's more of a conceptual difference… "slashless" names are for pages that stand on their own. http://example.com/contact use a trailing slash for pages with "sub-pages." http://example.com/user/ maybe /user/ gives me my user page (once logged in)… http://example.com/user/3390 …but the same route with a number after it gives me a particular user's page. - in this example, if the browser tries to access "/user" with no trailing slash, flask will automatically redirect it to "/user/". - but the reverse is not true – "/contact/" will give a 404, not a redirect.
Client-server communication
GET vs POST remember these methods? when the user fills out a form element and submits it… the server gets a POST request, where the body contains the data from the form. POST / HTTP/1.1 Host: 127.0.0.1 User-Agent: Mozilla/5.0 Accept: */* Content-Length: 26 Content-Type: application/x-www-form-urlencoded anumber=12345&astring=test let's look at fl3_form.py.
NEVER. TRUST. THE CLIENT. Being sneaky the curl command-line tool lets us send HTTP requests manually. curl --data "anumber=12345&astring=test" 127.0.0.1:5000/ but what if we sent bogus data? curl --data "ohno=1337" 127.0.0.1:5000/ in this case, Flask helps us. when we try to access "anumber" or "astring", we get a KeyError. Flask catches that, and responds with a 400 Bad Request. but what if we try entering not-a-number in the number field? even in the browser? huh… no checking. you have no guarantees that the client is going to send you valid, well-formed data. NEVER. TRUST. THE CLIENT.
"Logging in" the idea behind logging in is simple: the user knows some secret that the server also knows. the user proves to the server that they are who they say they are. in fl4_login.py… we have a dict of users and passwords. the only way we can view our profile (curProfile) is by POSTing our username and password. what happens if we give a wrong username? well, that's our fault, really :^) what if we have multiple pages that need the user to be logged in? this seems like a really cumbersome way of doing it…