-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
140 lines (115 loc) · 3.86 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//main is a package that contains the logic and tests of the responseConverter.
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"sync"
"time"
)
const successStatusCode = 200
var maxGoroutines int64 = 10
//main is first method that is called when the consol application runs. It handles the parameters entered by the user.
func main() {
var parameters []string = os.Args[1:]
CreateRequest(parameters)
}
// CreteRequest is the public method that creates a request with the entered parameters.
// here it is checked whether the program can be called with the correct parameters.
func CreateRequest(parameters []string) {
isValidParameters := true
if parameters[0] == "-parallel" {
if len(parameters) < 3 {
fmt.Println("Missing parameter entered.")
fmt.Println("Example Request: -parallel 3 www.gooogle.com")
isValidParameters = false
}
numOfGoroutines, err := strconv.ParseInt(parameters[1], 10, 64)
if err != nil {
fmt.Println("If you are using '-parallel', you must enter this command as the first parameter and enter the number of goroutines after the '-parallel' command.")
isValidParameters = false
} else if numOfGoroutines < 1 {
fmt.Println("The number of goroutines cannot be less than 1.")
isValidParameters = false
}
parameters = parameters[2:]
maxGoroutines = numOfGoroutines
}
if isValidParameters && len(parameters) > 0 {
createUrlAndPrintResponse(parameters)
}
}
// createUrlAndPrintResponse is the method by which goroutines are created.
// within this method, createUrl(), getResponse(), convert() methods are called respectively. It prints valid results to the console.
func createUrlAndPrintResponse(parameters []string) {
var ch chan struct{} = make(chan struct{}, maxGoroutines) //sets how many goroutines will be used at the same time.
var wg sync.WaitGroup
for i := 0; i < len(parameters); i++ {
wg.Add(1)
ch <- struct{}{} // blocks the use of goroutines above the limit.
go func(parameter string) { // each parameter will be processed in different goroutines.
url, err := createUrl(parameter)
if err == nil {
response, err := getResponse(url)
if err == nil {
md5text := convert(response)
fmt.Println(url + " " + md5text)
}
}
<-ch
wg.Done()
}(parameters[i])
}
wg.Wait() // blocks the main goroutine termination before other goroutines run.
}
//createUrl adds schema to the url If the url doesn't have any schema. If it's not a valid url, an error is returned.
func createUrl(item string) (result string, err error) {
if !strings.Contains(item, "://") {
item = "http://" + item
}
u, err := url.Parse(item)
if err != nil || u.Host == "" || strings.HasPrefix(u.Host, ".") || strings.Contains(u.Host, "..") || strings.Count(":", u.Host) > 1 {
return item, fmt.Errorf("isNotValid")
}
if u.Scheme == "" || !(u.Scheme == "ftp" || u.Scheme == "http" || u.Scheme == "https") {
return item, fmt.Errorf("isNotValid")
}
if !strings.Contains(u.Host, ":") && !strings.Contains(u.Host, ".") {
return item, fmt.Errorf("isNotValid")
}
if u.Port() != "" {
_, portValidation := strconv.ParseInt(u.Port(), 10, 64)
if portValidation != nil {
return item, fmt.Errorf("isNotValid")
}
}
return item, err
}
//getResponse creates a request and returns its response as a string.
func getResponse(url string) (string, error) {
client := http.Client{
Timeout: 5 * time.Second,
}
resp, err := client.Get(url)
if err != nil || resp.StatusCode != successStatusCode {
return "", err
}
defer resp.Body.Close()
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
response := string(responseData)
return response, err
}
//convert converts string value to mv5 hash and returns as a string.
func convert(text string) string {
hash := md5.Sum([]byte(text))
return hex.EncodeToString(hash[:])
}