0
# Static Files and Utilities
1
2
Static file serving, HTTP utilities, and helper functions for common web development tasks including file serving, security utilities, and HTTP helper functions.
3
4
## Capabilities
5
6
### Static File Serving
7
8
Serve static files with proper MIME types, caching headers, and security features.
9
10
```python { .api }
11
def static_file(filename, root, mimetype='auto', download=False, charset='UTF-8'):
12
"""
13
Serve static files with proper MIME types and caching headers.
14
15
Parameters:
16
- filename: str, file name to serve
17
- root: str, root directory path
18
- mimetype: str, MIME type ('auto' for automatic detection)
19
- download: bool, force download with Content-Disposition header
20
- charset: str, character encoding for text files
21
22
Returns:
23
HTTPResponse: file response with proper headers
24
25
Raises:
26
HTTPError: 404 if file not found, 403 if access denied
27
"""
28
```
29
30
Usage:
31
32
```python
33
@route('/static/<filepath:path>')
34
def serve_static(filepath):
35
return static_file(filepath, root='./static/')
36
37
@route('/downloads/<filename>')
38
def download_file(filename):
39
return static_file(filename, root='./downloads/', download=True)
40
41
@route('/css/<filename>')
42
def serve_css(filename):
43
return static_file(filename, root='./assets/css/',
44
mimetype='text/css')
45
46
@route('/images/<filename>')
47
def serve_image(filename):
48
return static_file(filename, root='./assets/images/',
49
mimetype='auto')
50
```
51
52
### HTTP Response Utilities
53
54
Utility functions for common HTTP response patterns.
55
56
```python { .api }
57
def abort(code=500, text='Unknown Error.'):
58
"""
59
Raise HTTPError with specified status code and message.
60
61
Parameters:
62
- code: int, HTTP status code (400, 404, 500, etc.)
63
- text: str, error message
64
65
Raises:
66
HTTPError: HTTP error response
67
"""
68
69
def redirect(url, code=None):
70
"""
71
Raise HTTPResponse that redirects to the specified URL.
72
73
Parameters:
74
- url: str, redirect URL (absolute or relative)
75
- code: int, HTTP redirect status code (302 default, 301 for permanent)
76
77
Raises:
78
HTTPResponse: redirect response
79
"""
80
```
81
82
Usage:
83
84
```python
85
@route('/admin')
86
def admin_panel():
87
if not user_is_admin():
88
abort(403, 'Access denied - admin privileges required')
89
return render_admin_panel()
90
91
@route('/old-url')
92
def old_url():
93
redirect('/new-url', code=301) # Permanent redirect
94
95
@route('/login-check')
96
def login_check():
97
if not logged_in():
98
redirect('/login?return_to=/dashboard')
99
return dashboard()
100
101
@route('/api/not-found')
102
def api_not_found():
103
abort(404, 'API endpoint not found')
104
```
105
106
### Debug Mode
107
108
Enable debug mode for development.
109
110
```python { .api }
111
def debug(mode=True):
112
"""
113
Enable or disable debug mode.
114
115
Parameters:
116
- mode: bool, True to enable debug mode, False to disable
117
"""
118
```
119
120
Usage:
121
122
```python
123
import bottle
124
125
# Enable debug mode
126
bottle.debug(True)
127
128
# Debug mode effects:
129
# - Detailed error pages with tracebacks
130
# - Auto-reload on file changes (with reloader=True)
131
# - Exception propagation for debugging tools
132
```
133
134
### Date and Time Utilities
135
136
HTTP date formatting and parsing functions.
137
138
```python { .api }
139
def http_date(value):
140
"""
141
Format date/time for HTTP headers (RFC 2822 format).
142
143
Parameters:
144
- value: datetime, time tuple, or timestamp
145
146
Returns:
147
str: HTTP-formatted date string
148
"""
149
150
def parse_date(ims):
151
"""
152
Parse HTTP date string to timestamp.
153
154
Parameters:
155
- ims: str, HTTP date string
156
157
Returns:
158
float: timestamp or None if parsing fails
159
"""
160
```
161
162
Usage:
163
164
```python
165
from datetime import datetime
166
import bottle
167
168
@route('/api/timestamp')
169
def api_timestamp():
170
now = datetime.now()
171
bottle.response.set_header('Date', bottle.http_date(now))
172
173
# Handle If-Modified-Since header
174
ims = bottle.request.get_header('If-Modified-Since')
175
if ims:
176
ims_timestamp = bottle.parse_date(ims)
177
if ims_timestamp and ims_timestamp >= now.timestamp():
178
bottle.abort(304) # Not Modified
179
180
return {'timestamp': now.isoformat()}
181
```
182
183
### Authentication Utilities
184
185
HTTP authentication parsing and basic auth decorator.
186
187
```python { .api }
188
def parse_auth(header):
189
"""
190
Parse HTTP Authorization header.
191
192
Parameters:
193
- header: str, Authorization header value
194
195
Returns:
196
tuple: (method, credentials) or None if invalid
197
"""
198
199
def auth_basic(check, realm="private", text="Access denied"):
200
"""
201
HTTP Basic Authentication decorator.
202
203
Parameters:
204
- check: function, authentication check function (username, password) -> bool
205
- realm: str, authentication realm
206
- text: str, access denied message
207
208
Returns:
209
function: authentication decorator
210
"""
211
```
212
213
Usage:
214
215
```python
216
def check_credentials(username, password):
217
return username == 'admin' and password == 'secret'
218
219
@route('/admin')
220
@auth_basic(check_credentials, realm='Admin Area')
221
def admin():
222
return 'Welcome to admin area!'
223
224
@route('/api/auth-info')
225
def auth_info():
226
auth_header = request.get_header('Authorization')
227
if auth_header:
228
method, credentials = parse_auth(auth_header) or (None, None)
229
return {'method': method, 'has_credentials': bool(credentials)}
230
return {'authenticated': False}
231
```
232
233
### Range Request Utilities
234
235
Support for HTTP range requests and partial content.
236
237
```python { .api }
238
def parse_range_header(header, maxlen=0):
239
"""
240
Parse HTTP Range header for partial content requests.
241
242
Parameters:
243
- header: str, Range header value
244
- maxlen: int, maximum content length
245
246
Returns:
247
list: list of (start, end) tuples or empty list if invalid
248
"""
249
```
250
251
Usage:
252
253
```python
254
@route('/video/<filename>')
255
def serve_video(filename):
256
file_path = f'./videos/{filename}'
257
if not os.path.exists(file_path):
258
abort(404)
259
260
range_header = request.get_header('Range')
261
if range_header:
262
ranges = parse_range_header(range_header, os.path.getsize(file_path))
263
if ranges:
264
# Handle range request
265
start, end = ranges[0]
266
response.status = 206 # Partial Content
267
response.set_header('Content-Range', f'bytes {start}-{end}/{os.path.getsize(file_path)}')
268
269
return static_file(filename, root='./videos/')
270
```
271
272
### Security Utilities
273
274
Security-related helper functions for cookies and HTML.
275
276
```python { .api }
277
def cookie_encode(data, key, digestmod=None):
278
"""
279
Encode and sign cookie data.
280
281
Parameters:
282
- data: dict, cookie data to encode
283
- key: str or bytes, signing key
284
- digestmod: hashlib digest module (default: sha256)
285
286
Returns:
287
str: encoded and signed cookie value
288
"""
289
290
def cookie_decode(data, key, digestmod=None):
291
"""
292
Decode and verify signed cookie data.
293
294
Parameters:
295
- data: str, encoded cookie value
296
- key: str or bytes, signing key
297
- digestmod: hashlib digest module (default: sha256)
298
299
Returns:
300
dict: decoded cookie data or None if invalid
301
"""
302
303
def cookie_is_encoded(data):
304
"""
305
Check if cookie data is encoded/signed.
306
307
Parameters:
308
- data: str, cookie value
309
310
Returns:
311
bool: True if cookie appears to be encoded
312
"""
313
314
def html_escape(string):
315
"""
316
Escape HTML entities in string.
317
318
Parameters:
319
- string: str, string to escape
320
321
Returns:
322
str: HTML-escaped string
323
"""
324
325
def html_quote(string):
326
"""
327
Quote string for use in HTML attributes.
328
329
Parameters:
330
- string: str, string to quote
331
332
Returns:
333
str: quoted string safe for HTML attributes
334
"""
335
```
336
337
Usage:
338
339
```python
340
# Secure cookie handling
341
@route('/set-secure-cookie')
342
def set_secure_cookie():
343
data = {'user_id': 123, 'role': 'user'}
344
cookie_value = cookie_encode(data, 'secret-key')
345
response.set_cookie('secure_data', cookie_value)
346
return 'Secure cookie set'
347
348
@route('/get-secure-cookie')
349
def get_secure_cookie():
350
cookie_value = request.get_cookie('secure_data')
351
if cookie_value and cookie_is_encoded(cookie_value):
352
data = cookie_decode(cookie_value, 'secret-key')
353
if data:
354
return f'User ID: {data["user_id"]}, Role: {data["role"]}'
355
return 'No valid secure cookie found'
356
357
# HTML escaping
358
@route('/safe-output/<user_input>')
359
def safe_output(user_input):
360
safe_input = html_escape(user_input)
361
return f'<p>You entered: {safe_input}</p>'
362
363
@route('/safe-attribute/<value>')
364
def safe_attribute(value):
365
safe_value = html_quote(value)
366
return f'<input type="text" value="{safe_value}">'
367
```
368
369
### Path and Route Utilities
370
371
Utilities for path manipulation and route discovery.
372
373
```python { .api }
374
def yieldroutes(func):
375
"""
376
Extract routes from a function that contains route definitions.
377
378
Parameters:
379
- func: function, function containing route decorators
380
381
Yields:
382
Route: route instances defined in the function
383
"""
384
385
def path_shift(script_name, path_info, shift=1):
386
"""
387
Shift path components between SCRIPT_NAME and PATH_INFO.
388
389
Parameters:
390
- script_name: str, current SCRIPT_NAME
391
- path_info: str, current PATH_INFO
392
- shift: int, number of path components to shift
393
394
Returns:
395
tuple: (new_script_name, new_path_info)
396
"""
397
```
398
399
### Data Conversion Utilities
400
401
Helper functions for data type conversion and validation.
402
403
```python { .api }
404
def makelist(data):
405
"""
406
Convert data to list format.
407
408
Parameters:
409
- data: any, data to convert to list
410
411
Returns:
412
list: data as list (wraps single items, preserves existing lists)
413
"""
414
415
def tob(s, enc='utf8'):
416
"""
417
Convert string to bytes.
418
419
Parameters:
420
- s: str, string to convert
421
- enc: str, encoding to use
422
423
Returns:
424
bytes: encoded bytes
425
"""
426
427
def touni(s, enc='utf8', err='strict'):
428
"""
429
Convert to unicode string.
430
431
Parameters:
432
- s: str or bytes, data to convert
433
- enc: str, encoding to use for bytes
434
- err: str, error handling strategy
435
436
Returns:
437
str: unicode string
438
"""
439
```
440
441
Usage:
442
443
```python
444
# Data conversion
445
@route('/api/data')
446
def api_data():
447
# Ensure list format
448
tags = makelist(request.query.get('tags', []))
449
450
# Handle bytes/string conversion
451
raw_data = request.body
452
text_data = touni(raw_data, enc='utf8')
453
454
return {
455
'tags': tags,
456
'data_length': len(text_data),
457
'encoding': 'utf8'
458
}
459
```