Repository: syncthing/syncthing
File: cmd/stcrashreceiver/stcrashreceiver.go (Go)

Code before:

	switch req.Method {
	case http.MethodGet:
		r.serveGet(base, w, req)
	case http.MethodHead:
		r.serveHead(base, w, req)
	case http.MethodPut:
		r.servePut(base, w, req)
	default:
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
	}
}

// serveGet responds to GET requests by serving the uncompressed report.
func (r *crashReceiver) serveGet(base string, w http.ResponseWriter, req *http.Request) {
	path := filepath.Join(r.dirFor(base), base)
	fullPath := filepath.Join(r.dir, path)
	if fd, err := os.Open(fullPath + ".gz"); err == nil {
		// There is a compressed report
		defer fd.Close()
		gr, err := gzip.NewReader(fd)
		if err != nil {
			http.Error(w, "Internal server error", http.StatusInternalServerError)
			return
		}
		_, _ = io.Copy(w, gr) // best effort
		return
	}
	if _, err := os.Lstat(fullPath); err == nil {
		http.ServeFile(w, req, fullPath)
		return
	}
	http.Error(w, "Not found", http.StatusNotFound)
}

// serveHead responds to HEAD requests by checking if the named report
// already exists in the system.
func (r *crashReceiver) serveHead(base string, w http.ResponseWriter, _ *http.Request) {
	path := filepath.Join(r.dirFor(base), base)
	fullPath := filepath.Join(r.dir, path)
	if _, err := os.Lstat(fullPath + ".gz"); err == nil {
		// There is a compressed report
		return
	}
	if _, err := os.Lstat(fullPath); err == nil {
		// There is an uncompressed report
		return
	}
	http.Error(w, "Not found", http.StatusNotFound)
}


Review comment (suggestion):
In theory you could just wedge content-encoding: gzip and return the zipped bytes, but yeah, this shouldn't matter much.

Code after:

	// The location of the report on disk, compressed
	fullPath := filepath.Join(r.dir, r.dirFor(reportID), reportID) + ".gz"

	switch req.Method {
	case http.MethodGet:
		r.serveGet(fullPath, w, req)
	case http.MethodHead:
		r.serveHead(fullPath, w, req)
	case http.MethodPut:
		r.servePut(reportID, fullPath, w, req)
	default:
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
	}
}

// serveGet responds to GET requests by serving the uncompressed report.
func (r *crashReceiver) serveGet(fullPath string, w http.ResponseWriter, _ *http.Request) {
	fd, err := os.Open(fullPath)
	if err != nil {
		http.Error(w, "Not found", http.StatusNotFound)
		return
	}

	defer fd.Close()
	gr, err := gzip.NewReader(fd)
	if err != nil {
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}
	_, _ = io.Copy(w, gr) // best effort
}

// serveHead responds to HEAD requests by checking if the named report
// already exists in the system.
func (r *crashReceiver) serveHead(fullPath string, w http.ResponseWriter, _ *http.Request) {
	if _, err := os.Lstat(fullPath); err != nil {
		http.Error(w, "Not found", http.StatusNotFound)
	}
}

// servePut accepts and stores the given report.
func (r *crashReceiver) servePut(reportID, fullPath string, w http.ResponseWriter, req *http.Request) {
	// Ensure the destination directory exists
	if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
		log.Println("Creating directory:", err)
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	// Read at most maxRequestSize of report data.