aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArlo Breault <abreault@wikimedia.org>2021-05-20 08:31:30 -0400
committerArlo Breault <arlolra@gmail.com>2021-06-02 13:03:21 -0400
commit7880b5ca8057e27b20d550ad862087ef52c258a4 (patch)
treebd895d7546741bdf14f4aeccbc0451e8cd12b23d
parentafd54c5d4cecc15fd37db50720c1ea209edca375 (diff)
downloadsnowflake-7880b5ca8057e27b20d550ad862087ef52c258a4.tar.gz
snowflake-7880b5ca8057e27b20d550ad862087ef52c258a4.zip
Move http handlers to a separate file
-rw-r--r--broker/broker.go196
-rw-r--r--broker/http.go205
2 files changed, 205 insertions, 196 deletions
diff --git a/broker/broker.go b/broker/broker.go
index 3355339..cfc6a1b 100644
--- a/broker/broker.go
+++ b/broker/broker.go
@@ -8,10 +8,8 @@ package main
import (
"container/heap"
"crypto/tls"
- "errors"
"flag"
"io"
- "io/ioutil"
"log"
"net/http"
"os"
@@ -21,17 +19,12 @@ import (
"syscall"
"time"
- "git.torproject.org/pluggable-transports/snowflake.git/common/messages"
"git.torproject.org/pluggable-transports/snowflake.git/common/safelog"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"golang.org/x/crypto/acme/autocert"
)
-const (
- readLimit = 100000 // Maximum number of bytes to be read from an HTTP request
-)
-
type BrokerContext struct {
snowflakes *SnowflakeHeap
restrictedSnowflakes *SnowflakeHeap
@@ -69,38 +62,6 @@ func NewBrokerContext(metricsLogger *log.Logger) *BrokerContext {
}
}
-// Implements the http.Handler interface
-type SnowflakeHandler struct {
- *IPC
- handle func(*IPC, http.ResponseWriter, *http.Request)
-}
-
-// Implements the http.Handler interface
-type MetricsHandler struct {
- logFilename string
- handle func(string, http.ResponseWriter, *http.Request)
-}
-
-func (sh SnowflakeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Access-Control-Allow-Origin", "*")
- w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Session-ID")
- // Return early if it's CORS preflight.
- if "OPTIONS" == r.Method {
- return
- }
- sh.handle(sh.IPC, w, r)
-}
-
-func (mh MetricsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Access-Control-Allow-Origin", "*")
- w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Session-ID")
- // Return early if it's CORS preflight.
- if "OPTIONS" == r.Method {
- return
- }
- mh.handle(mh.logFilename, w, r)
-}
-
// Proxies may poll for client offers concurrently.
type ProxyPoll struct {
id string
@@ -176,169 +137,12 @@ func (ctx *BrokerContext) AddSnowflake(id string, proxyType string, natType stri
return snowflake
}
-/*
-For snowflake proxies to request a client from the Broker.
-*/
-func proxyPolls(i *IPC, w http.ResponseWriter, r *http.Request) {
- body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, readLimit))
- if err != nil {
- log.Println("Invalid data.")
- w.WriteHeader(http.StatusBadRequest)
- return
- }
-
- arg := messages.Arg{
- Body: body,
- RemoteAddr: r.RemoteAddr,
- NatType: "",
- }
-
- var response []byte
- err = i.ProxyPolls(arg, &response)
- switch {
- case err == nil:
- case errors.Is(err, messages.ErrBadRequest):
- w.WriteHeader(http.StatusBadRequest)
- return
- case errors.Is(err, messages.ErrInternal):
- fallthrough
- default:
- log.Println(err)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- if _, err := w.Write(response); err != nil {
- log.Printf("proxyPolls unable to write offer with error: %v", err)
- }
-}
-
// Client offer contains an SDP and the NAT type of the client
type ClientOffer struct {
natType string
sdp []byte
}
-/*
-Expects a WebRTC SDP offer in the Request to give to an assigned
-snowflake proxy, which responds with the SDP answer to be sent in
-the HTTP response back to the client.
-*/
-func clientOffers(i *IPC, w http.ResponseWriter, r *http.Request) {
- body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, readLimit))
- if err != nil {
- log.Printf("Error reading client request: %s", err.Error())
- w.WriteHeader(http.StatusBadRequest)
- return
- }
-
- arg := messages.Arg{
- Body: body,
- RemoteAddr: "",
- NatType: r.Header.Get("Snowflake-NAT-Type"),
- }
-
- var response []byte
- err = i.ClientOffers(arg, &response)
- switch {
- case err == nil:
- case errors.Is(err, messages.ErrUnavailable):
- w.WriteHeader(http.StatusServiceUnavailable)
- return
- case errors.Is(err, messages.ErrTimeout):
- w.WriteHeader(http.StatusGatewayTimeout)
- return
- default:
- log.Println(err)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- if _, err := w.Write(response); err != nil {
- log.Printf("clientOffers unable to write answer with error: %v", err)
- }
-}
-
-/*
-Expects snowflake proxes which have previously successfully received
-an offer from proxyHandler to respond with an answer in an HTTP POST,
-which the broker will pass back to the original client.
-*/
-func proxyAnswers(i *IPC, w http.ResponseWriter, r *http.Request) {
- body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, readLimit))
- if err != nil {
- log.Println("Invalid data.")
- w.WriteHeader(http.StatusBadRequest)
- return
- }
-
- arg := messages.Arg{
- Body: body,
- RemoteAddr: "",
- NatType: "",
- }
-
- var response []byte
- err = i.ProxyAnswers(arg, &response)
- switch {
- case err == nil:
- case errors.Is(err, messages.ErrBadRequest):
- w.WriteHeader(http.StatusBadRequest)
- return
- case errors.Is(err, messages.ErrInternal):
- fallthrough
- default:
- log.Println(err)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- if _, err := w.Write(response); err != nil {
- log.Printf("proxyAnswers unable to write answer response with error: %v", err)
- }
-}
-
-func debugHandler(i *IPC, w http.ResponseWriter, r *http.Request) {
- var response string
-
- err := i.Debug(new(interface{}), &response)
- if err != nil {
- log.Println(err)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- if _, err := w.Write([]byte(response)); err != nil {
- log.Printf("writing proxy information returned error: %v ", err)
- }
-}
-
-func robotsTxtHandler(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- if _, err := w.Write([]byte("User-agent: *\nDisallow: /\n")); err != nil {
- log.Printf("robotsTxtHandler unable to write, with this error: %v", err)
- }
-}
-
-func metricsHandler(metricsFilename string, w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
-
- if metricsFilename == "" {
- http.NotFound(w, r)
- return
- }
- metricsFile, err := os.OpenFile(metricsFilename, os.O_RDONLY, 0644)
- if err != nil {
- log.Println("Error opening metrics file for reading")
- http.NotFound(w, r)
- return
- }
-
- if _, err := io.Copy(w, metricsFile); err != nil {
- log.Printf("copying metricsFile returned error: %v", err)
- }
-}
-
func main() {
var acmeEmail string
var acmeHostnamesCommas string
diff --git a/broker/http.go b/broker/http.go
new file mode 100644
index 0000000..6555d7a
--- /dev/null
+++ b/broker/http.go
@@ -0,0 +1,205 @@
+package main
+
+import (
+ "errors"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+
+ "git.torproject.org/pluggable-transports/snowflake.git/common/messages"
+)
+
+const (
+ readLimit = 100000 // Maximum number of bytes to be read from an HTTP request
+)
+
+// Implements the http.Handler interface
+type SnowflakeHandler struct {
+ *IPC
+ handle func(*IPC, http.ResponseWriter, *http.Request)
+}
+
+func (sh SnowflakeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Access-Control-Allow-Origin", "*")
+ w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Session-ID")
+ // Return early if it's CORS preflight.
+ if "OPTIONS" == r.Method {
+ return
+ }
+ sh.handle(sh.IPC, w, r)
+}
+
+// Implements the http.Handler interface
+type MetricsHandler struct {
+ logFilename string
+ handle func(string, http.ResponseWriter, *http.Request)
+}
+
+func (mh MetricsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Access-Control-Allow-Origin", "*")
+ w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Session-ID")
+ // Return early if it's CORS preflight.
+ if "OPTIONS" == r.Method {
+ return
+ }
+ mh.handle(mh.logFilename, w, r)
+}
+
+func robotsTxtHandler(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ if _, err := w.Write([]byte("User-agent: *\nDisallow: /\n")); err != nil {
+ log.Printf("robotsTxtHandler unable to write, with this error: %v", err)
+ }
+}
+
+func metricsHandler(metricsFilename string, w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+
+ if metricsFilename == "" {
+ http.NotFound(w, r)
+ return
+ }
+ metricsFile, err := os.OpenFile(metricsFilename, os.O_RDONLY, 0644)
+ if err != nil {
+ log.Println("Error opening metrics file for reading")
+ http.NotFound(w, r)
+ return
+ }
+
+ if _, err := io.Copy(w, metricsFile); err != nil {
+ log.Printf("copying metricsFile returned error: %v", err)
+ }
+}
+
+func debugHandler(i *IPC, w http.ResponseWriter, r *http.Request) {
+ var response string
+
+ err := i.Debug(new(interface{}), &response)
+ if err != nil {
+ log.Println(err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ if _, err := w.Write([]byte(response)); err != nil {
+ log.Printf("writing proxy information returned error: %v ", err)
+ }
+}
+
+/*
+For snowflake proxies to request a client from the Broker.
+*/
+func proxyPolls(i *IPC, w http.ResponseWriter, r *http.Request) {
+ body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, readLimit))
+ if err != nil {
+ log.Println("Invalid data.")
+ w.WriteHeader(http.StatusBadRequest)
+ return
+ }
+
+ arg := messages.Arg{
+ Body: body,
+ RemoteAddr: r.RemoteAddr,
+ NatType: "",
+ }
+
+ var response []byte
+ err = i.ProxyPolls(arg, &response)
+ switch {
+ case err == nil:
+ case errors.Is(err, messages.ErrBadRequest):
+ w.WriteHeader(http.StatusBadRequest)
+ return
+ case errors.Is(err, messages.ErrInternal):
+ fallthrough
+ default:
+ log.Println(err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ if _, err := w.Write(response); err != nil {
+ log.Printf("proxyPolls unable to write offer with error: %v", err)
+ }
+}
+
+/*
+Expects a WebRTC SDP offer in the Request to give to an assigned
+snowflake proxy, which responds with the SDP answer to be sent in
+the HTTP response back to the client.
+*/
+func clientOffers(i *IPC, w http.ResponseWriter, r *http.Request) {
+ body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, readLimit))
+ if err != nil {
+ log.Printf("Error reading client request: %s", err.Error())
+ w.WriteHeader(http.StatusBadRequest)
+ return
+ }
+
+ arg := messages.Arg{
+ Body: body,
+ RemoteAddr: "",
+ NatType: r.Header.Get("Snowflake-NAT-Type"),
+ }
+
+ var response []byte
+ err = i.ClientOffers(arg, &response)
+ switch {
+ case err == nil:
+ case errors.Is(err, messages.ErrUnavailable):
+ w.WriteHeader(http.StatusServiceUnavailable)
+ return
+ case errors.Is(err, messages.ErrTimeout):
+ w.WriteHeader(http.StatusGatewayTimeout)
+ return
+ default:
+ log.Println(err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ if _, err := w.Write(response); err != nil {
+ log.Printf("clientOffers unable to write answer with error: %v", err)
+ }
+}
+
+/*
+Expects snowflake proxes which have previously successfully received
+an offer from proxyHandler to respond with an answer in an HTTP POST,
+which the broker will pass back to the original client.
+*/
+func proxyAnswers(i *IPC, w http.ResponseWriter, r *http.Request) {
+ body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, readLimit))
+ if err != nil {
+ log.Println("Invalid data.")
+ w.WriteHeader(http.StatusBadRequest)
+ return
+ }
+
+ arg := messages.Arg{
+ Body: body,
+ RemoteAddr: "",
+ NatType: "",
+ }
+
+ var response []byte
+ err = i.ProxyAnswers(arg, &response)
+ switch {
+ case err == nil:
+ case errors.Is(err, messages.ErrBadRequest):
+ w.WriteHeader(http.StatusBadRequest)
+ return
+ case errors.Is(err, messages.ErrInternal):
+ fallthrough
+ default:
+ log.Println(err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ if _, err := w.Write(response); err != nil {
+ log.Printf("proxyAnswers unable to write answer response with error: %v", err)
+ }
+}