Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/templates/cache.go
2844 views
1
package templates
2
3
import (
4
"os"
5
"time"
6
7
"github.com/projectdiscovery/utils/conversion"
8
mapsutil "github.com/projectdiscovery/utils/maps"
9
)
10
11
// Templates is a cache for caching and storing templates for reuse.
12
type Cache struct {
13
items *mapsutil.SyncLockMap[string, parsedTemplate]
14
}
15
16
// New returns a new templates cache
17
func NewCache() *Cache {
18
return &Cache{
19
items: mapsutil.NewSyncLockMap[string, parsedTemplate](),
20
}
21
}
22
23
type parsedTemplate struct {
24
template *Template
25
raw string
26
err error
27
filePath string
28
modTime time.Time
29
}
30
31
// setModTime sets the modification time of the file if it exists.
32
func (p *parsedTemplate) setModTime(id string) {
33
if stat, err := os.Stat(id); err == nil {
34
p.modTime = stat.ModTime()
35
}
36
}
37
38
// isValid checks if the cached template is still valid based on the file's
39
// modification time.
40
func (p *parsedTemplate) isValid(templatePath string) bool {
41
if p.modTime.IsZero() {
42
return true
43
}
44
45
stat, err := os.Stat(templatePath)
46
if err != nil {
47
return false
48
}
49
50
return stat.ModTime().Equal(p.modTime)
51
}
52
53
// Has returns true if the cache has a template. The template
54
// is returned along with any errors if found.
55
func (t *Cache) Has(template string) (*Template, []byte, error) {
56
value, ok := t.items.Get(template)
57
if !ok {
58
return nil, nil, nil
59
}
60
61
if !value.isValid(template) {
62
t.items.Delete(template)
63
64
return nil, nil, nil
65
}
66
67
return value.template, conversion.Bytes(value.raw), value.err
68
}
69
70
// Store stores a template with data and error
71
func (t *Cache) Store(id string, tpl *Template, raw []byte, err error) {
72
entry := parsedTemplate{
73
template: tpl,
74
err: err,
75
raw: conversion.String(raw),
76
filePath: id,
77
}
78
79
entry.setModTime(id)
80
_ = t.items.Set(id, entry)
81
}
82
83
// StoreWithoutRaw stores a template without raw data for memory efficiency
84
func (t *Cache) StoreWithoutRaw(id string, tpl *Template, err error) {
85
entry := parsedTemplate{
86
template: tpl,
87
err: err,
88
raw: "",
89
filePath: id,
90
}
91
92
entry.setModTime(id)
93
_ = t.items.Set(id, entry)
94
}
95
96
// Get returns only the template without raw bytes
97
func (t *Cache) Get(id string) (*Template, error) {
98
value, ok := t.items.Get(id)
99
if !ok {
100
return nil, nil
101
}
102
return value.template, value.err
103
}
104
105
// Purge the cache
106
func (t *Cache) Purge() {
107
t.items.Clear()
108
}
109
110