@@ -49,6 +49,13 @@ type QUICConn struct {
49
49
// A QUICConfig configures a [QUICConn].
50
50
type QUICConfig struct {
51
51
TLSConfig * Config
52
+
53
+ // EnableStoreSessionEvent may be set to true to enable the
54
+ // [QUICStoreSession] event for client connections.
55
+ // When this event is enabled, sessions are not automatically
56
+ // stored in the client session cache.
57
+ // The application should use [QUICConn.StoreSession] to store sessions.
58
+ EnableStoreSessionEvent bool
52
59
}
53
60
54
61
// A QUICEventKind is a type of operation on a QUIC connection.
@@ -87,10 +94,29 @@ const (
87
94
// QUICRejectedEarlyData indicates that the server rejected 0-RTT data even
88
95
// if we offered it. It's returned before QUICEncryptionLevelApplication
89
96
// keys are returned.
97
+ // This event only occurs on client connections.
90
98
QUICRejectedEarlyData
91
99
92
100
// QUICHandshakeDone indicates that the TLS handshake has completed.
93
101
QUICHandshakeDone
102
+
103
+ // QUICResumeSession indicates that a client is attempting to resume a previous session.
104
+ // [QUICEvent.SessionState] is set.
105
+ //
106
+ // For client connections, this event occurs when the session ticket is selected.
107
+ // For server connections, this event occurs when receiving the client's session ticket.
108
+ //
109
+ // The application may set [QUICEvent.SessionState.EarlyData] to false before the
110
+ // next call to [QUICConn.NextEvent] to decline 0-RTT even if the session supports it.
111
+ QUICResumeSession
112
+
113
+ // QUICStoreSession indicates that the server has provided state permitting
114
+ // the client to resume the session.
115
+ // [QUICEvent.SessionState] is set.
116
+ // The application should use [QUICConn.Store] session to store the [SessionState].
117
+ // The application may modify the [SessionState] before storing it.
118
+ // This event only occurs on client connections.
119
+ QUICStoreSession
94
120
)
95
121
96
122
// A QUICEvent is an event occurring on a QUIC connection.
@@ -109,6 +135,9 @@ type QUICEvent struct {
109
135
110
136
// Set for QUICSetReadSecret and QUICSetWriteSecret.
111
137
Suite uint16
138
+
139
+ // Set for QUICResumeSession and QUICStoreSession.
140
+ SessionState * SessionState
112
141
}
113
142
114
143
type quicState struct {
@@ -127,34 +156,39 @@ type quicState struct {
127
156
cancelc <- chan struct {} // handshake has been canceled
128
157
cancel context.CancelFunc
129
158
159
+ waitingForDrain bool
160
+
130
161
// readbuf is shared between HandleData and the handshake goroutine.
131
162
// HandshakeCryptoData passes ownership to the handshake goroutine by
132
163
// reading from signalc, and reclaims ownership by reading from blockedc.
133
164
readbuf []byte
134
165
135
166
transportParams []byte // to send to the peer
167
+
168
+ enableStoreSessionEvent bool
136
169
}
137
170
138
171
// QUICClient returns a new TLS client side connection using QUICTransport as the
139
172
// underlying transport. The config cannot be nil.
140
173
//
141
174
// The config's MinVersion must be at least TLS 1.3.
142
175
func QUICClient (config * QUICConfig ) * QUICConn {
143
- return newQUICConn (Client (nil , config .TLSConfig ))
176
+ return newQUICConn (Client (nil , config .TLSConfig ), config )
144
177
}
145
178
146
179
// QUICServer returns a new TLS server side connection using QUICTransport as the
147
180
// underlying transport. The config cannot be nil.
148
181
//
149
182
// The config's MinVersion must be at least TLS 1.3.
150
183
func QUICServer (config * QUICConfig ) * QUICConn {
151
- return newQUICConn (Server (nil , config .TLSConfig ))
184
+ return newQUICConn (Server (nil , config .TLSConfig ), config )
152
185
}
153
186
154
- func newQUICConn (conn * Conn ) * QUICConn {
187
+ func newQUICConn (conn * Conn , config * QUICConfig ) * QUICConn {
155
188
conn .quic = & quicState {
156
- signalc : make (chan struct {}),
157
- blockedc : make (chan struct {}),
189
+ signalc : make (chan struct {}),
190
+ blockedc : make (chan struct {}),
191
+ enableStoreSessionEvent : config .EnableStoreSessionEvent ,
158
192
}
159
193
conn .quic .events = conn .quic .eventArr [:0 ]
160
194
return & QUICConn {
@@ -190,6 +224,11 @@ func (q *QUICConn) NextEvent() QUICEvent {
190
224
// to catch callers erroniously retaining it.
191
225
qs .events [last ].Data [0 ] = 0
192
226
}
227
+ if qs .nextEvent >= len (qs .events ) && qs .waitingForDrain {
228
+ qs .waitingForDrain = false
229
+ <- qs .signalc
230
+ <- qs .blockedc
231
+ }
193
232
if qs .nextEvent >= len (qs .events ) {
194
233
qs .events = qs .events [:0 ]
195
234
qs .nextEvent = 0
@@ -255,6 +294,7 @@ func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
255
294
type QUICSessionTicketOptions struct {
256
295
// EarlyData specifies whether the ticket may be used for 0-RTT.
257
296
EarlyData bool
297
+ Extra [][]byte
258
298
}
259
299
260
300
// SendSessionTicket sends a session ticket to the client.
@@ -272,7 +312,25 @@ func (q *QUICConn) SendSessionTicket(opts QUICSessionTicketOptions) error {
272
312
return quicError (errors .New ("tls: SendSessionTicket called multiple times" ))
273
313
}
274
314
q .sessionTicketSent = true
275
- return quicError (c .sendSessionTicket (opts .EarlyData ))
315
+ return quicError (c .sendSessionTicket (opts .EarlyData , opts .Extra ))
316
+ }
317
+
318
+ // StoreSession stores a session previously received in a QUICStoreSession event
319
+ // in the ClientSessionCache.
320
+ // The application may process additional events or modify the SessionState
321
+ // before storing the session.
322
+ func (q * QUICConn ) StoreSession (session * SessionState ) error {
323
+ c := q .conn
324
+ if ! c .isClient {
325
+ return quicError (errors .New ("tls: StoreSessionTicket called on the server" ))
326
+ }
327
+ cacheKey := c .clientSessionCacheKey ()
328
+ if cacheKey == "" {
329
+ return nil
330
+ }
331
+ cs := & ClientSessionState {session : session }
332
+ c .config .ClientSessionCache .Put (cacheKey , cs )
333
+ return nil
276
334
}
277
335
278
336
// ConnectionState returns basic TLS details about the connection.
@@ -356,6 +414,27 @@ func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) {
356
414
last .Data = append (last .Data , data ... )
357
415
}
358
416
417
+ func (c * Conn ) quicResumeSession (session * SessionState ) error {
418
+ c .quic .events = append (c .quic .events , QUICEvent {
419
+ Kind : QUICResumeSession ,
420
+ SessionState : session ,
421
+ })
422
+ c .quic .waitingForDrain = true
423
+ for c .quic .waitingForDrain {
424
+ if err := c .quicWaitForSignal (); err != nil {
425
+ return err
426
+ }
427
+ }
428
+ return nil
429
+ }
430
+
431
+ func (c * Conn ) quicStoreSession (session * SessionState ) {
432
+ c .quic .events = append (c .quic .events , QUICEvent {
433
+ Kind : QUICStoreSession ,
434
+ SessionState : session ,
435
+ })
436
+ }
437
+
359
438
func (c * Conn ) quicSetTransportParameters (params []byte ) {
360
439
c .quic .events = append (c .quic .events , QUICEvent {
361
440
Kind : QUICTransportParameters ,
0 commit comments