LCOV - code coverage report
Current view: top level - waltz/h2 - fd_hpack_wr.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 84 86 97.7 %
Date: 2025-07-01 05:00:49 Functions: 11 20 55.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_waltz_h2_fd_hpack_wr_h
       2             : #define HEADER_fd_src_waltz_h2_fd_hpack_wr_h
       3             : 
       4             : /* fd_hpack_wr.h provides simple APIs to generate HPACK header entries.
       5             :    Generates somewhat wasteful serializations, but is quite simple. */
       6             : 
       7             : #include "fd_h2_base.h"
       8             : #include "fd_h2_rbuf.h"
       9             : 
      10          12 : #define FD_HPACK_INDEXED_SHORT( val ) ((uchar)( 0x80|(val) ))
      11             : 
      12             : #if FD_HAS_X86
      13             : #include <immintrin.h>
      14             : #endif
      15             : 
      16             : FD_PROTOTYPES_BEGIN
      17             : 
      18             : static inline ulong
      19             : fd_hpack_wr_varint(
      20             :     uchar code[9],
      21             :     uint  prefix,
      22             :     uint  addend,
      23             :     ulong number /* in [0,2^56) */
      24          57 : ) {
      25          57 :   ulong sz;
      26          57 :   if( number<addend ) {
      27          42 :     code[0] = (uchar)( prefix|number );
      28          42 :     sz = 1UL;
      29          42 :   } else {
      30          15 :     code[0] = (uchar)( prefix|addend );
      31          15 :     ulong tail = number-addend;
      32          15 : #if FD_HAS_X86 && defined(__BMI2__)
      33          15 :     ulong enc = _pdep_u64( tail, 0x7f7f7f7f7f7f7f7fUL );
      34             : #else
      35             :     ulong enc =
      36             :       ( ( tail<<0 )&0x000000000000007fUL ) |
      37             :       ( ( tail<<1 )&0x0000000000007f00UL ) |
      38             :       ( ( tail<<2 )&0x00000000007f0000UL ) |
      39             :       ( ( tail<<3 )&0x000000007f000000UL ) |
      40             :       ( ( tail<<4 )&0x0000007f00000000UL ) |
      41             :       ( ( tail<<5 )&0x00007f0000000000UL ) |
      42             :       ( ( tail<<6 )&0x007f000000000000UL ) |
      43             :       ( ( tail<<7 )&0x7f00000000000000UL );
      44             : #endif
      45          15 :     int   msb   = fd_ulong_find_msb_w_default( enc, 0 );
      46          15 :     int   shift = 64-(msb&0x38);
      47          15 :     ulong mask  = shift==64 ? 0UL : 0x8080808080808080UL>>shift;
      48          15 :     FD_STORE( ulong, code+1, enc|mask );
      49          15 :     sz = 2 + (ulong)( msb>>3 );
      50          15 :   }
      51          57 :   return sz;
      52          57 : }
      53             : 
      54             : static inline int
      55             : fd_hpack_wr_private_indexed( fd_h2_rbuf_t * rbuf_tx,
      56          12 :                              ulong          idx ) {
      57          12 :   if( FD_UNLIKELY( !fd_h2_rbuf_free_sz( rbuf_tx ) ) ) return 0;
      58          12 :   uchar code[1] = { FD_HPACK_INDEXED_SHORT( idx ) };
      59          12 :   fd_h2_rbuf_push( rbuf_tx, code, 1 );
      60          12 :   return 1;
      61          12 : }
      62             : 
      63             : static inline int
      64             : fd_hpack_wr_private_name_indexed_0(
      65             :     fd_h2_rbuf_t * rbuf_tx,
      66             :     ulong          key,
      67             :     ulong          value_len  /* in [0,128) */
      68          12 : ) {
      69          12 :   uchar prefix[10] = { (uchar)key };
      70          12 :   if( FD_UNLIKELY( fd_h2_rbuf_free_sz( rbuf_tx ) < sizeof(prefix)+value_len ) ) return 0;
      71          12 :   ulong prefix_len = 1+fd_hpack_wr_varint( prefix+1, 0x00, 0x7f, value_len );
      72          12 :   fd_h2_rbuf_push( rbuf_tx, prefix, prefix_len );
      73          12 :   return 1;
      74          12 : }
      75             : 
      76             : static inline int
      77           6 : fd_hpack_wr_method_post( fd_h2_rbuf_t * rbuf_tx ) {
      78           6 :   return fd_hpack_wr_private_indexed( rbuf_tx, 0x03 );
      79           6 : }
      80             : 
      81             : static inline int
      82             : fd_hpack_wr_scheme( fd_h2_rbuf_t * rbuf_tx,
      83           6 :                     int            is_https ) {
      84           6 :   if( is_https ) {
      85           6 :     return fd_hpack_wr_private_indexed( rbuf_tx, 0x07 );
      86           6 :   } else {
      87           0 :     return fd_hpack_wr_private_indexed( rbuf_tx, 0x06 );
      88           0 :   }
      89           6 : }
      90             : 
      91             : /* fd_hpack_wr_path writes a ':path: ...' header.  path_len must be in
      92             :    [0,128). */
      93             : 
      94             : static inline int
      95             : fd_hpack_wr_path( fd_h2_rbuf_t * rbuf_tx,
      96             :                   char const *   path,
      97           6 :                   ulong          path_len ) {
      98           6 :   if( FD_UNLIKELY( !fd_hpack_wr_private_name_indexed_0( rbuf_tx, 0x04, path_len ) ) ) return 0;
      99           6 :   fd_h2_rbuf_push( rbuf_tx, path, path_len );
     100           6 :   return 1;
     101           6 : }
     102             : 
     103             : /* fd_hpack_wr_trailers writes the 'te: trailers' header. */
     104             : 
     105             : static inline int
     106           6 : fd_hpack_wr_trailers( fd_h2_rbuf_t * rbuf_tx ) {
     107           6 :   static char const code[] =
     108           6 :     "\x00"
     109           6 :     "\x02" "te"
     110           6 :     "\x08" "trailers";
     111           6 :   if( FD_UNLIKELY( fd_h2_rbuf_free_sz( rbuf_tx )<sizeof(code)-1 ) ) return 0;
     112           6 :   fd_h2_rbuf_push( rbuf_tx, code, sizeof(code)-1 );
     113           6 :   return 1;
     114           6 : }
     115             : 
     116             : /* fd_hpack_wr_user_agent writes a 'user-agent' header.
     117             :    user_agent_len is in [0,128). */
     118             : 
     119             : static inline int
     120             : fd_hpack_wr_user_agent( fd_h2_rbuf_t * rbuf_tx,
     121           6 :                         ulong          user_agent_len ) {
     122           6 :   return fd_hpack_wr_private_name_indexed_0( rbuf_tx, 0x7a, user_agent_len );
     123           6 : }
     124             : 
     125             : /* fd_hpack_wr_auth_bearer writes an 'authorization: Bearer xxx' header.
     126             :    Uses a never-indexed literal to prevent compression attacks. */
     127             : 
     128             : static inline int
     129             : fd_hpack_wr_auth_bearer( fd_h2_rbuf_t * rbuf_tx,
     130             :                          char const *   auth_token,
     131           3 :                          ulong          auth_token_len ) {
     132           3 :   uchar prefix[11] = { 0x1f, 0x08 };
     133           3 :   ulong value_len = 7UL+auth_token_len;
     134           3 :   if( FD_UNLIKELY( fd_h2_rbuf_free_sz( rbuf_tx ) < sizeof(prefix)+value_len ) ) return 0;
     135           3 :   ulong prefix_len = 2+fd_hpack_wr_varint( prefix+2, 0x00, 0x7f, value_len );
     136           3 :   fd_h2_rbuf_push( rbuf_tx, prefix,     prefix_len     );
     137           3 :   fd_h2_rbuf_push( rbuf_tx, "Bearer ",  7              );
     138           3 :   fd_h2_rbuf_push( rbuf_tx, auth_token, auth_token_len );
     139           3 :   return 1;
     140           3 : }
     141             : 
     142             : /* fd_hpack_wr_authority writes an ':authority: host[:port]' header.
     143             :    Port is only specified if it is non-zero. */
     144             : 
     145             : static inline int
     146             : fd_hpack_wr_authority( fd_h2_rbuf_t * rbuf_tx,
     147             :                        char const *   host,
     148             :                        ulong          host_len,
     149           6 :                        ushort         port ) {
     150           6 :   char suffix_cstr[ 7 ];
     151           6 :   ulong port_cstr_len = fd_ushort_base10_dig_cnt( port );
     152           6 :   char * p = fd_cstr_init( suffix_cstr );
     153           6 :   p = fd_cstr_append_char( p, ':' );
     154           6 :   p = fd_cstr_append_ushort_as_text( p, 0, 0, port, port_cstr_len );
     155           6 :   ulong suffix_len = (ulong)p - (ulong)suffix_cstr;
     156           6 :   fd_cstr_fini( p );
     157             : 
     158             :   //if( !port ) suffix_len = 0;
     159           6 :   ulong value_len  = host_len+suffix_len;
     160             : 
     161           6 :   uchar prefix[10] = { (uchar)0x01 };
     162           6 :   if( FD_UNLIKELY( fd_h2_rbuf_free_sz( rbuf_tx ) < sizeof(prefix)+value_len ) ) return 0;
     163           6 :   ulong prefix_len = 1+fd_hpack_wr_varint( prefix+1, 0x00, 0x7f, value_len );
     164           6 :   fd_h2_rbuf_push( rbuf_tx, prefix,      prefix_len );
     165           6 :   fd_h2_rbuf_push( rbuf_tx, host,        host_len   );
     166           6 :   fd_h2_rbuf_push( rbuf_tx, suffix_cstr, suffix_len );
     167           6 :   return 1;
     168           6 : }
     169             : 
     170             : FD_PROTOTYPES_END
     171             : 
     172             : #endif /* HEADER_fd_src_waltz_h2_fd_hpack_wr_h */

Generated by: LCOV version 1.14