github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/routes/misc.go (about)

     1  package routes
     2  
     3  import (
     4  	"bytes"
     5  	"database/sql"
     6  	"io"
     7  	"net/http"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  
    12  	//"fmt"
    13  
    14  	c "github.com/Azareal/Gosora/common"
    15  	"github.com/Azareal/Gosora/common/phrases"
    16  )
    17  
    18  var cacheControlMaxAge = "max-age=" + strconv.Itoa(int(c.Day))      // TODO: Make this a c.Config value
    19  var cacheControlMaxAgeWeek = "max-age=" + strconv.Itoa(int(c.Week)) // TODO: Make this a c.Config value
    20  
    21  // GET functions
    22  func StaticFile(w http.ResponseWriter, r *http.Request) {
    23  	file, ok := c.StaticFiles.Get(r.URL.Path)
    24  	if !ok {
    25  		//c.DebugLogf("Failed to find '%s'", r.URL.Path) // TODO: Use MicroNotFound? Might be better than the unneccessary overhead of sprintf
    26  		w.WriteHeader(http.StatusNotFound)
    27  		return
    28  	}
    29  	h := w.Header()
    30  
    31  	if file.Length > 300 {
    32  		if h.Get("Range") != "" {
    33  			h.Set("Vary", "Accept-Encoding")
    34  			if len(file.Sha256) != 0 {
    35  				h.Set("Cache-Control", cacheControlMaxAgeWeek)
    36  			} else {
    37  				h.Set("Cache-Control", cacheControlMaxAge) //Cache-Control: max-age=31536000
    38  			}
    39  			ae := r.Header.Get("Accept-Encoding")
    40  
    41  			if file.BrLength > 300 && strings.Contains(ae, "br") {
    42  				h.Set("Content-Encoding", "br")
    43  				h.Set("Content-Length", file.StrBrLength)
    44  				http.ServeContent(w, r, r.URL.Path, file.Info.ModTime(), bytes.NewReader(file.BrData))
    45  				return
    46  			}
    47  
    48  			if file.GzipLength > 300 && strings.Contains(ae, "gzip") {
    49  				h.Set("Content-Encoding", "gzip")
    50  				h.Set("Content-Length", file.StrGzipLength)
    51  				http.ServeContent(w, r, r.URL.Path, file.Info.ModTime(), bytes.NewReader(file.GzipData))
    52  				return
    53  			}
    54  
    55  			h.Set("Content-Length", file.StrLength)
    56  			http.ServeContent(w, r, r.URL.Path, file.Info.ModTime(), bytes.NewReader(file.Data))
    57  			return
    58  		}
    59  	}
    60  
    61  	// Surely, there's a more efficient way of doing this?
    62  	t, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since"))
    63  	if err == nil && file.Info.ModTime().Before(t.Add(1*time.Second)) {
    64  		w.WriteHeader(http.StatusNotModified)
    65  		return
    66  	}
    67  	h.Set("Last-Modified", file.FormattedModTime)
    68  	h.Set("Content-Type", file.Mimetype)
    69  	if len(file.Sha256) != 0 {
    70  		h.Set("Cache-Control", cacheControlMaxAgeWeek)
    71  	} else {
    72  		h.Set("Cache-Control", cacheControlMaxAge) //Cache-Control: max-age=31536000
    73  	}
    74  	h.Set("Vary", "Accept-Encoding")
    75  
    76  	if file.BrLength > 0 && strings.Contains(r.Header.Get("Accept-Encoding"), "br") {
    77  		h.Set("Content-Encoding", "br")
    78  		h.Set("Content-Length", file.StrBrLength)
    79  		io.Copy(w, bytes.NewReader(file.BrData)) // Use w.Write instead?
    80  	} else if file.GzipLength > 0 && strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
    81  		h.Set("Content-Encoding", "gzip")
    82  		h.Set("Content-Length", file.StrGzipLength)
    83  		io.Copy(w, bytes.NewReader(file.GzipData)) // Use w.Write instead?
    84  	} else {
    85  		h.Set("Content-Length", file.StrLength)
    86  		io.Copy(w, bytes.NewReader(file.Data))
    87  	}
    88  	// Other options instead of io.Copy: io.CopyN(), w.Write(), http.ServeContent()
    89  }
    90  
    91  func Overview(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError {
    92  	h.Title = phrases.GetTitlePhrase("overview")
    93  	h.Zone = "overview"
    94  	return renderTemplate("overview", w, r, h, c.Page{h, tList, nil})
    95  }
    96  
    97  func CustomPage(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header, name string) c.RouteError {
    98  	h.Zone = "custom_page"
    99  	name = c.SanitiseSingleLine(name)
   100  	page, err := c.Pages.GetByName(name)
   101  	if err == nil {
   102  		h.Title = page.Title
   103  		return renderTemplate("custom_page", w, r, h, c.CustomPagePage{h, page})
   104  	} else if err != sql.ErrNoRows {
   105  		return c.InternalError(err, w, r)
   106  	}
   107  	h.Title = phrases.GetTitlePhrase("page")
   108  
   109  	// TODO: Pass the page name to the pre-render hook?
   110  	err = renderTemplate3("page_"+name, "tmpl_page", w, r, h, c.Page{h, tList, nil})
   111  	if err == c.ErrBadDefaultTemplate {
   112  		return c.NotFound(w, r, h)
   113  	} else if err != nil {
   114  		return c.InternalError(err, w, r)
   115  	}
   116  	return nil
   117  }
   118  
   119  // TODO: Set the cookie domain
   120  func ChangeTheme(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
   121  	//headerLite, _ := SimpleUserCheck(w, r, u)
   122  	// TODO: Rename js to something else, just in case we rewrite the JS side in WebAssembly?
   123  	js := r.PostFormValue("js") == "1"
   124  	newTheme := c.SanitiseSingleLine(r.PostFormValue("theme"))
   125  	//fmt.Printf("newTheme: %+v\n", newTheme)
   126  
   127  	theme, ok := c.Themes[newTheme]
   128  	if !ok || theme.HideFromThemes {
   129  		return c.LocalErrorJSQ("That theme doesn't exist", w, r, u, js)
   130  	}
   131  
   132  	cookie := http.Cookie{Name: "current_theme", Value: newTheme, Path: "/", MaxAge: int(c.Year)}
   133  	http.SetCookie(w, &cookie)
   134  	return actionSuccess(w, r, "/", js)
   135  }