Skip to content

Commit

Permalink
feat: Add headers, panic, echo and store utilities (#728)
Browse files Browse the repository at this point in the history
  • Loading branch information
guikcd authored Feb 7, 2025
1 parent 94ab967 commit c4f703b
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,13 @@ Several "utility" endpoints are provided with useful functionality for various s

| Method | Name | Description |
| ------ | ------------------------------ | --------------------------------------------------------------------------- |
| `GET` | `/utility/stress/{iterations}` | Stress the CPU with the number of iterations increasing the CPU consumption |
| `GET` | `/utility/status/{code}` | Returns HTTP response with given HTTP status code |
| `GET` | `/utility/headers` | Print the HTTP headers of the inbound request |
| `GET` | `/utility/panic` | Shutdown the application with an error code |
| `POST` | `/utility/echo` | Write back the POST payload sent |
| `POST` | `/utility/store` | Write the payload to a file and return a hash |
| `GET` | `/utility/store/{hash}` | Return the payload from the file system previously written |
| `GET` | `/utility/stress/{iterations}` | Stress the CPU with the number of iterations increasing the CPU consumption |

## Running

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,35 @@
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;

import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;

@Controller
@RequestMapping("/utility")
public class UtilityController {

private final ApplicationContext context;

public UtilityController(ApplicationContext context) {
this.context = context;
}

@GetMapping("/stress/{iterations}")
@ResponseBody
public double stress(@PathVariable int iterations) {
Expand All @@ -51,4 +72,75 @@ private double monteCarloPi(int iterations) {
public ResponseEntity<String> status(@PathVariable int code) {
return ResponseEntity.status(code).body("OK");
}

@GetMapping(value = "/headers", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<String, List<String>>> statusHeaders(@RequestHeader HttpHeaders headers) {
return ResponseEntity.ok()
.body(headers);
}

@GetMapping("/panic")
public ResponseEntity<String> panic() {
Thread thread = new Thread(() -> {
try {
Thread.sleep(500); // Small delay to allow response to be sent
SpringApplication.exit(context, () -> 1);
System.exit(255);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
thread.start();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Shutting down...");
}

// function /echo that answer the hash provided as POST input
@PostMapping("/echo")
@ResponseBody
public ResponseEntity<String> echo(@RequestBody String body) {
return ResponseEntity.ok()
.body(body);
}

// function /store what take a POST hash to write to a locally created file
@PostMapping("/store")
@ResponseBody
public ResponseEntity<String> store(@RequestBody String body) {
String filename = String.valueOf(Math.abs(body.hashCode())); // ensure positive number
try (java.io.FileWriter fileWriter = new java.io.FileWriter("/tmp/" + filename + ".json")) {
fileWriter.write(body);
return ResponseEntity.ok()
.body("{\"hash\": \"" + filename + "\"}");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Error writing file: " + e.getMessage());
}
}

// function /store/{hash} that read a local hash file
@GetMapping("/store/{hash}")
@ResponseBody
public ResponseEntity<String> store_hash(@PathVariable String hash) {
// Validate hash format - only allow numeric characters
if (!hash.matches("^[0-9]+$")) {
return ResponseEntity.badRequest()
.body("Invalid hash format");
}

// Normalize the path and verify it's within the intended directory
Path filePath = Paths.get("/tmp", hash + ".json").normalize();
if (!filePath.startsWith("/tmp/")) {
return ResponseEntity.badRequest()
.body("Invalid path");
}

try {
String body = new String(Files.readAllBytes(filePath));
return ResponseEntity.ok()
.body(body);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("Error reading file: " + e.getMessage());
}
}
}

0 comments on commit c4f703b

Please sign in to comment.