blob: 7d4aecedcf811a8e2664a5848b19c5a4014ce062 [file] [log] [blame]
Sergiusz Bazanskia51df9c2019-07-13 16:07:13 +02001package main
2
3// Copyright 2019 Serge Bazanski
4//
5// Permission to use, copy, modify, and/or distribute this software for any
6// purpose with or without fee is hereby granted, provided that the above
7// copyright notice and this permission notice appear in all copies.
8//
9// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
12// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
14// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17import (
18 "crypto/rand"
19 "encoding/json"
20 "flag"
21 "io"
22 "io/ioutil"
23 "net"
24 "net/http"
25 "strconv"
26 "strings"
27
28 "github.com/golang/glog"
Sergiusz Bazanskif448f992019-07-13 16:16:23 +020029
Sergiusz Bazanskicea71e32019-07-21 15:30:08 +020030 "code.hackerspace.pl/hscloud/bgpwtf/speedtest/static"
Sergiusz Bazanskia51df9c2019-07-13 16:07:13 +020031)
32
33var (
34 flagBind string
35 flagUseForwardedFor bool
36)
37
38func cors(w http.ResponseWriter) {
39 w.Header().Add("Access-Control-Allow-Origin", "*")
40 w.Header().Add("Access-Control-Allow-Methods", "GET, POST")
41}
42
43func noCache(w http.ResponseWriter) {
44 w.Header().Add("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0, s-maxage=0")
45 w.Header().Add("Cache-Control", " post-check=0, pre-check=0")
46 w.Header().Add("Pragma", "no-cache")
47}
48
49func remoteIP(r *http.Request) net.IP {
50 remote := strings.TrimSpace(r.RemoteAddr)
51 if flagUseForwardedFor {
52 remote = strings.TrimSpace(r.Header.Get("X-Forwarded-For"))
53 }
54
55 if remote == "" {
56 return nil
57 }
58
59 if strings.HasPrefix(remote, "[") {
60 // Looks like a [::1] v6 address
61 inner := strings.Split(strings.Split(remote, "[")[1], "]")[0]
62 return net.ParseIP(inner)
63 }
64
65 if strings.Count(remote, ":") == 1 {
66 // Looks like a :4321 port suffix
67 inner := strings.Split(remote, ":")[0]
68 return net.ParseIP(inner)
69 }
70
71 return net.ParseIP(remote)
72}
73
74func init() {
75 flag.Set("logtostderr", "true")
76}
77
78func main() {
79 flag.StringVar(&flagBind, "bind", "0.0.0.0:8080", "Address at which to serve HTTP requests")
80 flag.BoolVar(&flagUseForwardedFor, "use_forwarded_for", false, "Honor X-Forwarded-For headers to detect user IP")
81 flag.Parse()
82 http.HandleFunc("/empty", func(w http.ResponseWriter, r *http.Request) {
83 cors(w)
84 noCache(w)
85 w.Header().Add("Connection", "keep-alive")
86 w.WriteHeader(http.StatusOK)
87 io.Copy(ioutil.Discard, r.Body)
88 })
89 http.HandleFunc("/garbage", func(w http.ResponseWriter, r *http.Request) {
90 cors(w)
91 w.Header().Add("Content-Description", "File Tranfer")
92 w.Header().Add("Content-Type", "application/octet-stream")
93 w.Header().Add("Content-Disposition", "attachment; filename=random.dat")
94 w.Header().Add("Content-Transfer-Encoding", "binary")
95 noCache(w)
96 w.WriteHeader(http.StatusOK)
97
98 chunks := 4
99 if val, err := strconv.Atoi(r.Header.Get("ckSize")); err == nil {
100 if val > 0 && val <= 1024 {
101 chunks = val
102 }
103 }
104
105 chunk := make([]byte, 1024*1024)
106 rand.Read(chunk)
107
108 for i := 0; i < chunks; i += 1 {
109 w.Write(chunk)
110 }
111 })
112 http.HandleFunc("/ip", func(w http.ResponseWriter, r *http.Request) {
113 cors(w)
114 noCache(w)
115
116 res := struct {
117 ProcessedString string `json:processedString`
118 RawISPInfo string `json:rawIspInfo`
119 }{
120 ProcessedString: "",
121 RawISPInfo: "",
122 }
123
124 ip := remoteIP(r)
125 if ip != nil {
126 res.ProcessedString = ip.String()
127 }
128
129 w.Header().Set("Content-Type", "application/json")
130
131 json.NewEncoder(w).Encode(res)
132 })
133 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
Sergiusz Bazanskicea71e32019-07-21 15:30:08 +0200134 w.Write(static.Data["bgpwtf/speedtest/index.html"])
Sergiusz Bazanskia51df9c2019-07-13 16:07:13 +0200135 })
136 http.HandleFunc("/speedtest.js", func(w http.ResponseWriter, r *http.Request) {
Sergiusz Bazanskicea71e32019-07-21 15:30:08 +0200137 w.Write(static.Data["bgpwtf/speedtest/speedtest.js"])
Sergiusz Bazanskia51df9c2019-07-13 16:07:13 +0200138 })
139 http.HandleFunc("/speedtest_worker.js", func(w http.ResponseWriter, r *http.Request) {
Sergiusz Bazanskicea71e32019-07-21 15:30:08 +0200140 w.Write(static.Data["bgpwtf/speedtest/speedtest_worker.js"])
Sergiusz Bazanskia51df9c2019-07-13 16:07:13 +0200141 })
142
143 glog.Infof("Starting up at %v", flagBind)
144 err := http.ListenAndServe(flagBind, nil)
145 if err != nil {
146 glog.Exit(err)
147 }
148}