Line data Source code
1 : #include "fd_grpc_codec.h" 2 : #include "../h2/fd_hpack.h" 3 : #include "../h2/fd_hpack_wr.h" 4 : 5 : static int 6 6 : fd_hpack_wr_content_type_grpc( fd_h2_rbuf_t * rbuf_tx ) { 7 6 : static char const code[] = 8 6 : "\x5f" "\x16" "application/grpc+proto"; 9 6 : if( FD_UNLIKELY( fd_h2_rbuf_free_sz( rbuf_tx)<sizeof(code)-1 ) ) return 0; 10 6 : fd_h2_rbuf_push( rbuf_tx, code, sizeof(code)-1 ); 11 6 : return 1; 12 6 : } 13 : 14 : int 15 : fd_grpc_h2_gen_request_hdrs( fd_grpc_req_hdrs_t const * req, 16 : fd_h2_rbuf_t * rbuf_tx, 17 : char const * version, 18 6 : ulong version_len ) { 19 6 : if( FD_UNLIKELY( !fd_hpack_wr_method_post( rbuf_tx ) ) ) return 0; 20 6 : if( FD_UNLIKELY( !fd_hpack_wr_scheme( rbuf_tx, 1 ) ) ) return 0; 21 6 : if( FD_UNLIKELY( !fd_hpack_wr_path( rbuf_tx, req->path, req->path_len ) ) ) return 0; 22 6 : if( FD_UNLIKELY( !fd_hpack_wr_authority( rbuf_tx, req->host, req->host_len, req->port ) ) ) return 0; 23 6 : if( FD_UNLIKELY( !fd_hpack_wr_trailers( rbuf_tx ) ) ) return 0; 24 6 : if( FD_UNLIKELY( !fd_hpack_wr_content_type_grpc( rbuf_tx ) ) ) return 0; 25 : 26 6 : static char const user_agent[] = "grpc-firedancer/"; 27 6 : ulong const user_agent_len = sizeof(user_agent)-1 + version_len; 28 6 : if( FD_UNLIKELY( !fd_hpack_wr_user_agent( rbuf_tx, user_agent_len ) ) ) return 0; 29 6 : fd_h2_rbuf_push( rbuf_tx, user_agent, sizeof(user_agent)-1 ); 30 6 : fd_h2_rbuf_push( rbuf_tx, version, version_len ); 31 : 32 6 : if( req->bearer_auth_len ) { 33 3 : if( FD_UNLIKELY( !fd_hpack_wr_auth_bearer( rbuf_tx, req->bearer_auth, req->bearer_auth_len ) ) ) return 0; 34 3 : } 35 6 : return 1; 36 6 : } 37 : 38 : /* fd_grpc_h2_parse_num parses a decimal number in [1,999]. */ 39 : 40 : static uint 41 : fd_grpc_h2_parse_num( char const * num, 42 0 : ulong num_len ) { 43 0 : num_len = fd_ulong_min( num_len, 10 ); 44 0 : char num_cstr[ 11 ]; 45 0 : fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( num_cstr ), num, num_len ) ); 46 0 : return fd_cstr_to_uint( num_cstr ); 47 0 : } 48 : 49 : int 50 : fd_grpc_h2_read_response_hdrs( fd_grpc_resp_hdrs_t * resp, 51 : fd_h2_hdr_matcher_t const * matcher, 52 : uchar const * payload, 53 18 : ulong payload_sz ) { 54 18 : fd_hpack_rd_t hpack_rd[1]; 55 18 : fd_hpack_rd_init( hpack_rd, payload, payload_sz ); 56 18 : while( !fd_hpack_rd_done( hpack_rd ) ) { 57 3 : static FD_TL uchar scratch_buf[ 4096 ]; 58 3 : uchar * scratch = scratch_buf; 59 3 : fd_h2_hdr_t hdr[1]; 60 3 : uint err = fd_hpack_rd_next( hpack_rd, hdr, &scratch, scratch_buf+sizeof(scratch_buf) ); 61 3 : if( FD_UNLIKELY( err ) ) { 62 3 : FD_LOG_WARNING(( "Failed to parse response headers (%u-%s)", err, fd_h2_strerror( err ) )); 63 3 : return FD_H2_ERR_PROTOCOL; 64 3 : } 65 : 66 0 : int hdr_idx = fd_h2_hdr_match( matcher, hdr->name, hdr->name_len, hdr->hint ); 67 0 : switch( hdr_idx ) { 68 0 : case FD_H2_HDR_STATUS: 69 0 : resp->h2_status = fd_grpc_h2_parse_num( hdr->value, hdr->value_len ); 70 0 : break; 71 0 : case FD_H2_HDR_CONTENT_TYPE: 72 0 : resp->is_grpc_proto = 73 0 : ( 0==strncmp( hdr->value, "application/grpc", hdr->value_len ) || 74 0 : 0==strncmp( hdr->value, "application/grpc+proto", hdr->value_len ) ); 75 0 : break; 76 0 : case FD_GRPC_HDR_STATUS: 77 0 : resp->grpc_status = fd_grpc_h2_parse_num( hdr->value, hdr->value_len ); 78 0 : break; 79 0 : case FD_GRPC_HDR_MESSAGE: 80 0 : resp->grpc_msg_len = (uint)fd_ulong_min( hdr->value_len, sizeof(resp->grpc_msg) ); 81 0 : if( resp->grpc_msg_len ) { 82 0 : fd_memcpy( resp->grpc_msg, hdr->value, resp->grpc_msg_len ); 83 0 : } 84 0 : break; 85 0 : } 86 0 : } 87 15 : return FD_H2_SUCCESS; 88 18 : } 89 : 90 : char const * 91 0 : fd_grpc_status_cstr( uint status ) { 92 0 : switch( status ) { 93 0 : case FD_GRPC_STATUS_OK: return "ok"; 94 0 : case FD_GRPC_STATUS_CANCELLED: return "cancelled"; 95 0 : case FD_GRPC_STATUS_UNKNOWN: return "unknown"; 96 0 : case FD_GRPC_STATUS_INVALID_ARGUMENT: return "invalid argument"; 97 0 : case FD_GRPC_STATUS_DEADLINE_EXCEEDED: return "deadline exceeded"; 98 0 : case FD_GRPC_STATUS_NOT_FOUND: return "not found"; 99 0 : case FD_GRPC_STATUS_ALREADY_EXISTS: return "already exists"; 100 0 : case FD_GRPC_STATUS_PERMISSION_DENIED: return "permission denied"; 101 0 : case FD_GRPC_STATUS_RESOURCE_EXHAUSTED: return "resource exhausted"; 102 0 : case FD_GRPC_STATUS_FAILED_PRECONDITION: return "failed precondition"; 103 0 : case FD_GRPC_STATUS_ABORTED: return "aborted"; 104 0 : case FD_GRPC_STATUS_OUT_OF_RANGE: return "out of range"; 105 0 : case FD_GRPC_STATUS_UNIMPLEMENTED: return "unimplemented"; 106 0 : case FD_GRPC_STATUS_INTERNAL: return "internal"; 107 0 : case FD_GRPC_STATUS_UNAVAILABLE: return "unavailable"; 108 0 : case FD_GRPC_STATUS_DATA_LOSS: return "data loss"; 109 0 : case FD_GRPC_STATUS_UNAUTHENTICATED: return "unauthenticated"; 110 0 : default: return "unknown"; 111 0 : } 112 0 : }