Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions hello_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,61 @@ import (
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"
"unicode"

"github.com/gorilla/mux"
)

func handler(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
name := query.Get("name")
log.Printf("Received request for %s\n", name)
// Sanitize name for logging by removing control characters
sanitizedName := sanitizeForLogging(name)
log.Printf("Received request for %s\n", sanitizedName)
w.Write([]byte(CreateGreeting(name)))
}

func CreateGreeting(name string) string {
// Trim leading and trailing whitespace
name = strings.TrimSpace(name)

// Return "Hello, Guest" if input is empty after trim
if name == "" {
name = "Guest"
return "Hello, Guest\n"
}

// Limit name length to 100 characters
if len(name) > 100 {
name = name[:100]
}

// Strip control characters (including newlines)
name = sanitizeControlChars(name)

return "Hello, " + name + "\n"
}

// sanitizeControlChars removes or replaces control characters from input
func sanitizeControlChars(s string) string {
return strings.Map(func(r rune) rune {
if unicode.IsControl(r) {
return -1 // Remove control characters
}
return r
}, s)
}

// sanitizeForLogging sanitizes input for safe logging
func sanitizeForLogging(s string) string {
if s == "" {
return "<empty>"
}
return sanitizeControlChars(s)
}

func main() {
// Create Server and Route Handlers
r := mux.NewRouter()
Expand Down
143 changes: 142 additions & 1 deletion hello_server_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package main
import (

"strings"
"time"
"testing"
)
Expand Down Expand Up @@ -36,6 +36,147 @@ func TestGreetingDefault(t *testing.T) {
t.Errorf("Greeting was incorrect, got: %s, want: %s.", greeting, "Hello, Guest\n")
}
}

// Test case for whitespace-only names
func TestGreeting_WhitespaceOnly(t *testing.T) {
testCases := []string{
" ",
" ",
"\t",
"\t\t",
" \t ",
"\n",
"\r\n",
}

for _, input := range testCases {
greeting := CreateGreeting(input)
if greeting != "Hello, Guest\n" {
t.Errorf("Greeting for whitespace input %q was incorrect, got: %s, want: %s.", input, greeting, "Hello, Guest\n")
}
}
}

// Test case for long names (>100 characters)
func TestGreeting_LongName(t *testing.T) {
longName := strings.Repeat("a", 150) // 150 characters
greeting := CreateGreeting(longName)
expectedName := strings.Repeat("a", 100) // Should be truncated to 100
expected := "Hello, " + expectedName + "\n"

if greeting != expected {
t.Errorf("Greeting for long name was incorrect, got length: %d, want length: %d", len(greeting), len(expected))
}

// Verify the name portion is exactly 100 characters
nameOnly := strings.TrimPrefix(strings.TrimSuffix(greeting, "\n"), "Hello, ")
if len(nameOnly) != 100 {
t.Errorf("Name was not truncated properly, got length: %d, want: 100", len(nameOnly))
}
}

// Test case for names with newlines and control characters
func TestGreeting_NewlineInjection(t *testing.T) {
testCases := []struct {
input string
expected string
}{
{"John\nAdmin", "Hello, JohnAdmin\n"}, // Newline removed
{"Jane\rDoe", "Hello, JaneDoe\n"}, // Carriage return removed
{"Bob\tSmith", "Hello, BobSmith\n"}, // Tab removed
{"Alice\x00", "Hello, Alice\n"}, // Null character removed
{"Test\x01\x02", "Hello, Test\n"}, // Control characters removed
}

for _, tc := range testCases {
greeting := CreateGreeting(tc.input)
if greeting != tc.expected {
t.Errorf("Greeting for input %q was incorrect, got: %q, want: %q", tc.input, greeting, tc.expected)
}
}
}

// Test case for names with special symbols
func TestGreeting_SpecialSymbols(t *testing.T) {
testCases := []struct {
input string
expected string
}{
{"Jane!@#", "Hello, Jane!@#\n"},
{"User$%^", "Hello, User$%^\n"},
{"Test&*()", "Hello, Test&*()\n"},
{"Name-_+=", "Hello, Name-_+=\n"},
{"User[]{}|", "Hello, User[]{}|\n"},
}

for _, tc := range testCases {
greeting := CreateGreeting(tc.input)
if greeting != tc.expected {
t.Errorf("Greeting for input %q was incorrect, got: %q, want: %q", tc.input, greeting, tc.expected)
}
}
}

// Test case for names with leading/trailing whitespace
func TestGreeting_TrimWhitespace(t *testing.T) {
testCases := []struct {
input string
expected string
}{
{" John ", "Hello, John\n"},
{"\tJane\t", "Hello, Jane\n"},
{" \n Bob \r ", "Hello, Bob\n"},
{" Alice ", "Hello, Alice\n"},
}

for _, tc := range testCases {
greeting := CreateGreeting(tc.input)
if greeting != tc.expected {
t.Errorf("Greeting for input %q was incorrect, got: %q, want: %q", tc.input, greeting, tc.expected)
}
}
}

// Test case for sanitization helper functions
func TestSanitizeControlChars(t *testing.T) {
testCases := []struct {
input string
expected string
}{
{"normal", "normal"},
{"with\nnewline", "withnewline"},
{"with\ttab", "withtab"},
{"with\rcarriage", "withcarriage"},
{"with\x00null", "withnull"},
{"", ""},
}

for _, tc := range testCases {
result := sanitizeControlChars(tc.input)
if result != tc.expected {
t.Errorf("sanitizeControlChars for input %q was incorrect, got: %q, want: %q", tc.input, result, tc.expected)
}
}
}

func TestSanitizeForLogging(t *testing.T) {
testCases := []struct {
input string
expected string
}{
{"", "<empty>"},
{"normal", "normal"},
{"with\nnewline", "withnewline"},
{"with\ttab", "withtab"},
}

for _, tc := range testCases {
result := sanitizeForLogging(tc.input)
if result != tc.expected {
t.Errorf("sanitizeForLogging for input %q was incorrect, got: %q, want: %q", tc.input, result, tc.expected)
}
}
}