0
# WSGI Integration
1
2
WSGI middleware components for integrating PDF generation directly into web applications with automatic HTML-to-PDF conversion, content filtering, and seamless web framework integration.
3
4
## Capabilities
5
6
### WSGI Middleware Architecture
7
8
Complete WSGI middleware system for automatic PDF conversion in web applications with flexible filtering and processing capabilities.
9
10
```python { .api }
11
class Filter:
12
"""
13
Base WSGI filter class for content transformation.
14
15
Provides foundation for WSGI-based content filtering
16
and transformation with pluggable processing pipeline.
17
"""
18
def __init__(self, app):
19
"""
20
Initialize WSGI filter with wrapped application.
21
22
Args:
23
app: WSGI application to wrap
24
"""
25
26
def __call__(self, environ, start_response):
27
"""
28
WSGI application interface for request processing.
29
30
Args:
31
environ (dict): WSGI environment dictionary
32
start_response (callable): WSGI start_response callable
33
34
Returns:
35
Response iterator
36
"""
37
38
def should_filter(self):
39
"""
40
Determine if filtering should be applied to current request.
41
42
Returns:
43
bool: True if request should be filtered
44
"""
45
46
def filter(self):
47
"""
48
Apply filter transformation to response content.
49
50
Processes response content and applies necessary
51
transformations based on filter configuration.
52
"""
53
54
class HTMLFilter(Filter):
55
"""
56
HTML-specific WSGI filter for HTML content processing.
57
58
Extends base Filter with HTML-specific processing
59
capabilities and content type handling.
60
"""
61
62
class PisaMiddleware(HTMLFilter):
63
"""
64
WSGI middleware for automatic HTML-to-PDF conversion.
65
66
Intercepts HTML responses and converts them to PDF format
67
based on request parameters and configuration settings.
68
"""
69
```
70
71
### Automatic PDF Conversion
72
73
Seamless integration that automatically converts HTML responses to PDF based on URL parameters, headers, or content negotiation.
74
75
#### Basic WSGI Integration
76
77
```python
78
from xhtml2pdf.wsgi import PisaMiddleware
79
from your_web_app import app
80
81
# Wrap your WSGI application
82
pdf_enabled_app = PisaMiddleware(app)
83
84
# Use with any WSGI server
85
if __name__ == '__main__':
86
from wsgiref.simple_server import make_server
87
server = make_server('localhost', 8080, pdf_enabled_app)
88
server.serve_forever()
89
```
90
91
#### Framework-Specific Integration
92
93
**Flask Integration:**
94
95
```python
96
from flask import Flask, render_template
97
from xhtml2pdf.wsgi import PisaMiddleware
98
99
app = Flask(__name__)
100
101
@app.route('/report')
102
def generate_report():
103
return render_template('report.html', data=get_report_data())
104
105
# Enable PDF conversion middleware
106
app.wsgi_app = PisaMiddleware(app.wsgi_app)
107
108
# Access as PDF: /report?format=pdf
109
# Or with Accept header: Accept: application/pdf
110
```
111
112
**Django Integration:**
113
114
```python
115
# settings.py
116
MIDDLEWARE = [
117
# ... other middleware
118
'xhtml2pdf.wsgi.PisaMiddleware',
119
]
120
121
# Or in wsgi.py
122
from django.core.wsgi import get_wsgi_application
123
from xhtml2pdf.wsgi import PisaMiddleware
124
125
application = get_wsgi_application()
126
application = PisaMiddleware(application)
127
```
128
129
**Pyramid Integration:**
130
131
```python
132
from pyramid.config import Configurator
133
from xhtml2pdf.wsgi import PisaMiddleware
134
135
def main(global_config, **settings):
136
config = Configurator(settings=settings)
137
138
# Configure routes and views
139
config.add_route('report', '/report')
140
config.scan()
141
142
app = config.make_wsgi_app()
143
return PisaMiddleware(app)
144
```
145
146
### Content Negotiation
147
148
Automatic PDF conversion based on HTTP content negotiation, URL parameters, and custom headers.
149
150
```python
151
# URL parameter-based conversion
152
# GET /invoice/123?format=pdf
153
154
# Accept header-based conversion
155
# Accept: application/pdf
156
157
# Custom header-based conversion
158
# X-PDF-Convert: true
159
160
# File extension-based conversion
161
# GET /report.pdf
162
```
163
164
### Advanced Configuration
165
166
Comprehensive configuration options for PDF conversion behavior, styling, and processing parameters.
167
168
```python
169
class ConfigurablePisaMiddleware(PisaMiddleware):
170
"""
171
Enhanced WSGI middleware with advanced configuration options.
172
"""
173
def __init__(self, app, **config):
174
"""
175
Initialize middleware with configuration options.
176
177
Args:
178
app: WSGI application to wrap
179
**config: Configuration options:
180
- pdf_triggers: List of trigger conditions
181
- default_css: Default CSS for PDF conversion
182
- base_path: Base path for resource resolution
183
- debug: Debug level for PDF processing
184
- link_callback: Custom link resolution function
185
- page_size: Default page size (A4, Letter, etc.)
186
- margins: Page margins specification
187
- orientation: Page orientation (portrait/landscape)
188
"""
189
super().__init__(app)
190
self.config = {
191
'pdf_triggers': ['format=pdf', 'application/pdf'],
192
'default_css': self.get_default_css(),
193
'base_path': '',
194
'debug': 0,
195
'link_callback': None,
196
'page_size': 'A4',
197
'margins': '1in',
198
'orientation': 'portrait'
199
}
200
self.config.update(config)
201
202
def get_default_css(self):
203
"""
204
Get default CSS for PDF conversion.
205
206
Returns:
207
str: Default CSS stylesheet for PDF formatting
208
"""
209
return """
210
@page {
211
size: A4;
212
margin: 1in;
213
}
214
body {
215
font-family: Arial, sans-serif;
216
font-size: 11pt;
217
line-height: 1.4;
218
}
219
"""
220
221
# Usage with configuration
222
app = ConfigurablePisaMiddleware(
223
your_app,
224
pdf_triggers=['format=pdf', '.pdf', 'application/pdf'],
225
page_size='Letter',
226
margins='0.5in',
227
debug=1
228
)
229
```
230
231
### Custom PDF Processing
232
233
Advanced customization options for PDF generation including custom styling, headers, footers, and post-processing.
234
235
```python
236
class CustomPisaMiddleware(PisaMiddleware):
237
"""
238
Custom WSGI middleware with enhanced PDF processing.
239
"""
240
241
def process_pdf_request(self, environ, html_content):
242
"""
243
Custom PDF processing with enhanced features.
244
245
Args:
246
environ (dict): WSGI environment
247
html_content (str): HTML content to convert
248
249
Returns:
250
bytes: Generated PDF content
251
"""
252
# Add custom headers and footers
253
enhanced_html = self.add_headers_footers(html_content, environ)
254
255
# Apply custom CSS based on request
256
css = self.get_request_css(environ)
257
258
# Custom link callback for resource resolution
259
def custom_link_callback(uri, rel):
260
return self.resolve_resource(uri, rel, environ)
261
262
# Generate PDF with custom options
263
import io
264
from xhtml2pdf import pisa
265
266
output = io.BytesIO()
267
result = pisa.pisaDocument(
268
enhanced_html,
269
dest=output,
270
default_css=css,
271
link_callback=custom_link_callback,
272
path=self.get_base_path(environ),
273
debug=self.config.get('debug', 0)
274
)
275
276
if result.err:
277
raise Exception(f"PDF generation failed: {result.log}")
278
279
return output.getvalue()
280
281
def add_headers_footers(self, html, environ):
282
"""
283
Add custom headers and footers to HTML content.
284
"""
285
header = f"""
286
<div class="pdf-header">
287
Generated on {datetime.now().strftime('%Y-%m-%d %H:%M')}
288
| {environ.get('HTTP_HOST', 'localhost')}
289
</div>
290
"""
291
292
footer = """
293
<div class="pdf-footer">
294
Page <pdf:pagenumber> of <pdf:pagecount>
295
</div>
296
"""
297
298
# Inject header/footer styles and content
299
return self.inject_pdf_elements(html, header, footer)
300
```
301
302
### Error Handling and Logging
303
304
Comprehensive error handling and logging for WSGI PDF conversion operations.
305
306
```python
307
import logging
308
from xhtml2pdf.wsgi import PisaMiddleware
309
310
class LoggingPisaMiddleware(PisaMiddleware):
311
"""
312
WSGI middleware with enhanced logging and error handling.
313
"""
314
315
def __init__(self, app, logger=None):
316
super().__init__(app)
317
self.logger = logger or logging.getLogger(__name__)
318
319
def __call__(self, environ, start_response):
320
try:
321
return super().__call__(environ, start_response)
322
except Exception as e:
323
self.logger.error(f"PDF conversion failed: {e}", exc_info=True)
324
325
# Return error response
326
error_html = f"""
327
<html>
328
<body>
329
<h1>PDF Conversion Error</h1>
330
<p>Unable to generate PDF: {str(e)}</p>
331
</body>
332
</html>
333
"""
334
335
response_headers = [
336
('Content-Type', 'text/html'),
337
('Content-Length', str(len(error_html)))
338
]
339
start_response('500 Internal Server Error', response_headers)
340
return [error_html.encode('utf-8')]
341
342
# Configure logging
343
logging.basicConfig(level=logging.INFO)
344
app = LoggingPisaMiddleware(your_app)
345
```
346
347
### Performance Optimization
348
349
Caching and performance optimization strategies for high-traffic web applications.
350
351
```python
352
import hashlib
353
from functools import lru_cache
354
355
class CachingPisaMiddleware(PisaMiddleware):
356
"""
357
WSGI middleware with PDF caching capabilities.
358
"""
359
360
def __init__(self, app, cache_size=128, cache_ttl=3600):
361
super().__init__(app)
362
self.cache_size = cache_size
363
self.cache_ttl = cache_ttl
364
self.pdf_cache = {}
365
366
@lru_cache(maxsize=128)
367
def generate_cached_pdf(self, content_hash, html_content):
368
"""
369
Generate PDF with caching based on content hash.
370
371
Args:
372
content_hash (str): Hash of HTML content
373
html_content (str): HTML content to convert
374
375
Returns:
376
bytes: Generated PDF content
377
"""
378
import io
379
from xhtml2pdf import pisa
380
381
output = io.BytesIO()
382
result = pisa.pisaDocument(html_content, dest=output)
383
384
if result.err:
385
raise Exception("PDF generation failed")
386
387
return output.getvalue()
388
389
def get_content_hash(self, html_content):
390
"""
391
Generate hash of HTML content for caching.
392
"""
393
return hashlib.md5(html_content.encode('utf-8')).hexdigest()
394
```
395
396
## Usage Examples
397
398
### Simple Web Application
399
400
```python
401
from xhtml2pdf.wsgi import PisaMiddleware
402
403
def simple_app(environ, start_response):
404
"""
405
Simple WSGI application that returns HTML content.
406
"""
407
html = """
408
<html>
409
<body>
410
<h1>Hello World</h1>
411
<p>This can be converted to PDF!</p>
412
</body>
413
</html>
414
"""
415
416
response_headers = [
417
('Content-Type', 'text/html'),
418
('Content-Length', str(len(html)))
419
]
420
start_response('200 OK', response_headers)
421
return [html.encode('utf-8')]
422
423
# Enable PDF conversion
424
app = PisaMiddleware(simple_app)
425
426
# Access as PDF: /?format=pdf
427
```
428
429
### Enterprise Integration
430
431
```python
432
from xhtml2pdf.wsgi import PisaMiddleware
433
434
class EnterprisePisaMiddleware(PisaMiddleware):
435
"""
436
Enterprise-grade WSGI middleware with security and audit features.
437
"""
438
439
def __init__(self, app, audit_logger=None, security_config=None):
440
super().__init__(app)
441
self.audit_logger = audit_logger
442
self.security_config = security_config or {}
443
444
def __call__(self, environ, start_response):
445
# Security checks
446
if not self.authorize_pdf_access(environ):
447
start_response('403 Forbidden', [])
448
return [b'PDF access denied']
449
450
# Audit logging
451
if self.audit_logger:
452
self.audit_logger.info(
453
f"PDF requested: {environ.get('PATH_INFO')} "
454
f"by {environ.get('REMOTE_ADDR')}"
455
)
456
457
return super().__call__(environ, start_response)
458
459
def authorize_pdf_access(self, environ):
460
"""
461
Check if user is authorized for PDF conversion.
462
"""
463
# Implement your authorization logic
464
return True
465
```
466
467
## Types
468
469
```python { .api }
470
class Filter:
471
"""
472
Base WSGI filter class for content transformation.
473
474
Attributes:
475
app: Wrapped WSGI application
476
"""
477
478
class HTMLFilter(Filter):
479
"""
480
HTML-specific WSGI filter for HTML content processing.
481
482
Extends base Filter with HTML processing capabilities.
483
"""
484
485
class PisaMiddleware(HTMLFilter):
486
"""
487
WSGI middleware for automatic HTML-to-PDF conversion.
488
489
Provides seamless PDF generation from HTML responses
490
with configurable triggers and processing options.
491
"""
492
```