1 /**
2 * Connector
3 *
4 * Copyright:
5 * (C) 2012-2015 Tatsuhiro Tsujikawa
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Distributed under the terms of the MIT license with an additional section 1.2 of the curl/libcurl project.
10 * Consult the provided LICENSE.md file for details
11 */12 modulelibhttp2.connector;
13 14 importlibhttp2.types;
15 importlibhttp2.frame;
16 importlibhttp2.session;
17 18 19 public:
20 abstractclassConnector21 {
22 public:
23 ////////////////// Protocol ////////////////////////24 25 /**
26 * Callback function invoked when Session wants to send data to the
27 * remote peer. The implementation of this function must send at most
28 * |data.length| bytes of data stored in |data|.
29 * It must return the number of bytes sent if
30 * it succeeds. If it cannot send any single byte without blocking,
31 * it must return $(D ErrorCode.WOULDBLOCK). For other errors,
32 * it must return $(D ErrorCode.CALLBACK_FAILURE).
33 *
34 * This callback is required if the application uses
35 * $(D Session.send) to send data to the remote endpoint. If
36 * the application uses solely $(D Session.memSend) instead,
37 * this callback function is unnecessary.
38 */39 intwrite(inubyte[] data);
40 /**
41 * Callback function invoked when `DataFlags.NO_COPY` is
42 * used in `DataProvider` to send complete DATA frame.
43 *
44 * The |frame| is a DATA frame to send. The |framehd| is the
45 * serialized frame header (9 bytes). The |length| is the length of
46 * application data to send (this does not include padding). The
47 * |source| is the same pointer passed to `DataProvider`.
48 *
49 * The application first must send frame header |framehd| of length 9
50 * bytes. If `frame->padlen > 0`, send 1 byte of value
51 * `frame->padlen - 1`. Then send exactly |length| bytes of
52 * application data. Finally, if `frame->padlen > 0`, send
53 * `frame->padlen - 1` bytes of zero (they are padding).
54 *
55 * The application has to send complete DATA frame in this callback.
56 * If all data were written successfully, return 0.
57 *
58 * If it cannot send it all, just return
59 * `ErrorCode.WOULDBLOCK`, the library will call this callback
60 * with the same parameters later (It is recommended to send complete
61 * DATA frame at once in this function to deal with error; if partial
62 * frame data has already sent, it is impossible to send another data
63 * in that state, and all we can do is tear down connection). If
64 * application decided to reset this stream, return
65 * `ErrorCode.TEMPORAL_CALLBACK_FAILURE`, then the library
66 * will send RST_STREAM with INTERNAL_ERROR as error code. The
67 * application can also return `ErrorCode.CALLBACK_FAILURE`,
68 * which will result in connection closure. Returning any other value
69 * is treated as if `ErrorCode.CALLBACK_FAILURE` was returned.
70 */71 ErrorCodewriteData(inFrameframe, ubyte[] frame_hd, uintlength);
72 73 /**
74 * Callback function invoked when Session wants to receive data from
75 * the remote peer. The implementation of this function must read at
76 * most |data.length| bytes of data and store it in |data|.
77 *
78 * It must return the number of
79 * bytes written in |buf| if it succeeds. If it cannot read any
80 * single byte without blocking, it must return
81 * $(D ErrorCode.WOULDBLOCK). If it gets EOF before it reads any
82 * single byte, it must return $(D ErrorCode.EOF). For other
83 * errors, it must return $(D ErrorCode.CALLBACK_FAILURE).
84 * Returning 0 is treated as $(D ErrorCode.WOULDBLOCK).
85 *
86 * This callback is required if the application uses
87 * $(D Session.recv) to receive data from the remote endpoint.
88 * If the application uses solely `http2_session_mem_recv()`
89 * instead, this callback function is unnecessary.
90 */91 intread(ubyte[] data);
92 93 /**
94 * Callback function invoked when the stream |stream_id| is closed.
95 * The reason of closure is indicated by the |error_code|. The
96 * |error_code| is usually one of $(D FrameError), but that
97 * is not guaranteed.
98 *
99 * This function is also called for a stream in reserved state.
100 *
101 * If this callback returns false, it is treated as fatal error and
102 * $(D Session.recv) and $(D Session.send) functions
103 * immediately return $(D ErrorCode.CALLBACK_FAILURE).
104 */105 boolonStreamExit(intstream_id, FrameErrorerror_code);
106 107 /////////////////// Receiving ////////////////////////108 109 /**
110 * Callback function invoked by $(D Session.recv) when a frame
111 * is received. The |user_data| pointer is the third argument passed
112 * in to the call to `http2_session_client_new()` or
113 * `http2_session_server_new()`.
114 *
115 * If frame is HEADERS or PUSH_PROMISE, the ``nva``
116 * member of their data structure are always ``NULL`` and 0
117 * respectively. The header fields are emitted via
118 * $(D onFrameHeader).
119 *
120 * For HEADERS, PUSH_PROMISE and DATA frames, this callback may be
121 * called after stream is closed (see $(D Connector.onStreamExit)).
122 *
123 * Only HEADERS and DATA frame can signal the end of incoming data.
124 * If ``frame.hd.flags & FrameFlags.END_STREAM`` is nonzero, the
125 * |frame| is the last frame from the remote peer in this stream.
126 *
127 * This callback won't be called for CONTINUATION frames.
128 * HEADERS/PUSH_PROMISE + CONTINUATIONs are treated as single frame.
129 *
130 * If false value is returned, it is treated as fatal error and
131 * $(D Session.recv) and $(D Session.memRecv) functions
132 * immediately return $(D ErrorCode.CALLBACK_FAILURE).
133 */134 boolonFrame(inFrameframe);
135 136 /**
137 * Callback function invoked when a frame header is received. The
138 * |hd| points to received frame header.
139 *
140 * Unlike $(D Connector.onFrame), this callback will
141 * also be called when frame header of CONTINUATION frame is received.
142 *
143 * If both $(D Connector.onFrameHeader) and
144 * $(D Connector.onHeaders) are set and HEADERS or
145 * PUSH_PROMISE is received, $(D Connector.onFrameReady)
146 * will be called first.
147 *
148 * The implementation of this function must return true if it succeeds.
149 * If false value is returned, it is treated as fatal error and
150 * $(D Session.recv) and `http2_session_mem_recv()` functions
151 * immediately return $(D ErrorCode.CALLBACK_FAILURE).
152 */153 boolonFrameHeader(inFrameHeaderhd);
154 155 /**
156 * Callback function invoked when the reception of header block in
157 * HEADERS or PUSH_PROMISE is started. Each header header field
158 * will be emitted by $(D Connector.onHeaderField)`.
159 *
160 * The ``frame.hd.flags`` may not have
161 * $(D FrameFlags.END_HEADERS) flag set, which indicates that one
162 * or more CONTINUATION frames are involved. But the application does
163 * not need to care about that because the header fields are
164 * emitted transparently regardless of CONTINUATION frames.
165 *
166 * If this callback returns false, stream fails with `ErrorCode.CALLBACK_FAILURE`
167 */168 boolonHeaders(inFrameframe);
169 170 171 /**
172 * Callback function invoked when a header header field is received
173 * for the |frame|. The |hf.name| of length |hf.name.length| is header name.
174 * The |hf.value| of length |hf.value.length| is header value. The |hf.flags|
175 * is a $(D HeaderFlag).
176 *
177 * If $(D HeaderFlag.NO_INDEX) is set in |hf.flags|, the receiver
178 * must not index this header field when forwarding it to the next
179 * hop. More specifically, "Literal Header Field never Indexed"
180 * representation must be used in HPACK encoding.
181 *
182 * When this callback is invoked, $(D frame.hd.type) is either
183 * $(D FrameFlags.HEADERS) or $(D FrameFlags.PUSH_PROMISE). After all
184 * header fields are processed with this callback, and no
185 * error has been detected, $(D Connector.onFrame) will be invoked.
186 * If there is an error in decompression, $(D Connector.onFrame) for the |frame|
187 * will not be invoked.
188 *
189 * The |value| may be null if the |value.length| is 0.
190 *
191 * Please note that unless `setNoHTTPMessaging()` is
192 * used, nghttp2 library does perform validation against |hf.name|
193 * and |hf.value| using `hf.validateName()` and
194 * `hf.validateValue()`. In addition to this, libhttp2
195 * performs vaidation based on HTTP Messaging rule, which is briefly
196 * explained in `HTTP Messaging`_ section.
197 *
198 * If the application uses $(D Session.memRecv), it can enable
199 * $(D pause) to make $(D Session.memRecv) return without processing
200 * further input bytes. The memory pointed by |frame|, |name| and |value|
201 * parameters are retained until $(D Session.memRecv) or $(D Session.recv) is called.
202 * The application must retain the input bytes which was used to
203 * produce these parameters, because it may refer to the memory region
204 * included in the input bytes.
205 *
206 * Enabling $(D rst_stream) will close the stream by issuing RST_STREAM with
207 * $(D FrameError.INTERNAL_ERROR). In this case, $(D Connector.onFrame) will
208 * not be invoked. If a different error code is desirable, use
209 * $(D submitRstStream) with a desired error code and then
210 * set $(D rst_stream) to true.
211 *
212 * The implementation of this function must return true if it succeeds.
213 * If false is returned, it is treated as $(D ErrorCode.CALLBACK_FAILURE) and
214 * in this case, $(D Session.recv) or $(D Session.memRecv) functions immediately
215 * return $(D ErrorCode.CALLBACK_FAILURE).
216 */217 boolonHeaderField(inFrameframe, HeaderFieldhf, refboolpause, refboolrst_stream);
218 219 /**
220 * Callback function invoked when a chunk of data in DATA frame is
221 * received. The |stream_id| is the stream this DATA frame belongs
222 * to. The |flags| is the flags of DATA frame which this data chunk
223 * is contained. ``(flags & FrameFlags.END_STREAM) != 0`` does not
224 * necessarily mean this chunk of data is the last one in the stream.
225 * You should use $(D Connector.onFrame) to determine that all data
226 * frames are received.
227 *
228 *
229 * The memory pointed by the |data| is not copied within $(D Session.memRecv)
230 * or $(D Session.recv), so the data provider controls its lifetime. This
231 * can be either $(D Connector.read) for $(D Session.recv), or a $(D ubyte[])
232 * slice from the one provided to $(D Session.memRecv)
233 *
234 * If the application uses $(D Session.memRecv), it can set |pause|
235 * to make $(D Session.memRecv) return without processing further input bytes.
236 *
237 * If the function returns false, $(D Session.memRecv) or $(D Session.recv)
238 * would return with $(D ErrorCode.CALLBACK_FAILURE).
239 */240 boolonDataChunk(FrameFlagsflags, intstream_id, inubyte[] data, refboolpause);
241 242 /**
243 * Callback function invoked by $(D Session.recv) when an
244 * invalid non-DATA frame is received. The |error_code| indicates the
245 * error. It is usually one of the $(D FrameError) but
246 * that is not guaranteed. When this callback function is invoked,
247 * the library automatically submits either RST_STREAM or GOAWAY
248 * frame.
249 *
250 * If frame is HEADERS or PUSH_PROMISE, the ``hfa``
251 * member of thee data structure is always ``null``
252 *
253 * If this callback returns false, it is treated as fatal error and
254 * $(D Session.recv) and $(D Session.send) functions
255 * immediately return $(D ErrorCode.CALLBACK_FAILURE).
256 */257 boolonInvalidFrame(inFrameframe, FrameErrorerror_code, stringreason = "");
258 259 /////////////////// Sending /////////////////////////260 261 /**
262 * Callback function invoked after the non-DATA frame |frame| is not
263 * sent because of the error. The error is indicated by the
264 * |error_code|, which is one of the values defined in
265 * $(D ErrorCode).
266 *
267 * If this callback returns false, it is treated as fatal error and
268 * $(D Session.recv) and $(D Session.send) functions
269 * immediately return $(D ErrorCode.CALLBACK_FAILURE).
270 */271 boolonFrameFailure(inFrameframe, ErrorCodeerror_code);
272 273 /**
274 * Callback function invoked just before the non-DATA frame |frame| is
275 * sent.
276 *
277 * The implementation of this function must return true if it succeeds.
278 * If this callback returns false, it is treated as fatal error and
279 * $(D Session.recv) and $(D Session.send) functions
280 * immediately return $(D ErrorCode.CALLBACK_FAILURE).
281 */282 boolonFrameReady(inFrameframe);
283 284 /**
285 * Callback function invoked after the frame |frame| is sent.
286 *
287 * If this callback returns false, it is treated as fatal error and
288 * $(D Session.recv) and $(D Session.send) functions
289 * immediately return $(D ErrorCode.CALLBACK_FAILURE).
290 */291 boolonFrameSent(inFrameframe);
292 293 /**
294 * Callback function invoked when the library asks application how
295 * many padding bytes are required for the transmission of the
296 * |frame|. The application must choose the total length of payload
297 * including padded bytes in range [frame.hd.length, max_payloadlen],
298 * inclusive. Choosing number not in this range will be treated as
299 * $(D ErrorCode.CALLBACK_FAILURE). Returning ``frame.hd.length``
300 * means no padding is added. Returning $(D ErrorCode.CALLBACK_FAILURE) will make
301 * $(D Session.send()) function immediately return $(D ErrorCode.CALLBACK_FAILURE).
302 */303 intselectPaddingLength(inFrameframe, intmax_payloadlen)
304 {
305 returnframe.hd.length;
306 }
307 308 /**
309 * Callback function invoked when library wants to get max length of
310 * data to send data to the remote peer. The implementation of this
311 * function should return a value in the following range. [1,
312 * min(|session_remote_window_size|, |stream_remote_window_size|,
313 * |remote_max_frame_size|)]. If a value greater than this range is
314 * returned than the max allow value will be used. Returning a value
315 * smaller than this range is treated as
316 * $(D ErrorCode.CALLBACK_FAILURE). The |frame_type| is provided
317 * for future extensibility and identifies the type of frame (see
318 * $(D FrameType)) for which to get the length for.
319 * Currently supported frame types are: $(D HTTP2_DATA).
320 *
321 * This callback can be used to control the length in bytes for which
322 * $(D DataProvider) is allowed to send to the
323 * remote endpoint. This callback is optional. Returning
324 * $(D ErrorCode.CALLBACK_FAILURE) will signal the entire session
325 * failure..
326 */327 intmaxFrameSize(FrameTypeframe_type, intstream_id, intsession_remote_window_size, intstream_remote_window_size, uintremote_max_frame_size)
328 {
329 importstd.algorithm : min;
330 returnmin(session_remote_window_size, stream_remote_window_size, remote_max_frame_size);
331 }
332 333 334 }
335 336 classCallbackConnector : Connector337 {
338 public:
339 /**
340 * Callback function invoked when the session wants to send data to
341 * the remote peer. This callback is not necessary if the
342 * application uses solely $(D Session.memSend) to serialize
343 * data to transmit.
344 */345 intdelegate(inubyte[]) write_cb;
346 347 /**
348 * Callback function invoked when $(D DataFlags.NO_COPY) is used in $(D DataProvider)
349 * to avoid data copy.
350 */351 ErrorCodedelegate(inFrame, ubyte[], uint) write_data_cb;
352 353 /**
354 * Callback function invoked when the session wants to receive data
355 * from the remote peer. This callback is not necessary if the
356 * application uses solely `nghttp2_session_mem_recv()` to process
357 * received data.
358 */359 intdelegate(ubyte[]) read_cb;
360 361 /**
362 * Callback function invoked when the stream is closed.
363 */364 booldelegate(int, FrameError) on_stream_exit_cb;
365 366 /**
367 * Callback function invoked by $(D Session.recv) when a
368 * frame is received.
369 */370 booldelegate(inFrame) on_frame_cb;
371 372 /**
373 * Sets callback function invoked when a frame header is received.
374 */375 booldelegate(inFrameHeader) on_frame_header_cb;
376 377 /**
378 * Callback function invoked when the reception of header block in
379 * HEADERS or PUSH_PROMISE is started.
380 */381 booldelegate(inFrame) on_headers_cb;
382 383 /**
384 * Callback function invoked when a header name/value pair is
385 * received.
386 */387 booldelegate(inFrame, inHeaderField, refbool, refbool) on_header_field_cb;
388 389 /**
390 * Callback function invoked when a chunk of data in DATA frame is
391 * received.
392 */393 booldelegate(FrameFlags, int, inubyte[], refbool) on_data_chunk_cb;
394 395 /**
396 * Callback function invoked by $(D Session.recv) when an
397 * invalid non-DATA frame is received.
398 */399 booldelegate(inFrame, FrameError) on_invalid_frame_cb;
400 401 /**
402 * The callback function invoked when a non-DATA frame is not sent
403 * because of an error.
404 */405 booldelegate(inFrame, ErrorCode) on_frame_failure_cb;
406 407 /**
408 * Callback function invoked before a non-DATA frame is sent.
409 */410 booldelegate(inFrame) on_frame_ready_cb;
411 412 /**
413 * Callback function invoked after a frame is sent.
414 */415 booldelegate(inFrame) on_frame_sent_cb;
416 417 /**
418 * Callback function invoked when the library asks application how
419 * many padding bytes are required for the transmission of the given
420 * frame.
421 */422 intdelegate(inFrame, int) select_padding_length_cb;
423 424 /**
425 * The callback function used to determine the length allowed in
426 * $(D DataProvider)
427 */428 intdelegate(FrameType, int, int, int, uint) max_frame_size_cb;
429 430 ///////////////// Derived //////////////////431 override:
432 intwrite(inubyte[] data)
433 {
434 if (!write_cb)
435 returntrue;
436 returnwrite_cb(data);
437 }
438 439 ErrorCodewriteData(inFrameframe, ubyte[] frame_hd, uintlength)
440 {
441 if (!write_data_cb)
442 returnErrorCode.OK;
443 returnwrite_data_cb(frame, frame_hd, length);
444 }
445 446 447 intread(ubyte[] data)
448 {
449 if (!read_cb)
450 returntrue;
451 returnread_cb(data);
452 }
453 454 boolonStreamExit(intstream_id, FrameErrorerror_code)
455 {
456 if (!on_stream_exit_cb)
457 returntrue;
458 returnon_stream_exit_cb(stream_id, error_code);
459 }
460 461 boolonFrame(inFrameframe)
462 {
463 if (!on_frame_cb)
464 returntrue;
465 returnon_frame_cb(frame);
466 }
467 468 boolonFrameHeader(inFrameHeaderhd)
469 {
470 if (!on_frame_header_cb)
471 returntrue;
472 returnon_frame_header_cb(hd);
473 }
474 475 boolonHeaders(inFrameframe)
476 {
477 if (!on_headers_cb)
478 returntrue;
479 returnon_headers_cb(frame);
480 }
481 482 boolonHeaderField(inFrameframe, HeaderFieldhf, refboolpause, refboolrst_stream)
483 {
484 if (!on_header_field_cb)
485 returntrue;
486 returnon_header_field_cb(frame, hf, pause, rst_stream);
487 }
488 489 boolonDataChunk(FrameFlagsflags, intstream_id, inubyte[] data, refboolpause)
490 {
491 if (!on_data_chunk_cb)
492 returntrue;
493 returnon_data_chunk_cb(flags, stream_id, data, pause);
494 }
495 496 boolonInvalidFrame(inFrameframe, FrameErrorerror_code, stringreason)
497 {
498 if (!on_invalid_frame_cb)
499 returntrue;
500 returnon_invalid_frame_cb(frame, error_code);
501 }
502 503 boolonFrameFailure(inFrameframe, ErrorCodeerror_code)
504 {
505 if (!on_frame_failure_cb)
506 returntrue;
507 returnon_frame_failure_cb(frame, error_code);
508 }
509 510 boolonFrameReady(inFrameframe)
511 {
512 if (!on_frame_ready_cb)
513 returntrue;
514 returnon_frame_ready_cb(frame);
515 }
516 517 boolonFrameSent(inFrameframe)
518 {
519 if (!on_frame_sent_cb)
520 returntrue;
521 returnon_frame_sent_cb(frame);
522 }
523 524 intselectPaddingLength(inFrameframe, intmax_payloadlen)
525 {
526 if (!select_padding_length_cb)
527 returnsuper.selectPaddingLength(frame, max_payloadlen);
528 returnselect_padding_length_cb(frame, max_payloadlen);
529 }
530 531 intmaxFrameSize(FrameTypeframe_type, intstream_id, intsession_remote_window_size, intstream_remote_window_size, uintremote_max_frame_size)
532 {
533 if (!max_frame_size_cb)
534 returnsuper.maxFrameSize(frame_type, stream_id, session_remote_window_size, stream_remote_window_size, remote_max_frame_size);
535 returnmax_frame_size_cb(frame_type, stream_id, session_remote_window_size, stream_remote_window_size, remote_max_frame_size);
536 }
537 538 }