Refactor API, RAW and WEB

This commit is contained in:
Leonid Maslakov 2023-01-08 18:01:44 +07:00
parent b19f86642b
commit a54180d464
24 changed files with 235 additions and 382 deletions

View File

@ -351,89 +351,14 @@ func main() {
}
// Handlers
http.HandleFunc("/robots.txt", func(rw http.ResponseWriter, req *http.Request) {
webData.RobotsTxtHand(rw, req)
})
if *flagRobotsDisallow == false {
http.HandleFunc("/sitemap.xml", func(rw http.ResponseWriter, req *http.Request) {
webData.SitemapHand(rw, req)
})
}
http.HandleFunc("/style.css", func(rw http.ResponseWriter, req *http.Request) {
webData.StyleCSSHand(rw, req)
})
http.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
webData.MainHand(rw, req)
webData.Handler(rw, req)
})
http.HandleFunc("/main.js", func(rw http.ResponseWriter, req *http.Request) {
webData.MainJSHand(rw, req)
})
http.HandleFunc("/history.js", func(rw http.ResponseWriter, req *http.Request) {
webData.HistoryJSHand(rw, req)
})
http.HandleFunc("/code.js", func(rw http.ResponseWriter, req *http.Request) {
webData.CodeJSHand(rw, req)
})
http.HandleFunc("/paste.js", func(rw http.ResponseWriter, req *http.Request) {
webData.PasteJSHand(rw, req)
})
http.HandleFunc("/settings", func(rw http.ResponseWriter, req *http.Request) {
webData.SettingsHand(rw, req)
})
http.HandleFunc("/terms", func(rw http.ResponseWriter, req *http.Request) {
webData.TermsOfUseHand(rw, req)
})
http.HandleFunc("/raw/", func(rw http.ResponseWriter, req *http.Request) {
rawData.RawHand(rw, req)
rawData.Hand(rw, req)
})
http.HandleFunc("/dl/", func(rw http.ResponseWriter, req *http.Request) {
webData.DlHand(rw, req)
})
http.HandleFunc("/emb/", func(rw http.ResponseWriter, req *http.Request) {
webData.EmbeddedHand(rw, req)
})
http.HandleFunc("/emb_help/", func(rw http.ResponseWriter, req *http.Request) {
webData.EmbeddedHelpHand(rw, req)
})
http.HandleFunc("/about", func(rw http.ResponseWriter, req *http.Request) {
webData.AboutHand(rw, req)
})
http.HandleFunc("/about/authors", func(rw http.ResponseWriter, req *http.Request) {
webData.AuthorsHand(rw, req)
})
http.HandleFunc("/about/license", func(rw http.ResponseWriter, req *http.Request) {
webData.LicenseHand(rw, req)
})
http.HandleFunc("/about/source_code", func(rw http.ResponseWriter, req *http.Request) {
webData.SourceCodePageHand(rw, req)
})
http.HandleFunc("/docs", func(rw http.ResponseWriter, req *http.Request) {
webData.DocsHand(rw, req)
})
http.HandleFunc("/docs/apiv1", func(rw http.ResponseWriter, req *http.Request) {
webData.DocsApiV1Hand(rw, req)
})
http.HandleFunc("/docs/api_libs", func(rw http.ResponseWriter, req *http.Request) {
webData.DocsApiLibsHand(rw, req)
})
http.HandleFunc("/api/", func(rw http.ResponseWriter, req *http.Request) {
apiv1Data.MainHand(rw, req)
})
http.HandleFunc("/api/v1/new", func(rw http.ResponseWriter, req *http.Request) {
apiv1Data.NewHand(rw, req)
})
http.HandleFunc("/api/v1/get", func(rw http.ResponseWriter, req *http.Request) {
apiv1Data.GetHand(rw, req)
})
http.HandleFunc("/api/v1/getServerInfo", func(rw http.ResponseWriter, req *http.Request) {
apiv1Data.GetServerInfoHand(rw, req)
apiv1Data.Hand(rw, req)
})
// Run background job

View File

@ -24,6 +24,7 @@ import (
"git.lcomrade.su/root/lenpaste/internal/netshare"
"git.lcomrade.su/root/lenpaste/internal/storage"
chromaLexers "github.com/alecthomas/chroma/v2/lexers"
"net/http"
)
type Data struct {
@ -75,3 +76,33 @@ func Load(db storage.DB, cfg config.Config) *Data {
UiDefaultLifeTime: &cfg.UiDefaultLifetime,
}
}
func (data *Data) Hand(rw http.ResponseWriter, req *http.Request) {
// Process request
var err error
switch req.URL.Path {
// Search engines
case "/api/v1/new":
err = data.newHand(rw, req)
case "/api/v1/get":
err = data.getHand(rw, req)
case "/api/v1/getServerInfo":
err = data.getServerInfoHand(rw, req)
default:
err = netshare.ErrNotFound
}
// Log
if err == nil {
data.Log.HttpRequest(req, 200)
} else {
code, err := data.writeError(rw, req, err)
if err != nil {
data.Log.HttpError(req, err)
} else {
data.Log.HttpRequest(req, code)
}
}
}

View File

@ -32,7 +32,7 @@ type errorType struct {
Error string `json:"error"`
}
func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error) {
func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error) (int, error) {
var resp errorType
var eTmp429 *netshare.ErrTooManyRequests
@ -70,7 +70,6 @@ func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error)
} else {
resp.Code = 500
resp.Error = "Internal Server Error"
data.Log.HttpError(req, e)
}
rw.Header().Set("Content-Type", "application/json")
@ -78,7 +77,8 @@ func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error)
err := json.NewEncoder(rw).Encode(resp)
if err != nil {
data.Log.HttpError(req, err)
return
return 500, err
}
return resp.Code, nil
}

View File

@ -26,21 +26,16 @@ import (
)
// GET /api/v1/get
func (data *Data) GetHand(rw http.ResponseWriter, req *http.Request) {
func (data *Data) getHand(rw http.ResponseWriter, req *http.Request) error {
// Check rate limit
err := data.RateLimitGet.CheckAndUse(netshare.GetClientAddr(req))
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// Log request
data.Log.HttpRequest(req)
// Check method
if req.Method != "GET" {
data.writeError(rw, req, netshare.ErrMethodNotAllowed)
return
return netshare.ErrMethodNotAllowed
}
// Get paste ID
@ -50,15 +45,13 @@ func (data *Data) GetHand(rw http.ResponseWriter, req *http.Request) {
// Check paste id
if pasteID == "" {
data.writeError(rw, req, netshare.ErrBadRequest)
return
return netshare.ErrBadRequest
}
// Get paste
paste, err := data.DB.PasteGet(pasteID)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// If "one use" paste
@ -67,8 +60,7 @@ func (data *Data) GetHand(rw http.ResponseWriter, req *http.Request) {
// Delete paste
err = data.DB.PasteDelete(pasteID)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
} else {
@ -82,10 +74,5 @@ func (data *Data) GetHand(rw http.ResponseWriter, req *http.Request) {
// Return response
rw.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(rw).Encode(paste)
if err != nil {
data.Log.HttpError(req, err)
return
}
return json.NewEncoder(rw).Encode(paste)
}

View File

@ -32,12 +32,9 @@ type newPasteAnswer struct {
}
// POST /api/v1/new
func (data *Data) NewHand(rw http.ResponseWriter, req *http.Request) {
func (data *Data) newHand(rw http.ResponseWriter, req *http.Request) error {
var err error
// Log request
data.Log.HttpRequest(req)
// Check auth
if *data.LenPasswdFile != "" {
authOk := false
@ -46,36 +43,27 @@ func (data *Data) NewHand(rw http.ResponseWriter, req *http.Request) {
if authExist == true {
authOk, err = lenpasswd.LoadAndCheck(*data.LenPasswdFile, user, pass)
if err != nil {
data.writeError(rw, req, netshare.ErrInternal)
return
return err
}
}
if authOk == false {
data.writeError(rw, req, netshare.ErrUnauthorized)
return
return netshare.ErrUnauthorized
}
}
// Check method
if req.Method != "POST" {
data.writeError(rw, req, netshare.ErrMethodNotAllowed)
return
return netshare.ErrMethodNotAllowed
}
// Get form data and create paste
pasteID, createTime, deleteTime, err := netshare.PasteAddFromForm(req, data.DB, data.RateLimitNew, *data.TitleMaxLen, *data.BodyMaxLen, *data.MaxLifeTime, *data.Lexers)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// Return response
rw.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(rw).Encode(newPasteAnswer{ID: pasteID, CreateTime: createTime, DeleteTime: deleteTime})
if err != nil {
data.Log.HttpError(req, err)
return
}
return json.NewEncoder(rw).Encode(newPasteAnswer{ID: pasteID, CreateTime: createTime, DeleteTime: deleteTime})
}

View File

@ -41,14 +41,10 @@ type serverInfoType struct {
}
// GET /api/v1/getServerInfo
func (data *Data) GetServerInfoHand(rw http.ResponseWriter, req *http.Request) {
// Log request
data.Log.HttpRequest(req)
func (data *Data) getServerInfoHand(rw http.ResponseWriter, req *http.Request) error {
// Check method
if req.Method != "GET" {
data.writeError(rw, req, netshare.ErrMethodNotAllowed)
return
return netshare.ErrMethodNotAllowed
}
// Prepare data
@ -70,10 +66,5 @@ func (data *Data) GetServerInfoHand(rw http.ResponseWriter, req *http.Request) {
// Return response
rw.Header().Set("Content-Type", "application/json")
err := json.NewEncoder(rw).Encode(serverInfo)
if err != nil {
data.Log.HttpError(req, err)
return
}
return json.NewEncoder(rw).Encode(serverInfo)
}

View File

@ -44,10 +44,10 @@ func (cfg Logger) Error(e error) {
fmt.Fprintln(os.Stderr, time.Now().Format(cfg.TimeFormat), "[ERROR] ", e.Error())
}
func (cfg Logger) HttpRequest(req *http.Request) {
fmt.Fprintln(os.Stdout, time.Now().Format(cfg.TimeFormat), "[REQUEST]", netshare.GetClientAddr(req).String(), req.Method, req.URL.Path, "(User-Agent: "+req.UserAgent()+")")
func (cfg Logger) HttpRequest(req *http.Request, code int) {
fmt.Fprintln(os.Stdout, time.Now().Format(cfg.TimeFormat), "[REQUEST]", netshare.GetClientAddr(req).String(), req.Method, code, req.URL.Path, "(User-Agent: "+req.UserAgent()+")")
}
func (cfg Logger) HttpError(req *http.Request, e error) {
fmt.Fprintln(os.Stderr, time.Now().Format(cfg.TimeFormat), "[ERROR] ", netshare.GetClientAddr(req).String(), req.Method, req.URL.Path, "(User-Agent: "+req.UserAgent()+")", "Error:", e.Error())
fmt.Fprintln(os.Stderr, time.Now().Format(cfg.TimeFormat), "[ERROR] ", netshare.GetClientAddr(req).String(), req.Method, 500, req.URL.Path, "(User-Agent: "+req.UserAgent()+")", "Error:", e.Error())
}

View File

@ -23,6 +23,7 @@ import (
"git.lcomrade.su/root/lenpaste/internal/logger"
"git.lcomrade.su/root/lenpaste/internal/netshare"
"git.lcomrade.su/root/lenpaste/internal/storage"
"net/http"
)
type Data struct {
@ -39,3 +40,19 @@ func Load(db storage.DB, cfg config.Config) *Data {
RateLimitGet: cfg.RateLimitGet,
}
}
func (data *Data) Hand(rw http.ResponseWriter, req *http.Request) {
err := data.rawHand(rw, req)
if err == nil {
data.Log.HttpRequest(req, 200)
} else {
code, err := data.writeError(rw, req, err)
if err != nil {
data.Log.HttpError(req, err)
} else {
data.Log.HttpRequest(req, code)
}
}
}

View File

@ -27,7 +27,7 @@ import (
"strconv"
)
func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error) {
func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error) (int, error) {
var errText string
var errCode int
@ -40,13 +40,12 @@ func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error)
} else if errors.As(e, &eTmp429) {
errCode = 429
errText = "Too Many Requests"
errText = "429 Too Many Requests"
rw.Header().Set("Retry-After", strconv.FormatInt(eTmp429.RetryAfter, 10))
} else {
errCode = 500
errText = "500 Internal Server Error"
data.Log.HttpError(req, e)
}
// Write response
@ -55,6 +54,8 @@ func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error)
_, err := io.WriteString(rw, errText)
if err != nil {
data.Log.HttpError(req, e)
return 500, err
}
return errCode, nil
}

View File

@ -20,36 +20,24 @@ package raw
import (
"git.lcomrade.su/root/lenpaste/internal/netshare"
"git.lcomrade.su/root/lenpaste/internal/storage"
"io"
"net/http"
)
// Pattern: /raw/
func (data *Data) RawHand(rw http.ResponseWriter, req *http.Request) {
func (data *Data) rawHand(rw http.ResponseWriter, req *http.Request) error {
// Check rate limit
err := data.RateLimitGet.CheckAndUse(netshare.GetClientAddr(req))
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// Log request
data.Log.HttpRequest(req)
// Read DB
pasteID := string([]rune(req.URL.Path)[5:])
paste, err := data.DB.PasteGet(pasteID)
if err != nil {
if err == storage.ErrNotFoundID {
data.writeError(rw, req, err)
return
} else {
data.writeError(rw, req, err)
return
}
return err
}
// If "one use" paste
@ -57,8 +45,7 @@ func (data *Data) RawHand(rw http.ResponseWriter, req *http.Request) {
// Delete paste
err = data.DB.PasteDelete(pasteID)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
}
@ -67,7 +54,8 @@ func (data *Data) RawHand(rw http.ResponseWriter, req *http.Request) {
_, err = io.WriteString(rw, paste.Body)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
return nil
}

View File

@ -26,6 +26,8 @@ import (
"git.lcomrade.su/root/lenpaste/internal/storage"
chromaLexers "github.com/alecthomas/chroma/v2/lexers"
"html/template"
"net/http"
"strings"
textTemplate "text/template"
)
@ -264,3 +266,75 @@ func Load(db storage.DB, cfg config.Config) (*Data, error) {
return &data, nil
}
func (data *Data) Handler(rw http.ResponseWriter, req *http.Request) {
// Process request
var err error
switch req.URL.Path {
// Search engines
case "/robots.txt":
err = data.robotsTxtHand(rw, req)
case "/sitemap.xml":
err = data.sitemapHand(rw, req)
// Resources
case "/style.css":
err = data.styleCSSHand(rw, req)
case "/main.js":
err = data.mainJSHand(rw, req)
case "/history.js":
err = data.historyJSHand(rw, req)
case "/code.js":
err = data.codeJSHand(rw, req)
case "/paste.js":
err = data.pasteJSHand(rw, req)
case "/about":
err = data.aboutHand(rw, req)
case "/about/authors":
err = data.authorsHand(rw, req)
case "/about/license":
err = data.licenseHand(rw, req)
case "/about/source_code":
err = data.sourceCodePageHand(rw, req)
case "/docs":
err = data.docsHand(rw, req)
case "/docs/apiv1":
err = data.docsApiV1Hand(rw, req)
case "/docs/api_libs":
err = data.docsApiLibsHand(rw, req)
// Pages
case "/":
err = data.newPasteHand(rw, req)
case "/settings":
err = data.settingsHand(rw, req)
case "/terms":
err = data.termsOfUseHand(rw, req)
// Else
default:
if strings.HasPrefix(req.URL.Path, "/dl/") {
err = data.dlHand(rw, req)
} else if strings.HasPrefix(req.URL.Path, "/emb/") {
err = data.embeddedHand(rw, req)
} else if strings.HasPrefix(req.URL.Path, "/emb_help/") {
err = data.embeddedHelpHand(rw, req)
} else {
err = data.getPasteHand(rw, req)
}
}
// Log
if err == nil {
data.Log.HttpRequest(req, 200)
} else {
code, err := data.writeError(rw, req, err)
if err != nil {
data.Log.HttpError(req, err)
} else {
data.Log.HttpRequest(req, code)
}
}
}

View File

@ -45,11 +45,7 @@ type aboutMinTmp struct {
}
// Pattern: /about
func (data *Data) AboutHand(rw http.ResponseWriter, req *http.Request) {
// Log request
data.Log.HttpRequest(req)
// Prepare data
func (data *Data) aboutHand(rw http.ResponseWriter, req *http.Request) error {
dataTmpl := aboutTmpl{
Version: *data.Version,
TitleMaxLen: *data.TitleMaxLen,
@ -64,53 +60,24 @@ func (data *Data) AboutHand(rw http.ResponseWriter, req *http.Request) {
Translate: data.Locales.findLocale(req).translate,
}
// Show page
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
err := data.About.Execute(rw, dataTmpl)
if err != nil {
data.writeError(rw, req, err)
}
return data.About.Execute(rw, dataTmpl)
}
// Pattern: /about/authors
func (data *Data) AuthorsHand(rw http.ResponseWriter, req *http.Request) {
// Log request
data.Log.HttpRequest(req)
// Show page
func (data *Data) authorsHand(rw http.ResponseWriter, req *http.Request) error {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
err := data.Authors.Execute(rw, aboutMinTmp{Translate: data.Locales.findLocale(req).translate})
if err != nil {
data.writeError(rw, req, err)
}
return data.Authors.Execute(rw, aboutMinTmp{Translate: data.Locales.findLocale(req).translate})
}
// Pattern: /about/license
func (data *Data) LicenseHand(rw http.ResponseWriter, req *http.Request) {
// Log request
data.Log.HttpRequest(req)
// Show page
func (data *Data) licenseHand(rw http.ResponseWriter, req *http.Request) error {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
err := data.License.Execute(rw, aboutMinTmp{Translate: data.Locales.findLocale(req).translate})
if err != nil {
data.writeError(rw, req, err)
}
return data.License.Execute(rw, aboutMinTmp{Translate: data.Locales.findLocale(req).translate})
}
// Pattern: /about/source_code
func (data *Data) SourceCodePageHand(rw http.ResponseWriter, req *http.Request) {
// Log request
data.Log.HttpRequest(req)
// Show page
func (data *Data) sourceCodePageHand(rw http.ResponseWriter, req *http.Request) error {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
err := data.SourceCodePage.Execute(rw, aboutMinTmp{Translate: data.Locales.findLocale(req).translate})
if err != nil {
data.writeError(rw, req, err)
}
return data.SourceCodePage.Execute(rw, aboutMinTmp{Translate: data.Locales.findLocale(req).translate})
}

View File

@ -27,24 +27,19 @@ import (
)
// Pattern: /dl/
func (data *Data) DlHand(rw http.ResponseWriter, req *http.Request) {
func (data *Data) dlHand(rw http.ResponseWriter, req *http.Request) error {
// Check rate limit
err := data.RateLimitGet.CheckAndUse(netshare.GetClientAddr(req))
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// Log request
data.Log.HttpRequest(req)
// Read DB
pasteID := string([]rune(req.URL.Path)[4:])
paste, err := data.DB.PasteGet(pasteID)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// If "one use" paste
@ -52,8 +47,7 @@ func (data *Data) DlHand(rw http.ResponseWriter, req *http.Request) {
// Delete paste
err = data.DB.PasteDelete(pasteID)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
}
@ -79,4 +73,6 @@ func (data *Data) DlHand(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("Expires", "0")
http.ServeContent(rw, req, fileName, createTime, strings.NewReader(paste.Body))
return nil
}

View File

@ -37,41 +37,23 @@ type docsApiV1Tmpl struct {
}
// Pattern: /docs
func (data *Data) DocsHand(rw http.ResponseWriter, req *http.Request) {
data.Log.HttpRequest(req)
func (data *Data) docsHand(rw http.ResponseWriter, req *http.Request) error {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
err := data.Docs.Execute(rw, docsTmpl{Translate: data.Locales.findLocale(req).translate})
if err != nil {
data.writeError(rw, req, err)
return
}
return data.Docs.Execute(rw, docsTmpl{Translate: data.Locales.findLocale(req).translate})
}
// Pattern: /docs/apiv1
func (data *Data) DocsApiV1Hand(rw http.ResponseWriter, req *http.Request) {
data.Log.HttpRequest(req)
func (data *Data) docsApiV1Hand(rw http.ResponseWriter, req *http.Request) error {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
err := data.DocsApiV1.Execute(rw, docsApiV1Tmpl{
return data.DocsApiV1.Execute(rw, docsApiV1Tmpl{
MaxLenAuthorAll: netshare.MaxLengthAuthorAll,
Translate: data.Locales.findLocale(req).translate,
Highlight: data.Themes.findTheme(req, data.UiDefaultTheme).tryHighlight,
})
if err != nil {
data.writeError(rw, req, err)
return
}
}
// Pattern: /docs/api_libs
func (data *Data) DocsApiLibsHand(rw http.ResponseWriter, req *http.Request) {
data.Log.HttpRequest(req)
func (data *Data) docsApiLibsHand(rw http.ResponseWriter, req *http.Request) error {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
err := data.DocsApiLibs.Execute(rw, docsTmpl{Translate: data.Locales.findLocale(req).translate})
if err != nil {
data.writeError(rw, req, err)
return
}
return data.DocsApiLibs.Execute(rw, docsTmpl{Translate: data.Locales.findLocale(req).translate})
}

View File

@ -39,18 +39,15 @@ type embTmpl struct {
}
// Pattern: /emb/
func (data *Data) EmbeddedHand(rw http.ResponseWriter, req *http.Request) {
func (data *Data) embeddedHand(rw http.ResponseWriter, req *http.Request) error {
errorNotFound := false
// Check rate limit
err := data.RateLimitGet.CheckAndUse(netshare.GetClientAddr(req))
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// Log request
errorNotFound := false
data.Log.HttpRequest(req)
// Get paste ID
pasteID := string([]rune(req.URL.Path)[5:])
@ -61,8 +58,7 @@ func (data *Data) EmbeddedHand(rw http.ResponseWriter, req *http.Request) {
errorNotFound = true
} else {
data.writeError(rw, req, err)
return
return err
}
}
@ -82,9 +78,5 @@ func (data *Data) EmbeddedHand(rw http.ResponseWriter, req *http.Request) {
}
// Show paste
err = data.EmbeddedPage.Execute(rw, tmplData)
if err != nil {
data.writeError(rw, req, err)
return
}
return data.EmbeddedPage.Execute(rw, tmplData)
}

View File

@ -37,25 +37,20 @@ type embHelpTmpl struct {
}
// Pattern: /emb_help/
func (data *Data) EmbeddedHelpHand(rw http.ResponseWriter, req *http.Request) {
func (data *Data) embeddedHelpHand(rw http.ResponseWriter, req *http.Request) error {
// Check rate limit
err := data.RateLimitGet.CheckAndUse(netshare.GetClientAddr(req))
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// Log request
data.Log.HttpRequest(req)
// Get paste ID
pasteID := string([]rune(req.URL.Path)[10:])
// Read DB
paste, err := data.DB.PasteGet(pasteID)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// Show paste
@ -69,9 +64,5 @@ func (data *Data) EmbeddedHelpHand(rw http.ResponseWriter, req *http.Request) {
Highlight: data.Themes.findTheme(req, data.UiDefaultTheme).tryHighlight,
}
err = data.EmbeddedHelpPage.Execute(rw, tmplData)
if err != nil {
data.writeError(rw, req, err)
return
}
return data.EmbeddedHelpPage.Execute(rw, tmplData)
}

View File

@ -34,7 +34,7 @@ type errorTmpl struct {
Translate func(string, ...interface{}) template.HTML
}
func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error) {
func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error) (int, error) {
errData := errorTmpl{
Code: 0,
AdminName: *data.AdminName,
@ -69,7 +69,6 @@ func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error)
} else {
errData.Code = 500
data.Log.HttpError(req, e)
}
// Write response header
@ -79,6 +78,8 @@ func (data *Data) writeError(rw http.ResponseWriter, req *http.Request, e error)
// Render template
err := data.ErrorPage.Execute(rw, errData)
if err != nil {
data.Log.HttpError(req, err)
return 500, err
}
return errData.Code, nil
}

View File

@ -46,21 +46,16 @@ type pasteTmpl struct {
Translate func(string, ...interface{}) template.HTML
}
type pasteJsTmpl struct {
Translate func(string, ...interface{}) template.HTML
}
type pasteContinueTmpl struct {
ID string
Translate func(string, ...interface{}) template.HTML
}
func (data *Data) getPaste(rw http.ResponseWriter, req *http.Request) {
func (data *Data) getPasteHand(rw http.ResponseWriter, req *http.Request) error {
// Check rate limit
err := data.RateLimitGet.CheckAndUse(netshare.GetClientAddr(req))
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// Get paste ID
@ -69,8 +64,7 @@ func (data *Data) getPaste(rw http.ResponseWriter, req *http.Request) {
// Read DB
paste, err := data.DB.PasteGet(pasteID)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// If "one use" paste
@ -84,20 +78,13 @@ func (data *Data) getPaste(rw http.ResponseWriter, req *http.Request) {
Translate: data.Locales.findLocale(req).translate,
}
err = data.PasteContinue.Execute(rw, tmplData)
if err != nil {
data.writeError(rw, req, err)
return
}
return
return data.PasteContinue.Execute(rw, tmplData)
}
// If continue button pressed delete paste
err = data.DB.PasteDelete(pasteID)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
}
@ -135,16 +122,5 @@ func (data *Data) getPaste(rw http.ResponseWriter, req *http.Request) {
}
// Show paste
err = data.PastePage.Execute(rw, tmplData)
if err != nil {
data.writeError(rw, req, err)
return
}
}
func (data *Data) PasteJSHand(rw http.ResponseWriter, req *http.Request) {
data.Log.HttpRequest(req)
rw.Header().Set("Content-Type", "application/javascript; charset=utf-8")
data.PasteJS.Execute(rw, pasteJsTmpl{Translate: data.Locales.findLocale(req).translate})
return data.PastePage.Execute(rw, tmplData)
}

View File

@ -1,38 +0,0 @@
// Copyright (C) 2021-2023 Leonid Maslakov.
// This file is part of Lenpaste.
// Lenpaste is free software: you can redistribute it
// and/or modify it under the terms of the
// GNU Affero Public License as published by the
// Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
// Lenpaste is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Affero Public License for more details.
// You should have received a copy of the GNU Affero Public License along with Lenpaste.
// If not, see <https://www.gnu.org/licenses/>.
package web
import (
"net/http"
)
// Pattern: /
func (data *Data) MainHand(rw http.ResponseWriter, req *http.Request) {
// Log request
data.Log.HttpRequest(req)
// If main page
if req.URL.Path == "/" {
data.newPaste(rw, req)
// Else show paste
} else {
data.getPaste(rw, req)
}
}

View File

@ -43,7 +43,7 @@ type createTmpl struct {
Translate func(string, ...interface{}) template.HTML
}
func (data *Data) newPaste(rw http.ResponseWriter, req *http.Request) {
func (data *Data) newPasteHand(rw http.ResponseWriter, req *http.Request) error {
var err error
// Check auth
@ -56,8 +56,7 @@ func (data *Data) newPaste(rw http.ResponseWriter, req *http.Request) {
if authExist == true {
authOk, err = lenpasswd.LoadAndCheck(*data.LenPasswdFile, user, pass)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
}
@ -71,13 +70,12 @@ func (data *Data) newPaste(rw http.ResponseWriter, req *http.Request) {
if req.Method == "POST" {
pasteID, _, _, err := netshare.PasteAddFromForm(req, data.DB, data.RateLimitNew, *data.TitleMaxLen, *data.BodyMaxLen, *data.MaxLifeTime, *data.Lexers)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
// Redirect to paste
writeRedirect(rw, req, "/"+pasteID, 302)
return
return nil
}
// Else show create page
@ -98,9 +96,5 @@ func (data *Data) newPaste(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
err = data.Main.Execute(rw, tmplData)
if err != nil {
data.writeError(rw, req, err)
return
}
return data.Main.Execute(rw, tmplData)
}

View File

@ -32,40 +32,38 @@ type jsTmpl struct {
Theme func(string) string
}
func (data *Data) StyleCSSHand(rw http.ResponseWriter, req *http.Request) {
data.Log.HttpRequest(req)
func (data *Data) styleCSSHand(rw http.ResponseWriter, req *http.Request) error {
rw.Header().Set("Content-Type", "text/css; charset=utf-8")
data.StyleCSS.Execute(rw, jsTmpl{
return data.StyleCSS.Execute(rw, jsTmpl{
Translate: data.Locales.findLocale(req).translate,
Theme: data.Themes.findTheme(req, data.UiDefaultTheme).theme,
})
}
func (data *Data) MainJSHand(rw http.ResponseWriter, req *http.Request) {
data.Log.HttpRequest(req)
func (data *Data) mainJSHand(rw http.ResponseWriter, req *http.Request) error {
rw.Header().Set("Content-Type", "application/javascript; charset=utf-8")
rw.Write(*data.MainJS)
return nil
}
func (data *Data) CodeJSHand(rw http.ResponseWriter, req *http.Request) {
data.Log.HttpRequest(req)
func (data *Data) codeJSHand(rw http.ResponseWriter, req *http.Request) error {
rw.Header().Set("Content-Type", "application/javascript; charset=utf-8")
data.CodeJS.Execute(rw, jsTmpl{Translate: data.Locales.findLocale(req).translate})
return data.CodeJS.Execute(rw, jsTmpl{Translate: data.Locales.findLocale(req).translate})
}
func (data *Data) HistoryJSHand(rw http.ResponseWriter, req *http.Request) {
data.Log.HttpRequest(req)
func (data *Data) historyJSHand(rw http.ResponseWriter, req *http.Request) error {
rw.Header().Set("Content-Type", "application/javascript; charset=utf-8")
data.HistoryJS.Execute(rw, jsTmpl{
return data.HistoryJS.Execute(rw, jsTmpl{
Translate: data.Locales.findLocale(req).translate,
Theme: data.Themes.findTheme(req, data.UiDefaultTheme).theme,
})
}
func (data *Data) pasteJSHand(rw http.ResponseWriter, req *http.Request) error {
rw.Header().Set("Content-Type", "application/javascript; charset=utf-8")
return data.PasteJS.Execute(rw, jsTmpl{Translate: data.Locales.findLocale(req).translate})
}
func init() {
resp := "\u0045\u0072\u0072\u006f\u0072\u002e\u0020\u0059\u006f\u0075\u0020\u006d\u0061"
resp += "\u0079\u0020\u0062\u0065\u0020\u0076\u0069\u006f\u006c\u0061\u0074\u0069\u006e"

View File

@ -45,12 +45,9 @@ type settingsTmpl struct {
}
// Pattern: /settings
func (data *Data) SettingsHand(rw http.ResponseWriter, req *http.Request) {
func (data *Data) settingsHand(rw http.ResponseWriter, req *http.Request) error {
var err error
// Log request
data.Log.HttpRequest(req)
// Check auth
authOk := true
@ -61,8 +58,7 @@ func (data *Data) SettingsHand(rw http.ResponseWriter, req *http.Request) {
if authExist == true {
authOk, err = lenpasswd.LoadAndCheck(*data.LenPasswdFile, user, pass)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
}
}
@ -181,4 +177,6 @@ func (data *Data) SettingsHand(rw http.ResponseWriter, req *http.Request) {
writeRedirect(rw, req, "/settings", 302)
}
return nil
}

View File

@ -24,9 +24,7 @@ import (
"net/http"
)
func (data *Data) RobotsTxtHand(rw http.ResponseWriter, req *http.Request) {
data.Log.HttpRequest(req)
func (data *Data) robotsTxtHand(rw http.ResponseWriter, req *http.Request) error {
// Generate robots.txt
robotsTxt := "User-agent: *\nDisallow: /\n"
@ -41,13 +39,16 @@ func (data *Data) RobotsTxtHand(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
_, err := io.WriteString(rw, robotsTxt)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
return nil
}
func (data *Data) SitemapHand(rw http.ResponseWriter, req *http.Request) {
data.Log.HttpRequest(req)
func (data *Data) sitemapHand(rw http.ResponseWriter, req *http.Request) error {
if *data.RobotsDisallow {
return netshare.ErrNotFound
}
// Get protocol and host
proto := netshare.GetProtocol(req.Header)
@ -66,7 +67,8 @@ func (data *Data) SitemapHand(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("Content-Type", "text/xml; charset=utf-8")
_, err := io.WriteString(rw, sitemapXML)
if err != nil {
data.writeError(rw, req, err)
return
return err
}
return nil
}

View File

@ -31,19 +31,11 @@ type termsOfUseTmpl struct {
}
// Pattern: /terms
func (data *Data) TermsOfUseHand(rw http.ResponseWriter, req *http.Request) {
// Log request
data.Log.HttpRequest(req)
// Show page
func (data *Data) termsOfUseHand(rw http.ResponseWriter, req *http.Request) error {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
err := data.TermsOfUse.Execute(rw, termsOfUseTmpl{
return data.TermsOfUse.Execute(rw, termsOfUseTmpl{
TermsOfUse: *data.ServerTermsOfUse,
Highlight: data.Themes.findTheme(req, data.UiDefaultTheme).tryHighlight,
Translate: data.Locales.findLocale(req).translate},
)
if err != nil {
data.writeError(rw, req, err)
}
}