Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions _examples/reusable-sessions/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package main
import (
"context"
"fmt"
"os"
"time"

"github.com/fastly/compute-sdk-go/fsthttp"
Expand All @@ -14,10 +15,10 @@ func main() {
var requests int
fsthttp.ServeMany(func(ctx context.Context, w fsthttp.ResponseWriter, r *fsthttp.Request) {
requests++
fmt.Fprintf(w, "Request %v, Hello, %s!\n", requests, r.RemoteAddr)
fmt.Fprintf(w, "Request %v, Hello, %s (%q, %q)!\n", requests, r.RemoteAddr, os.Getenv("FASTLY_TRACE_ID"), r.RequestID)
}, &fsthttp.ServeManyOptions{
NextTimeout: 10 * time.Second,
NextTimeout: 1 * time.Second,
MaxRequests: 100,
MaxLifetime: 10 * time.Second,
MaxLifetime: 5 * time.Second,
})
}
85 changes: 85 additions & 0 deletions fsthttp/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ type Request struct {
// TLSInfo collects TLS metadata for incoming requests received over HTTPS.
TLSInfo TLSInfo

// Fingerprint collects fingerprint metadata for incoming requests
fingerprint *Fingerprint

// SendPollInterval determines how often the Send method will check for
// completed requests. While polling, the Go runtime is suspended, and all
// user code stops execution. A shorter interval will make Send more
Expand Down Expand Up @@ -111,6 +114,9 @@ type Request struct {
// discarded.
ManualFramingMode bool

// RequestID is the current Fastly request ID
RequestID string

sent bool // a request may only be sent once

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

reqID, err := abiReq.DownstreamRequestID()
if err != nil {
return nil, fmt.Errorf("get request id: %w", err)
}

header := NewHeader()
keys := abiReq.GetHeaderNames(RequestLimits.maxHeaderNameLen)
for keys.Next() {
Expand Down Expand Up @@ -214,6 +225,23 @@ func newClientRequest(abiReq *fastly.HTTPRequest, abiReqBody *fastly.HTTPBody) (
if err != nil {
return nil, fmt.Errorf("get TLS JA3 MD5: %w", err)
}

tlsInfo.JA4, err = abiReq.DownstreamTLSJA4()
if err != nil {
return nil, fmt.Errorf("get TLS JA4: %w", err)
}

tlsInfo.RawClientCertificate, err = abiReq.DownstreamTLSRawCertificate()
if err != nil {
return nil, fmt.Errorf("get TLS raw client certificate: %w", err)
}

if tlsInfo.RawClientCertificate != nil {
tlsInfo.ClientCertIsVerified, err = abiReq.DownstreamTLSClientCertVerifyResult()
if err != nil {
return nil, fmt.Errorf("get TLS client certificate verify: %w", err)
}
}
}

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

Expand Down Expand Up @@ -342,6 +371,39 @@ func (req *Request) AddCookie(c *Cookie) {
}
}

// Fingerprint returns a fleshed-out Fingerprint object for the request.
func (req *Request) Fingerprint() (*Fingerprint, error) {
if req.fingerprint != nil {
return req.fingerprint, nil
}

var err error

var fingerprint Fingerprint
fingerprint.H2, err = req.abi.req.DownstreamH2Fingerprint()
if err != nil {
if status, ok := fastly.IsFastlyError(err); ok && status != fastly.FastlyStatusNone {
return nil, fmt.Errorf("get H2 fingerprint: %w", err)
}
}

fingerprint.OH, err = req.abi.req.DownstreamOHFingerprint()
if err != nil {
if status, ok := fastly.IsFastlyError(err); ok && status != fastly.FastlyStatusNone {
return nil, fmt.Errorf("get OH fingerprint: %w", err)
}
}

fingerprint.DDOSDetected, err = req.abi.req.DownstreamDDOSDetected()
if err != nil {
return nil, fmt.Errorf("get ddos detected: %w", err)
}

req.fingerprint = &fingerprint

return req.fingerprint, nil
}

// Send the request to the named backend. Requests may only be sent to
// backends that have been preconfigured in your service, regardless of
// their URL. Once sent, a request cannot be sent again.
Expand Down Expand Up @@ -945,6 +1007,29 @@ type TLSInfo struct {
// JA3MD5 contains the bytes of the JA3 signature of the client TLS request.
// See https://www.fastly.com/blog/the-state-of-tls-fingerprinting-whats-working-what-isnt-and-whats-next
JA3MD5 []byte

// JA4 contains the bytes of the JA4 signature of the client TLS request.
// See https://github.com/FoxIO-LLC/ja4/blob/main/technical_details/JA4.md
JA4 []byte

// RawClientCertificate contains the bytes of the raw client certificate, if one was provided.
RawClientCertificate []byte

// ClientCertIsVerified is true if the provided client certificate is valid.
ClientCertIsVerified bool
}

// Fingerprint holds various fingerprints for a request.
type Fingerprint struct {

// H2 is the HTTP/2 fingerprint of a client request if available
H2 []byte

// OH is a fingerprint of the client request's original headers
OH []byte

// DDOSDetected is true if the request was determined to be part of a DDOS attack.
DDOSDetected bool
}

// DecompressResponseOptions control the auto decompress response behaviour.
Expand Down
36 changes: 36 additions & 0 deletions internal/abi/fastly/hostcalls_noguest.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,42 @@ func (r *HTTPRequest) DownstreamTLSJA3MD5() ([]byte, error) {
return nil, fmt.Errorf("not implemented")
}

func (r *HTTPRequest) DownstreamH2Fingerprint() ([]byte, error) {
return nil, fmt.Errorf("not implemented")
}

func (r *HTTPRequest) DownstreamRequestID() (string, error) {
return "", fmt.Errorf("not implemented")
}

func (r *HTTPRequest) DownstreamOHFingerprint() ([]byte, error) {
return nil, fmt.Errorf("not implemented")
}

func (r *HTTPRequest) DownstreamDDOSDetected() (bool, error) {
return false, fmt.Errorf("not implemented")
}

func (r *HTTPRequest) DownstreamTLSRawCertificate() ([]byte, error) {
return nil, fmt.Errorf("not implemented")
}

func (r *HTTPRequest) DownstreamTLSClientCertVerifyResult() (bool, error) {
return false, fmt.Errorf("not implemented")
}

func (r *HTTPRequest) DownstreamTLSJA4() ([]byte, error) {
return nil, fmt.Errorf("not implemented")
}

func (r *HTTPRequest) DownstreamComplianceRegion() (string, error) {
return "", fmt.Errorf("not implemented")
}

func (r *HTTPRequest) DownstreamFastlyKeyIsValid() (bool, error) {
return false, fmt.Errorf("not implemented")
}

func NewHTTPRequest() (*HTTPRequest, error) {
return nil, fmt.Errorf("not implemented")
}
Expand Down
Loading
Loading