2024-07-02 14:24:08 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2024-07-02 17:48:05 +03:00
|
|
|
"bufio"
|
|
|
|
"bytes"
|
|
|
|
"database/sql"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
2024-07-02 14:24:08 +03:00
|
|
|
"github.com/valyala/fasthttp"
|
|
|
|
)
|
|
|
|
|
2024-07-02 17:48:05 +03:00
|
|
|
const behindProxy = true
|
|
|
|
|
|
|
|
var removeHeaders = map[string]bool{
|
|
|
|
"date": true,
|
|
|
|
"expires": true,
|
|
|
|
"server": true,
|
|
|
|
}
|
|
|
|
|
|
|
|
var conn *sql.DB
|
|
|
|
var stmt *sql.Stmt
|
|
|
|
|
2024-07-02 14:24:08 +03:00
|
|
|
func main() {
|
2024-07-02 17:48:05 +03:00
|
|
|
db, err := sql.Open("sqlite3", "archive.db")
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
conn = db
|
|
|
|
defer db.Close()
|
|
|
|
|
|
|
|
sel_stmt, err := db.Prepare("select id, code from data where method = ? and url = ? limit 1")
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
stmt = sel_stmt
|
2024-07-02 18:09:09 +03:00
|
|
|
defer sel_stmt.Close()
|
2024-07-02 17:48:05 +03:00
|
|
|
|
2024-07-02 14:24:08 +03:00
|
|
|
fasthttp.ListenAndServe("127.0.0.1:4001", handler)
|
|
|
|
}
|
|
|
|
|
|
|
|
func handler(ctx *fasthttp.RequestCtx) {
|
2024-07-02 17:48:05 +03:00
|
|
|
// -- find in DB and read id+code
|
|
|
|
uri := ctx.URI()
|
|
|
|
|
|
|
|
var scheme []byte
|
|
|
|
if behindProxy {
|
|
|
|
scheme = ctx.Request.Header.Peek("X-Forwarded-Proto")
|
|
|
|
} else {
|
|
|
|
scheme = uri.Scheme()
|
|
|
|
}
|
|
|
|
|
|
|
|
host, port := parseHost(
|
|
|
|
uri.Host(),
|
|
|
|
bytes.Equal(scheme, []byte("https")),
|
|
|
|
)
|
|
|
|
|
|
|
|
row := stmt.QueryRow(
|
2024-07-02 18:14:30 +03:00
|
|
|
string(ctx.Method()),
|
2024-07-02 17:48:05 +03:00
|
|
|
fmt.Sprintf(
|
2024-07-02 18:08:15 +03:00
|
|
|
"%s://%s:%s%s",
|
2024-07-02 17:48:05 +03:00
|
|
|
scheme,
|
|
|
|
host,
|
|
|
|
port,
|
|
|
|
ctx.RequestURI(),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
var id int
|
|
|
|
var code int
|
|
|
|
|
|
|
|
err := row.Scan(&id, &code)
|
2024-07-02 18:13:22 +03:00
|
|
|
if err == sql.ErrNoRows {
|
2024-07-02 17:48:05 +03:00
|
|
|
ctx.Response.SetStatusCode(404)
|
|
|
|
return
|
2024-07-02 18:13:22 +03:00
|
|
|
} else if err != nil {
|
2024-07-02 18:22:32 +03:00
|
|
|
sendError(ctx, "Unable to fetch row: ", err)
|
2024-07-02 18:13:22 +03:00
|
|
|
return
|
2024-07-02 17:48:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// -- set status code
|
2024-07-02 18:37:55 +03:00
|
|
|
ctx.Response.SetStatusCode(code)
|
2024-07-02 17:48:05 +03:00
|
|
|
|
|
|
|
// -- find in FS and read headers+body
|
|
|
|
path := "storage/" + string(id)
|
|
|
|
|
|
|
|
fh, err := os.Open(path + "/headers")
|
|
|
|
if err != nil {
|
2024-07-02 18:22:32 +03:00
|
|
|
sendError(ctx, "Unable to read headers: ", err)
|
2024-07-02 17:48:05 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
sc := bufio.NewScanner(fh)
|
|
|
|
for sc.Scan() {
|
|
|
|
header := strings.SplitN(sc.Text(), ": ", 2)
|
|
|
|
name, value := strings.ToLower(header[0]), header[1]
|
|
|
|
if removeHeaders[name] {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
ctx.Response.Header.Add(name, value)
|
|
|
|
}
|
|
|
|
fh.Close()
|
|
|
|
|
|
|
|
fb, err := os.Open(path + "/body")
|
|
|
|
if err != nil {
|
2024-07-02 18:22:32 +03:00
|
|
|
sendError(ctx, "Unable to read body: ", err)
|
2024-07-02 17:48:05 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Response.SetBodyStream(fb, -1)
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseHost(host []byte, https bool) ([]byte, []byte) {
|
|
|
|
idx := bytes.LastIndex(host, []byte(":"))
|
2024-07-02 17:57:42 +03:00
|
|
|
var resHost, port []byte
|
2024-07-02 17:48:05 +03:00
|
|
|
if idx != -1 {
|
2024-07-02 17:57:42 +03:00
|
|
|
resHost = host[:idx]
|
2024-07-02 17:48:05 +03:00
|
|
|
port = host[idx+1:]
|
|
|
|
} else {
|
2024-07-02 17:57:42 +03:00
|
|
|
resHost = host
|
2024-07-02 17:48:05 +03:00
|
|
|
if https {
|
|
|
|
port = []byte("443")
|
|
|
|
} else {
|
|
|
|
port = []byte("80")
|
|
|
|
}
|
|
|
|
}
|
2024-07-02 17:57:42 +03:00
|
|
|
return resHost, port
|
2024-07-02 14:24:08 +03:00
|
|
|
}
|
2024-07-02 18:22:32 +03:00
|
|
|
|
|
|
|
func sendError(ctx *fasthttp.RequestCtx, msg string, err error) {
|
|
|
|
ctx.Response.SetStatusCode(500)
|
|
|
|
ctx.Response.SetBodyString(msg + err.Error())
|
|
|
|
}
|