Using Python for CGI programming Guido van Rossum







![Strings • "hello"+"world" "helloworld" • "hello"*3 "hellohello" # repetition • "hello"[0] "h" # indexing Strings • "hello"+"world" "helloworld" • "hello"*3 "hellohello" # repetition • "hello"[0] "h" # indexing](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-8.jpg)
![Lists • a = [99, "bottles of beer", ["on", "the", "wall"]] • Flexible arrays, Lists • a = [99, "bottles of beer", ["on", "the", "wall"]] • Flexible arrays,](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-9.jpg)
![More list operations >>> a = range(5) # [0, 1, 2, 3, 4] >>> More list operations >>> a = range(5) # [0, 1, 2, 3, 4] >>>](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-10.jpg)

![More dictionary ops • Keys, values, items: • d. keys() -> ["duck", "back"] • More dictionary ops • Keys, values, items: • d. keys() -> ["duck", "back"] •](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-12.jpg)




![Changing a shared list a = [1, 2, 3] a 1 2 3 a Changing a shared list a = [1, 2, 3] a 1 2 3 a](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-17.jpg)

![Control structures if condition: while condition: statements [elif condition: statements]. . . else: for Control structures if condition: while condition: statements [elif condition: statements]. . . else: for](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-19.jpg)
















![File objects • f = open(filename[, mode[, buffersize]) – mode can be "r", "w", File objects • f = open(filename[, mode[, buffersize]) – mode can be "r", "w",](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-36.jpg)




















![Cookie example import os, cgi, Cookie c["user"] = user c = Cookie() print c Cookie example import os, cgi, Cookie c["user"] = user c = Cookie() print c](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-57.jpg)

















- Slides: 74

Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston, Virginia, USA) guido@python. org www. python. org 11/12/1999 © 1999 CNRI, Guido van Rossum 1

Overview • 1 minute advocacy • 30 minutes basic Python tutorial • 30 minutes on Python CGI programming • 30 minutes CGI case study: FAQ wizard • Spanish Inquisition 11/12/1999 © 1999 CNRI, Guido van Rossum 2

Why Python? • Have your cake and eat it, too: Productivity and readable code • VHLLs will gain on system languages (John Ousterhout) • "Life is better without braces" (Bruce Eckel) 11/12/1999 © 1999 CNRI, Guido van Rossum 3

Basic Python tutorial 11/12/1999 © 1999 CNRI, Guido van Rossum 4

Tutorial outline • interactive "shell" • basic types: numbers, strings • container types: lists, dictionaries, tuples • variables • control structures • functions & procedures • classes & instances • modules & packages • exceptions • files & standard library 11/12/1999 © 1999 CNRI, Guido van Rossum 5

Interactive “shell” • Great for learning the language • Great for experimenting with the library • Great for testing your own modules • Type statements or expressions at prompt: >>> print "Hello, world" Hello, world >>> x = 12**2 >>> x/2 72 >>> # this is a comment 11/12/1999 © 1999 CNRI, Guido van Rossum 6

Numbers • The usual suspects • 12, 3. 14, 0 x. FF, 0377, (-1+2)*3/4**5, abs(x), 0<x<=5 • C-style shifting & masking • 1<<16, x&0 xff, x|1, ~x, x^y • Integer division truncates : -( • 1/2 -> 0 # float(1)/2 -> 0. 5 • Long (arbitrary precision), complex • 2 L**100 -> 1267650600228229401496703205376 L • 1 j**2 -> (-1+0 j) 11/12/1999 © 1999 CNRI, Guido van Rossum 7
![Strings helloworld helloworld hello3 hellohello repetition hello0 h indexing Strings • "hello"+"world" "helloworld" • "hello"*3 "hellohello" # repetition • "hello"[0] "h" # indexing](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-8.jpg)
Strings • "hello"+"world" "helloworld" • "hello"*3 "hellohello" # repetition • "hello"[0] "h" # indexing • "hello"[-1] "o" # (from end) • "hello"[1: 4] "ell" # slicing • len("hello") 5 # size • "hello" < "jello" 1 # comparison • "e" in "hello" 1 # concatenation # search • "escapes: n etc, 33 etc, xff etc" • 'single quotes' '''triple quotes''' r"raw strings" 11/12/1999 © 1999 CNRI, Guido van Rossum 8
![Lists a 99 bottles of beer on the wall Flexible arrays Lists • a = [99, "bottles of beer", ["on", "the", "wall"]] • Flexible arrays,](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-9.jpg)
Lists • a = [99, "bottles of beer", ["on", "the", "wall"]] • Flexible arrays, not Lisp-like linked lists • Same operators as for strings • a+b, a*3, a[0], a[-1], a[1: ], len(a) • Item and slice assignment • a[0] = 98 • a[1: 2] = ["bottles", "of", "beer"] -> [98, "bottles", "of", "beer", ["on", "the", "wall"]] • del a[-1] 11/12/1999 # -> [98, "bottles", "of", "beer"] © 1999 CNRI, Guido van Rossum 9
![More list operations a range5 0 1 2 3 4 More list operations >>> a = range(5) # [0, 1, 2, 3, 4] >>>](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-10.jpg)
More list operations >>> a = range(5) # [0, 1, 2, 3, 4] >>> a. append(5) # [0, 1, 2, 3, 4, 5] >>> a. pop() # [0, 1, 2, 3, 4] 5 >>> a. insert(0, 5. 5) # [5. 5, 0, 1, 2, 3, 4] >>> a. pop(0) # [0, 1, 2, 3, 4] 5. 5 >>> a. reverse() # [4, 3, 2, 1, 0] >>> a. sort() # [0, 1, 2, 3, 4] 11/12/1999 © 1999 CNRI, Guido van Rossum 10

Dictionaries • Hash tables, "associative arrays" • d = {"duck": "eend", "water": "water"} • Lookup: • d["duck"] -> "eend" • d["back"] # raises Key. Error exception • Delete, insert, overwrite: • del d["water"] # {"duck": "eend", "back": "rug"} • d["back"] = "rug" # {"duck": "eend", "back": "rug"} • d["duck"] = "duik" # {"duck": "duik", "back": "rug"} 11/12/1999 © 1999 CNRI, Guido van Rossum 11
![More dictionary ops Keys values items d keys duck back More dictionary ops • Keys, values, items: • d. keys() -> ["duck", "back"] •](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-12.jpg)
More dictionary ops • Keys, values, items: • d. keys() -> ["duck", "back"] • d. values() -> ["duik", "rug"] • d. items() -> [("duck", "duik"), ("back", "rug")] • Presence check: • d. has_key("duck") -> 1; d. has_key("spam") -> 0 • Values of any type; keys almost any • {"name": "Guido", "age": 43, ("hello", "world"): 1, 42: "yes", "flag": ["red", "white", "blue"]} 11/12/1999 © 1999 CNRI, Guido van Rossum 12

Dictionary details • Keys must be immutable: – numbers, strings, tuples of immutables • these cannot be changed after creation – reason is hashing (fast lookup technique) – not lists or other dictionaries • these types of objects can be changed "in place" – no restrictions on values • Keys will be listed in arbitrary order – again, because of hashing 11/12/1999 © 1999 CNRI, Guido van Rossum 13

Tuples • key = (lastname, firstname) • point = x, y, z # paren’s optional • x, y, z = point • lastname = key[0] • singleton = (1, ) # trailing comma! • empty = () # parentheses! • tuples vs. lists; tuples immutable 11/12/1999 © 1999 CNRI, Guido van Rossum 14

Variables • No need to declare • Need to assign (initialize) • use of uninitialized variable raises exception • Not typed if friendly: greeting = "hello world" else: greeting = 12**2 print greeting • Everything is a variable: • functions, modules, classes 11/12/1999 © 1999 CNRI, Guido van Rossum 15

Reference semantics • Assignment manipulates references • x = y does not make a copy of y • x = y makes x reference the object y references • Very useful; but beware! • Example: >>> a = [1, 2, 3]; b = a >>> a. append(4); print b [1, 2, 3, 4] 11/12/1999 © 1999 CNRI, Guido van Rossum 16
![Changing a shared list a 1 2 3 a 1 2 3 a Changing a shared list a = [1, 2, 3] a 1 2 3 a](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-17.jpg)
Changing a shared list a = [1, 2, 3] a 1 2 3 a b=a b a a. append(4) 4 b 11/12/1999 © 1999 CNRI, Guido van Rossum 17

Changing an integer a=1 a b=a 1 b a new int object created by add operator (1+1) 2 a = a+1 b 11/12/1999 1 © 1999 CNRI, Guido van Rossum old reference deleted by assignment (a=. . . ) 18
![Control structures if condition while condition statements elif condition statements else for Control structures if condition: while condition: statements [elif condition: statements]. . . else: for](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-19.jpg)
Control structures if condition: while condition: statements [elif condition: statements]. . . else: for var in sequence: statements break continue 11/12/1999 © 1999 CNRI, Guido van Rossum 19

Grouping indentation In Python: In C: for i in range(20): for (i = 0; i < 20; i++) if i%3 == 0: { print i if (i%3 == 0) { if i%5 == 0: printf("%dn", i); print "Bingo!" if (i%5 == 0) { print "---" printf("Bingo!n"); } } printf("---n"); } 11/12/1999 © 1999 CNRI, Guido van Rossum 0 Bingo! ------3 ------6 ------9 ------12 ------15 Bingo! ------18 ----- 20

Functions, procedures def name(arg 1, arg 2, . . . ): "documentation" # optional statements return # from procedure return expression # from function 11/12/1999 © 1999 CNRI, Guido van Rossum 21

Example function def gcd(a, b): "greatest common divisor" while a != 0: a, b = b%a, a # parallel assignment return b >>> gcd. __doc__ 'greatest common divisor' >>> gcd(12, 20) 4 11/12/1999 © 1999 CNRI, Guido van Rossum 22

Classes class name: "documentation" statements -orclass name(baseclass 1, baseclass 2, . . . ): . . . Typically, statements contains method definitions: def name(self, arg 1, arg 2, . . . ): . . . May also contain class variable assignments 11/12/1999 © 1999 CNRI, Guido van Rossum 23

Example class Stack: "A well-known data structure…" def __init__(self): # constructor self. items = [] def push(self, x): self. items. append(x) # the sky is the limit def pop(self): x = self. items[-1] # what happens if it’s empty? del self. items[-1] return x def empty(self): return len(self. items) == 0 11/12/1999 # Boolean result © 1999 CNRI, Guido van Rossum 24

Using classes • To create an instance, simply call the class object: x = Stack() # no 'new' operator! • To use methods of the instance, call using dot notation: x. empty() # -> 1 x. push(1) x. empty() # [1] # -> 0 x. push("hello") x. pop() # [1, "hello"] # -> "hello" # [1] • To inspect instance variables, use dot notation: x. items 11/12/1999 # -> [1] © 1999 CNRI, Guido van Rossum 25

Subclassing class Fancy. Stack(Stack): "stack with added ability to inspect inferior stack items" def peek(self, n): "peek(0) returns top; peek(-1) returns item below that; etc. " size = len(self. items) assert 0 <= n < size # test precondition return self. items[size-1 -n] 11/12/1999 © 1999 CNRI, Guido van Rossum 26

Subclassing (2) class Limited. Stack(Fancy. Stack): "fancy stack with limit on stack size" def __init__(self, limit): self. limit = limit Fancy. Stack. __init__(self) # base class constructor def push(self, x): assert len(self. items) < self. limit Fancy. Stack. push(self, x) 11/12/1999 # "super" method call © 1999 CNRI, Guido van Rossum 27

Class & instance variables class Connection: verbose = 0 # class variable def __init__(self, host): self. host = host # instance variable def debug(self, v): self. verbose = v # make instance variable! def connect(self): if self. verbose: # class or instance variable? print "connecting to", self. host 11/12/1999 © 1999 CNRI, Guido van Rossum 28

Instance variable rules • On use via instance (self. x), search order: – (1) instance, (2) class, (3) base classes – this also works for method lookup • On assigment via instance (self. x =. . . ): – always makes an instance variable • Class variables "default" for instance variables • But. . . ! – mutable class variable: one copy shared by all – mutable instance variable: each instance its own 11/12/1999 © 1999 CNRI, Guido van Rossum 29

Modules • Collection of stuff in foo. py file – functions, classes, variables • Importing modules: – import string; print string. join(L) – from string import join; print join(L) • Rename after import: – import string; s = string; del string 11/12/1999 © 1999 CNRI, Guido van Rossum 30

Packages • Collection of modules in directory • Must have __init__. py file • May contain subpackages • Import syntax: – from P. Q. M import foo; print foo() – from P. Q import M; print M. foo() – import P. Q. M; print P. Q. M. foo() 11/12/1999 © 1999 CNRI, Guido van Rossum 31

Catching exceptions def foo(x): return 1. 0/x def bar(x): try: print foo(x) except Zero. Division. Error, message: print "Can’t divide by zero: ", message bar(0) 11/12/1999 © 1999 CNRI, Guido van Rossum 32

Try-finally: cleanup f = open(file) try: process_file(f) finally: f. close() # always executed print "OK" # executed on success only 11/12/1999 © 1999 CNRI, Guido van Rossum 33

Raising exceptions • raise Index. Error("k out of range") • raise Index. Error, "k out of range" • try: something except: # catch everything print "Oops" raise # reraise 11/12/1999 © 1999 CNRI, Guido van Rossum 34

More on exceptions • User-defined exceptions – subclass Exception or any other standard exception • Old Python: exceptions can be strings – WATCH OUT: compared by object identity, not == • Last caught exception info: – sys. exc_info() == (exc_type, exc_value, exc_traceback) • Last uncaught exception (traceback printed): – sys. last_type, sys. last_value, sys. last_traceback • Printing exceptions: traceback module 11/12/1999 © 1999 CNRI, Guido van Rossum 35
![File objects f openfilename mode buffersize mode can be r w File objects • f = open(filename[, mode[, buffersize]) – mode can be "r", "w",](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-36.jpg)
File objects • f = open(filename[, mode[, buffersize]) – mode can be "r", "w", "a" (like C stdio); default "r" – append "b" for text translation mode – append "+" for read/write open – buffersize: 0=unbuffered; 1=line-buffered; buffered • methods: – read([nbytes]), readline(), readlines() – write(string), writelines(list) – seek(pos[, how]), tell() – fileno(), flush(), close() 11/12/1999 © 1999 CNRI, Guido van Rossum 36

Standard library • Core: – os, sys, string, getopt, String. IO, struct, pickle, . . . • Regular expressions: – re module; Perl-5 style patterns and matching rules • Internet: – socket, rfc 822, httplib, htmllib, ftplib, smtplib, . . . • Miscellaneous: – pdb (debugger), profile+pstats – Tkinter (Tcl/Tk interface), audio, *dbm, . . . 11/12/1999 © 1999 CNRI, Guido van Rossum 37

Python CGI programming 11/12/1999 © 1999 CNRI, Guido van Rossum 38

Outline • HTML forms • Basic CGI usage • Setting up a debugging framework • Security • Handling persistent data • Locking • Sessions • Cookies • File upload • Generating HTML • Performance 11/12/1999 © 1999 CNRI, Guido van Rossum 39

A typical HTML form <form method="POST" action="http: //host. com/cgi-bin/test. py"> <p>Your first name: <input type="text" name="firstname"> <p>Your last name: <input type="text" name="lastname"> <p>Click here to submit form: <input type="submit" value="Yeah!"> <input type="hidden" name="session" value="1 f 9 a 2"> </form> 11/12/1999 © 1999 CNRI, Guido van Rossum 40

A typical CGI script #!/usr/local/bin/python import cgi def main(): print "Content-type: text/htmln" form = cgi. Field. Storage() # parse query if form. has_key("firstname") and form["firstname"]. value != "": print "<h 1>Hello", form["firstname"]. value, "</h 1>" else: print "<h 1>Error! Please enter first name. </h 1>" main() 11/12/1999 © 1999 CNRI, Guido van Rossum 41

CGI script structure • Check form fields – use cgi. Field. Storage class to parse query • takes care of decoding, handles GET and POST • "foo=ab+cd%21 ef&bar=spam" --> {'foo': 'ab cd!ef', 'bar': 'spam'} # (well, actually, . . . ) • Perform action – this is up to you! – database interfaces available • Generate HTTP + HTML output – print statements are simplest – template solutions available 11/12/1999 © 1999 CNRI, Guido van Rossum 42

Structure refinement form = cgi. Field. Storage() if not form: . . . display blank form. . . elif. . . valid form. . . : . . . perform action, display results (or next form). . . else: . . . display error message (maybe repeating form). . . 11/12/1999 © 1999 CNRI, Guido van Rossum 43

Field. Storage details • Behaves like a dictionary: –. keys(), . has_key() # but not others! – dictionary-like object ("mapping") • Items – values are Mini. Field. Storage instances • . value gives field value! – if multiple values: list of Mini. Field. Storage instances • if type(. . . ) == types. List. Type: . . . – may also be Field. Storage instances • used for file upload (test. file attribute) 11/12/1999 © 1999 CNRI, Guido van Rossum 44

Other CGI niceties • cgi. escape(s) – translate "<", "&", ">" to "< ", "& ", ">" • cgi. parse_qs(string, keep_blank_values=0) – parse query string to dictionary {"foo": ["bar"], . . . } • cgi. parse([file], . . . ) – ditto, takes query string from default locations • urllib. quote(s), urllib. unquote(s) – convert between "~" and "%7 e" (etc. ) • urllib. urlencode(dict) – convert dictionary {"foo": "bar", . . . } to query string "foo=bar&. . . " # note asymmetry with parse_qs() above 11/12/1999 © 1999 CNRI, Guido van Rossum 45

Dealing with bugs • Things go wrong, you get a traceback. . . • By default, tracebacks usually go to the server's error_log file. . . • Printing a traceback to stdout is tricky – could happen before "Content-type" is printed – could happen in the middle of HTML markup – could contain markup itself • What's needed is a. . . 11/12/1999 © 1999 CNRI, Guido van Rossum 46

Debugging framework import cgi def main(): print "Content-type: text/htmln" # Do this first try: import worker # module that does the real work except: print "<!-- --><hr><h 1>Oops. An error occurred. </h 1>" cgi. print_exception() # Prints traceback, safely main() 11/12/1999 © 1999 CNRI, Guido van Rossum 47

Security notes • Watch out when passing fields to the shell – e. g. os. popen("finger %s" % form["user"]. value) – what if the value is "; cat /etc/passwd". . . • Solutions: – Quote: • user = pipes. quote(form["user"]. value) – Refuse: • if not re. match(r"^w+$", user): . . . error. . . – Sanitize: • user = re. sub(r"W", "", form["user"]. value) 11/12/1999 © 1999 CNRI, Guido van Rossum 48

Using persistent data • Store/update data: – In plain files (simplest) • FAQ wizard uses this – In a (g)dbm file (better performance) • string keys, string values – In a "shelf" (stores objects) • avoids parsing/unparsing the values – In a real database (if you must) • 3 rd party database extensions available • not my field of expertise 11/12/1999 © 1999 CNRI, Guido van Rossum 49

Plain files key =. . . username, or session key, or whatever. . . try: f = open(key, "r") data = f. read() # read previous data f. close() except IOError: data = "" # no file yet: provide initial data = update(data, form) # do whatever must be done f = open(key, "w") f. write(data) # write new data f. close() # (could delete the file instead if updated data is empty) 11/12/1999 © 1999 CNRI, Guido van Rossum 50

(G)DBM files # better performance if there are many records import gdbm key =. . . username, or session key, or whatever. . . db = gdbm. open("DATABASE", "w") # open for reading+writing if db. has_key(key): data = db[key] # read previous data else: data = "" # provide initial data = update(data, form) db[key] = data # write new data db. close() 11/12/1999 © 1999 CNRI, Guido van Rossum 51

Shelves # a shelf is a (g)dbm files that stores pickled Python objects import shelve class User. Data: . . . key =. . . username, or session key, or whatever. . . db = shelve. open("DATABASE", "w") # open for reading+writing if db. has_key(key): data = db[key] # an object! else: data = User. Data(key) # create a new instance data. update(form) db[key] = data db. close() 11/12/1999 © 1999 CNRI, Guido van Rossum 52

Locking • (G)DBM files and shelves are not protected against concurrent updates! • Multiple readers, single writer usually OK – simplest approach: only lock when writing • Good filesystem-based locking is hard – no cross-platform solutions – unpleasant facts of life: • processes sometimes die without unlocking • processes sometimes take longer than expected • NFS semantics 11/12/1999 © 1999 CNRI, Guido van Rossum 53

A simple lock solution import os, time def unlock(self): assert self. locked class Lock: self. locked = 0 os. rmdir(self. filename) def __init__(self, filename): self. filename = filename # auto-unlock when lock object is deleted self. locked = 0 def __del__(self): if self. locked: def lock(self): self. unlock() assert not self. locked while 1: try: # for a big production with timeouts, os. mkdir(self. filename) # see the Mailman source code (Lock. File. py); self. locked = 1 # it works on all Unixes and supports NFS; return # but not on Windows, # or break except os. error, err: # and the code is very complex. . . time. sleep(1) 11/12/1999 © 1999 CNRI, Guido van Rossum 54

Sessions • How to correlate requests from same user? – Assign session key on first contact – Incorporate session key in form or in URL – In form: use hidden input field: • <input type="hidden" name="session" value="1 f 9 a 2"> – In URL: • http: //myhost. com/cgi-bin/myprog. py/1 f 9 a 2 • passed in environment (os. environ[. . . ]): – PATH_INFO=/1 f 9 a 2 – PATH_TRANSLATED=<rootdir>/1 f 9 a 2 11/12/1999 © 1999 CNRI, Guido van Rossum 55

Cookies • How to correlate sessions from the same user? – Store "cookie" in browser • controversial, but useful – Module: Cookie. py (Tim O'Malley) • writes "Set-Cookie" headers • parses HTTP_COOKIE environment variable – Note: using cookies affects our debug framework • cookies must be printed as part of HTTP headers • cheapest solution: – move printing of blank line into worker module – (and into exception handler of debug framework) 11/12/1999 © 1999 CNRI, Guido van Rossum 56
![Cookie example import os cgi Cookie cuser user c Cookie print c Cookie example import os, cgi, Cookie c["user"] = user c = Cookie() print c](https://slidetodoc.com/presentation_image_h2/15fb3a0b2f250de07116930bce17deb1/image-57.jpg)
Cookie example import os, cgi, Cookie c["user"] = user c = Cookie() print c try: c. load(os. environ["HTTP_COOKIE"]) except Key. Error: pass form = cgi. Field. Storage() try: user = form["user"]. value except Key. Error: try: user = c["user"]. value except Key. Error: user = "nobody" 11/12/1999 print """ <form action="/cgi-bin/test. py" method="get"> <input type="text" name="user" value="%s"> </form> """ % cgi. escape(user) # debug: show the cookie header we wrote print "<pre>" print cgi. escape(str(c)) print "</pre>" © 1999 CNRI, Guido van Rossum 57

File upload example import cgi form = cgi. Field. Storage() if not form: print """ <form action="/cgi-bin/test. py" method="POST" enctype="multipart/form-data"> <input type="file" name="filename"> <input type="submit"> </form> """ elif form. has_key("filename"): item = form["filename"] if item. file: data = item. file. read() # read contents of file print cgi. escape(data) # rather dumb action 11/12/1999 © 1999 CNRI, Guido van Rossum 58

Generating HTML • HTMLgen (Robin Friedrich) http: //starship. python. net/crew/friedrich/HTMLgen/html/main. html >>> print H(1, "Chapter One") <H 1>Chapter One</H 1> >>> print A("http: //www. python. org/", "Home page") <A HREF="http: //www. python. org/">Home page</A> >>> # etc. (tables, forms, the works) • HTMLcreate (Laurence Tratt) http: //www. spods. dcs. kcl. ac. uk/~laurie/comp/python/htmlcreate/ • not accessible at this time 11/12/1999 © 1999 CNRI, Guido van Rossum 59

CGI performance • What causes slow response? – One process per CGI invocation • process creation (fork+exec) • Python interpreter startup time • importing library modules (somewhat fixable) – Connecting to a database! • this can be the killer if you use a real database – Your code? • probably not the bottleneck! 11/12/1999 © 1999 CNRI, Guido van Rossum 60

Avoiding fork() • Python in Apache (mod_pyapache) • problems: stability; internal design • advantage: CGI compatible • may work if CGI scripts are simple and trusted • doesn't avoid database connection delay • Use Python as webserver • slow for static content (use different port) • advantage: total control; session state is easy • Fast. CGI, HTTPDAPI etc. • ZOPE 11/12/1999 © 1999 CNRI, Guido van Rossum 61

ZOPE • Z Object Publishing Environment – http: //www. zope. org – complete dynamic website management tool • written in cross-platform Python; Open Source – http: //host/path/to/object? size=5&type=spam • calls path. to. object(size=5, type="spam") – DTML: templatized HTML (embedded Python code) – ZOBD (Z Object Data. Base; stores Python objects) • transactionsm selective undo, etc. – etc. , etc. 11/12/1999 © 1999 CNRI, Guido van Rossum 62

Case study 11/12/1999 © 1999 CNRI, Guido van Rossum 63

FAQ wizard • Tools/faqwiz. py in Python distribution • http: //www. python. org /cgi-bin/faqw. py 11/12/1999 © 1999 CNRI, Guido van Rossum 64

faqw. py - bootstrap import os, sys try: FAQDIR = "/usr/people/guido/python/FAQ" SRCDIR = "/usr/people/guido/python/src/Tools/faqwiz" os. chdir(FAQDIR) sys. path. insert(0, SRCDIR) import faqwiz except System. Exit, n: sys. exit(n) except: t, v, tb = sys. exc_type, sys. exc_value, sys. exc_traceback print import cgi. print_exception(t, v, tb) 11/12/1999 © 1999 CNRI, Guido van Rossum 65

faqwiz. py - main code class Faq. Wizard: def go(self): print 'Content-type: text/html' def __init__(self): req = self. ui. req or 'home' self. ui = User. Input() mname = 'do_%s' % req self. dir = Faq. Dir() try: meth = getattr(self, mname) def do_home(self): self. prologue(T_HOME) emit(HOME) except Attribute. Error: self. error("Bad request type %s. " % `req`) else: try: def do_search(self): . . . def do_index(self): . . . def do_roulette(self): . . . def do_show(self): . . . def do_edit(self): . . . def do_review(self): . . . def do_help(self): . . . meth() except Invalid. File, exc: self. error("Invalid entry file name %s" % exc. file) except No. Such. File, exc: self. error("No entry with file name %s" % exc. file) except No. Such. Section, exc: self. error("No section number %s" % exc. section) . . . etc. . . self. epilogue() 11/12/1999 © 1999 CNRI, Guido van Rossum 66

Example: do_roulette() def do_roulette(self): import random files = self. dir. list() if not files: self. error("No entries. ") return file = random. choice(files) self. prologue(T_ROULETTE) emit(ROULETTE) self. dir. show(file) 11/12/1999 © 1999 CNRI, Guido van Rossum 67

Persistency • All data stored in files (faq. NN. MMM. htp) • Backed up by RCS files (RCS/faq. NN. MMM. htp, v) – RCS logs and diffs viewable • RCS commands invoked with os. system() or os. popen() • search implemented by opening and reading each file • NO LOCKING! – infrequent updates expected • in practice, one person makes most updates : -) – one historic case of two users adding an entry to the same section at the same time; one got an error back – not generally recommended 11/12/1999 © 1999 CNRI, Guido van Rossum 68

faqconf. py, faqcust. py • faqconf. py defines named string constants for every bit of output generated by faqwiz. py – designed for customization (e. g. i 18 n) – so you can customize your own faq wizard – e. g. OWNEREMAIL = "guido@python. org" – this includes the list of sections in your faq : -( • faqcust. py defines overrides for faqconf. py – so you don't need to edit faqwiz. py • to make it easier to upgrade to newer faqwiz version 11/12/1999 © 1999 CNRI, Guido van Rossum 69

Webchecker • Tools/webchecker. py in Python distribution • Not a CGI application but a web client application – while still pages to do: • request page via http • parse html, collecting links – pages once requested won't be requested again – links outside original tree treated as leaves • existence checked but links not followed – reports on bad links • what the bad URL is • on which page(s) it is referenced – could extend for other reporting 11/12/1999 © 1999 CNRI, Guido van Rossum 70

Reference URLs • Python websites – http: //www. python. org (official site) – http: //starship. python. net (community) • Python web programming topic guide – http: //www. python. org/topics/web/ • These slides on the web (soon) – http: //www. python. org/doc/essays/ppt/sd 99 east. ppt 11/12/1999 © 1999 CNRI, Guido van Rossum 71

Reference books • http: //www. python. org/psa/bookstore/ • 1996 – Programming Python (Lutz) – [Internet Programming with Python (Watters e. a. )] • 1998 – Python Pocket Reference (Lutz) • 1999 – Learning Python (Lutz, Ascher) – Python: Essential Reference (Beazley) – Quick Python Book (Harms, Mc. Donald) • Expected 1999/2000 – Win 32, Tkinter, teach-yourself-in-24 -hrs, annotated archives, . . . 11/12/1999 © 1999 CNRI, Guido van Rossum 72

Any questions? 11/12/1999 © 1999 CNRI, Guido van Rossum 73

Nobody expects the Spanish Inquisition! 11/12/1999 © 1999 CNRI, Guido van Rossum 74