Request » History » Version 5
Elmer de Looff, 2012-04-27 12:18
POST explained, still needs 'arrays' and file upload
1 | 1 | Jan Klopper | h1. Request |
---|---|---|---|
2 | 1 | Jan Klopper | |
3 | 5 | Elmer de Looff | {{>toc}} |
4 | 5 | Elmer de Looff | |
5 | 3 | Elmer de Looff | The @Request@ object is an abstraction of the incoming HTTP request. This allows one simple interface that is independent of the underlying server that µWeb runs on (either [[Standalone]] using BaseHTTPServer, or [[Apache]] mode on @mod_python@). |
6 | 1 | Jan Klopper | |
7 | 4 | Elmer de Looff | From PageMaker methods, the request object is accessible as the @self.req@ member. The request object contains all the information about the incoming request: query arguments, post data, cookies and environment data. It is also the object where you define cookies that need to be provided to the client. |
8 | 1 | Jan Klopper | |
9 | 4 | Elmer de Looff | h1. Query arguments |
10 | 4 | Elmer de Looff | |
11 | 4 | Elmer de Looff | All query arguments provided by the client are present on the request object. They are also accessible directly on the [[PageMaker]] object. The following code demonstrates both ways to access a query argument: |
12 | 4 | Elmer de Looff | |
13 | 5 | Elmer de Looff | <pre><code class="html"> |
14 | 5 | Elmer de Looff | ... |
15 | 5 | Elmer de Looff | <form> |
16 | 5 | Elmer de Looff | <label for="name">Name: </label><input id="name" name="name" /> |
17 | 5 | Elmer de Looff | <input type="submit" value="Tell us your name" /> |
18 | 5 | Elmer de Looff | </form> |
19 | 5 | Elmer de Looff | ... |
20 | 5 | Elmer de Looff | </code></pre> |
21 | 5 | Elmer de Looff | |
22 | 1 | Jan Klopper | <pre><code class="python"> |
23 | 5 | Elmer de Looff | def NameFromQuery(self): |
24 | 4 | Elmer de Looff | # Retrieves the 'name' argument from the request object: |
25 | 4 | Elmer de Looff | name = self.req.vars['get'].getfirst('name') |
26 | 4 | Elmer de Looff | |
27 | 4 | Elmer de Looff | # Retrieves the 'name' argument directly from the PageMaker instance (linked to the request): |
28 | 4 | Elmer de Looff | name = self.get.getfirst('name') |
29 | 4 | Elmer de Looff | return name |
30 | 4 | Elmer de Looff | </code></pre> |
31 | 4 | Elmer de Looff | |
32 | 4 | Elmer de Looff | Using the @getfirst@ method, you get a single string returned from the query argument mapping, or a @None@ if no such value exists. Much like a dictionary's @get@ method, you can provide a second argument to the method, and have that returned instead as the default. |
33 | 4 | Elmer de Looff | |
34 | 1 | Jan Klopper | Now, HTTP allows the client to provide the same query argument multiple times. Using @getfirst@ you would only get the very first defined argument. So a request that looks like @http://example.org/group?name=Bob&name=Mark&name=Jenny@ would only return 'Bob' in the previous example. To get all their names printed, you can use the following: |
35 | 1 | Jan Klopper | |
36 | 5 | Elmer de Looff | <pre><code class="html"> |
37 | 5 | Elmer de Looff | ... |
38 | 5 | Elmer de Looff | <form action="/group"> |
39 | 5 | Elmer de Looff | <h2>Names in this group</h2> |
40 | 5 | Elmer de Looff | <!-- These would likely be generated with Javascript, but written here for demonstrative purposes --> |
41 | 5 | Elmer de Looff | <label for="name_1">Name: </label><input id="name_1" name="name" /> |
42 | 5 | Elmer de Looff | <label for="name_2">Name: </label><input id="name_2" name="name" /> |
43 | 5 | Elmer de Looff | <label for="name_3">Name: </label><input id="name_3" name="name" /> |
44 | 5 | Elmer de Looff | <input type="submit" value="Send these names" /> |
45 | 5 | Elmer de Looff | </form> |
46 | 5 | Elmer de Looff | ... |
47 | 5 | Elmer de Looff | </code></pre> |
48 | 5 | Elmer de Looff | |
49 | 1 | Jan Klopper | <pre><code class="python"> |
50 | 5 | Elmer de Looff | def MemberNames(self): |
51 | 1 | Jan Klopper | names = self.get.getlist('name') |
52 | 1 | Jan Klopper | return ', '.join(names) |
53 | 1 | Jan Klopper | </code></pre> |
54 | 1 | Jan Klopper | |
55 | 1 | Jan Klopper | This returns a neat comma-separated string with all the provided names. The @getlist@ method does not take a default, but will instead return an empty list when there are no values for the requested argument name. |
56 | 1 | Jan Klopper | |
57 | 5 | Elmer de Looff | h1. Post data |
58 | 1 | Jan Klopper | |
59 | 5 | Elmer de Looff | Submitted form data is available on the request object as well. The interface is similar to that of the query arguments, and the @FieldStorage@ class already present in the @cgi@ module. If we take our initial example form handler, but now receive the data through HTTP POST, the code would look like this: |
60 | 1 | Jan Klopper | |
61 | 5 | Elmer de Looff | <pre><code class="html"> |
62 | 5 | Elmer de Looff | ... |
63 | 5 | Elmer de Looff | <form method="post"> |
64 | 5 | Elmer de Looff | <label for="name">Name: </label><input id="name" name="name" /> |
65 | 5 | Elmer de Looff | <input type="submit" value="Tell us your name" /> |
66 | 5 | Elmer de Looff | </form> |
67 | 5 | Elmer de Looff | ... |
68 | 5 | Elmer de Looff | </code></pre> |
69 | 1 | Jan Klopper | |
70 | 5 | Elmer de Looff | <pre><code class="python"> |
71 | 5 | Elmer de Looff | def NameFromPost(self): |
72 | 5 | Elmer de Looff | # Retrieves the 'name' value from the request object: |
73 | 5 | Elmer de Looff | name = self.req.vars['post'].getfirst('name') |
74 | 1 | Jan Klopper | |
75 | 5 | Elmer de Looff | # Retrieves the 'name' value directly from the PageMaker instance (linked to the request): |
76 | 5 | Elmer de Looff | name = self.post.getfirst('name') |
77 | 5 | Elmer de Looff | return name |
78 | 5 | Elmer de Looff | </code></pre> |
79 | 1 | Jan Klopper | |
80 | 5 | Elmer de Looff | Like with the query arguments, @getfirst@ accepts a second argument that provides a default other than @None@. |
81 | 1 | Jan Klopper | |
82 | 5 | Elmer de Looff | Multiple values are again possible in the FieldStorage, but these work exactly like they do in the query arguments, so please have a look at those. |
83 | 2 | Elmer de Looff | |
84 | 5 | Elmer de Looff | h2. Uploading files |
85 | 1 | Jan Klopper | |
86 | 5 | Elmer de Looff | h2. Structured data using POST |
87 | 5 | Elmer de Looff | |
88 | 5 | Elmer de Looff | h1. Cookies |
89 | 5 | Elmer de Looff | |
90 | 1 | Jan Klopper | self.cookies contains the cookies send by the browser, as the interface to create them from the server. |
91 | 1 | Jan Klopper | |
92 | 1 | Jan Klopper | h3. Retrieving a cookie |
93 | 1 | Jan Klopper | You can fetch the content of cookie by accessig the self.cookie dict with the name of the desired cookie as its key. |
94 | 1 | Jan Klopper | The returned cookie object has a value member containing the actual value of the requested cookie. |
95 | 1 | Jan Klopper | <pre> |
96 | 1 | Jan Klopper | <code class="python"> |
97 | 1 | Jan Klopper | self.cookies['sample'].value |
98 | 1 | Jan Klopper | </code> |
99 | 1 | Jan Klopper | </pre> |
100 | 1 | Jan Klopper | |
101 | 5 | Elmer de Looff | h1. Environment |
102 | 1 | Jan Klopper | |
103 | 1 | Jan Klopper | The env variable is a dictionary containing the following items; |
104 | 1 | Jan Klopper | * CONTENT_TYPE |
105 | 1 | Jan Klopper | * CONTENT_LENGTH |
106 | 1 | Jan Klopper | * HTTP_COOKIE |
107 | 1 | Jan Klopper | * HTTP_HOST |
108 | 1 | Jan Klopper | * HTTP_REFERER |
109 | 1 | Jan Klopper | * HTTP_USER_AGENT |
110 | 1 | Jan Klopper | * PATH_INFO |
111 | 1 | Jan Klopper | * QUERY_STRING |
112 | 1 | Jan Klopper | * REMOTE_ADDR |
113 | 1 | Jan Klopper | * REQUEST_METHOD |
114 | 1 | Jan Klopper | * UWEB_MODE 'STANDALONE' / 'MOD_PYTHON' |
115 | 1 | Jan Klopper | |
116 | 5 | Elmer de Looff | h2. Extended environment |
117 | 5 | Elmer de Looff | |
118 | 1 | Jan Klopper | If more detail is required about the environment, you can issue a call to the self.req.ExtendedEnvironment() method, which will inject more details into the env var. This is a much slower operation than the normal env call, so that's why its tucked away in a separate method. |
119 | 1 | Jan Klopper | |
120 | 1 | Jan Klopper | * AUTH_TYPE |
121 | 1 | Jan Klopper | * CONNECTION_ID |
122 | 1 | Jan Klopper | * DOCUMENT_ROOT |
123 | 1 | Jan Klopper | * RAW_REQUEST |
124 | 1 | Jan Klopper | * REMOTE_HOST |
125 | 1 | Jan Klopper | * REMOTE_USER |
126 | 1 | Jan Klopper | * SERVER_NAME |
127 | 1 | Jan Klopper | * SERVER_PORT |
128 | 1 | Jan Klopper | * SERVER_LOCAL_NAME |
129 | 1 | Jan Klopper | * SERVER_LOCAL_IP |
130 | 2 | Elmer de Looff | * SERVER_PROTOCOL |
131 | 1 | Jan Klopper | |
132 | 1 | Jan Klopper | And in case of a @mod_python@ setup you will also get: |
133 | 1 | Jan Klopper | * MODPYTHON_HANDLER |
134 | 1 | Jan Klopper | * MODPYTHON_INTERPRETER |
135 | 1 | Jan Klopper | * MODPYTHON_PHASE |
136 | 5 | Elmer de Looff | |
137 | 5 | Elmer de Looff | h1. Setting cookies |