11package httparenahandler
22
33import (
4- "database/sql"
5- "encoding/json"
64 "fmt"
75 "io"
8- "math"
96 "net/http"
107 "os"
118 "path/filepath"
12- "runtime"
139 "strconv"
1410 "strings"
1511
1612 "github.com/caddyserver/caddy/v2"
1713 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
1814 "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
1915 "github.com/caddyserver/caddy/v2/modules/caddyhttp"
20- _ "modernc.org/sqlite"
2116)
2217
2318func init () {
2419 caddy .RegisterModule (Handler {})
2520 httpcaddyfile .RegisterHandlerDirective ("httparena" , parseCaddyfile )
2621}
2722
28- type Rating struct {
29- Score float64 `json:"score"`
30- Count int `json:"count"`
31- }
32-
33- type ProcessedItem struct {
34- ID int `json:"id"`
35- Name string `json:"name"`
36- Category string `json:"category"`
37- Price float64 `json:"price"`
38- Quantity int `json:"quantity"`
39- Active bool `json:"active"`
40- Tags []string `json:"tags"`
41- Rating Rating `json:"rating"`
42- Total float64 `json:"total"`
43- }
44-
45- type ProcessResponse struct {
46- Items []ProcessedItem `json:"items"`
47- Count int `json:"count"`
48- }
49-
5023type staticFile struct {
5124 data []byte
5225 contentType string
5326}
5427
55- type RawItem struct {
56- ID int `json:"id"`
57- Name string `json:"name"`
58- Category string `json:"category"`
59- Price float64 `json:"price"`
60- Quantity int `json:"quantity"`
61- Active bool `json:"active"`
62- Tags []string `json:"tags"`
63- Rating Rating `json:"rating"`
64- }
65-
6628type Handler struct {
67- dataset []RawItem
68- jsonLargeResponse []byte
69- staticFiles map [string ]staticFile
70- db * sql.DB
29+ staticFiles map [string ]staticFile
7130}
7231
7332func (Handler ) CaddyModule () caddy.ModuleInfo {
@@ -78,46 +37,6 @@ func (Handler) CaddyModule() caddy.ModuleInfo {
7837}
7938
8039func (h * Handler ) Provision (ctx caddy.Context ) error {
81- path := os .Getenv ("DATASET_PATH" )
82- if path == "" {
83- path = "/data/dataset.json"
84- }
85- data , err := os .ReadFile (path )
86- if err != nil {
87- return nil // dataset not available, /json will 500
88- }
89-
90- if err := json .Unmarshal (data , & h .dataset ); err != nil {
91- return nil
92- }
93-
94- // Load large dataset for /compression
95- largeData , err := os .ReadFile ("/data/dataset-large.json" )
96- if err == nil {
97- var largeDataset []struct {
98- ID int `json:"id"`
99- Name string `json:"name"`
100- Category string `json:"category"`
101- Price float64 `json:"price"`
102- Quantity int `json:"quantity"`
103- Active bool `json:"active"`
104- Tags []string `json:"tags"`
105- Rating Rating `json:"rating"`
106- }
107- if err := json .Unmarshal (largeData , & largeDataset ); err == nil {
108- largeItems := make ([]ProcessedItem , len (largeDataset ))
109- for i , d := range largeDataset {
110- largeItems [i ] = ProcessedItem {
111- ID : d .ID , Name : d .Name , Category : d .Category ,
112- Price : d .Price , Quantity : d .Quantity , Active : d .Active ,
113- Tags : d .Tags , Rating : d .Rating ,
114- Total : math .Round (d .Price * float64 (d .Quantity )* 100 ) / 100 ,
115- }
116- }
117- h .jsonLargeResponse , _ = json .Marshal (ProcessResponse {Items : largeItems , Count : len (largeItems )})
118- }
119- }
120-
12140 // Load static files
12241 mimeTypes := map [string ]string {
12342 ".css" : "text/css" , ".js" : "application/javascript" , ".html" : "text/html" ,
@@ -143,13 +62,6 @@ func (h *Handler) Provision(ctx caddy.Context) error {
14362 }
14463 }
14564
146- // Open SQLite database
147- db , err := sql .Open ("sqlite" , "file:/data/benchmark.db?mode=ro&immutable=1" )
148- if err == nil {
149- db .SetMaxOpenConns (runtime .NumCPU ())
150- h .db = db
151- }
152-
15365 return nil
15466}
15567
@@ -191,27 +103,6 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyht
191103 w .Write ([]byte ("ok" ))
192104 return nil
193105
194- case "/json" :
195- if h .dataset != nil {
196- items := make ([]ProcessedItem , len (h .dataset ))
197- for i , d := range h .dataset {
198- items [i ] = ProcessedItem {
199- ID : d .ID , Name : d .Name , Category : d .Category ,
200- Price : d .Price , Quantity : d .Quantity , Active : d .Active ,
201- Tags : d .Tags , Rating : d .Rating ,
202- Total : math .Round (d .Price * float64 (d .Quantity )* 100 ) / 100 ,
203- }
204- }
205- resp , _ := json .Marshal (ProcessResponse {Items : items , Count : len (items )})
206- w .Header ().Set ("Content-Type" , "application/json" )
207- w .Header ().Set ("Server" , "caddy" )
208- w .Header ().Set ("Content-Length" , strconv .Itoa (len (resp )))
209- w .Write (resp )
210- } else {
211- http .Error (w , "No dataset" , 500 )
212- }
213- return nil
214-
215106 case "/baseline2" :
216107 sum := sumQuery (r )
217108 w .Header ().Set ("Content-Type" , "text/plain" )
@@ -232,77 +123,6 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyht
232123 fmt .Fprint (w , sum )
233124 return nil
234125
235- case "/upload" :
236- if r .Method == "POST" && r .Body != nil {
237- n , _ := io .Copy (io .Discard , r .Body )
238- w .Header ().Set ("Content-Type" , "text/plain" )
239- w .Header ().Set ("Server" , "caddy" )
240- fmt .Fprintf (w , "%d" , n )
241- } else {
242- http .Error (w , "POST required" , 405 )
243- }
244- return nil
245-
246- case "/compression" :
247- if h .jsonLargeResponse != nil {
248- w .Header ().Set ("Content-Type" , "application/json" )
249- w .Header ().Set ("Server" , "caddy" )
250- w .Write (h .jsonLargeResponse )
251- } else {
252- http .Error (w , "No dataset" , 500 )
253- }
254- return nil
255-
256- case "/db" :
257- if h .db == nil {
258- http .Error (w , "DB not available" , 500 )
259- return nil
260- }
261- minStr := r .URL .Query ().Get ("min" )
262- maxStr := r .URL .Query ().Get ("max" )
263- minPrice := 10.0
264- maxPrice := 50.0
265- if v , err := strconv .ParseFloat (minStr , 64 ); err == nil {
266- minPrice = v
267- }
268- if v , err := strconv .ParseFloat (maxStr , 64 ); err == nil {
269- maxPrice = v
270- }
271- rows , err := h .db .Query ("SELECT id, name, category, price, quantity, active, tags, rating_score, rating_count FROM items WHERE price BETWEEN ? AND ? LIMIT 50" , minPrice , maxPrice )
272- if err != nil {
273- http .Error (w , "Query failed" , 500 )
274- return nil
275- }
276- defer rows .Close ()
277- var items []map [string ]interface {}
278- for rows .Next () {
279- var dbId int
280- var name , category , tags string
281- var price float64
282- var quantity int
283- var active int
284- var ratingScore float64
285- var ratingCount int
286- if err := rows .Scan (& dbId , & name , & category , & price , & quantity , & active , & tags , & ratingScore , & ratingCount ); err != nil {
287- continue
288- }
289- var tagsArr []string
290- json .Unmarshal ([]byte (tags ), & tagsArr )
291- items = append (items , map [string ]interface {}{
292- "id" : dbId , "name" : name , "category" : category ,
293- "price" : price , "quantity" : quantity , "active" : active == 1 ,
294- "tags" : tagsArr ,
295- "rating" : map [string ]interface {}{"score" : ratingScore , "count" : ratingCount },
296- })
297- }
298- resp := map [string ]interface {}{
299- "items" : items ,
300- "count" : len (items ),
301- }
302- w .Header ().Set ("Content-Type" , "application/json" )
303- w .Header ().Set ("Server" , "caddy" )
304- json .NewEncoder (w ).Encode (resp )
305- return nil
306126 }
307127
308128 if strings .HasPrefix (path , "/static/" ) {
0 commit comments