or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-structures.mddev-server.mdexceptions.mdhttp-utilities.mdindex.mdmiddleware.mdrequest-response.mdrouting.mdsecurity.mdtesting.mdurl-wsgi-utils.md

http-utilities.mddocs/

0

# HTTP Utilities

1

2

Comprehensive HTTP parsing and formatting utilities for headers, cookies, dates, ETags, cache control, and content negotiation. These low-level functions provide the foundation for HTTP protocol handling in Werkzeug.

3

4

## Capabilities

5

6

### Header Parsing and Formatting

7

8

Functions for parsing and formatting HTTP headers with proper escaping and encoding.

9

10

```python { .api }

11

def quote_header_value(value, allow_token=True):

12

"""

13

Add double quotes around a header value if needed.

14

15

Parameters:

16

- value: The value to quote (will be converted to string)

17

- allow_token: If False, always quote even if value contains only token chars

18

19

Returns:

20

Quoted header value string

21

"""

22

23

def unquote_header_value(value):

24

"""

25

Remove quotes from a header value and unescape internal quotes.

26

27

Parameters:

28

- value: Quoted header value string

29

30

Returns:

31

Unquoted header value

32

"""

33

34

def parse_list_header(value):

35

"""

36

Parse a header that contains a comma-separated list.

37

38

Parameters:

39

- value: Header value string

40

41

Returns:

42

List of individual values

43

"""

44

45

def parse_dict_header(value):

46

"""

47

Parse a header that contains key=value pairs.

48

49

Parameters:

50

- value: Header value string with key=value pairs

51

52

Returns:

53

Dictionary of key-value pairs

54

"""

55

56

def parse_options_header(value):

57

"""

58

Parse a Content-Type-like header with main value and parameters.

59

60

Parameters:

61

- value: Header value string (e.g., "text/html; charset=utf-8")

62

63

Returns:

64

Tuple of (main_value, parameters_dict)

65

"""

66

67

def dump_options_header(header, options):

68

"""

69

Create a Content-Type-like header from main value and options.

70

71

Parameters:

72

- header: Main header value

73

- options: Dictionary of parameters

74

75

Returns:

76

Complete header string

77

"""

78

79

def dump_header(iterable):

80

"""

81

Dump an iterable into a header value.

82

83

Parameters:

84

- iterable: Dictionary or iterable to convert to header

85

86

Returns:

87

Header string representation

88

"""

89

```

90

91

### Accept Header Processing

92

93

Functions for parsing and handling HTTP Accept headers with quality values.

94

95

```python { .api }

96

def parse_accept_header(value, cls=None):

97

"""

98

Parse an Accept header into structured data.

99

100

Parameters:

101

- value: Accept header string

102

- cls: Accept class to use (Accept, MIMEAccept, LanguageAccept, CharsetAccept)

103

104

Returns:

105

Accept object with parsed values and quality scores

106

"""

107

```

108

109

### Cache Control Headers

110

111

Functions for parsing and managing Cache-Control headers.

112

113

```python { .api }

114

def parse_cache_control_header(value, on_update=None, cls=None):

115

"""

116

Parse Cache-Control header into structured object.

117

118

Parameters:

119

- value: Cache-Control header string

120

- on_update: Callback function for updates

121

- cls: Cache control class (RequestCacheControl or ResponseCacheControl)

122

123

Returns:

124

Cache control object with directive properties

125

"""

126

```

127

128

### Content Security Policy

129

130

Functions for parsing and formatting CSP headers.

131

132

```python { .api }

133

def parse_csp_header(value, on_update=None, cls=None):

134

"""

135

Parse Content-Security-Policy header.

136

137

Parameters:

138

- value: CSP header string

139

- on_update: Callback function for updates

140

- cls: CSP class to use

141

142

Returns:

143

ContentSecurityPolicy object

144

"""

145

146

def dump_csp_header(header):

147

"""

148

Convert CSP object to header string.

149

150

Parameters:

151

- header: ContentSecurityPolicy object

152

153

Returns:

154

CSP header string

155

"""

156

```

157

158

### Set Headers

159

160

Functions for parsing set-like headers.

161

162

```python { .api }

163

def parse_set_header(value, on_update=None, cls=None):

164

"""

165

Parse set-like headers (comma-separated values).

166

167

Parameters:

168

- value: Header value string

169

- on_update: Callback for updates

170

- cls: Set class to use

171

172

Returns:

173

HeaderSet object

174

"""

175

```

176

177

### ETag Functions

178

179

Functions for generating, parsing, and validating ETags.

180

181

```python { .api }

182

def generate_etag(data):

183

"""

184

Generate an ETag from data using SHA-1 hash.

185

186

Parameters:

187

- data: Raw data bytes to hash

188

189

Returns:

190

ETag string (quoted hash)

191

"""

192

193

def quote_etag(etag, weak=False):

194

"""

195

Quote an ETag value for use in headers.

196

197

Parameters:

198

- etag: ETag value to quote

199

- weak: Whether this is a weak ETag (prepends W/)

200

201

Returns:

202

Quoted ETag string

203

"""

204

205

def unquote_etag(etag):

206

"""

207

Unquote an ETag and determine if it's weak.

208

209

Parameters:

210

- etag: Quoted ETag string or None

211

212

Returns:

213

Tuple of (unquoted_etag, is_weak)

214

"""

215

216

def parse_etags(value):

217

"""

218

Parse ETags header (If-Match, If-None-Match).

219

220

Parameters:

221

- value: ETags header string

222

223

Returns:

224

ETags object containing strong/weak etags and star flag

225

"""

226

227

def is_resource_modified(environ, etag=None, data=None, last_modified=None, ignore_if_range=True):

228

"""

229

Check if a resource was modified based on conditional headers.

230

231

Parameters:

232

- environ: WSGI environment or Request object

233

- etag: Current ETag of the resource

234

- data: Raw data to generate ETag from

235

- last_modified: Last modified timestamp

236

- ignore_if_range: Whether to ignore If-Range header

237

238

Returns:

239

True if resource was modified (should send full response)

240

"""

241

```

242

243

### Date and Time Functions

244

245

Functions for parsing and formatting HTTP dates.

246

247

```python { .api }

248

def http_date(timestamp=None):

249

"""

250

Format a timestamp as HTTP date string.

251

252

Parameters:

253

- timestamp: Unix timestamp, datetime, or None for current time

254

255

Returns:

256

HTTP date string (RFC 7231 format)

257

"""

258

259

def parse_date(value):

260

"""

261

Parse HTTP date string to datetime object.

262

263

Parameters:

264

- value: HTTP date string

265

266

Returns:

267

datetime object or None if parsing failed

268

"""

269

270

def parse_age(value=None):

271

"""

272

Parse Age header value.

273

274

Parameters:

275

- value: Age header string

276

277

Returns:

278

timedelta object representing the age

279

"""

280

281

def dump_age(age=None):

282

"""

283

Format age as Age header string.

284

285

Parameters:

286

- age: timedelta, int (seconds), or None

287

288

Returns:

289

Age header string

290

"""

291

```

292

293

### Cookie Functions

294

295

Functions for parsing and creating HTTP cookies.

296

297

```python { .api }

298

def parse_cookie(header, cls=None):

299

"""

300

Parse Cookie header into dictionary.

301

302

Parameters:

303

- header: Cookie header string

304

- cls: Dictionary class to use for result

305

306

Returns:

307

Dictionary of cookie name-value pairs

308

"""

309

310

def dump_cookie(key, value="", max_age=None, expires=None, path="/", domain=None, secure=False, httponly=False, charset="utf-8", sync_expires=True, max_size=4093, samesite=None):

311

"""

312

Create Set-Cookie header string.

313

314

Parameters:

315

- key: Cookie name

316

- value: Cookie value

317

- max_age: Maximum age in seconds

318

- expires: Expiration date (datetime or timestamp)

319

- path: Cookie path

320

- domain: Cookie domain

321

- secure: Only send over HTTPS

322

- httponly: Prevent JavaScript access

323

- charset: Character encoding for value

324

- sync_expires: Sync expires with max_age

325

- max_size: Maximum cookie size

326

- samesite: SameSite attribute ('Strict', 'Lax', 'None')

327

328

Returns:

329

Complete Set-Cookie header string

330

"""

331

```

332

333

### Range Header Functions

334

335

Functions for handling HTTP Range requests.

336

337

```python { .api }

338

def parse_range_header(value, make_inclusive=True):

339

"""

340

Parse Range header for partial content requests.

341

342

Parameters:

343

- value: Range header string (e.g., "bytes=0-1023")

344

- make_inclusive: Whether to make ranges inclusive

345

346

Returns:

347

Range object with units and range specifications

348

"""

349

350

def parse_content_range_header(value, on_update=None, cls=None):

351

"""

352

Parse Content-Range header from partial content responses.

353

354

Parameters:

355

- value: Content-Range header string

356

- on_update: Callback for updates

357

- cls: ContentRange class to use

358

359

Returns:

360

ContentRange object

361

"""

362

363

def parse_if_range_header(value):

364

"""

365

Parse If-Range header (ETag or date).

366

367

Parameters:

368

- value: If-Range header string

369

370

Returns:

371

IfRange object containing ETag or date

372

"""

373

374

def is_byte_range_valid(start, stop, length):

375

"""

376

Check if a byte range is valid for given content length.

377

378

Parameters:

379

- start: Range start position

380

- stop: Range stop position

381

- length: Total content length

382

383

Returns:

384

True if range is valid

385

"""

386

```

387

388

### Header Classification

389

390

Functions for classifying and filtering HTTP headers.

391

392

```python { .api }

393

def is_entity_header(header):

394

"""

395

Check if header is an entity header.

396

397

Entity headers describe the content of the message body.

398

399

Parameters:

400

- header: Header name

401

402

Returns:

403

True if header is an entity header

404

"""

405

406

def is_hop_by_hop_header(header):

407

"""

408

Check if header is a hop-by-hop header.

409

410

Hop-by-hop headers are meaningful only for a single connection.

411

412

Parameters:

413

- header: Header name

414

415

Returns:

416

True if header is hop-by-hop

417

"""

418

419

def remove_entity_headers(headers, allowed=None):

420

"""

421

Remove entity headers from header collection.

422

423

Parameters:

424

- headers: Headers object or list of (name, value) tuples

425

- allowed: Set of entity headers to keep

426

427

Returns:

428

New Headers object without entity headers

429

"""

430

431

def remove_hop_by_hop_headers(headers):

432

"""

433

Remove hop-by-hop headers from header collection in-place.

434

435

Parameters:

436

- headers: Headers object or list of (name, value) tuples

437

"""

438

```

439

440

### Constants and Enums

441

442

HTTP status codes and policy enums.

443

444

```python { .api }

445

# HTTP status code mappings

446

HTTP_STATUS_CODES: dict[int, str] = {

447

100: "Continue",

448

200: "OK",

449

201: "Created",

450

204: "No Content",

451

301: "Moved Permanently",

452

302: "Found",

453

304: "Not Modified",

454

400: "Bad Request",

455

401: "Unauthorized",

456

403: "Forbidden",

457

404: "Not Found",

458

405: "Method Not Allowed",

459

500: "Internal Server Error",

460

# ... complete mapping available

461

}

462

463

class COEP(Enum):

464

"""Cross Origin Embedder Policy values."""

465

UNSAFE_NONE = "unsafe-none"

466

REQUIRE_CORP = "require-corp"

467

468

class COOP(Enum):

469

"""Cross Origin Opener Policy values."""

470

UNSAFE_NONE = "unsafe-none"

471

SAME_ORIGIN_ALLOW_POPUPS = "same-origin-allow-popups"

472

SAME_ORIGIN = "same-origin"

473

```

474

475

## Usage Examples

476

477

### Content Type and Accept Headers

478

479

```python

480

from werkzeug.http import parse_options_header, dump_options_header, parse_accept_header

481

482

def handle_content_negotiation(request):

483

# Parse Content-Type header

484

content_type, params = parse_options_header(request.headers.get('Content-Type'))

485

charset = params.get('charset', 'utf-8')

486

487

print(f"Content type: {content_type}, Charset: {charset}")

488

# Output: Content type: application/json, Charset: utf-8

489

490

# Create Content-Type header

491

ct_header = dump_options_header('text/html', {'charset': 'utf-8'})

492

print(ct_header) # "text/html; charset=utf-8"

493

494

# Parse Accept header

495

accept = parse_accept_header(request.headers.get('Accept'))

496

best_match = accept.best_match(['text/html', 'application/json', 'text/plain'])

497

498

if best_match == 'application/json':

499

return create_json_response()

500

elif best_match == 'text/html':

501

return create_html_response()

502

else:

503

return create_plain_text_response()

504

```

505

506

### ETag Generation and Validation

507

508

```python

509

from werkzeug.http import generate_etag, is_resource_modified, quote_etag

510

from werkzeug.wrappers import Response

511

import json

512

513

def serve_with_etag(request, data):

514

# Generate ETag from data

515

data_bytes = json.dumps(data, sort_keys=True).encode('utf-8')

516

etag = generate_etag(data_bytes)

517

518

# Check if resource was modified

519

if not is_resource_modified(request.environ, etag=etag):

520

# Return 304 Not Modified

521

response = Response(status=304)

522

response.headers['ETag'] = quote_etag(etag)

523

return response

524

525

# Return full response with ETag

526

response = Response(json.dumps(data), mimetype='application/json')

527

response.headers['ETag'] = quote_etag(etag)

528

return response

529

```

530

531

### Cookie Handling

532

533

```python

534

from werkzeug.http import parse_cookie, dump_cookie

535

from werkzeug.wrappers import Request, Response

536

from datetime import datetime, timedelta

537

538

def session_management(environ, start_response):

539

request = Request(environ)

540

541

# Parse incoming cookies

542

cookies = parse_cookie(request.headers.get('Cookie', ''))

543

session_id = cookies.get('session_id')

544

545

response = Response("Session handling example")

546

547

if not session_id:

548

# Create new session

549

session_id = generate_session_id() # Your function

550

551

# Set secure session cookie

552

cookie_header = dump_cookie(

553

'session_id',

554

session_id,

555

max_age=3600, # 1 hour

556

path='/',

557

secure=True,

558

httponly=True,

559

samesite='Lax'

560

)

561

response.headers['Set-Cookie'] = cookie_header

562

563

# Set additional cookies

564

theme_cookie = dump_cookie(

565

'theme',

566

'dark',

567

expires=datetime.now() + timedelta(days=30),

568

path='/'

569

)

570

response.headers.add('Set-Cookie', theme_cookie)

571

572

return response(environ, start_response)

573

```

574

575

### Range Request Handling

576

577

```python

578

from werkzeug.http import parse_range_header, is_byte_range_valid

579

from werkzeug.wrappers import Request, Response

580

import os

581

582

def serve_file_with_ranges(request, file_path):

583

file_size = os.path.getsize(file_path)

584

585

# Parse Range header

586

range_header = request.headers.get('Range')

587

if range_header:

588

try:

589

ranges = parse_range_header(range_header)

590

if ranges and ranges.ranges:

591

# Get first range

592

start, end = ranges.ranges[0]

593

594

# Handle open-ended ranges

595

if start is None:

596

start = max(0, file_size - end)

597

end = file_size

598

elif end is None or end >= file_size:

599

end = file_size

600

601

# Validate range

602

if is_byte_range_valid(start, end, file_size):

603

# Serve partial content

604

with open(file_path, 'rb') as f:

605

f.seek(start)

606

data = f.read(end - start)

607

608

response = Response(

609

data,

610

status=206, # Partial Content

611

headers={

612

'Content-Range': f'bytes {start}-{end-1}/{file_size}',

613

'Accept-Ranges': 'bytes',

614

'Content-Length': str(len(data))

615

}

616

)

617

return response

618

except (ValueError, IndexError):

619

pass # Invalid range, serve full file

620

621

# Serve full file

622

with open(file_path, 'rb') as f:

623

data = f.read()

624

625

response = Response(

626

data,

627

headers={

628

'Accept-Ranges': 'bytes',

629

'Content-Length': str(file_size)

630

}

631

)

632

return response

633

```

634

635

### Cache Control Headers

636

637

```python

638

from werkzeug.http import parse_cache_control_header

639

from werkzeug.datastructures import ResponseCacheControl

640

from werkzeug.wrappers import Response

641

from datetime import datetime, timedelta

642

643

def handle_caching(request):

644

# Parse request cache control

645

cache_control = parse_cache_control_header(

646

request.headers.get('Cache-Control')

647

)

648

649

if cache_control.no_cache:

650

# Client doesn't want cached response

651

response = generate_fresh_response()

652

elif cache_control.max_age is not None:

653

# Client specifies max age

654

response = get_cached_response_if_fresh(cache_control.max_age)

655

else:

656

response = get_normal_response()

657

658

# Set response cache control

659

response.cache_control.public = True

660

response.cache_control.max_age = 3600 # 1 hour

661

response.cache_control.must_revalidate = True

662

663

# Set other caching headers

664

response.expires = datetime.utcnow() + timedelta(hours=1)

665

response.last_modified = datetime.utcnow()

666

667

return response

668

```

669

670

### Date and Time Handling

671

672

```python

673

from werkzeug.http import http_date, parse_date, parse_age, dump_age

674

from datetime import datetime, timedelta

675

676

def date_header_examples():

677

# Current time as HTTP date

678

now_header = http_date()

679

print(now_header) # "Wed, 21 Oct 2015 07:28:00 GMT"

680

681

# Specific timestamp

682

timestamp = 1445412480

683

date_header = http_date(timestamp)

684

685

# Parse HTTP date

686

parsed = parse_date("Wed, 21 Oct 2015 07:28:00 GMT")

687

print(parsed) # datetime(2015, 10, 21, 7, 28, 0)

688

689

# Age header handling

690

age = timedelta(hours=2, minutes=30)

691

age_header = dump_age(age)

692

print(age_header) # "9000" (seconds)

693

694

parsed_age = parse_age("9000")

695

print(parsed_age) # timedelta(seconds=9000)

696

```

697

698

### Content Security Policy

699

700

```python

701

from werkzeug.datastructures import ContentSecurityPolicy

702

from werkzeug.http import dump_csp_header, parse_csp_header

703

704

def setup_csp():

705

# Create CSP policy

706

csp = ContentSecurityPolicy()

707

csp.default_src = ["'self'"]

708

csp.script_src = ["'self'", "'unsafe-inline'", "https://cdn.example.com"]

709

csp.style_src = ["'self'", "'unsafe-inline'"]

710

csp.img_src = ["'self'", "data:", "https:"]

711

712

# Convert to header string

713

csp_header = dump_csp_header(csp)

714

715

# Parse existing CSP header

716

existing_csp = "default-src 'self'; script-src 'self' 'unsafe-inline'"

717

parsed_csp = parse_csp_header(existing_csp)

718

719

return csp_header

720

```

721

722

### Header Utilities

723

724

```python

725

from werkzeug.http import (

726

quote_header_value, unquote_header_value,

727

remove_entity_headers, is_hop_by_hop_header

728

)

729

from werkzeug.datastructures import Headers

730

731

def header_processing():

732

# Quote/unquote header values

733

quoted = quote_header_value("filename with spaces.txt")

734

print(quoted) # '"filename with spaces.txt"'

735

736

unquoted = unquote_header_value(quoted)

737

print(unquoted) # "filename with spaces.txt"

738

739

# Header classification

740

print(is_hop_by_hop_header('Connection')) # True

741

print(is_hop_by_hop_header('Content-Type')) # False

742

743

# Filter headers for forwarding

744

headers = Headers([

745

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

746

('Content-Length', '1234'),

747

('Connection', 'close'),

748

('X-Custom', 'value')

749

])

750

751

# Remove entity headers (for HEAD requests)

752

filtered = remove_entity_headers(headers, allowed={'Content-Type'})

753

# Result has Content-Type and X-Custom, but not Content-Length

754

```

755

756

## Form Data Parsing

757

758

Low-level utilities for parsing form data from HTTP requests, including multipart and URL-encoded data handling.

759

760

```python { .api }

761

def parse_form_data(environ, stream_factory=None, max_form_memory_size=None, max_content_length=None, cls=None, silent=True, *, max_form_parts=None):

762

"""

763

Parse form data from WSGI environ.

764

765

Parameters:

766

- environ: WSGI environment dictionary

767

- stream_factory: Callable for creating file streams

768

- max_form_memory_size: Maximum memory for form data

769

- max_content_length: Maximum total content length

770

- cls: MultiDict class to use (default: MultiDict)

771

- silent: Don't raise on parsing errors

772

- max_form_parts: Maximum number of multipart parts

773

774

Returns:

775

Tuple of (stream, form_dict, files_dict)

776

"""

777

778

def default_stream_factory(total_content_length, content_type, filename, content_length=None):

779

"""

780

Default stream factory for file uploads.

781

782

Parameters:

783

- total_content_length: Total request content length

784

- content_type: Content type of the part

785

- filename: Filename if provided

786

- content_length: Content length of this part

787

788

Returns:

789

File-like object for storing upload data

790

"""

791

792

class FormDataParser:

793

def __init__(self, stream_factory=None, max_form_memory_size=None, max_content_length=None, cls=None, silent=True, *, max_form_parts=None):

794

"""

795

Advanced form data parser with configurable limits.

796

797

Parameters:

798

- stream_factory: Callable for creating file streams

799

- max_form_memory_size: Maximum memory for form data

800

- max_content_length: Maximum total content length

801

- cls: MultiDict class to use

802

- silent: Don't raise on parsing errors

803

- max_form_parts: Maximum number of multipart parts

804

"""

805

806

def parse_from_environ(self, environ):

807

"""

808

Parse form data from WSGI environment.

809

810

Parameters:

811

- environ: WSGI environment dictionary

812

813

Returns:

814

Tuple of (stream, form_dict, files_dict)

815

"""

816

```