or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-concurrency.mddebugging.mdgreen-stdlib.mdindex.mdmonkey-patching.mdnetworking.mdresource-pooling.mdsynchronization.mdthread-pools.mdweb-server.md

web-server.mddocs/

0

# Web Server

1

2

Production-ready WSGI server implementation for hosting web applications with built-in support for WebSocket upgrades. Eventlet's WSGI server provides high-performance concurrent request handling.

3

4

## Capabilities

5

6

### WSGI Server

7

8

A full-featured WSGI server that can host any WSGI-compliant web application.

9

10

```python { .api }

11

def server(sock, site, log=None, environ=None, max_size=None,

12

max_http_version=None, protocol=wsgi.HttpProtocol,

13

server_event=None, minimum_chunk_size=None,

14

log_x_forwarded_for=True, custom_pool=None,

15

keepalive=True, log_output=True, log_format=None,

16

url_length_limit=8192, debug=True, socket_timeout=None,

17

capitalize_response_headers=True):

18

"""

19

Start a WSGI server handling requests on the given socket.

20

21

Parameters:

22

- sock: listening socket to accept connections from

23

- site: WSGI application callable

24

- log: file-like object for access logging (default: sys.stdout)

25

- environ: dict of additional WSGI environ variables

26

- max_size: int, maximum number of concurrent connections

27

- max_http_version: str, maximum HTTP version to support

28

- protocol: protocol class for handling HTTP requests

29

- server_event: Event object signaled when server starts

30

- minimum_chunk_size: int, minimum chunk size for chunked encoding

31

- log_x_forwarded_for: bool, whether to log X-Forwarded-For header

32

- custom_pool: GreenPool instance for connection handling

33

- keepalive: bool, whether to support HTTP keep-alive

34

- log_output: bool, whether to enable access logging

35

- log_format: str, custom log format string

36

- url_length_limit: int, maximum URL length in bytes

37

- debug: bool, whether to include debug information in errors

38

- socket_timeout: int or None, socket timeout in seconds (default: None)

39

- capitalize_response_headers: bool, whether to capitalize response headers

40

41

Returns:

42

None (runs until interrupted)

43

"""

44

45

def format_date_time(timestamp):

46

"""

47

Format a unix timestamp to HTTP standard date/time string.

48

49

Parameters:

50

- timestamp: float, unix timestamp

51

52

Returns:

53

str: formatted date string for HTTP headers

54

"""

55

```

56

57

### WebSocket Support

58

59

WebSocket protocol implementation that integrates with WSGI applications.

60

61

```python { .api }

62

class WebSocketWSGI:

63

"""

64

Wraps a websocket handler function in a WSGI application.

65

Enables WebSocket support within WSGI frameworks.

66

"""

67

68

def __init__(self, handler):

69

"""

70

Create a WebSocket WSGI wrapper.

71

72

Parameters:

73

- handler: callable(ws) that handles WebSocket connections

74

"""

75

76

def __call__(self, environ, start_response):

77

"""

78

WSGI application interface.

79

80

Parameters:

81

- environ: WSGI environment dict

82

- start_response: WSGI start_response callable

83

84

Returns:

85

WSGI response iterable

86

"""

87

88

class WebSocket:

89

"""

90

WebSocket connection object for sending and receiving messages.

91

"""

92

93

def send(self, message):

94

"""

95

Send a message to the WebSocket client.

96

97

Parameters:

98

- message: str or bytes, message to send

99

100

Returns:

101

None

102

103

Raises:

104

ConnectionClosed: if WebSocket connection is closed

105

"""

106

107

def receive(self):

108

"""

109

Receive a message from the WebSocket client.

110

111

Returns:

112

str or bytes: received message

113

114

Raises:

115

ConnectionClosed: if WebSocket connection is closed

116

"""

117

118

def close(self):

119

"""

120

Close the WebSocket connection.

121

122

Returns:

123

None

124

"""

125

126

@property

127

def closed(self):

128

"""

129

Check if the WebSocket connection is closed.

130

131

Returns:

132

bool: True if closed, False if open

133

"""

134

```

135

136

## Usage Examples

137

138

### Basic WSGI Application

139

140

```python

141

import eventlet

142

import eventlet.wsgi

143

144

def hello_world_app(environ, start_response):

145

"""Simple WSGI application"""

146

status = '200 OK'

147

headers = [('Content-Type', 'text/plain')]

148

start_response(status, headers)

149

return [b'Hello, World!']

150

151

def run_wsgi_server():

152

"""Run a basic WSGI server"""

153

# Create listening socket

154

sock = eventlet.listen(('localhost', 8080))

155

print("WSGI server listening on localhost:8080")

156

157

# Start WSGI server

158

eventlet.wsgi.server(sock, hello_world_app)

159

160

if __name__ == "__main__":

161

run_wsgi_server()

162

```

163

164

### Flask Application

165

166

```python

167

import eventlet

168

import eventlet.wsgi

169

from flask import Flask

170

171

app = Flask(__name__)

172

173

@app.route('/')

174

def hello():

175

return 'Hello from Flask on Eventlet!'

176

177

@app.route('/users/<int:user_id>')

178

def get_user(user_id):

179

return f'User ID: {user_id}'

180

181

@app.route('/api/data')

182

def api_data():

183

# Simulate some async work

184

eventlet.sleep(0.1)

185

return {'message': 'Data from API', 'status': 'success'}

186

187

def run_flask_server():

188

"""Run Flask application with Eventlet WSGI server"""

189

sock = eventlet.listen(('localhost', 5000))

190

print("Flask server with Eventlet listening on localhost:5000")

191

192

eventlet.wsgi.server(

193

sock,

194

app,

195

log_output=True,

196

max_size=1000 # Max 1000 concurrent connections

197

)

198

199

if __name__ == "__main__":

200

# Enable monkey patching for Flask compatibility

201

eventlet.monkey_patch()

202

run_flask_server()

203

```

204

205

### WebSocket Chat Server

206

207

```python

208

import eventlet

209

import eventlet.wsgi

210

import eventlet.websocket

211

212

# Store connected clients

213

clients = set()

214

215

def websocket_handler(ws):

216

"""Handle WebSocket connections"""

217

clients.add(ws)

218

print(f"Client connected. Total clients: {len(clients)}")

219

220

try:

221

while not ws.closed:

222

message = ws.receive()

223

if message is None:

224

break

225

226

print(f"Received: {message}")

227

228

# Broadcast message to all connected clients

229

disconnected = set()

230

for client in clients:

231

try:

232

client.send(f"Broadcast: {message}")

233

except:

234

disconnected.add(client)

235

236

# Remove disconnected clients

237

clients -= disconnected

238

239

except eventlet.websocket.ConnectionClosed:

240

pass

241

finally:

242

clients.discard(ws)

243

print(f"Client disconnected. Total clients: {len(clients)}")

244

245

def websocket_app(environ, start_response):

246

"""WSGI app that handles WebSocket upgrades"""

247

if environ.get('HTTP_UPGRADE', '').lower() == 'websocket':

248

# Handle WebSocket upgrade

249

return eventlet.websocket.WebSocketWSGI(websocket_handler)(environ, start_response)

250

else:

251

# Handle regular HTTP requests

252

status = '200 OK'

253

headers = [('Content-Type', 'text/html')]

254

start_response(status, headers)

255

256

return [b"""

257

<!DOCTYPE html>

258

<html>

259

<head><title>WebSocket Chat</title></head>

260

<body>

261

<div id="messages"></div>

262

<input type="text" id="messageInput" placeholder="Type a message...">

263

<button onclick="sendMessage()">Send</button>

264

265

<script>

266

const ws = new WebSocket('ws://localhost:8080');

267

const messages = document.getElementById('messages');

268

269

ws.onmessage = function(event) {

270

const div = document.createElement('div');

271

div.textContent = event.data;

272

messages.appendChild(div);

273

};

274

275

function sendMessage() {

276

const input = document.getElementById('messageInput');

277

ws.send(input.value);

278

input.value = '';

279

}

280

281

document.getElementById('messageInput').addEventListener('keypress', function(e) {

282

if (e.key === 'Enter') {

283

sendMessage();

284

}

285

});

286

</script>

287

</body>

288

</html>

289

"""]

290

291

def run_websocket_server():

292

"""Run WebSocket chat server"""

293

sock = eventlet.listen(('localhost', 8080))

294

print("WebSocket chat server listening on localhost:8080")

295

296

eventlet.wsgi.server(sock, websocket_app, debug=True)

297

298

if __name__ == "__main__":

299

eventlet.monkey_patch()

300

run_websocket_server()

301

```

302

303

### Production WSGI Server with Configuration

304

305

```python

306

import eventlet

307

import eventlet.wsgi

308

import logging

309

import sys

310

311

def create_wsgi_app():

312

"""Create a sample WSGI application"""

313

def app(environ, start_response):

314

path = environ.get('PATH_INFO', '/')

315

316

if path == '/':

317

status = '200 OK'

318

headers = [('Content-Type', 'text/html')]

319

start_response(status, headers)

320

return [b'<h1>Production WSGI Server</h1>']

321

322

elif path == '/health':

323

status = '200 OK'

324

headers = [('Content-Type', 'application/json')]

325

start_response(status, headers)

326

return [b'{"status": "healthy"}']

327

328

else:

329

status = '404 Not Found'

330

headers = [('Content-Type', 'text/plain')]

331

start_response(status, headers)

332

return [b'Page not found']

333

334

return app

335

336

def run_production_server():

337

"""Run production WSGI server with full configuration"""

338

# Set up logging

339

logging.basicConfig(

340

level=logging.INFO,

341

format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'

342

)

343

344

# Create application

345

app = create_wsgi_app()

346

347

# Create listening socket

348

sock = eventlet.listen(('0.0.0.0', 8000))

349

print("Production WSGI server listening on 0.0.0.0:8000")

350

351

# Configure custom environment variables

352

custom_environ = {

353

'SERVER_NAME': 'eventlet-server',

354

'SERVER_SOFTWARE': 'Eventlet/1.0'

355

}

356

357

# Start server with production configuration

358

eventlet.wsgi.server(

359

sock,

360

app,

361

log=sys.stdout, # Access log output

362

environ=custom_environ,

363

max_size=2000, # Max concurrent connections

364

keepalive=True, # Enable HTTP keep-alive

365

log_x_forwarded_for=True, # Log X-Forwarded-For header

366

url_length_limit=16384, # 16KB URL limit

367

socket_timeout=30, # 30 second socket timeout

368

debug=False, # Disable debug mode for production

369

capitalize_response_headers=True

370

)

371

372

if __name__ == "__main__":

373

eventlet.monkey_patch()

374

run_production_server()

375

```

376

377

### WSGI with Custom Logging

378

379

```python

380

import eventlet

381

import eventlet.wsgi

382

import logging

383

import time

384

from io import StringIO

385

386

class WSGILogger:

387

"""Custom WSGI access logger"""

388

389

def __init__(self, logger):

390

self.logger = logger

391

392

def write(self, msg):

393

"""Write log message"""

394

if msg.strip(): # Ignore empty messages

395

self.logger.info(msg.strip())

396

397

def flush(self):

398

"""Flush any buffered output"""

399

pass

400

401

def timed_wsgi_app(environ, start_response):

402

"""WSGI app that tracks request timing"""

403

start_time = time.time()

404

405

# Process request

406

path = environ.get('PATH_INFO', '/')

407

408

if path.startswith('/slow'):

409

# Simulate slow endpoint

410

eventlet.sleep(2.0)

411

response = b'Slow response completed'

412

else:

413

response = b'Fast response'

414

415

# Calculate processing time

416

processing_time = time.time() - start_time

417

418

status = '200 OK'

419

headers = [

420

('Content-Type', 'text/plain'),

421

('X-Processing-Time', f'{processing_time:.3f}s')

422

]

423

start_response(status, headers)

424

425

return [response]

426

427

def run_logged_server():

428

"""Run server with custom logging"""

429

# Set up logger

430

logger = logging.getLogger('wsgi_access')

431

logger.setLevel(logging.INFO)

432

433

handler = logging.StreamHandler()

434

formatter = logging.Formatter(

435

'%(asctime)s - %(name)s - %(message)s'

436

)

437

handler.setFormatter(formatter)

438

logger.addHandler(handler)

439

440

# Create custom log writer

441

log_writer = WSGILogger(logger)

442

443

# Start server

444

sock = eventlet.listen(('localhost', 8080))

445

print("Logged WSGI server listening on localhost:8080")

446

447

eventlet.wsgi.server(

448

sock,

449

timed_wsgi_app,

450

log=log_writer,

451

log_format='%(client_ip)s - "%(request_line)s" %(status_code)s %(body_length)s %(wall_seconds).6f',

452

log_output=True

453

)

454

455

if __name__ == "__main__":

456

eventlet.monkey_patch()

457

run_logged_server()

458

```

459

460

### SSL/HTTPS WSGI Server

461

462

```python

463

import eventlet

464

import eventlet.wsgi

465

import ssl

466

467

def https_app(environ, start_response):

468

"""WSGI app for HTTPS server"""

469

status = '200 OK'

470

headers = [

471

('Content-Type', 'text/html'),

472

('Strict-Transport-Security', 'max-age=31536000; includeSubDomains')

473

]

474

start_response(status, headers)

475

476

return [b'''

477

<html>

478

<head><title>Secure HTTPS Server</title></head>

479

<body>

480

<h1>Secure Connection</h1>

481

<p>This page is served over HTTPS using Eventlet.</p>

482

</body>

483

</html>

484

''']

485

486

def run_https_server():

487

"""Run HTTPS WSGI server"""

488

# Create socket and wrap with SSL

489

sock = eventlet.listen(('localhost', 8443))

490

491

# Wrap socket with SSL

492

ssl_sock = eventlet.wrap_ssl(

493

sock,

494

certfile='server.crt', # SSL certificate file

495

keyfile='server.key', # SSL private key file

496

server_side=True,

497

ssl_version=ssl.PROTOCOL_TLS,

498

ciphers='ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:!aNULL:!MD5:!DSS'

499

)

500

501

print("HTTPS WSGI server listening on https://localhost:8443")

502

503

eventlet.wsgi.server(

504

ssl_sock,

505

https_app,

506

log_output=True,

507

debug=False

508

)

509

510

if __name__ == "__main__":

511

eventlet.monkey_patch()

512

run_https_server()

513

```

514

515

## Configuration Options

516

517

### Server Performance Tuning

518

519

```python

520

# High-concurrency configuration

521

eventlet.wsgi.server(

522

sock,

523

app,

524

max_size=5000, # Support 5000 concurrent connections

525

socket_timeout=120, # 2 minute timeout

526

keepalive=True, # Enable keep-alive for efficiency

527

minimum_chunk_size=8192 # Larger chunks for better performance

528

)

529

530

# Memory-constrained configuration

531

eventlet.wsgi.server(

532

sock,

533

app,

534

max_size=500, # Limit concurrent connections

535

socket_timeout=30, # Shorter timeout

536

url_length_limit=4096 # Smaller URL limit

537

)

538

```

539

540

### Custom Protocol Handling

541

542

```python

543

import eventlet.wsgi

544

545

class CustomProtocol(eventlet.wsgi.HttpProtocol):

546

"""Custom HTTP protocol with additional features"""

547

548

def handle_one_request(self):

549

"""Override to add custom request handling"""

550

# Add custom headers or logging

551

result = super().handle_one_request()

552

return result

553

554

# Use custom protocol

555

eventlet.wsgi.server(

556

sock,

557

app,

558

protocol=CustomProtocol

559

)

560

```