Example #1
0
func main() {
	var err error
	log := log.New(os.Stdout, "- ", log.LstdFlags)

	// Initialize boxes
	staticBox = rice.MustFindBox("static")
	templateBox = rice.MustFindBox("templates")

	log.Println("Listen host: " + cfg.Host)
	log.Println("Listen port: " + strconv.Itoa(cfg.Port))
	log.Println("Read timeout: " +
		strconv.Itoa(cfg.ReadTimeout) + " seconds")
	log.Println("Write timeout: " +
		strconv.Itoa(cfg.WriteTimeout) + " seconds")
	log.Println("Max header size: " +
		strconv.Itoa(cfg.MaxHeaderBytes) + " bytes")
	log.Println("Access log file: " + cfg.AccessLog)
	log.Println("Cache invalidation enabled: " +
		strconv.FormatBool(cfg.CacheInvalidation))
	log.Println("Workers: " +
		strconv.Itoa(cfg.Workers))
	log.Println("Expiration time: " +
		strconv.FormatInt(cfg.Expiration, 10) + " seconds")
	log.Println("Files directory: " + cfg.Filedir)
	log.Println("Temp directory: " + cfg.Tempdir)
	//log.Println("Log directory: " + cfg.Logdir)
	log.Println("Baseurl: " + cfg.Baseurl)

	var trigger = cfg.TriggerNewBin
	if trigger == "" {
		trigger = "Not set"
	}
	log.Println("Trigger - New bin: " + trigger)

	trigger = cfg.TriggerUploadFile
	if trigger == "" {
		trigger = "Not set"
	}
	log.Println("Trigger - Upload file: " + trigger)

	trigger = cfg.TriggerDownloadBin
	if trigger == "" {
		trigger = "Not set"
	}
	log.Println("Trigger - Download bin: " + trigger)

	trigger = cfg.TriggerDownloadFile
	if trigger == "" {
		trigger = "Not set"
	}
	log.Println("Trigger - Download file: " + trigger)

	trigger = cfg.TriggerDeleteBin
	if trigger == "" {
		trigger = "Not set"
	}
	log.Println("Trigger - Delete bin: " + trigger)

	trigger = cfg.TriggerDeleteFile
	if trigger == "" {
		trigger = "Not set"
	}
	log.Println("Trigger - Delete file: " + trigger)

	//fmt.Println("Trigger Expired bin: " + cfg.TriggerExpiredBin)

	accessLogWriter, err := os.OpenFile(cfg.AccessLog, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		fmt.Println("Unable to open access log file: " + err.Error())
		os.Exit(2)
	}

	m = metrics.Init()

	startTime := time.Now().UTC()
	backend, err = fs.InitBackend(cfg.Baseurl, cfg.Filedir, cfg.Tempdir, cfg.Expiration, log)
	if err != nil {
		log.Fatalln(err.Error())
	}
	finishTime := time.Now().UTC()
	elapsedTime := finishTime.Sub(startTime)
	backend.Log.Println("Backend initialized in: " + elapsedTime.String())

	log.Println("Backend: " + backend.Info())
	log.Println("Filebin server starting...")

	// Start dispatcher that will handle all background processing
	model.StartDispatcher(cfg.Workers, WorkQueue, &backend)

	// Sending all files through the batch process to ensure thumbnails
	// are generated.
	for _, bin := range backend.GetBins() {
		files := backend.GetFiles(bin)
		for _, filename := range files {
			j := model.Job{}
			j.Filename = filename
			j.Bin = bin
			j.Log = log
			j.Cfg = &cfg
			WorkQueue <- j
		}
	}

	router := mux.NewRouter()

	router.Handle("/static/{path:.*}", http.StripPrefix("/static/", http.FileServer(staticBox.HTTPBox()))).Methods("GET", "HEAD")

	http.Handle("/", httpInterceptor(router))

	// Accept trailing slashes.
	// Disabling this feature for now since it might not be needed. Try to
	// find some other way of accepting trailing slashes where appropriate
	// instead of globally.
	//router.StrictSlash(true)

	// Skip reqHandler to avoid logging of requests to this endpoint
	router.HandleFunc("/filebin-status", api.FilebinStatus).Methods("GET", "HEAD")

	router.HandleFunc("/admin", basicAuth(reqHandler(api.AdminDashboard))).Methods("GET", "HEAD")
	router.HandleFunc("/admin/events", basicAuth(reqHandler(api.AdminEvents))).Methods("GET", "HEAD")
	router.HandleFunc("/admin/bins", basicAuth(reqHandler(api.AdminBins))).Methods("GET", "HEAD")
	router.HandleFunc("/admin/counters", basicAuth(reqHandler(api.AdminCounters))).Methods("GET", "HEAD")
	router.HandleFunc("/readme", reqHandler(api.Readme)).Methods("GET", "HEAD")
	router.HandleFunc("/", reqHandler(api.NewBin)).Methods("GET", "HEAD")
	router.HandleFunc("/", reqHandler(api.Upload)).Methods("POST")
	router.HandleFunc("/archive/{bin:[A-Za-z0-9_-]+}/{format:[a-z]+}", reqHandler(api.FetchArchive)).Methods("GET", "HEAD")
	router.HandleFunc("/album/{bin:[A-Za-z0-9_-]+}", reqHandler(api.FetchAlbum)).Methods("GET", "HEAD")
	router.HandleFunc("/{bin:[A-Za-z0-9_-]+}", reqHandler(api.FetchBin)).Methods("GET", "HEAD")
	router.HandleFunc("/{bin:[A-Za-z0-9_-]+}", reqHandler(api.DeleteBin)).Methods("DELETE")
	router.HandleFunc("/{bin:[A-Za-z0-9_-]+}/{filename:.+}", reqHandler(api.FetchFile)).Methods("GET", "HEAD")
	router.HandleFunc("/{bin:[A-Za-z0-9_-]+}/{filename:.+}", reqHandler(api.DeleteFile)).Methods("DELETE")
	router.HandleFunc("/{path:.*}", reqHandler(api.PurgeHandler)).Methods("PURGE")

	logRouter := handlers.CombinedLoggingHandler(accessLogWriter, router)

	server := &http.Server{
		Addr:           cfg.Host + ":" + strconv.Itoa(cfg.Port),
		Handler:        logRouter,
		ReadTimeout:    time.Duration(cfg.ReadTimeout) * time.Second,
		WriteTimeout:   time.Duration(cfg.WriteTimeout) * time.Second,
		MaxHeaderBytes: cfg.MaxHeaderBytes,
	}

	err = server.ListenAndServe()
	if err != nil {
		log.Panicln(err.Error())
	}
}
Example #2
0
func Upload(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	r.Close = true

	bin := r.Header.Get("bin")
	if err := verifyBin(bin); err != nil {
		http.Error(w, "Invalid bin", 400)
		return
	}

	b, err := ctx.Backend.GetBinMetaData(bin)
	if err == nil {
		if b.Expired {
			http.Error(w, "This bin expired "+b.ExpiresReadable+".", 410)
			return
		}
	}

	filename := sanitizeFilename(r.Header.Get("filename"))
	if err := verifyFilename(filename); err != nil {
		http.Error(w, "Invalid filename", 400)
		return
	}

	ctx.Metrics.Incr("current-upload")
	defer ctx.Metrics.Decr("current-upload")

	event := ctx.Events.New(ctx.RemoteAddr, []string{"file", "upload"}, bin, filename)
	defer event.Done()

	if i, err := strconv.Atoi(r.Header.Get("content-length")); err == nil {
		event.Update("Size: "+humanize.Bytes(uint64(i)), 0)
	}

	if ctx.Backend.BinExists(bin) == false {
		if cfg.TriggerNewBin != "" {
			ctx.Log.Println("Executing trigger: New bin")
			triggerNewBinHandler(cfg.TriggerNewBin, bin)
		}
	}

	f, err := ctx.Backend.UploadFile(bin, filename, r.Body)
	if err != nil {
		ctx.Log.Println(err)
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		event.Update(err.Error(), 2)
		return
	}

	ctx.Metrics.Incr("total-upload")

	if cfg.TriggerUploadFile != "" {
		ctx.Log.Println("Executing trigger: Uploaded file")
		triggerUploadFileHandler(cfg.TriggerUploadFile, f.Bin, f.Filename)
	}

	// Purging any old content
	if cfg.CacheInvalidation {
		for _, l := range f.Links {
			if err := shared.PurgeURL(l.Href, ctx.Log); err != nil {
				ctx.Log.Println(err)
			}
		}
	}

	j := model.Job{}
	j.Filename = f.Filename
	j.Bin = f.Bin
	j.Log = ctx.Log
	j.Cfg = &cfg
	ctx.WorkQueue <- j

	w.Header().Set("Content-Type", "application/json")

	var status = 201
	output.JSONresponse(w, status, f, ctx)
}