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