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 18 : #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 18 : ) {
29 18 : ulong sz;
30 18 : if( number<addend ) {
31 18 : code[0] = (uchar)( prefix|number );
32 18 : sz = 1UL;
33 18 : } else {
34 0 : code[0] = (uchar)( prefix|addend );
35 0 : ulong tail = number-addend;
36 0 : #if FD_HAS_X86 && defined(__BMI2__)
37 0 : 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 0 : int msb = fd_ulong_find_msb_w_default( enc, 0 );
50 0 : int shift = 64-(msb&0x38);
51 0 : ulong mask = shift==64 ? 0UL : 0x8080808080808080UL>>shift;
52 0 : FD_STORE( ulong, code+1, enc|mask );
53 0 : sz = 2 + (ulong)( msb>>3 );
54 0 : }
55 18 : return sz;
56 18 : }
57 :
58 : static inline int
59 : fd_hpack_wr_private_indexed( fd_h2_rbuf_t * rbuf_tx,
60 18 : ulong idx ) {
61 18 : if( FD_UNLIKELY( !fd_h2_rbuf_free_sz( rbuf_tx ) ) ) return 0;
62 18 : uchar code[1] = { FD_HPACK_INDEXED_SHORT( idx ) };
63 18 : fd_h2_rbuf_push( rbuf_tx, code, 1 );
64 18 : return 1;
65 18 : }
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 18 : ) {
73 18 : uchar prefix[10] = { (uchar)key };
74 18 : if( FD_UNLIKELY( fd_h2_rbuf_free_sz( rbuf_tx ) < sizeof(prefix)+value_len ) ) return 0;
75 18 : ulong prefix_len = 1+fd_hpack_wr_varint( prefix+1, 0x00, 0x7f, value_len );
76 18 : fd_h2_rbuf_push( rbuf_tx, prefix, prefix_len );
77 18 : return 1;
78 18 : }
79 :
80 : static inline int
81 9 : fd_hpack_wr_method_post( fd_h2_rbuf_t * rbuf_tx ) {
82 9 : return fd_hpack_wr_private_indexed( rbuf_tx, 0x03 );
83 9 : }
84 :
85 : static inline int
86 : fd_hpack_wr_scheme( fd_h2_rbuf_t * rbuf_tx,
87 9 : int is_https ) {
88 9 : if( is_https ) {
89 9 : return fd_hpack_wr_private_indexed( rbuf_tx, 0x07 );
90 9 : } else {
91 0 : return fd_hpack_wr_private_indexed( rbuf_tx, 0x06 );
92 0 : }
93 9 : }
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 9 : ulong path_len ) {
102 9 : if( FD_UNLIKELY( !fd_hpack_wr_private_name_indexed_0( rbuf_tx, 0x04, path_len ) ) ) return 0;
103 9 : fd_h2_rbuf_push( rbuf_tx, path, path_len );
104 9 : return 1;
105 9 : }
106 :
107 : /* fd_hpack_wr_trailers writes the 'te: trailers' header. */
108 :
109 : static inline int
110 9 : fd_hpack_wr_trailers( fd_h2_rbuf_t * rbuf_tx ) {
111 9 : static char const code[] =
112 9 : "\x00"
113 9 : "\x02" "te"
114 9 : "\x08" "trailers";
115 9 : if( FD_UNLIKELY( fd_h2_rbuf_free_sz( rbuf_tx )<sizeof(code)-1 ) ) return 0;
116 9 : fd_h2_rbuf_push( rbuf_tx, code, sizeof(code)-1 );
117 9 : return 1;
118 9 : }
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 9 : ulong user_agent_len ) {
126 9 : return fd_hpack_wr_private_name_indexed_0( rbuf_tx, 0x7a, user_agent_len );
127 9 : }
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 0 : ulong auth_token_len ) {
136 0 : uchar prefix[11] = { 0x1f, 0x08 };
137 0 : ulong value_len = 7UL+auth_token_len;
138 0 : if( FD_UNLIKELY( fd_h2_rbuf_free_sz( rbuf_tx ) < sizeof(prefix)+value_len ) ) return 0;
139 0 : ulong prefix_len = 2+fd_hpack_wr_varint( prefix+2, 0x00, 0x7f, value_len );
140 0 : fd_h2_rbuf_push( rbuf_tx, prefix, prefix_len );
141 0 : fd_h2_rbuf_push( rbuf_tx, "Bearer ", 7 );
142 0 : fd_h2_rbuf_push( rbuf_tx, auth_token, auth_token_len );
143 0 : return 1;
144 0 : }
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 0 : ushort port ) {
154 0 : char suffix_cstr[ 7 ];
155 0 : ulong port_cstr_len = fd_ushort_base10_dig_cnt( port );
156 0 : char * p = fd_cstr_init( suffix_cstr );
157 0 : p = fd_cstr_append_char( p, ':' );
158 0 : p = fd_cstr_append_ushort_as_text( p, 0, 0, port, port_cstr_len );
159 0 : ulong suffix_len = (ulong)p - (ulong)suffix_cstr;
160 0 : fd_cstr_fini( p );
161 :
162 : //if( !port ) suffix_len = 0;
163 0 : ulong value_len = host_len+suffix_len;
164 :
165 0 : uchar prefix[10] = { (uchar)0x01 };
166 0 : if( FD_UNLIKELY( fd_h2_rbuf_free_sz( rbuf_tx ) < sizeof(prefix)+value_len ) ) return 0;
167 0 : ulong prefix_len = 1+fd_hpack_wr_varint( prefix+1, 0x00, 0x7f, value_len );
168 0 : fd_h2_rbuf_push( rbuf_tx, prefix, prefix_len );
169 0 : fd_h2_rbuf_push( rbuf_tx, host, host_len );
170 0 : fd_h2_rbuf_push( rbuf_tx, suffix_cstr, suffix_len );
171 0 : return 1;
172 0 : }
173 :
174 : FD_PROTOTYPES_END
175 :
176 : #endif /* HEADER_fd_src_waltz_h2_fd_hpack_wr_h */
|