@@ -76,6 +76,12 @@ type Request struct {
76
76
// TLSInfo collects TLS metadata for incoming requests received over HTTPS.
77
77
TLSInfo TLSInfo
78
78
79
+ // tlsClientCertificateInfo is information about the tls client certificate, if available
80
+ clientCertificate * TLSClientCertificateInfo
81
+
82
+ // FastlyMeta collects Fastly-specific metadata for incoming requests
83
+ fastlyMeta * FastlyMeta
84
+
79
85
// SendPollInterval determines how often the Send method will check for
80
86
// completed requests. While polling, the Go runtime is suspended, and all
81
87
// user code stops execution. A shorter interval will make Send more
@@ -106,12 +112,17 @@ type Request struct {
106
112
// discarded.
107
113
ManualFramingMode bool
108
114
115
+ // RequestID is the current Fastly request ID
116
+ RequestID string
117
+
109
118
sent bool // a request may only be sent once
110
119
111
- abi struct {
112
- req * fastly.HTTPRequest
113
- body * fastly.HTTPBody
114
- }
120
+ abi reqAbi
121
+ }
122
+
123
+ type reqAbi struct {
124
+ req * fastly.HTTPRequest
125
+ body * fastly.HTTPBody
115
126
}
116
127
117
128
// NewRequest constructs an outgoing request with the given HTTP method, URI,
@@ -160,6 +171,11 @@ func newClientRequest(abiReq *fastly.HTTPRequest, abiReqBody *fastly.HTTPBody) (
160
171
return nil , fmt .Errorf ("get protocol version: %w" , err )
161
172
}
162
173
174
+ reqID , err := abiReq .DownstreamRequestID ()
175
+ if err != nil {
176
+ return nil , fmt .Errorf ("get request id: %w" , err )
177
+ }
178
+
163
179
header := NewHeader ()
164
180
keys := abiReq .GetHeaderNames ()
165
181
for keys .Next () {
@@ -209,6 +225,12 @@ func newClientRequest(abiReq *fastly.HTTPRequest, abiReqBody *fastly.HTTPBody) (
209
225
if err != nil {
210
226
return nil , fmt .Errorf ("get TLS JA3 MD5: %w" , err )
211
227
}
228
+
229
+ tlsInfo .JA4 , err = abiReq .DownstreamTLSJA4 ()
230
+ if err != nil {
231
+ return nil , fmt .Errorf ("get TLS JA4: %w" , err )
232
+ }
233
+
212
234
}
213
235
214
236
// Setting the fsthttp.Request Host field to the url.URL Host field is
@@ -226,6 +248,8 @@ func newClientRequest(abiReq *fastly.HTTPRequest, abiReqBody *fastly.HTTPBody) (
226
248
RemoteAddr : remoteAddr .String (),
227
249
ServerAddr : serverAddr .String (),
228
250
TLSInfo : tlsInfo ,
251
+ RequestID : reqID ,
252
+ abi : reqAbi {req : abiReq , body : abiReqBody },
229
253
}, nil
230
254
}
231
255
@@ -337,6 +361,44 @@ func (req *Request) AddCookie(c *Cookie) {
337
361
}
338
362
}
339
363
364
+ // FastlyMeta returns a fleshed-out FastlyMeta object for the request.
365
+ func (req * Request ) FastlyMeta () (* FastlyMeta , error ) {
366
+ if req .fastlyMeta != nil {
367
+ return req .fastlyMeta , nil
368
+ }
369
+
370
+ var err error
371
+
372
+ var fastlyMeta FastlyMeta
373
+ fastlyMeta .H2 , err = req .abi .req .DownstreamH2Fingerprint ()
374
+ if err != nil {
375
+ if status , ok := fastly .IsFastlyError (err ); ok && status != fastly .FastlyStatusNone {
376
+ return nil , fmt .Errorf ("get H2 fingerprint: %w" , err )
377
+ }
378
+ }
379
+
380
+ fastlyMeta .OH , err = req .abi .req .DownstreamOHFingerprint ()
381
+ if err != nil {
382
+ if status , ok := fastly .IsFastlyError (err ); ok && status != fastly .FastlyStatusNone {
383
+ return nil , fmt .Errorf ("get OH fingerprint: %w" , err )
384
+ }
385
+ }
386
+
387
+ fastlyMeta .DDOSDetected , err = req .abi .req .DownstreamDDOSDetected ()
388
+ if err != nil {
389
+ return nil , fmt .Errorf ("get ddos detected: %w" , err )
390
+ }
391
+
392
+ fastlyMeta .FastlyKeyIsValid , err = req .abi .req .DownstreamFastlyKeyIsValid ()
393
+ if err != nil {
394
+ return nil , fmt .Errorf ("get fastly key is valid: %w" , err )
395
+ }
396
+
397
+ req .fastlyMeta = & fastlyMeta
398
+
399
+ return req .fastlyMeta , nil
400
+ }
401
+
340
402
// Send the request to the named backend. Requests may only be sent to
341
403
// backends that have been preconfigured in your service, regardless of
342
404
// their URL. Once sent, a request cannot be sent again.
@@ -940,6 +1002,59 @@ type TLSInfo struct {
940
1002
// JA3MD5 contains the bytes of the JA3 signature of the client TLS request.
941
1003
// See https://www.fastly.com/blog/the-state-of-tls-fingerprinting-whats-working-what-isnt-and-whats-next
942
1004
JA3MD5 []byte
1005
+
1006
+ // JA4 contains the bytes of the JA4 signature of the client TLS request.
1007
+ // See https://github.com/FoxIO-LLC/ja4/blob/main/technical_details/JA4.md
1008
+ JA4 []byte
1009
+ }
1010
+
1011
+ func (req * Request ) TLSClientCertificateInfo () (* TLSClientCertificateInfo , error ) {
1012
+ if req .clientCertificate != nil {
1013
+ return req .clientCertificate , nil
1014
+ }
1015
+
1016
+ var err error
1017
+ var cert TLSClientCertificateInfo
1018
+
1019
+ cert .RawClientCertificate , err = req .abi .req .DownstreamTLSRawClientCertificate ()
1020
+ if err != nil {
1021
+ return nil , fmt .Errorf ("get TLS raw client certificate: %w" , err )
1022
+ }
1023
+
1024
+ if cert .RawClientCertificate != nil {
1025
+ cert .ClientCertIsVerified , err = req .abi .req .DownstreamTLSClientCertVerifyResult ()
1026
+ if err != nil {
1027
+ return nil , fmt .Errorf ("get TLS client certificate verify: %w" , err )
1028
+ }
1029
+ }
1030
+
1031
+ req .clientCertificate = & cert
1032
+ return req .clientCertificate , nil
1033
+ }
1034
+
1035
+ type TLSClientCertificateInfo struct {
1036
+ // RawClientCertificate contains the bytes of the raw client certificate, if one was provided.
1037
+ RawClientCertificate []byte
1038
+
1039
+ // ClientCertIsVerified is true if the provided client certificate is valid.
1040
+ ClientCertIsVerified bool
1041
+ }
1042
+
1043
+ // FastlyMeta holds various Fastly-specific metadata for a request.
1044
+ type FastlyMeta struct {
1045
+
1046
+ // H2 is the HTTP/2 fingerprint of a client request if available
1047
+ H2 []byte
1048
+
1049
+ // OH is a fingerprint of the client request's original headers
1050
+ OH []byte
1051
+
1052
+ // DDOSDetected is true if the request was determined to be part of a DDOS attack.
1053
+ DDOSDetected bool
1054
+
1055
+ // FastlyKeyIsValid is true if the request contains a valid Fastly API token.
1056
+ // This is for services to restrict authenticating PURGE requests for the readthrough cache.
1057
+ FastlyKeyIsValid bool
943
1058
}
944
1059
945
1060
// DecompressResponseOptions control the auto decompress response behaviour.
0 commit comments