示例#1
0
文件: api.go 项目: jmcarbo/filebin
func Upload(w http.ResponseWriter, r *http.Request, cfg config.Configuration, ctx model.Context) {
	var err error
	f := model.File{}
	f.RemoteAddr = r.RemoteAddr
	f.UserAgent = r.Header.Get("User-Agent")

	// Extract the tag from the request
	if r.Header.Get("tag") == "" {
		tag := randomString(cfg.DefaultTagLength)
		err = f.SetTag(tag)
		ctx.Log.Println("Tag generated: " + f.Tag)
	} else {
		tag := r.Header.Get("tag")
		err = f.SetTag(tag)
		ctx.Log.Println("Tag specified: " + tag)
	}
	if err != nil {
		ctx.Log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	f.SetTagDir(cfg.Filedir)
	ctx.Log.Println("Tag directory: " + f.TagDir)

	// Write the request body to a temporary file
	err = f.WriteTempfile(r.Body, cfg.Tempdir)
	if err != nil {
		ctx.Log.Println("Unable to write tempfile: ", err)

		// Clean up by removing the tempfile
		f.ClearTemp()

		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}
	ctx.Log.Println("Tempfile: " + f.Tempfile)
	ctx.Log.Println("Tempfile size: " + strconv.FormatInt(f.Bytes, 10) + " bytes")

	// Do not accept files that are 0 bytes
	if f.Bytes == 0 {
		ctx.Log.Println("Empty files are not allowed. Aborting.")

		// Clean up by removing the tempfile
		f.ClearTemp()

		http.Error(w, "No content. The file size must be more than "+
			"0 bytes.", http.StatusBadRequest)
		return
	}

	// Calculate and verify the checksum
	checksum := r.Header.Get("content-sha256")
	if checksum != "" {
		ctx.Log.Println("Checksum specified: " + checksum)
	}
	err = f.VerifySHA256(checksum)
	ctx.Log.Println("Checksum calculated: " + f.Checksum)
	if err != nil {
		ctx.Log.Println("The specified checksum did not match")
		http.Error(w, "Checksum did not match", http.StatusConflict)
		return
	}

	// Trigger new tag
	t := model.Tag{}
	t.SetTag(f.Tag)
	t.SetTagDir(cfg.Filedir)
	if !t.TagDirExists() {
		if cfg.TriggerNewTag != "" {
			ctx.Log.Println("Executing trigger: New tag")
			triggerNewTagHandler(cfg.TriggerNewTag, f.Tag)
		}
	}

	// Create the tag directory if it does not exist
	err = f.EnsureTagDirectoryExists()
	if err != nil {
		ctx.Log.Println("Unable to create tag directory: ", f.TagDir)
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
		return
	}

	t.CalculateExpiration(cfg.Expiration)
	expired, err := t.IsExpired(cfg.Expiration)
	if err != nil {
		ctx.Log.Println(err)
		http.Error(w, "Internal server error", 500)
		return
	}
	if expired {
		ctx.Log.Println("The tag has expired. Aborting.")
		http.Error(w, "This tag has expired.", 410)
		return
	}

	// Extract the filename from the request
	fname := r.Header.Get("filename")
	if fname == "" {
		ctx.Log.Println("Filename generated: " + f.Checksum)
		f.SetFilename(f.Checksum)
	} else {
		ctx.Log.Println("Filename specified: " + fname)
		err = f.SetFilename(fname)
		if err != nil {
			ctx.Log.Println(err)
			http.Error(w, "Invalid filename specified. It contains illegal characters or is too short.",
				http.StatusBadRequest)
			return
		}
	}

	if fname != f.Filename {
		ctx.Log.Println("Filename sanitized: " + f.Filename)
	}

	err = f.DetectMIME()
	if err != nil {
		ctx.Log.Println("Unable to detect MIME: ", err)
	} else {
		ctx.Log.Println("MIME detected: " + f.MIME)
	}

	ctx.Log.Println("Media type: " + f.MediaType())
	if f.MediaType() == "image" {
		err = f.ParseExif()
		if err != nil {
			ctx.Log.Println(err)
		}

		if exif.IsCriticalError(err) == false {
			err = f.ExtractDateTime()
			if err != nil {
				ctx.Log.Println(err)
			}
		}

		// iOS devices provide only one filename even when uploading
		// multiple images. Providing some workaround for this below.
		// XXX: Refactoring needed.
		if isWorkaroundNeeded(f.UserAgent) && !f.DateTime.IsZero() {
			var fname string
			dt := f.DateTime.Format("060102-150405")

			// List of filenames to modify
			if f.Filename == "image.jpeg" {
				fname = "img-" + dt + ".jpeg"
			}
			if f.Filename == "image.gif" {
				fname = "img-" + dt + ".gif"
			}
			if f.Filename == "image.png" {
				fname = "img-" + dt + ".png"
			}

			if fname != "" {
				ctx.Log.Println("Filename workaround triggered")
				ctx.Log.Println("Filename modified: " + fname)
				err = f.SetFilename(fname)
				if err != nil {
					ctx.Log.Println(err)
				}
			}
		}

		//err = f.GenerateThumbnail()
		//if err != nil {
		//	ctx.Log.Println(err)
		//}

		extra := make(map[string]string)
		if !f.DateTime.IsZero() {
			extra["DateTime"] = f.DateTime.String()
		}
		f.Extra = extra
	}

	// Promote file from tempdir to the published tagdir
	f.Publish()

	// Clean up by removing the tempfile
	f.ClearTemp()

	err = f.StatInfo()
	if err != nil {
		ctx.Log.Println(err)
		http.Error(w, "Internal Server Error", 500)
		return
	}

	f.GenerateLinks(cfg.Baseurl)
	f.CreatedAt = time.Now().UTC()
	//f.ExpiresAt = time.Now().UTC().Add(24 * 7 * 4 * time.Hour)

	if cfg.TriggerUploadedFile != "" {
		ctx.Log.Println("Executing trigger: Uploaded file")
		triggerUploadedFileHandler(cfg.TriggerUploadedFile, f.Tag, f.Filename)
	}

	ctx.WorkQueue <- f

	headers := make(map[string]string)
	headers["Content-Type"] = "application/json"

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