Top Banner
11/12/1999 © 1999 CNRI, Guido van Rossum 1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston, Virginia, USA) [email protected] www.python.org
74

11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

Mar 27, 2015

Download

Documents

Trinity Kearney
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 1

Using Python for CGI programming

Guido van RossumCNRI

(Corporation for National Research Initiatives, Reston, Virginia, USA)

[email protected]

Page 2: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 2

Overview

• 1 minute advocacy

• 30 minutes basic Python tutorial

• 30 minutes on Python CGI programming

• 30 minutes CGI case study: FAQ wizard

• Spanish Inquisition

Page 3: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 3

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)

Page 4: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 4

Basic Python tutorial

Page 5: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 5

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

Page 6: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 6

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

Page 7: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 7

Numbers

• The usual suspects• 12, 3.14, 0xFF, 0377, (-1+2)*3/4**5, abs(x), 0<x<=5

• C-style shifting & masking• 1<<16, x&0xff, x|1, ~x, x^y

• Integer division truncates :-(• 1/2 -> 0 # float(1)/2 -> 0.5

• Long (arbitrary precision), complex• 2L**100 -> 1267650600228229401496703205376L

• 1j**2 -> (-1+0j)

Page 8: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 8

Strings

• "hello"+"world" "helloworld" # concatenation

• "hello"*3 "hellohellohello" # 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 # search

• "escapes: \n etc, \033 etc, \xff etc"

• 'single quotes' '''triple quotes''' r"raw strings"

Page 9: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 9

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] # -> [98, "bottles", "of", "beer"]

Page 10: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 10

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]

Page 11: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 11

Dictionaries

• Hash tables, "associative arrays"• d = {"duck": "eend", "water": "water"}

• Lookup:• d["duck"] -> "eend"

• d["back"] # raises KeyError 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"}

Page 12: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 12

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"]}

Page 13: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 13

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

Page 14: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 14

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

Page 15: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 15

Variables

• No need to declare

• Need to assign (initialize)• use of uninitialized variable raises exception

• Not typedif friendly: greeting = "hello world"

else: greeting = 12**2

print greeting

• Everything is a variable:• functions, modules, classes

Page 16: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 16

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]

Page 17: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 17

a

1 2 3

b

a

1 2 3

b

4

a = [1, 2, 3]

a.append(4)

b = a

a 1 2 3

Changing a shared list

Page 18: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 18

a

1

b

a

1b

a = 1

a = a+1

b = a

a 1

2

Changing an integer

old reference deletedby assignment (a=...)

new int object createdby add operator (1+1)

Page 19: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 19

Control structures

if condition:

statements

[elif condition:

statements] ...

else:

statements

while condition:

statements

for var in sequence:

statements

break

continue

Page 20: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 20

Grouping indentation

In Python:

for i in range(20):

if i%3 == 0:

print i

if i%5 == 0:

print "Bingo!"

print "---"

In C:

for (i = 0; i < 20; i++)

{

if (i%3 == 0) {

printf("%d\n", i);

if (i%5 == 0) {

printf("Bingo!\n"); }

}

printf("---\n");

}

0Bingo!---------3---------6---------9---------12---------15Bingo!---------18------

Page 21: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 21

Functions, procedures

def name(arg1, arg2, ...):

"documentation" # optional

statements

return # from procedure

return expression # from function

Page 22: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 22

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

Page 23: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 23

Classes

class name:

"documentation"

statements

-or-

class name(baseclass1, baseclass2, ...):

...

Typically, statements contains method definitions:

def name(self, arg1, arg2, ...):

...

May also contain class variable assignments

Page 24: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 24

Example class

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 # Boolean result

Page 25: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 25

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) # [1]

x.empty() # -> 0

x.push("hello") # [1, "hello"]

x.pop() # -> "hello" # [1]

• To inspect instance variables, use dot notation:x.items # -> [1]

Page 26: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 26

Subclassing

class FancyStack(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]

Page 27: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 27

Subclassing (2)

class LimitedStack(FancyStack):

"fancy stack with limit on stack size"

def __init__(self, limit):

self.limit = limit

FancyStack.__init__(self) # base class constructor

def push(self, x):

assert len(self.items) < self.limit

FancyStack.push(self, x) # "super" method call

Page 28: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 28

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

Page 29: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 29

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

Page 30: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 30

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

Page 31: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 31

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()

Page 32: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 32

Catching exceptions

def foo(x):

return 1.0/x

def bar(x):

try:

print foo(x)

except ZeroDivisionError, message:

print "Can’t divide by zero:", message

bar(0)

Page 33: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 33

Try-finally: cleanup

f = open(file)

try:

process_file(f)

finally:

f.close() # always executed

print "OK" # executed on success only

Page 34: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 34

Raising exceptions

• raise IndexError

• raise IndexError("k out of range")

• raise IndexError, "k out of range"

• try: somethingexcept: # catch everything print "Oops" raise # reraise

Page 35: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 35

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

Page 36: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 36

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()

Page 37: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 37

Standard library

• Core:– os, sys, string, getopt, StringIO, struct, pickle, ...

• Regular expressions:– re module; Perl-5 style patterns and matching rules

• Internet:– socket, rfc822, httplib, htmllib, ftplib, smtplib, ...

• Miscellaneous:– pdb (debugger), profile+pstats

– Tkinter (Tcl/Tk interface), audio, *dbm, ...

Page 38: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 38

Python CGI programming

Page 39: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 39

Outline

• HTML forms

• Basic CGI usage

• Setting up a debugging framework

• Security

• Handling persistent data

• Locking

• Sessions

• Cookies

• File upload

• Generating HTML

• Performance

Page 40: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 40

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="1f9a2">

</form>

Page 41: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 41

A typical CGI script

#!/usr/local/bin/python

import cgi

def main():

print "Content-type: text/html\n"

form = cgi.FieldStorage() # parse query

if form.has_key("firstname") and form["firstname"].value != "":

print "<h1>Hello", form["firstname"].value, "</h1>"

else:

print "<h1>Error! Please enter first name.</h1>"

main()

Page 42: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 42

CGI script structure

• Check form fields– use cgi.FieldStorage class to parse query

• takes care of decoding, handles GET and POST

• "foo=ab+cd%21ef&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

Page 43: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 43

Structure refinement

form = cgi.FieldStorage()

if not form:

...display blank form...

elif ...valid form...:

...perform action, display results (or next form)...

else:

...display error message (maybe repeating form)...

Page 44: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 44

FieldStorage details

• Behaves like a dictionary:– .keys(), .has_key() # but not others!

– dictionary-like object ("mapping")

• Items– values are MiniFieldStorage instances

• .value gives field value!

– if multiple values: list of MiniFieldStorage instances• if type(...) == types.ListType: ...

– may also be FieldStorage instances• used for file upload (test .file attribute)

Page 45: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 45

Other CGI niceties

• cgi.escape(s)– translate "<", "&", ">" to "&lt;", "&amp;", "&gt"

• 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 "%7e" (etc.)

• urllib.urlencode(dict)– convert dictionary {"foo": "bar", ...} to query string

"foo=bar&..." # note asymmetry with parse_qs() above

Page 46: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 46

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...

Page 47: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 47

Debugging framework

import cgi

def main():

print "Content-type: text/html\n" # Do this first

try:

import worker # module that does the real work

except:

print "<!-- --><hr><h1>Oops. An error occurred.</h1>"

cgi.print_exception() # Prints traceback, safely

main()

Page 48: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 48

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)

Page 49: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 49

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)• 3rd party database extensions available

• not my field of expertise

Page 50: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 50

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

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)

Page 51: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 51

(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

data = update(data, form)

db[key] = data # write new data

db.close()

Page 52: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 52

Shelves

# a shelf is a (g)dbm files that stores pickled Python objects

import shelve

class UserData: ...

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 = UserData(key) # create a new instance

data.update(form)

db[key] = data

db.close()

Page 53: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 53

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

Page 54: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 54

A simple lock solutionimport os, time

class Lock:

def __init__(self, filename):

self.filename = filename

self.locked = 0

def lock(self):

assert not self.locked

while 1:

try:

os.mkdir(self.filename)

self.locked = 1

return # or break

except os.error, err:

time.sleep(1)

def unlock(self):

assert self.locked

self.locked = 0

os.rmdir(self.filename)

# auto-unlock when lock object is deleted

def __del__(self):

if self.locked:

self.unlock()

# for a big production with timeouts,

# see the Mailman source code (LockFile.py);

# it works on all Unixes and supports NFS;

# but not on Windows,

# and the code is very complex...

Page 55: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 55

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="1f9a2">

– In URL:• http://myhost.com/cgi-bin/myprog.py/1f9a2

• passed in environment (os.environ[...]):– PATH_INFO=/1f9a2

– PATH_TRANSLATED=<rootdir>/1f9a2

Page 56: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 56

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)

Page 57: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 57

Cookie exampleimport os, cgi, Cookie

c = Cookie.Cookie()

try:

c.load(os.environ["HTTP_COOKIE"])

except KeyError:

pass

form = cgi.FieldStorage()

try:

user = form["user"].value

except KeyError:

try:

user = c["user"].value

except KeyError:

user = "nobody"

c["user"] = user

print c

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>"

Page 58: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 58

File upload example

import cgi

form = cgi.FieldStorage()

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

Page 59: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 59

Generating HTML

• HTMLgen (Robin Friedrich)http://starship.python.net/crew/friedrich/HTMLgen/html/main.html

>>> print H(1, "Chapter One")

<H1>Chapter One</H1>

>>> 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

Page 60: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 60

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!

Page 61: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 61

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

• FastCGI, HTTPDAPI etc.

• ZOPE

Page 62: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 62

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 DataBase; stores Python objects)• transactionsm selective undo, etc.

– etc., etc.

Page 63: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

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

Case study

Page 64: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 64

FAQ wizard

• Tools/faqwiz/faqwiz.py in Python distribution

• http://www.python.org/cgi-bin/faqw.py

Page 65: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 65

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 SystemExit, n:

sys.exit(n)

except:

t, v, tb = sys.exc_type, sys.exc_value, sys.exc_traceback

print

import cgi

cgi.print_exception(t, v, tb)

Page 66: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 66

faqwiz.py - main codeclass FaqWizard:

def __init__(self):

self.ui = UserInput()

self.dir = FaqDir()

def do_home(self):

self.prologue(T_HOME)

emit(HOME)

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): ...

...etc...

def go(self):

print 'Content-type: text/html'

req = self.ui.req or 'home'

mname = 'do_%s' % req

try:

meth = getattr(self, mname)

except AttributeError:

self.error("Bad request type %s." % `req`)

else:

try:

meth()

except InvalidFile, exc:

self.error("Invalid entry file name %s" % exc.file)

except NoSuchFile, exc:

self.error("No entry with file name %s" % exc.file)

except NoSuchSection, exc:

self.error("No section number %s" % exc.section)

self.epilogue()

Page 67: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 67

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)

Page 68: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 68

Persistency

• All data stored in files (faqNN.MMM.htp)

• Backed up by RCS files (RCS/faqNN.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

Page 69: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 69

faqconf.py, faqcust.py

• faqconf.py defines named string constants for every bit of output generated by faqwiz.py– designed for customization (e.g. i18n)

– so you can customize your own faq wizard

– e.g. OWNEREMAIL = "[email protected]"

– 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

Page 70: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 70

Webchecker

• Tools/webchecker/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

Page 71: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 71

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/sd99east.ppt

Page 72: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 72

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, McDonald)

• Expected 1999/2000– Win 32, Tkinter, teach-yourself-in-24-hrs, annotated archives, ...

Page 73: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 73

Any questions?

Page 74: 11/12/1999© 1999 CNRI, Guido van Rossum1 Using Python for CGI programming Guido van Rossum CNRI (Corporation for National Research Initiatives, Reston,

11/12/1999 © 1999 CNRI, Guido van Rossum 74

Nobody expects theSpanish Inquisition!