Skip to content

Commit e3966a1

Browse files
committed
internal,fsthttp: add bot detection hostcalls
1 parent 9154c96 commit e3966a1

File tree

4 files changed

+380
-0
lines changed

4 files changed

+380
-0
lines changed

fsthttp/bot.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package fsthttp
2+
3+
import "github.com/fastly/compute-sdk-go/internal/abi/fastly"
4+
5+
type BotCategory = fastly.BotCategory
6+
7+
const (
8+
// BotCategoryNone indicates bot detection was not executed, or no bot was detected.
9+
BotCategoryNone = fastly.BotCategoryNone
10+
11+
// BotCategorySuspected is for a suspected bot.
12+
BotCategorySuspected = fastly.BotCategorySuspected
13+
14+
// BotCategoryAccessibility is for tools that make content accessible (e.g., screen readers).
15+
BotCategoryAccessibility = fastly.BotCategoryAccessibility
16+
17+
// BotCategoryAICrawler is for crawlers used for training AIs and LLMs, generally used for building AI models or indexes.
18+
BotCategoryAICrawler = fastly.BotCategoryAICrawler
19+
20+
// BotCategoryAIFetcher is for fetchers used by AIs and LLMs for enriching results in response to a user query.
21+
BotCategoryAIFetcher = fastly.BotCategoryAIFetcher
22+
23+
// BotCategoryContentFetcher is for tools that extract content from websites to be used elsewhere.
24+
BotCategoryContentFetcher = fastly.BotCategoryContentFetcher
25+
26+
// BotCategoryMonitoringSiteTools is for tools that access your website to monitor things like performance, uptime, and proving domain control.
27+
BotCategoryMonitoringSiteTools = fastly.BotCategoryMonitoringSiteTools
28+
29+
// BotCategoryOnlineMarketing is for crawlers from online marketing platforms (e.g., Facebook, Pinterest).
30+
BotCategoryOnlineMarketing = fastly.BotCategoryOnlineMarketing
31+
32+
// BotCategoryPagePreview is for tools that access your website to show a preview of the page in other online services and social media platforms.
33+
BotCategoryPagePreview = fastly.BotCategoryPagePreview
34+
35+
// BotCategoryPlatformIntegrations is for integration with other platforms by accessing the website's API, notably Webhooks.
36+
BotCategoryPlatformIntegrations = fastly.BotCategoryPlatformIntegrations
37+
38+
// BotCategoryResearch is for commercial and academic tools that collect and analyze data for research purposes.
39+
BotCategoryResearch = fastly.BotCategoryResearch
40+
41+
// BotCategorySearchEngineCrawler is for crawlers that index your website for search engines.
42+
BotCategorySearchEngineCrawler = fastly.BotCategorySearchEngineCrawler
43+
44+
// BotCategorySearchEngineSpecialization is for tools that support search engine optimization tasks (e.g., link analysis, ranking).
45+
BotCategorySearchEngineSpecialization = fastly.BotCategorySearchEngineSpecialization
46+
47+
// BotCategorySecurityTools is for security analysis tools that inspect your website for vulnerabilities, misconfigurations and other security features.
48+
BotCategorySecurityTools = fastly.BotCategorySecurityTools
49+
50+
// BotCategoryUnknown indicates the detected bot belongs to a category not recognized by this SDK version.
51+
BotCategoryUnknown = fastly.BotCategoryUnknown
52+
)
53+
54+
type BotDetectionResult struct {
55+
// Analyzed indicates if the request was analyzed by the bot detection framework.
56+
Analyzed bool
57+
58+
// Detected indicates if a bot was detected.
59+
Detected bool
60+
61+
// Name is string identifying the specific bot detected (e.g., `GoogleBot`, `GPTBot`, `Bingbot`).
62+
// Returns the empty string if bot detection was not executed or no bot was detected.
63+
//
64+
// Note: String values may change over time. Use this for logging or informational purposes.
65+
// For conditional logic, use CategoryKind.
66+
Name string
67+
68+
// Category is a string indicating the type of bot detected (e.g., `SEARCH-ENGINE-CRAWLER`, `AI-CRAWLER`,
69+
// `SUSPECTED-BOT`).
70+
//
71+
// Note: String values may change over time. Use this for logging or informational purposes.
72+
// For conditional logic, use [`get_bot_category_kind()`][Self::get_bot_category_kind].
73+
Category string
74+
75+
// An enum uniquely identifying the type of bot detected.
76+
CategoryKind BotCategory
77+
78+
// Verified is whether the detected bot is a verified bot.
79+
Verfied bool
80+
}
81+
82+
func (r *Request) BotDetection() (*BotDetectionResult, error) {
83+
var result BotDetectionResult
84+
85+
var err error
86+
if result.Analyzed, err = r.downstream.req.DownstreamBotAnalyzed(); err != nil {
87+
return nil, err
88+
}
89+
90+
// Didn't analyze the request? Nothing else to do.
91+
if !result.Analyzed {
92+
return &result, nil
93+
}
94+
95+
if result.Detected, err = r.downstream.req.DownstreamBotDetected(); err != nil {
96+
return nil, err
97+
}
98+
99+
// Request wasn't detected as a bot? Nothing to fill in.
100+
if !result.Detected {
101+
return &result, nil
102+
}
103+
104+
if result.Name, err = r.downstream.req.DownstreamBotName(); err != nil {
105+
return nil, err
106+
}
107+
108+
if result.Category, err = r.downstream.req.DownstreamBotCategory(); err != nil {
109+
return nil, err
110+
}
111+
112+
if result.Verfied, err = r.downstream.req.DownstreamBotVerified(); err != nil {
113+
return nil, err
114+
}
115+
116+
return &result, nil
117+
}

internal/abi/fastly/hostcalls_noguest.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,30 @@ func (r *HTTPRequest) DownstreamFastlyKeyIsValid() (bool, error) {
147147
return false, fmt.Errorf("not implemented")
148148
}
149149

150+
func (r *HTTPRequest) DownstreamBotAnalyzed() (bool, error) {
151+
return false, fmt.Errorf("not implemented")
152+
}
153+
154+
func (r *HTTPRequest) DownstreamBotDetected() (bool, error) {
155+
return false, fmt.Errorf("not implemented")
156+
}
157+
158+
func (r *HTTPRequest) DownstreamBotName() (string, error) {
159+
return "", fmt.Errorf("not implemented")
160+
}
161+
162+
func (r *HTTPRequest) DownstreamBotCategory() (string, error) {
163+
return "", fmt.Errorf("not implemented")
164+
}
165+
166+
func (r *HTTPRequest) DownstreamBotCategoryKind() (uint32, error) {
167+
return 0, fmt.Errorf("not implemented")
168+
}
169+
170+
func (r *HTTPRequest) DownstreamBotVerified() (bool, error) {
171+
return false, fmt.Errorf("not implemented")
172+
}
173+
150174
func NewHTTPRequest() (*HTTPRequest, error) {
151175
return nil, fmt.Errorf("not implemented")
152176
}

internal/abi/fastly/http_guest.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,190 @@ func (r *HTTPRequest) DownstreamFastlyKeyIsValid() (bool, error) {
18321832
return valid.b, nil
18331833
}
18341834

1835+
// witx:
1836+
//
1837+
// (@interface func (export "downstream_bot_analyzed")
1838+
// (param $req $request_handle)
1839+
// (result $err (expected $bot_analyzed (error $fastly_status)))
1840+
// )
1841+
//
1842+
//go:wasmimport fastly_http_downstream downstream_bot_analyzed
1843+
//go:noescape
1844+
func fastlyHTTPDownstreamBotAnalyzed(
1845+
req requestHandle,
1846+
analyzed prim.Pointer[bool],
1847+
) FastlyStatus
1848+
1849+
func (r *HTTPRequest) DownstreamBotAnalyzed() (bool, error) {
1850+
var analyzed struct {
1851+
b bool
1852+
_ prim.Usize // align padding
1853+
}
1854+
if err := fastlyHTTPDownstreamBotAnalyzed(
1855+
r.h,
1856+
prim.ToPointer(&analyzed.b),
1857+
).toError(); err != nil {
1858+
return false, err
1859+
}
1860+
1861+
return analyzed.b, nil
1862+
}
1863+
1864+
// witx:
1865+
//
1866+
// (@interface func (export "downstream_bot_detected")
1867+
// (param $req $request_handle)
1868+
// (result $err (expected $bot_detected (error $fastly_status)))
1869+
// )
1870+
//
1871+
//go:wasmimport fastly_http_downstream downstream_bot_detected
1872+
//go:noescape
1873+
func fastlyHTTPDownstreamBotDetected(
1874+
req requestHandle,
1875+
analyzed prim.Pointer[bool],
1876+
) FastlyStatus
1877+
1878+
func (r *HTTPRequest) DownstreamBotDetected() (bool, error) {
1879+
var detected struct {
1880+
b bool
1881+
_ prim.Usize // align padding
1882+
}
1883+
if err := fastlyHTTPDownstreamBotDetected(
1884+
r.h,
1885+
prim.ToPointer(&detected.b),
1886+
).toError(); err != nil {
1887+
return false, err
1888+
}
1889+
1890+
return detected.b, nil
1891+
}
1892+
1893+
// witx:
1894+
//
1895+
// (@interface func (export "downstream_bot_name")
1896+
// (param $req $request_handle)
1897+
// (param $bot_name_out (@witx pointer (@witx char8)))
1898+
// (param $bot_name_max_len (@witx usize))
1899+
// (param $nwritten_out (@witx pointer (@witx usize)))
1900+
// (result $err (expected (error $fastly_status)))
1901+
// )
1902+
//
1903+
//go:wasmimport fastly_http_downstream downstream_bot_name
1904+
//go:noescape
1905+
func fastlyHTTPReqDownstreamBotName(
1906+
req requestHandle,
1907+
botNameOut prim.Pointer[prim.Char8],
1908+
botNameMaxLen prim.Usize,
1909+
nwrittenOut prim.Pointer[prim.Usize],
1910+
) FastlyStatus
1911+
1912+
// DownstreamBotName returns the bot name detected
1913+
func (r *HTTPRequest) DownstreamBotName() (string, error) {
1914+
value, err := withAdaptiveBuffer(DefaultSmallBufLen, func(buf *prim.WriteBuffer) FastlyStatus {
1915+
return fastlyHTTPReqDownstreamBotName(
1916+
r.h,
1917+
prim.ToPointer(buf.Char8Pointer()),
1918+
buf.Cap(),
1919+
prim.ToPointer(buf.NPointer()),
1920+
)
1921+
})
1922+
if err != nil {
1923+
return "", err
1924+
}
1925+
return value.ToString(), nil
1926+
}
1927+
1928+
// witx:
1929+
//
1930+
// (@interface func (export "downstream_bot_category")
1931+
// (param $req $request_handle)
1932+
// (param $bot_category_out (@witx pointer (@witx char8)))
1933+
// (param $bot_category_max_len (@witx usize))
1934+
// (param $nwritten_out (@witx pointer (@witx usize)))
1935+
// (result $err (expected (error $fastly_status)))
1936+
// )
1937+
//
1938+
//go:wasmimport fastly_http_downstream downstream_bot_category
1939+
//go:noescape
1940+
func fastlyHTTPReqDownstreamBotCategory(
1941+
req requestHandle,
1942+
botCategoryOut prim.Pointer[prim.Char8],
1943+
botCategoryMaxLen prim.Usize,
1944+
nwrittenOut prim.Pointer[prim.Usize],
1945+
) FastlyStatus
1946+
1947+
// DownstreamBotCategory returns the bot category
1948+
func (r *HTTPRequest) DownstreamBotCategory() (string, error) {
1949+
value, err := withAdaptiveBuffer(DefaultSmallBufLen, func(buf *prim.WriteBuffer) FastlyStatus {
1950+
return fastlyHTTPReqDownstreamBotCategory(
1951+
r.h,
1952+
prim.ToPointer(buf.Char8Pointer()),
1953+
buf.Cap(),
1954+
prim.ToPointer(buf.NPointer()),
1955+
)
1956+
})
1957+
if err != nil {
1958+
return "", err
1959+
}
1960+
return value.ToString(), nil
1961+
}
1962+
1963+
// witx:
1964+
//
1965+
// (@interface func (export "downstream_bot_category_kind")
1966+
// (param $req $request_handle)
1967+
// (result $err (expected $bot_category_kind (error $fastly_status)))
1968+
// )
1969+
//
1970+
//go:wasmimport fastly_http_downstream downstream_bot_category_kind
1971+
//go:noescape
1972+
func fastlyHTTPDownstreamBotCategoryKind(
1973+
req requestHandle,
1974+
kind prim.Pointer[prim.U32],
1975+
) FastlyStatus
1976+
1977+
func (r *HTTPRequest) DownstreamBotCategoryKind() (uint32, error) {
1978+
var kind prim.U32
1979+
if err := fastlyHTTPDownstreamBotCategoryKind(
1980+
r.h,
1981+
prim.ToPointer(&kind),
1982+
).toError(); err != nil {
1983+
return 0, err
1984+
}
1985+
1986+
return uint32(kind), nil
1987+
}
1988+
1989+
// witx:
1990+
//
1991+
// (@interface func (export "downstream_bot_verified")
1992+
//
1993+
// (param $req $request_handle)
1994+
// (result $err (expected $bot_verified (error $fastly_status)))
1995+
// )
1996+
//
1997+
//go:wasmimport fastly_http_downstream downstream_bot_verified
1998+
//go:noescape
1999+
func fastlyHTTPDownstreamBotVerified(
2000+
req requestHandle,
2001+
analyzed prim.Pointer[bool],
2002+
) FastlyStatus
2003+
2004+
func (r *HTTPRequest) DownstreamBotVerified() (bool, error) {
2005+
var verified struct {
2006+
b bool
2007+
_ prim.Usize // align padding
2008+
}
2009+
if err := fastlyHTTPDownstreamBotVerified(
2010+
r.h,
2011+
prim.ToPointer(&verified.b),
2012+
).toError(); err != nil {
2013+
return false, err
2014+
}
2015+
2016+
return verified.b, nil
2017+
}
2018+
18352019
// witx:
18362020
//
18372021
// ;;; Hostcall for Fastly Compute guests to inspect request HTTP traffic

0 commit comments

Comments
 (0)