or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

connection.mdevents.mdexceptions.mdindex.mdstates.md

states.mddocs/

0

# Protocol States

1

2

State constants and role definitions for managing HTTP/1.1 connection lifecycle and protocol compliance. h11 uses a state machine to track the current phase of HTTP message exchange for both client and server roles.

3

4

## Capabilities

5

6

### Role Constants

7

8

Define the role of each side in the HTTP connection.

9

10

```python { .api }

11

CLIENT = ...

12

"""

13

Represents the client role in an HTTP connection.

14

15

Usage:

16

conn = h11.Connection(h11.CLIENT)

17

18

The client role:

19

- Sends requests and receives responses

20

- Initiates HTTP conversations

21

- Can send Request events when in IDLE state

22

- Receives Response events when waiting for server

23

"""

24

25

SERVER = ...

26

"""

27

Represents the server role in an HTTP connection.

28

29

Usage:

30

conn = h11.Connection(h11.SERVER)

31

32

The server role:

33

- Receives requests and sends responses

34

- Responds to HTTP conversations

35

- Receives Request events when in IDLE state

36

- Can send Response events after receiving complete request

37

"""

38

```

39

40

### Connection State Constants

41

42

States that track the progression of HTTP message exchange.

43

44

```python { .api }

45

IDLE = ...

46

"""

47

Initial state - ready for new request/response cycle.

48

49

Transitions:

50

- CLIENT: Can send Request → SEND_BODY or DONE

51

- SERVER: Waits to receive Request → SEND_RESPONSE

52

"""

53

54

SEND_RESPONSE = ...

55

"""

56

Server is ready to send response after receiving complete request.

57

58

Transitions:

59

- SERVER: Can send Response/InformationalResponse → SEND_BODY or DONE

60

- Only valid for SERVER role

61

"""

62

63

SEND_BODY = ...

64

"""

65

Ready to send message body data.

66

67

Transitions:

68

- Can send Data events with body chunks

69

- Send EndOfMessage → DONE

70

- Both CLIENT and SERVER can enter this state

71

"""

72

73

DONE = ...

74

"""

75

Finished with current request/response cycle.

76

77

Transitions:

78

- Wait for peer to finish their side

79

- Both sides DONE → PAUSED (for keep-alive) or connection closes

80

"""

81

82

MUST_CLOSE = ...

83

"""

84

Connection must be closed after current message completes.

85

86

Causes:

87

- HTTP/1.0 without keep-alive

88

- Connection: close header

89

- Protocol errors requiring connection termination

90

"""

91

92

CLOSED = ...

93

"""

94

Connection is closed - no further communication possible.

95

96

Terminal state:

97

- Cannot transition to other states

98

- Connection object should be discarded

99

"""

100

101

ERROR = ...

102

"""

103

Error state due to protocol violation.

104

105

Causes:

106

- Invalid HTTP messages

107

- State machine violations

108

- Calling send_failed()

109

- Protocol specification violations

110

"""

111

112

SWITCHED_PROTOCOL = ...

113

"""

114

Successfully switched to different protocol.

115

116

Usage:

117

- After successful HTTP/1.1 protocol upgrade

118

- Connection no longer follows HTTP/1.1 state machine

119

- Application handles new protocol directly

120

"""

121

```

122

123

## State Machine Behavior

124

125

### State Transitions

126

127

The state machine enforces HTTP/1.1 protocol rules through valid state transitions:

128

129

```python

130

# CLIENT state flow

131

IDLE → SEND_BODY # After sending Request with body

132

IDLE → DONE # After sending Request without body

133

SEND_BODY → DONE # After sending EndOfMessage

134

135

# SERVER state flow

136

IDLE → SEND_RESPONSE # After receiving Request

137

SEND_RESPONSE → SEND_BODY # After sending Response with body

138

SEND_RESPONSE → DONE # After sending Response without body

139

SEND_BODY → DONE # After sending EndOfMessage

140

141

# Common flows

142

DONE → IDLE # Start new cycle (keep-alive)

143

DONE → CLOSED # Connection closes

144

* → ERROR # Protocol violation

145

* → MUST_CLOSE # Connection must close

146

```

147

148

### State Checking

149

150

Check connection states to determine valid operations:

151

152

```python { .api }

153

# Check our current state

154

if conn.our_state is h11.IDLE:

155

# Can send new request (CLIENT) or expect request (SERVER)

156

pass

157

elif conn.our_state is h11.SEND_BODY:

158

# Can send Data or EndOfMessage events

159

pass

160

elif conn.our_state is h11.DONE:

161

# Finished our side, wait for peer or start new cycle

162

pass

163

164

# Check peer state

165

if conn.their_state is h11.DONE:

166

# Peer finished, might be able to start new cycle

167

pass

168

169

# Check both states

170

if conn.states == {h11.CLIENT: h11.DONE, h11.SERVER: h11.DONE}:

171

# Both sides done, can start new cycle

172

conn.start_next_cycle()

173

```

174

175

## Usage Patterns

176

177

### Basic State Monitoring

178

179

```python

180

import h11

181

182

conn = h11.Connection(h11.CLIENT)

183

184

print(f"Initial state: {conn.our_state}") # IDLE

185

186

# Send request

187

req = h11.Request(method=b'GET', target=b'/', headers=[(b'host', b'example.com')])

188

data = conn.send(req)

189

190

print(f"After request: {conn.our_state}") # DONE (no body)

191

192

# Process response

193

while conn.our_state is not h11.DONE or conn.their_state is not h11.DONE:

194

raw_data = receive_from_socket()

195

conn.receive_data(raw_data)

196

197

event = conn.next_event()

198

if event is h11.NEED_DATA:

199

continue

200

elif isinstance(event, h11.Response):

201

print(f"Response received, their state: {conn.their_state}")

202

elif isinstance(event, h11.EndOfMessage):

203

print(f"Response complete, their state: {conn.their_state}") # DONE

204

205

# Both sides done - can start new cycle if keep-alive

206

if conn.our_state is h11.DONE and conn.their_state is h11.DONE:

207

if conn.next_event() is h11.PAUSED:

208

conn.start_next_cycle()

209

print(f"New cycle started: {conn.our_state}") # IDLE

210

```

211

212

### Error Handling

213

214

```python

215

try:

216

# Attempt invalid state transition

217

invalid_event = h11.Response(status_code=200) # SERVER event from CLIENT

218

data = conn.send(invalid_event)

219

except h11.LocalProtocolError as e:

220

print(f"Protocol error: {e}")

221

print(f"Connection state: {conn.our_state}") # ERROR

222

223

# Connection is now in ERROR state

224

assert conn.our_state is h11.ERROR

225

```

226

227

### Connection Lifecycle Management

228

229

```python

230

def handle_connection(socket):

231

conn = h11.Connection(h11.SERVER)

232

233

while True:

234

# Check if connection should close

235

if conn.our_state is h11.MUST_CLOSE or conn.our_state is h11.CLOSED:

236

socket.close()

237

break

238

239

if conn.our_state is h11.ERROR:

240

# Protocol error - log and close

241

print("Protocol error, closing connection")

242

socket.close()

243

break

244

245

# Normal processing

246

raw_data = socket.recv(4096)

247

if not raw_data:

248

break

249

250

conn.receive_data(raw_data)

251

252

while True:

253

event = conn.next_event()

254

255

if event is h11.NEED_DATA:

256

break

257

elif event is h11.PAUSED:

258

# Ready for new request/response cycle

259

conn.start_next_cycle()

260

break

261

elif isinstance(event, h11.Request):

262

# Handle request based on current state

263

handle_request(conn, event, socket)

264

```

265

266

### Keep-Alive vs Connection Close

267

268

```python

269

def check_connection_persistence(conn):

270

"""Determine if connection will be kept alive or closed."""

271

272

if conn.our_state is h11.MUST_CLOSE:

273

return "must_close"

274

elif conn.our_state is h11.CLOSED:

275

return "closed"

276

elif conn.our_state is h11.DONE and conn.their_state is h11.DONE:

277

# Both sides done - check if keep-alive

278

next_event = conn.next_event()

279

if next_event is h11.PAUSED:

280

return "keep_alive"

281

else:

282

return "closing"

283

else:

284

return "in_progress"

285

286

# Usage

287

status = check_connection_persistence(conn)

288

if status == "keep_alive":

289

conn.start_next_cycle()

290

# Can process new request/response

291

elif status in ("must_close", "closed", "closing"):

292

# Clean up and close socket

293

pass

294

```