From 6673f6991391d71cf7f344ccaa24c63f6f8dcc78 Mon Sep 17 00:00:00 2001 From: Steven Polley Date: Sat, 30 May 2020 14:10:56 -0600 Subject: [PATCH] Update comments --- config.go | 16 ++++++++++------ main.go | 4 ++-- test.go | 31 ++++++++++++++++++++----------- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/config.go b/config.go index b3d7618..cee4487 100644 --- a/config.go +++ b/config.go @@ -6,26 +6,28 @@ import ( ) // config accepts a slice of type Redirect and returns an error -// it organizes the data from the input redirects in a way that makes sense for FortiOS objects +// it organizes the input data in a way that makes sense for FortiOS objects // then outputs the configuration to stdout func config(redirects []Redirect) error { // A map which contains the name of a redirect policy as the key, and a slice of strings as a value. - // The value of the string is the name of the url-rewrite-rule which needs to be referenced by the redirect policy object in FortiOS + // The value of the string is the name of the url-rewrite-rule which needs to be referenced by the redirect policy object in FortiOS redirectPolicies := make(map[string][]string) // Iterate over all redirects and output url-rewrite-rules - fmt.Printf("\n\n------------------------\n\n\n") + fmt.Printf("\n\n------------------------ COPY BELOW THIS LINE ------------------------\n\n\n") fmt.Println("config waf url-rewrite url-rewrite-rule") for _, redirect := range redirects { + + // Parse the source URL string into a URL object so we can extract features sourceURL, err := url.Parse(redirect.sourceURL) if err != nil { return fmt.Errorf("unable to parse source URL '%s': %v", redirect.sourceURL, err) } var ruleName, action string - if len(redirect.sourceURL) > 63 { // FortiOS only allows up to 63 characters + if len(redirect.sourceURL) > 63 { // FortiOS only allows up to 63 characters. There is potention for collission here. TBD: Reduce and replace characters in the middle of string with '...' and show characters at the end of the URL to make differentiation easier for operators of the WAF ruleName = redirect.sourceURL[:62] } else { ruleName = redirect.sourceURL @@ -37,6 +39,7 @@ func config(redirects []Redirect) error { action = "redirect" } + // Output FortiOS configuration syntax fmt.Printf("edit \"%s\"\n", ruleName) fmt.Printf("set location %s\n", redirect.destinationURL) fmt.Printf("set action %s\n", action) @@ -50,11 +53,12 @@ func config(redirects []Redirect) error { fmt.Println("end") fmt.Println("next") - // Add this rule to the policy map + // Add this rule to the slice inside the policy map. This is used to organize data for creating the url-rewrite-policy configuration below redirectPolicies[sourceURL.Host] = append(redirectPolicies[sourceURL.Host], ruleName) } fmt.Println("end") + // Output url-rewrite-policy configuration. // Iterate over values in the policy map and output the policy configuration fmt.Println("config waf url-rewrite url-rewrite-policy") for policyName, policyRules := range redirectPolicies { @@ -68,7 +72,7 @@ func config(redirects []Redirect) error { fmt.Println("end") fmt.Println("next") } - fmt.Println("end") + fmt.Printf("end\n\n\n") return nil } diff --git a/main.go b/main.go index a70b52c..c5b183a 100644 --- a/main.go +++ b/main.go @@ -64,12 +64,12 @@ func main() { // Determine the next steps if *action == "config" { - err := config(redirects) + err := config(redirects) // Function defined in config.go if err != nil { log.Fatalf("failed to build configuration: %v", err) } } else if *action == "test" { - err := test(redirects) + err := test(redirects) // Function defined in test.go if err != nil { log.Fatalf("failed to test redirects: %v", err) } diff --git a/test.go b/test.go index 6b438bf..2c05d74 100644 --- a/test.go +++ b/test.go @@ -12,21 +12,28 @@ var sem chan Empty // semaphore to limit requess in flight // test accepts a slice of type Redirect and returns an error // it performs actual HTTP GET requests on each source URL and validates that a redirect occurs // to the destination URL and that the redirect type/status code is correct +// This function makes use of concurrent requests to speed up testing. func test(redirects []Redirect) error { - wg := &sync.WaitGroup{} - mu := &sync.Mutex{} + // This string will hold output for any failed tests. It's displayed when all tests have completed var summaryOutput string - sem = make(Semaphore, *maxConcurrentRequests) + // Set up some tools to handle concurrency + wg := &sync.WaitGroup{} // Used to wait for all tests to finish + mu := &sync.Mutex{} // Used to lock shared memory in critical sections + sem = make(Semaphore, *maxConcurrentRequests) // Used to limit resources while having all requests queued up + // Loop through all redirects and queue them up for _, redirect := range redirects { - wg.Add(1) - P(1) + wg.Add(1) // Add 1 resource to waitgroup + P(1) // Take 1 resource from semaphore + // This anonymous function executes in a separate go routine and can run concurrently go func(redirect Redirect) { - defer V(1) - defer wg.Done() + defer V(1) // If function exits (error or otherwise), put 1 resource back into semaphore + defer wg.Done() // If function exits (error or otherwise), subtract 1 resource from waitgroup + + // Create an HTTP client and override CheckRedirect to return the last response error so we can check the redirect type client := &http.Client{ CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse @@ -46,33 +53,35 @@ func test(redirects []Redirect) error { // Check the status code if resp.StatusCode != redirect.statusCode { - // Modifying output is critical section + // Modifying summaryOutput is critical section mu.Lock() summaryOutput += fmt.Sprintf("redirect for source URL '%s': expected status code'%d': got '%d\n", redirect.sourceURL, redirect.statusCode, resp.StatusCode) mu.Unlock() return } - // Check that the redirect went to the correct location + // Parse response location URL from header into URL object destURL, err := resp.Location() if err != nil { log.Printf("failed to parse response location to URL: %v", err) } + // Check that the redirect went to the correct location if destURL.String() != redirect.destinationURL { - // Modifying output is critical section + // Modifying summyarOutput is critical section mu.Lock() summaryOutput += fmt.Sprintf("redirect for source URL '%s': expected '%s': got '%s\n", redirect.sourceURL, redirect.destinationURL, destURL.String()) mu.Unlock() return } - }(redirect) } + // Wait for all tests to complete wg.Wait() fmt.Printf("\ndone tests.\n---------------------------------------------\n") + // Display summaryOutput if any tests failed if len(summaryOutput) > 0 { fmt.Printf("Summary:\n\n%s", summaryOutput) } else {