}
defer file.Close()
- // Read file
- fileBytes, err := io.ReadAll(file)
+ // Get encryption key first (before reading large file)
+ encKey, err := utils.GetEncryptionKey(userID, derivedKey)
if err != nil {
- http.Error(w, fmt.Sprintf("Error reading file: %v", err), http.StatusInternalServerError)
+ http.Error(w, fmt.Sprintf("Error getting encryption key: %v", err), http.StatusInternalServerError)
return
}
- // Get encryption key
- encKey, err := utils.GetEncryptionKey(userID, derivedKey)
+ // Read file into a buffer (more memory efficient)
+ fileBytes, err := io.ReadAll(file)
if err != nil {
- http.Error(w, fmt.Sprintf("Error getting encryption key: %v", err), http.StatusInternalServerError)
+ http.Error(w, fmt.Sprintf("Error reading file: %v", err), http.StatusInternalServerError)
return
}
+ // Ensure fileBytes is cleared when function exits
+ defer func() { fileBytes = nil }()
// Encrypt file
encryptedFile, err := utils.EncryptFile(fileBytes, encKey)
http.Error(w, fmt.Sprintf("Error encrypting file: %v", err), http.StatusInternalServerError)
return
}
+ // Ensure encryptedFile is cleared when function exits
+ defer func() { encryptedFile = nil }()
+
+ // Clear original file data from memory immediately after encryption
+ fileBytes = nil
// Write file
if err := utils.WriteFile(encryptedFile, userID, uuid); err != nil {
return
}
+ // Clear encrypted data from memory immediately after writing
+ encryptedFile = nil
+
// Get month data
content, err := utils.GetMonth(userID, year, month)
if err != nil {
http.Error(w, fmt.Sprintf("Error reading file: %v", err), http.StatusInternalServerError)
return
}
+ // Ensure encryptedFile is cleared when function exits
+ defer func() { encryptedFile = nil }()
// Decrypt file
decryptedFile, err := utils.DecryptFile(encryptedFile, encKey)
http.Error(w, fmt.Sprintf("Error decrypting file: %v", err), http.StatusInternalServerError)
return
}
+ // Ensure decryptedFile is cleared when function exits
+ defer func() { decryptedFile = nil }()
+
+ // Clear encrypted data from memory immediately after decryption
+ encryptedFile = nil
// Set response headers for streaming
w.Header().Set("Content-Type", "application/octet-stream")
"github.com/phitux/dailytxt/backend/utils"
)
+// longTimeoutEndpoints defines endpoints that need extended timeouts
+var longTimeoutEndpoints = map[string]bool{
+ "/logs/uploadFile": true,
+ "/logs/downloadFile": true,
+ "/logs/exportData": true,
+ "/users/login": true,
+}
+
+// timeoutMiddleware applies different timeouts based on the endpoint
+func timeoutMiddleware(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // Check if this endpoint needs a long timeout
+ if longTimeoutEndpoints[r.URL.Path] {
+ // No timeout for these endpoints - let them run as long as needed
+ next.ServeHTTP(w, r)
+ } else {
+ // Apply 15 second timeout for normal endpoints
+ handler := http.TimeoutHandler(next, 15*time.Second, "Request timeout")
+ handler.ServeHTTP(w, r)
+ }
+ })
+}
+
func main() {
// Setup logging
logger := log.New(os.Stdout, "dailytxt: ", log.LstdFlags|log.Lmicroseconds|log.Lshortfile)
mux.HandleFunc("GET /logs/deleteDay", middleware.RequireAuth(handlers.DeleteDay))
mux.HandleFunc("GET /logs/exportData", middleware.RequireAuth(handlers.ExportData))
- // Create a handler chain with Logger and CORS middleware
- // Logger middleware will be executed first, then CORS
- handler := middleware.Logger(middleware.CORS(mux))
+ // Create a handler chain with Timeout, Logger and CORS middleware
+ // Timeout middleware will be executed first, then Logger, then CORS
+ handler := timeoutMiddleware(middleware.Logger(middleware.CORS(mux)))
- // Create the server
+ // Create the server without ReadTimeout/WriteTimeout (managed by middleware)
server := &http.Server{
- Addr: ":8000",
- Handler: handler,
- ReadTimeout: 15 * time.Second,
- WriteTimeout: 15 * time.Second,
- IdleTimeout: 60 * time.Second,
+ Addr: ":8000",
+ Handler: handler,
+ IdleTimeout: 60 * time.Second, // Keep IdleTimeout for cleanup
}
// Start the server in a goroutine