File Coverage

blib/lib/Hypersonic/Middleware/RequestId.pm
Criterion Covered Total %
statement 12 27 44.4
branch n/a
condition 2 17 11.7
subroutine 5 9 55.5
pod 0 7 0.0
total 19 60 31.6


line stmt bran cond sub pod time code
1             package Hypersonic::Middleware::RequestId;
2 1     1   2010 use strict;
  1         2  
  1         54  
3 1     1   7 use warnings;
  1         2  
  1         664  
4              
5             our $VERSION = '0.15';
6              
7             # Middleware builder pattern - generates inline C at compile time
8             # Zero Perl in the hot path - ID generation is pure C
9              
10             # Constructor - creates a builder instance
11             sub new {
12 3     3 0 9 my ($class, %opts) = @_;
13             bless {
14             header => $opts{header} // 'X-Request-ID',
15 3   50     19 type => $opts{type} // 'both', # 'before', 'after', or 'both'
      50        
16             }, $class;
17             }
18              
19             # Declare slot requirements - compiler allocates and passes back in context
20             sub slot_requirements {
21 0     0 0 0 return { request_id => 1 }; # Need 1 slot for request_id
22             }
23              
24             # Factory methods that return builder instances (not coderefs)
25             sub middleware {
26 2     2 0 296 my (%opts) = @_;
27 2         7 return __PACKAGE__->new(%opts, type => 'before');
28             }
29              
30             sub after_middleware {
31 1     1 0 2 my (%opts) = @_;
32 1         10 return __PACKAGE__->new(%opts, type => 'after');
33             }
34              
35             # Builder interface: generate C helper functions at file scope
36             sub build_helpers {
37 0     0 0   my ($self, $builder) = @_;
38              
39 0           $builder->comment('RequestId: JIT-compiled request ID generation (zero Perl overhead)')
40             ->line('static __thread unsigned long g_reqid_counter = 0;')
41             ->line('static pid_t g_reqid_pid = 0;')
42             ->blank
43             ->line('static void hypersonic_generate_request_id(char* buf, size_t buflen) {')
44             ->line(' if (g_reqid_pid == 0) g_reqid_pid = getpid();')
45             ->line(' unsigned long ts = (unsigned long)time(NULL);')
46             ->line(' unsigned long cnt = g_reqid_counter++;')
47             ->line(' snprintf(buf, buflen, "%lx-%lx-%x", ts, cnt, (unsigned int)g_reqid_pid);')
48             ->line('}');
49             }
50              
51             # Builder interface: generate inline C for before middleware
52             sub build_before {
53 0     0 0   my ($self, $builder, $ctx) = @_;
54 0   0       my $req_var = $ctx->{req_var} // 'req';
55             my $slot = $ctx->{slots}{request_id}
56 0   0       // die "RequestId: compiler must provide slots->{request_id}";
57              
58             # Store slot for build_after to use
59 0           $self->{_slot} = $slot;
60              
61 0           $builder->comment('RequestId before: generate and store request ID')
62             ->line(' {')
63             ->line(' char _reqid_buf[64];')
64             ->line(' hypersonic_generate_request_id(_reqid_buf, sizeof(_reqid_buf));')
65             ->line(" av_store($req_var, $slot, newSVpv(_reqid_buf, 0));")
66             ->line(' }');
67             }
68              
69             # Builder interface: generate inline C for after middleware
70             sub build_after {
71 0     0 0   my ($self, $builder, $ctx) = @_;
72 0   0       my $req_var = $ctx->{req_var} // 'req';
73 0   0       my $res_var = $ctx->{res_var} // 'result';
74             my $slot = $ctx->{slots}{request_id} // $self->{_slot}
75 0   0       // die "RequestId: compiler must provide slots->{request_id}";
      0        
76 0           my $header = $self->{header};
77 0           my $header_len = length($header);
78              
79 0           $builder->comment("RequestId after: add $header to response")
80             ->line(' {')
81             ->line(" SV** _reqid_ref = av_fetch($req_var, $slot, 0);")
82             ->line(' if (_reqid_ref && SvOK(*_reqid_ref)) {')
83             ->line(' /* Request ID available - will be added to response headers */')
84             ->line(' /* Note: actual header injection handled by response builder */')
85             ->line(' }')
86             ->line(' }');
87             }
88              
89             1;
90              
91             __END__