Skip to content

Commit ff659ed

Browse files
committed
internal,fsthtto: add additional downstream hostcalls
1 parent a35d8ba commit ff659ed

File tree

4 files changed

+438
-63
lines changed

4 files changed

+438
-63
lines changed

_examples/reusable-sessions/main.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package main
55
import (
66
"context"
77
"fmt"
8+
"os"
89
"time"
910

1011
"github.com/fastly/compute-sdk-go/fsthttp"
@@ -14,10 +15,10 @@ func main() {
1415
var requests int
1516
fsthttp.ServeMany(func(ctx context.Context, w fsthttp.ResponseWriter, r *fsthttp.Request) {
1617
requests++
17-
fmt.Fprintf(w, "Request %v, Hello, %s!\n", requests, r.RemoteAddr)
18+
fmt.Fprintf(w, "Request %v, Hello, %s (%q, %q)!\n", requests, r.RemoteAddr, os.Getenv("FASTLY_TRACE_ID"), r.RequestID)
1819
}, &fsthttp.ServeManyOptions{
19-
NextTimeout: 10 * time.Second,
20+
NextTimeout: 1 * time.Second,
2021
MaxRequests: 100,
21-
MaxLifetime: 10 * time.Second,
22+
MaxLifetime: 5 * time.Second,
2223
})
2324
}

fsthttp/request.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ type Request struct {
8181
// TLSInfo collects TLS metadata for incoming requests received over HTTPS.
8282
TLSInfo TLSInfo
8383

84+
// Fingerprint collects fingerprint metadata for incoming requests
85+
fingerprint *Fingerprint
86+
8487
// SendPollInterval determines how often the Send method will check for
8588
// completed requests. While polling, the Go runtime is suspended, and all
8689
// user code stops execution. A shorter interval will make Send more
@@ -111,6 +114,9 @@ type Request struct {
111114
// discarded.
112115
ManualFramingMode bool
113116

117+
// RequestID is the current Fastly request ID
118+
RequestID string
119+
114120
sent bool // a request may only be sent once
115121

116122
abi struct {
@@ -165,6 +171,11 @@ func newClientRequest(abiReq *fastly.HTTPRequest, abiReqBody *fastly.HTTPBody) (
165171
return nil, fmt.Errorf("get protocol version: %w", err)
166172
}
167173

174+
reqID, err := abiReq.DownstreamRequestID()
175+
if err != nil {
176+
return nil, fmt.Errorf("get request id: %w", err)
177+
}
178+
168179
header := NewHeader()
169180
keys := abiReq.GetHeaderNames(RequestLimits.maxHeaderNameLen)
170181
for keys.Next() {
@@ -214,6 +225,23 @@ func newClientRequest(abiReq *fastly.HTTPRequest, abiReqBody *fastly.HTTPBody) (
214225
if err != nil {
215226
return nil, fmt.Errorf("get TLS JA3 MD5: %w", err)
216227
}
228+
229+
tlsInfo.JA4, err = abiReq.DownstreamTLSJA4()
230+
if err != nil {
231+
return nil, fmt.Errorf("get TLS JA4: %w", err)
232+
}
233+
234+
tlsInfo.RawClientCertificate, err = abiReq.DownstreamTLSRawCertificate()
235+
if err != nil {
236+
return nil, fmt.Errorf("get TLS raw client certificate: %w", err)
237+
}
238+
239+
if tlsInfo.RawClientCertificate != nil {
240+
tlsInfo.ClientCertIsVerified, err = abiReq.DownstreamTLSClientCertVerifyResult()
241+
if err != nil {
242+
return nil, fmt.Errorf("get TLS client certificate verify: %w", err)
243+
}
244+
}
217245
}
218246

219247
// Setting the fsthttp.Request Host field to the url.URL Host field is
@@ -231,6 +259,7 @@ func newClientRequest(abiReq *fastly.HTTPRequest, abiReqBody *fastly.HTTPBody) (
231259
RemoteAddr: remoteAddr.String(),
232260
ServerAddr: serverAddr.String(),
233261
TLSInfo: tlsInfo,
262+
RequestID: reqID,
234263
}, nil
235264
}
236265

@@ -342,6 +371,39 @@ func (req *Request) AddCookie(c *Cookie) {
342371
}
343372
}
344373

374+
// Fingerprint returns a fleshed-out Fingerprint object for the request.
375+
func (req *Request) Fingerprint() (*Fingerprint, error) {
376+
if req.fingerprint != nil {
377+
return req.fingerprint, nil
378+
}
379+
380+
var err error
381+
382+
var fingerprint Fingerprint
383+
fingerprint.H2, err = req.abi.req.DownstreamH2Fingerprint()
384+
if err != nil {
385+
if status, ok := fastly.IsFastlyError(err); ok && status != fastly.FastlyStatusNone {
386+
return nil, fmt.Errorf("get H2 fingerprint: %w", err)
387+
}
388+
}
389+
390+
fingerprint.OH, err = req.abi.req.DownstreamOHFingerprint()
391+
if err != nil {
392+
if status, ok := fastly.IsFastlyError(err); ok && status != fastly.FastlyStatusNone {
393+
return nil, fmt.Errorf("get OH fingerprint: %w", err)
394+
}
395+
}
396+
397+
fingerprint.DDOSDetected, err = req.abi.req.DownstreamDDOSDetected()
398+
if err != nil {
399+
return nil, fmt.Errorf("get ddos detected: %w", err)
400+
}
401+
402+
req.fingerprint = &fingerprint
403+
404+
return req.fingerprint, nil
405+
}
406+
345407
// Send the request to the named backend. Requests may only be sent to
346408
// backends that have been preconfigured in your service, regardless of
347409
// their URL. Once sent, a request cannot be sent again.
@@ -945,6 +1007,29 @@ type TLSInfo struct {
9451007
// JA3MD5 contains the bytes of the JA3 signature of the client TLS request.
9461008
// See https://www.fastly.com/blog/the-state-of-tls-fingerprinting-whats-working-what-isnt-and-whats-next
9471009
JA3MD5 []byte
1010+
1011+
// JA4 contains the bytes of the JA4 signature of the client TLS request.
1012+
// See https://github.com/FoxIO-LLC/ja4/blob/main/technical_details/JA4.md
1013+
JA4 []byte
1014+
1015+
// RawClientCertificate contains the bytes of the raw client certificate, if one was provided.
1016+
RawClientCertificate []byte
1017+
1018+
// ClientCertIsVerified is true if the provided client certificate is valid.
1019+
ClientCertIsVerified bool
1020+
}
1021+
1022+
// Fingerprint holds various fingerprints for a request.
1023+
type Fingerprint struct {
1024+
1025+
// H2 is the HTTP/2 fingerprint of a client request if available
1026+
H2 []byte
1027+
1028+
// OH is a fingerprint of the client request's original headers
1029+
OH []byte
1030+
1031+
// DDOSDetected is true if the request was determined to be part of a DDOS attack.
1032+
DDOSDetected bool
9481033
}
9491034

9501035
// DecompressResponseOptions control the auto decompress response behaviour.

internal/abi/fastly/hostcalls_noguest.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,42 @@ func (r *HTTPRequest) DownstreamTLSJA3MD5() ([]byte, error) {
9191
return nil, fmt.Errorf("not implemented")
9292
}
9393

94+
func (r *HTTPRequest) DownstreamH2Fingerprint() ([]byte, error) {
95+
return nil, fmt.Errorf("not implemented")
96+
}
97+
98+
func (r *HTTPRequest) DownstreamRequestID() (string, error) {
99+
return "", fmt.Errorf("not implemented")
100+
}
101+
102+
func (r *HTTPRequest) DownstreamOHFingerprint() ([]byte, error) {
103+
return nil, fmt.Errorf("not implemented")
104+
}
105+
106+
func (r *HTTPRequest) DownstreamDDOSDetected() (bool, error) {
107+
return false, fmt.Errorf("not implemented")
108+
}
109+
110+
func (r *HTTPRequest) DownstreamTLSRawCertificate() ([]byte, error) {
111+
return nil, fmt.Errorf("not implemented")
112+
}
113+
114+
func (r *HTTPRequest) DownstreamTLSClientCertVerifyResult() (bool, error) {
115+
return false, fmt.Errorf("not implemented")
116+
}
117+
118+
func (r *HTTPRequest) DownstreamTLSJA4() ([]byte, error) {
119+
return nil, fmt.Errorf("not implemented")
120+
}
121+
122+
func (r *HTTPRequest) DownstreamComplianceRegion() (string, error) {
123+
return "", fmt.Errorf("not implemented")
124+
}
125+
126+
func (r *HTTPRequest) DownstreamFastlyKeyIsValid() (bool, error) {
127+
return false, fmt.Errorf("not implemented")
128+
}
129+
94130
func NewHTTPRequest() (*HTTPRequest, error) {
95131
return nil, fmt.Errorf("not implemented")
96132
}

0 commit comments

Comments
 (0)