LCOV - code coverage report
Current view: top level - waltz/grpc - fd_grpc_codec.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 46 89 51.7 %
Date: 2025-08-05 05:04:49 Functions: 4 5 80.0 %

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

Generated by: LCOV version 1.14