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 module libhttp2.connector; 13 14 import libhttp2.types; 15 import libhttp2.frame; 16 import libhttp2.session; 17 18 19 public: 20 abstract class Connector 21 { 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 int write(in ubyte[] 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 ErrorCode writeData(in Frame frame, ubyte[] frame_hd, uint length); 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 int read(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 bool onStreamExit(int stream_id, FrameError error_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 bool onFrame(in Frame frame); 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 bool onFrameHeader(in FrameHeader hd); 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 bool onHeaders(in Frame frame); 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 bool onHeaderField(in Frame frame, HeaderField hf, ref bool pause, ref bool rst_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 bool onDataChunk(FrameFlags flags, int stream_id, in ubyte[] data, ref bool pause); 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 bool onInvalidFrame(in Frame frame, FrameError error_code, string reason = ""); 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 bool onFrameFailure(in Frame frame, ErrorCode error_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 bool onFrameReady(in Frame frame); 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 bool onFrameSent(in Frame frame); 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 int selectPaddingLength(in Frame frame, int max_payloadlen) 304 { 305 return frame.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 int maxFrameSize(FrameType frame_type, int stream_id, int session_remote_window_size, int stream_remote_window_size, uint remote_max_frame_size) 328 { 329 import std.algorithm : min; 330 return min(session_remote_window_size, stream_remote_window_size, remote_max_frame_size); 331 } 332 333 334 } 335 336 class CallbackConnector : Connector 337 { 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 int delegate(in ubyte[]) 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 ErrorCode delegate(in Frame, 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 int delegate(ubyte[]) read_cb; 360 361 /** 362 * Callback function invoked when the stream is closed. 363 */ 364 bool delegate(int, FrameError) on_stream_exit_cb; 365 366 /** 367 * Callback function invoked by $(D Session.recv) when a 368 * frame is received. 369 */ 370 bool delegate(in Frame) on_frame_cb; 371 372 /** 373 * Sets callback function invoked when a frame header is received. 374 */ 375 bool delegate(in FrameHeader) 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 bool delegate(in Frame) on_headers_cb; 382 383 /** 384 * Callback function invoked when a header name/value pair is 385 * received. 386 */ 387 bool delegate(in Frame, in HeaderField, ref bool, ref bool) on_header_field_cb; 388 389 /** 390 * Callback function invoked when a chunk of data in DATA frame is 391 * received. 392 */ 393 bool delegate(FrameFlags, int, in ubyte[], ref bool) 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 bool delegate(in Frame, 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 bool delegate(in Frame, ErrorCode) on_frame_failure_cb; 406 407 /** 408 * Callback function invoked before a non-DATA frame is sent. 409 */ 410 bool delegate(in Frame) on_frame_ready_cb; 411 412 /** 413 * Callback function invoked after a frame is sent. 414 */ 415 bool delegate(in Frame) 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 int delegate(in Frame, int) select_padding_length_cb; 423 424 /** 425 * The callback function used to determine the length allowed in 426 * $(D DataProvider) 427 */ 428 int delegate(FrameType, int, int, int, uint) max_frame_size_cb; 429 430 ///////////////// Derived ////////////////// 431 override: 432 int write(in ubyte[] data) 433 { 434 if (!write_cb) 435 return true; 436 return write_cb(data); 437 } 438 439 ErrorCode writeData(in Frame frame, ubyte[] frame_hd, uint length) 440 { 441 if (!write_data_cb) 442 return ErrorCode.OK; 443 return write_data_cb(frame, frame_hd, length); 444 } 445 446 447 int read(ubyte[] data) 448 { 449 if (!read_cb) 450 return true; 451 return read_cb(data); 452 } 453 454 bool onStreamExit(int stream_id, FrameError error_code) 455 { 456 if (!on_stream_exit_cb) 457 return true; 458 return on_stream_exit_cb(stream_id, error_code); 459 } 460 461 bool onFrame(in Frame frame) 462 { 463 if (!on_frame_cb) 464 return true; 465 return on_frame_cb(frame); 466 } 467 468 bool onFrameHeader(in FrameHeader hd) 469 { 470 if (!on_frame_header_cb) 471 return true; 472 return on_frame_header_cb(hd); 473 } 474 475 bool onHeaders(in Frame frame) 476 { 477 if (!on_headers_cb) 478 return true; 479 return on_headers_cb(frame); 480 } 481 482 bool onHeaderField(in Frame frame, HeaderField hf, ref bool pause, ref bool rst_stream) 483 { 484 if (!on_header_field_cb) 485 return true; 486 return on_header_field_cb(frame, hf, pause, rst_stream); 487 } 488 489 bool onDataChunk(FrameFlags flags, int stream_id, in ubyte[] data, ref bool pause) 490 { 491 if (!on_data_chunk_cb) 492 return true; 493 return on_data_chunk_cb(flags, stream_id, data, pause); 494 } 495 496 bool onInvalidFrame(in Frame frame, FrameError error_code, string reason) 497 { 498 if (!on_invalid_frame_cb) 499 return true; 500 return on_invalid_frame_cb(frame, error_code); 501 } 502 503 bool onFrameFailure(in Frame frame, ErrorCode error_code) 504 { 505 if (!on_frame_failure_cb) 506 return true; 507 return on_frame_failure_cb(frame, error_code); 508 } 509 510 bool onFrameReady(in Frame frame) 511 { 512 if (!on_frame_ready_cb) 513 return true; 514 return on_frame_ready_cb(frame); 515 } 516 517 bool onFrameSent(in Frame frame) 518 { 519 if (!on_frame_sent_cb) 520 return true; 521 return on_frame_sent_cb(frame); 522 } 523 524 int selectPaddingLength(in Frame frame, int max_payloadlen) 525 { 526 if (!select_padding_length_cb) 527 return super.selectPaddingLength(frame, max_payloadlen); 528 return select_padding_length_cb(frame, max_payloadlen); 529 } 530 531 int maxFrameSize(FrameType frame_type, int stream_id, int session_remote_window_size, int stream_remote_window_size, uint remote_max_frame_size) 532 { 533 if (!max_frame_size_cb) 534 return super.maxFrameSize(frame_type, stream_id, session_remote_window_size, stream_remote_window_size, remote_max_frame_size); 535 return max_frame_size_cb(frame_type, stream_id, session_remote_window_size, stream_remote_window_size, remote_max_frame_size); 536 } 537 538 }