Changeset 67 in code for trunk/cmd


Ignore:
Timestamp:
Feb 11, 2024, 2:08:18 AM (16 months ago)
Author:
yakumo.izuru
Message:

リファクタリングと再設計

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

Location:
trunk/cmd/marisa
Files:
10 added
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/cmd/marisa/main.go

    r65 r67  
    22
    33import (
    4         "encoding/json"
    54        "flag"
    6         "fmt"
    7         "html/template"
    8         "io"
    9         "io/ioutil"
    105        "log"
    116        "net"
     
    149        "os"
    1510        "os/signal"
    16         "os/user"
    17         "path"
    18         "path/filepath"
    19         "strconv"
    2011        "syscall"
    21         "time"
    2212
    23         "github.com/dustin/go-humanize"
    24         "gopkg.in/ini.v1"
    2513        "marisa.chaotic.ninja/marisa"
    2614)
     
    5442
    5543var verbose bool
    56 
    57 func writefile(f *os.File, s io.ReadCloser, contentlength int64) error {
    58         buffer := make([]byte, 4096)
    59         eof := false
    60         sz := int64(0)
    61 
    62         defer f.Sync()
    63 
    64         for !eof {
    65                 n, err := s.Read(buffer)
    66                 if err != nil && err != io.EOF {
    67                         return err
    68                 } else if err == io.EOF {
    69                         eof = true
    70                 }
    71 
    72                 /* ensure we don't write more than expected */
    73                 r := int64(n)
    74                 if sz+r > contentlength {
    75                         r = contentlength - sz
    76                         eof = true
    77                 }
    78 
    79                 _, err = f.Write(buffer[:r])
    80                 if err != nil {
    81                         return err
    82                 }
    83                 sz += r
    84         }
    85 
    86         return nil
    87 }
    88 
    89 func writemeta(filename string, expiry int64) error {
    90 
    91         f, _ := os.Open(filename)
    92         stat, _ := f.Stat()
    93         size := stat.Size()
    94         f.Close()
    95 
    96         if expiry < 0 {
    97                 expiry = conf.expiry
    98         }
    99 
    100         meta := metadata{
    101                 Filename: filepath.Base(filename),
    102                 Size:     size,
    103                 Expiry:   time.Now().Unix() + expiry,
    104         }
    105 
    106         if verbose {
    107                 log.Printf("Saving metadata for %s in %s", meta.Filename, conf.metapath+"/"+meta.Filename+".json")
    108         }
    109 
    110         f, err := os.Create(conf.metapath + "/" + meta.Filename + ".json")
    111         if err != nil {
    112                 return err
    113         }
    114         defer f.Close()
    115 
    116         j, err := json.Marshal(meta)
    117         if err != nil {
    118                 return err
    119         }
    120 
    121         _, err = f.Write(j)
    122 
    123         return err
    124 }
    125 
    126 func servetemplate(w http.ResponseWriter, f string, d templatedata) {
    127         t, err := template.ParseFiles(conf.tmplpath + "/" + f)
    128         if err != nil {
    129                 http.Error(w, "Internal error", http.StatusInternalServerError)
    130                 return
    131         }
    132 
    133         if verbose {
    134                 log.Printf("Serving template %s", t.Name())
    135         }
    136 
    137         err = t.Execute(w, d)
    138         if err != nil {
    139                 fmt.Println(err)
    140         }
    141 }
    142 
    143 func uploaderPut(w http.ResponseWriter, r *http.Request) {
    144         /* limit upload size */
    145         if r.ContentLength > conf.maxsize {
    146                 http.Error(w, "File is too big", http.StatusRequestEntityTooLarge)
    147         }
    148 
    149         tmp, _ := ioutil.TempFile(conf.filepath, "*"+path.Ext(r.URL.Path))
    150         f, err := os.Create(tmp.Name())
    151         if err != nil {
    152                 fmt.Println(err)
    153                 return
    154         }
    155         defer f.Close()
    156 
    157         if verbose {
    158                 log.Printf("Writing %d bytes to %s", r.ContentLength, tmp.Name())
    159         }
    160 
    161         if err = writefile(f, r.Body, r.ContentLength); err != nil {
    162                 http.Error(w, "Internal error", http.StatusInternalServerError)
    163                 defer os.Remove(tmp.Name())
    164                 return
    165         }
    166         writemeta(tmp.Name(), conf.expiry)
    167 
    168         resp := conf.baseuri + conf.filectx + filepath.Base(tmp.Name())
    169         w.Write([]byte(resp + "\r\n"))
    170 }
    171 
    172 func uploaderPost(w http.ResponseWriter, r *http.Request) {
    173         /* read 32Mb at a time */
    174         r.ParseMultipartForm(32 << 20)
    175 
    176         links := []string{}
    177         for _, h := range r.MultipartForm.File["file"] {
    178                 if h.Size > conf.maxsize {
    179                         http.Error(w, "File is too big", http.StatusRequestEntityTooLarge)
    180                         return
    181                 }
    182 
    183                 post, err := h.Open()
    184                 if err != nil {
    185                         http.Error(w, "Internal error", http.StatusInternalServerError)
    186                         return
    187                 }
    188                 defer post.Close()
    189 
    190                 tmp, _ := ioutil.TempFile(conf.filepath, "*"+path.Ext(h.Filename))
    191                 f, err := os.Create(tmp.Name())
    192                 if err != nil {
    193                         http.Error(w, "Internal error", http.StatusInternalServerError)
    194                         return
    195                 }
    196                 defer f.Close()
    197 
    198                 if err = writefile(f, post, h.Size); err != nil {
    199                         http.Error(w, "Internal error", http.StatusInternalServerError)
    200                         defer os.Remove(tmp.Name())
    201                         return
    202                 }
    203 
    204                 expiry, err := strconv.Atoi(r.PostFormValue("expiry"))
    205                 if err != nil || expiry < 0 {
    206                         expiry = int(conf.expiry)
    207                 }
    208                 writemeta(tmp.Name(), int64(expiry))
    209 
    210                 link := conf.baseuri + conf.filectx + filepath.Base(tmp.Name())
    211                 links = append(links, link)
    212         }
    213 
    214         switch r.PostFormValue("output") {
    215         case "html":
    216                 data := templatedata{
    217                         Maxsize: humanize.IBytes(uint64(conf.maxsize)),
    218                         Links:   links,
    219                 }
    220                 servetemplate(w, "/index.html", data)
    221         case "json":
    222                 data, _ := json.Marshal(links)
    223                 w.Write(data)
    224         default:
    225                 for _, link := range links {
    226                         w.Write([]byte(link + "\r\n"))
    227                 }
    228         }
    229 }
    230 
    231 func uploaderGet(w http.ResponseWriter, r *http.Request) {
    232         // r.URL.Path is sanitized regarding "." and ".."
    233         filename := r.URL.Path
    234         if r.URL.Path == "/" || r.URL.Path == "/index.html" {
    235                 data := templatedata{Maxsize: humanize.IBytes(uint64(conf.maxsize))}
    236                 servetemplate(w, "/index.html", data)
    237                 return
    238         }
    239 
    240         if verbose {
    241                 log.Printf("Serving file %s", conf.rootdir+filename)
    242         }
    243 
    244         http.ServeFile(w, r, conf.rootdir+filename)
    245 }
    246 
    247 func uploaderDelete(w http.ResponseWriter, r *http.Request) {
    248         // r.URL.Path is sanitized regarding "." and ".."
    249         filename := r.URL.Path
    250         filepath := conf.filepath + filename
    251 
    252         if verbose {
    253                 log.Printf("Deleting file %s", filepath)
    254         }
    255 
    256         f, err := os.Open(filepath)
    257         if err != nil {
    258                 http.NotFound(w, r)
    259                 return
    260         }
    261         f.Close()
    262 
    263         // Force file expiration
    264         writemeta(filepath, 0)
    265         w.WriteHeader(http.StatusNoContent)
    266 }
    267 
    268 func uploader(w http.ResponseWriter, r *http.Request) {
    269         if verbose {
    270                 log.Printf("%s: <%s> %s %s %s", r.Host, r.RemoteAddr, r.Method, r.RequestURI, r.Proto)
    271         }
    272 
    273         switch r.Method {
    274         case "DELETE":
    275                 uploaderDelete(w, r)
    276         case "POST":
    277                 uploaderPost(w, r)
    278         case "PUT":
    279                 uploaderPut(w, r)
    280         case "GET":
    281                 uploaderGet(w, r)
    282         }
    283 }
    284 
    285 func parseconfig(file string) error {
    286         cfg, err := ini.Load(file)
    287         if err != nil {
    288                 return err
    289         }
    290 
    291         conf.listen = cfg.Section("").Key("listen").String()
    292         conf.user = cfg.Section("").Key("user").String()
    293         conf.group = cfg.Section("").Key("group").String()
    294         conf.baseuri = cfg.Section("").Key("baseuri").String()
    295         conf.filepath = cfg.Section("").Key("filepath").String()
    296         conf.metapath = cfg.Section("").Key("metapath").String()
    297         conf.filectx = cfg.Section("").Key("filectx").String()
    298         conf.rootdir = cfg.Section("").Key("rootdir").String()
    299         conf.chroot = cfg.Section("").Key("chroot").String()
    300         conf.tmplpath = cfg.Section("").Key("tmplpath").String()
    301         conf.maxsize, _ = cfg.Section("").Key("maxsize").Int64()
    302         conf.expiry, _ = cfg.Section("").Key("expiry").Int64()
    303 
    304         return nil
    305 }
    306 
    307 func usergroupids(username string, groupname string) (int, int, error) {
    308         u, err := user.Lookup(username)
    309         if err != nil {
    310                 return -1, -1, err
    311         }
    312 
    313         uid, _ := strconv.Atoi(u.Uid)
    314         gid, _ := strconv.Atoi(u.Gid)
    315 
    316         if conf.group != "" {
    317                 g, err := user.LookupGroup(groupname)
    318                 if err != nil {
    319                         return uid, -1, err
    320                 }
    321                 gid, _ = strconv.Atoi(g.Gid)
    322         }
    323 
    324         return uid, gid, nil
    325 }
    32644
    32745func main() {
Note: See TracChangeset for help on using the changeset viewer.