Просмотр исходного кода

Terminate unsuccessful tactics request connections

- To prevent dangling persistent HTTP conns in cases
  where the client fails to or is unable to close
  the connection gracefully.
Rod Hynes 7 лет назад
Родитель
Сommit
c1b0f381b7
3 измененных файлов с 35 добавлено и 34 удалено
  1. 20 0
      psiphon/common/net.go
  2. 7 7
      psiphon/common/tactics/tactics.go
  3. 8 27
      psiphon/server/meek.go

+ 20 - 0
psiphon/common/net.go

@@ -22,6 +22,7 @@ package common
 import (
 	"container/list"
 	"net"
+	"net/http"
 	"sync"
 	"sync/atomic"
 	"time"
@@ -76,6 +77,25 @@ func (conns *Conns) CloseAll() {
 	conns.conns = make(map[net.Conn]bool)
 }
 
+// TerminateHTTPConnection sends a 404 response to a client and also closes
+// the persistent connection.
+func TerminateHTTPConnection(
+	responseWriter http.ResponseWriter, request *http.Request) {
+
+	http.NotFound(responseWriter, request)
+
+	hijack, ok := responseWriter.(http.Hijacker)
+	if !ok {
+		return
+	}
+	conn, buffer, err := hijack.Hijack()
+	if err != nil {
+		return
+	}
+	buffer.Flush()
+	conn.Close()
+}
+
 // IPAddressFromAddr is a helper which extracts an IP address
 // from a net.Addr or returns "" if there is no IP address.
 func IPAddressFromAddr(addr net.Addr) string {

+ 7 - 7
psiphon/common/tactics/tactics.go

@@ -961,7 +961,7 @@ func (server *Server) handleSpeedTestRequest(
 	if err != nil {
 		server.logger.WithContextFields(
 			common.LogFields{"error": err}).Warning("failed to read request body")
-		w.WriteHeader(http.StatusNotFound)
+		common.TerminateHTTPConnection(w, r)
 		return
 	}
 
@@ -970,7 +970,7 @@ func (server *Server) handleSpeedTestRequest(
 	if err != nil {
 		server.logger.WithContextFields(
 			common.LogFields{"error": err}).Warning("failed to make response")
-		w.WriteHeader(http.StatusNotFound)
+		common.TerminateHTTPConnection(w, r)
 		return
 	}
 
@@ -992,7 +992,7 @@ func (server *Server) handleTacticsRequest(
 	if err != nil {
 		server.logger.WithContextFields(
 			common.LogFields{"error": err}).Warning("failed to read request body")
-		w.WriteHeader(http.StatusNotFound)
+		common.TerminateHTTPConnection(w, r)
 		return
 	}
 
@@ -1007,7 +1007,7 @@ func (server *Server) handleTacticsRequest(
 	if err != nil {
 		server.logger.WithContextFields(
 			common.LogFields{"error": err}).Warning("failed to unbox request")
-		w.WriteHeader(http.StatusNotFound)
+		common.TerminateHTTPConnection(w, r)
 		return
 	}
 
@@ -1015,7 +1015,7 @@ func (server *Server) handleTacticsRequest(
 	if err != nil {
 		server.logger.WithContextFields(
 			common.LogFields{"error": err}).Warning("invalid request parameters")
-		w.WriteHeader(http.StatusNotFound)
+		common.TerminateHTTPConnection(w, r)
 		return
 	}
 
@@ -1026,7 +1026,7 @@ func (server *Server) handleTacticsRequest(
 	if err != nil {
 		server.logger.WithContextFields(
 			common.LogFields{"error": err}).Warning("failed to get tactics")
-		w.WriteHeader(http.StatusNotFound)
+		common.TerminateHTTPConnection(w, r)
 		return
 	}
 
@@ -1042,7 +1042,7 @@ func (server *Server) handleTacticsRequest(
 	if err != nil {
 		server.logger.WithContextFields(
 			common.LogFields{"error": err}).Warning("failed to box response")
-		w.WriteHeader(http.StatusNotFound)
+		common.TerminateHTTPConnection(w, r)
 		return
 	}
 

+ 8 - 27
psiphon/server/meek.go

@@ -244,7 +244,7 @@ func (server *MeekServer) ServeHTTP(responseWriter http.ResponseWriter, request
 	}
 	if meekCookie == nil || len(meekCookie.Value) == 0 {
 		log.WithContext().Warning("missing meek cookie")
-		server.terminateConnection(responseWriter, request)
+		common.TerminateHTTPConnection(responseWriter, request)
 		return
 	}
 
@@ -256,7 +256,7 @@ func (server *MeekServer) ServeHTTP(responseWriter http.ResponseWriter, request
 					"header": header,
 					"value":  value,
 				}).Warning("prohibited meek header")
-				server.terminateConnection(responseWriter, request)
+				common.TerminateHTTPConnection(responseWriter, request)
 				return
 			}
 		}
@@ -277,7 +277,7 @@ func (server *MeekServer) ServeHTTP(responseWriter http.ResponseWriter, request
 		// Debug since session cookie errors commonly occur during
 		// normal operation.
 		log.WithContextFields(LogFields{"error": err}).Debug("session lookup failed")
-		server.terminateConnection(responseWriter, request)
+		common.TerminateHTTPConnection(responseWriter, request)
 		return
 	}
 
@@ -291,7 +291,7 @@ func (server *MeekServer) ServeHTTP(responseWriter http.ResponseWriter, request
 			endPoint, common.GeoIPData(geoIPData), responseWriter, request)
 		if !handled {
 			log.WithContextFields(LogFields{"endPoint": endPoint}).Info("unhandled endpoint")
-			server.terminateConnection(responseWriter, request)
+			common.TerminateHTTPConnection(responseWriter, request)
 		}
 		return
 	}
@@ -330,7 +330,7 @@ func (server *MeekServer) ServeHTTP(responseWriter http.ResponseWriter, request
 	// to session.cachedResponse.Reset may have already occured, so any further
 	// session.cachedResponse access may deplete resources (fail to refill the pool).
 	if atomic.LoadInt64(&session.requestCount) > requestNumber || session.deleted {
-		server.terminateConnection(responseWriter, request)
+		common.TerminateHTTPConnection(responseWriter, request)
 		return
 	}
 
@@ -351,7 +351,7 @@ func (server *MeekServer) ServeHTTP(responseWriter http.ResponseWriter, request
 			// also, golang network error messages may contain client IP.
 			log.WithContextFields(LogFields{"error": err}).Debug("read request failed")
 		}
-		server.terminateConnection(responseWriter, request)
+		common.TerminateHTTPConnection(responseWriter, request)
 
 		// Note: keep session open to allow client to retry
 
@@ -408,7 +408,7 @@ func (server *MeekServer) ServeHTTP(responseWriter http.ResponseWriter, request
 
 		if !session.cachedResponse.HasPosition(position) {
 			greaterThanSwapInt64(&session.metricCachedResponseMissPosition, int64(position))
-			server.terminateConnection(responseWriter, request)
+			common.TerminateHTTPConnection(responseWriter, request)
 			session.delete(true)
 			return
 		}
@@ -462,7 +462,7 @@ func (server *MeekServer) ServeHTTP(responseWriter http.ResponseWriter, request
 			// also, golang network error messages may contain client IP.
 			log.WithContextFields(LogFields{"error": responseError}).Debug("write response failed")
 		}
-		server.terminateConnection(responseWriter, request)
+		common.TerminateHTTPConnection(responseWriter, request)
 
 		// Note: keep session open to allow client to retry
 
@@ -710,25 +710,6 @@ func (server *MeekServer) httpConnStateCallback(conn net.Conn, connState http.Co
 	}
 }
 
-// terminateConnection sends a 404 response to a client and also closes
-// the persistent connection.
-func (server *MeekServer) terminateConnection(
-	responseWriter http.ResponseWriter, request *http.Request) {
-
-	http.NotFound(responseWriter, request)
-
-	hijack, ok := responseWriter.(http.Hijacker)
-	if !ok {
-		return
-	}
-	conn, buffer, err := hijack.Hijack()
-	if err != nil {
-		return
-	}
-	buffer.Flush()
-	conn.Close()
-}
-
 type meekSession struct {
 	// Note: 64-bit ints used with atomic operations are placed
 	// at the start of struct to ensure 64-bit alignment.