-
Notifications
You must be signed in to change notification settings - Fork 1
/
shortyserver.go
115 lines (100 loc) · 2.55 KB
/
shortyserver.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
package main
import (
"bytes"
"errors"
"fmt"
"io"
"net"
"regexp"
"time"
)
type ShortyServer struct {
port int // shorty server port
address string // shorty server address
starttime time.Time // when this server started?
urllifespan int64 // the URL lifespan
idlen int // length of ID
sh *ShortyHTTPd // pointer to ShortyHTTPd in use
log *ShortyLog // pointer to logger
}
/* process_conn processes the net.Conn of a new client and creates
* a new ShortyURL structure with users' supplied URL
*/
func (s *ShortyServer) process_conn(l net.Listener) {
/* channel for short urls */
urls := make(chan ShortyURL)
for {
c, err := l.Accept()
if err != nil { /* got an error? */
s.log.Printf("error: %s", err.Error())
err = nil
continue
}
/* data buffer */
var buffer bytes.Buffer
/* remote client info */
var remoteaddr net.Addr
remoteaddr = c.RemoteAddr()
s.log.Printf("processing connection from %s\n", remoteaddr.String())
i, err := io.Copy(&buffer, c)
if i <= 1 {
s.log.PrintErr("got null or no data from client\n")
continue
}
if err != nil { /* got an error? */
s.log.PrintErr(err.Error())
err = nil
continue
}
data := buffer.Bytes()
/* trim newline if found */
for {
char := data[len(data)-1]
if char == '\r' || char == '\n' {
data = data[:len(data)-1]
continue
}
break
}
/* process the url to generate a shorter one */
go s.process_url(string(data), urls)
url := <-urls
/* we add the newly created short url */
if url.err == nil {
short_urls = append(short_urls, url)
} else {
s.log.PrintErr(url.err.Error())
}
s.log.Printf("generated URL: %s", url.URL(s.sh))
/* pass short url to user */
c.Write([]byte(url.URL(s.sh)))
c.Close()
// debug
//s.log.Printf("%v", short_urls)
}
}
/* process_url processes the URL given by user and validates the data.
*/
func (s *ShortyServer) process_url(url string, c chan ShortyURL) (err error) {
short := ShortyURL{
timestamp: time.Now(),
}
// pre-regex validation
if url[0:4] != "http" && url[0:5] != "https" {
short.err = errors.New(fmt.Sprintf("invalid URL: %s", url))
c <- short
return
}
// regex validation
re := regexp.MustCompile("^(?:http(s)?:\\/\\/)?[\\w.-]+(?:\\.[\\w\\.-]+)+[\\w\\-\\._~:/?#[\\]@!\\$&'\\(\\)\\*\\+,;=.]+$")
if !re.MatchString(url) {
short.err = errors.New(fmt.Sprintf("invalid URL: %s", url))
c <- short
return
}
/* that's the original url */
short.src = url
short.shorten(url, s.idlen)
c <- short
return
}