Initial Commit
This commit is contained in:
134
cmd/main.go
Normal file
134
cmd/main.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func jailPath(wwwdata string, path string) (string, error) {
|
||||
base, err := filepath.Abs(wwwdata)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Join and clean the path
|
||||
joined := filepath.Join(base, path)
|
||||
clean := filepath.Clean(joined)
|
||||
|
||||
// Ensure it's inside base, otherwise clamp to base
|
||||
if !strings.HasPrefix(clean+string(os.PathSeparator), base+string(os.PathSeparator)) {
|
||||
return base, nil
|
||||
}
|
||||
|
||||
return clean, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
wwwdata, err := os.Getwd()
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error getting current working directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if len(os.Args) > 1 {
|
||||
wwwdata = os.Args[1]
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "Serving files from: %s\n", wwwdata)
|
||||
|
||||
// Wildcard route to handle all GET requests
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
path := r.URL.Path
|
||||
|
||||
// Log time, method, path, ip, user-agent to stderr
|
||||
fmt.Fprintf(os.Stderr, "%s - %s %s - %s - %s\n", time.Now().Format(time.RFC3339), r.Method, r.URL.Path, r.RemoteAddr, r.UserAgent())
|
||||
|
||||
if path[len(path)-1] == '/' {
|
||||
path += "index.typ"
|
||||
}
|
||||
|
||||
// Convert the path to absolute path
|
||||
filePath, err := jailPath(wwwdata, path)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, "Internal Server Error: Failed to jail request", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the file exists and is not a directory
|
||||
info, err := os.Stat(filePath)
|
||||
if os.IsNotExist(err) || info.IsDir() {
|
||||
// Check if a 404.typ file exists in the root directory
|
||||
path404 := filepath.Join(wwwdata, "404.typ")
|
||||
if _, err := os.Stat(path404); err == nil {
|
||||
filePath = path404
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
} else {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
|
||||
for k, v := range r.Header {
|
||||
headers[strings.ToLower(k)] = strings.Join(v[:], ",")
|
||||
}
|
||||
|
||||
query := make(map[string]string)
|
||||
for k, v := range r.URL.Query() {
|
||||
query[k] = strings.Join(v[:], ",")
|
||||
}
|
||||
|
||||
// Format request data as json for typst input
|
||||
data := struct {
|
||||
Method string `json:"method"`
|
||||
Path string `json:"path"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
Query map[string]string `json:"query"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Ip string `json:"ip,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
}{
|
||||
Method: r.Method,
|
||||
Path: r.URL.Path,
|
||||
Headers: headers,
|
||||
Query: query,
|
||||
Timestamp: time.Now().Format(time.RFC3339),
|
||||
Ip: r.RemoteAddr,
|
||||
Host: r.Host,
|
||||
}
|
||||
jsonData, err := json.Marshal(data)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, "Internal Server Error: Failed to parse request data", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
jsonString := string(jsonData)
|
||||
|
||||
fontsdir := filepath.Join(wwwdata, "fonts")
|
||||
|
||||
// Compile the response
|
||||
cmd := exec.Command("typst", "compile", filePath, "--font-path", fontsdir, "--input", "request="+jsonString, "-")
|
||||
|
||||
// Read stdout and send it to the response
|
||||
cmd.Stdout = w
|
||||
cmd.Stderr = os.Stderr
|
||||
w.Header().Set("Content-Type", "application/pdf")
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
http.Error(w, "Internal Server Error: Failed to compile document", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
Reference in New Issue
Block a user