Refactor RDP proxy handling and update related tests
This commit is contained in:
@@ -69,22 +69,24 @@ type VPNPacketIngressRoutePreference interface {
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
Local PeerIdentity
|
||||
SyntheticRuntime *SyntheticRuntime
|
||||
ProductionForwardingEnabled bool
|
||||
ProductionEnvelopeObserver ProductionEnvelopeObserver
|
||||
ProductionEnvelopeDelivery ProductionEnvelopeDelivery
|
||||
ProductionForwardTransport ProductionForwardTransport
|
||||
ProductionForwardLogger ProductionForwardLogger
|
||||
FabricServiceChannelLogger FabricServiceChannelAccessLogger
|
||||
RemoteWorkspaceFrameSink RemoteWorkspaceFrameSink
|
||||
ProductionRoutes []SyntheticRoute
|
||||
VPNPacketIngress VPNPacketIngress
|
||||
BackendProxyBaseURL string
|
||||
ClusterAuthorityPublicKey string
|
||||
ServiceChannelIntrospection bool
|
||||
FabricSessionEnabled bool
|
||||
FabricSessionLogger FabricSessionEventLogger
|
||||
Local PeerIdentity
|
||||
SyntheticRuntime *SyntheticRuntime
|
||||
ProductionForwardingEnabled bool
|
||||
ProductionEnvelopeObserver ProductionEnvelopeObserver
|
||||
ProductionEnvelopeDelivery ProductionEnvelopeDelivery
|
||||
ProductionForwardTransport ProductionForwardTransport
|
||||
ProductionForwardLogger ProductionForwardLogger
|
||||
DisableHTTPDataPlane bool
|
||||
FabricServiceChannelLogger FabricServiceChannelAccessLogger
|
||||
RemoteWorkspaceFrameSink RemoteWorkspaceFrameSink
|
||||
ProductionRoutes []SyntheticRoute
|
||||
VPNPacketIngress VPNPacketIngress
|
||||
BackendProxyBaseURL string
|
||||
ClusterAuthorityPublicKey string
|
||||
ServiceChannelIntrospection bool
|
||||
FabricSessionEnabled bool
|
||||
FabricSessionWebSocketEnabled bool
|
||||
FabricSessionLogger FabricSessionEventLogger
|
||||
}
|
||||
|
||||
func (s Server) Handler() http.Handler {
|
||||
@@ -92,7 +94,7 @@ func (s Server) Handler() http.Handler {
|
||||
mux.HandleFunc("/mesh/v1/health", s.handleHealth)
|
||||
mux.HandleFunc("/mesh/v1/forward", s.handleForward)
|
||||
mux.HandleFunc("/mesh/v1/synthetic/probe", s.handleSyntheticProbe)
|
||||
if s.FabricSessionEnabled {
|
||||
if s.FabricSessionEnabled && s.FabricSessionWebSocketEnabled {
|
||||
mux.HandleFunc("/mesh/v1/fabric/session/ws", s.handleFabricSessionWebSocket)
|
||||
}
|
||||
if s.RemoteWorkspaceFrameSink != nil {
|
||||
@@ -198,6 +200,7 @@ type FabricSessionEventLogEntry struct {
|
||||
Event string `json:"event"`
|
||||
ClusterID string `json:"cluster_id,omitempty"`
|
||||
NodeID string `json:"node_id,omitempty"`
|
||||
PeerID string `json:"peer_id,omitempty"`
|
||||
AcceptedBy string `json:"accepted_by,omitempty"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
SessionEvent fabricproto.SessionEventType `json:"session_event,omitempty"`
|
||||
@@ -2079,16 +2082,12 @@ func (s Server) handleForward(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
if s.DisableHTTPDataPlane {
|
||||
http.Error(w, "mesh data-plane forwarding requires QUIC fabric transport", http.StatusGone)
|
||||
return
|
||||
}
|
||||
if !s.ProductionForwardingEnabled {
|
||||
s.logProductionForward(ProductionForwardLogEntry{
|
||||
Event: "production_forward_rejected",
|
||||
ClusterID: s.Local.ClusterID,
|
||||
LocalNodeID: s.Local.NodeID,
|
||||
Reason: ErrForwardDisabled.Error(),
|
||||
StatusCode: http.StatusNotImplemented,
|
||||
OccurredAt: time.Now().UTC(),
|
||||
})
|
||||
http.Error(w, ErrForwardDisabled.Error(), http.StatusNotImplemented)
|
||||
s.rejectProductionForward(w, ProductionEnvelope{}, ErrForwardDisabled, forwardStatusCode(ErrForwardDisabled))
|
||||
return
|
||||
}
|
||||
var envelope ProductionEnvelope
|
||||
@@ -2104,54 +2103,57 @@ func (s Server) handleForward(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "invalid production mesh envelope", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if err := ValidateProductionEnvelope(s.Local, envelope, time.Now().UTC()); err != nil {
|
||||
result, err := s.ForwardProduction(r.Context(), envelope)
|
||||
if err != nil {
|
||||
s.rejectProductionForward(w, envelope, err, forwardStatusCode(err))
|
||||
return
|
||||
}
|
||||
writeProductionForwardResult(w, result)
|
||||
}
|
||||
|
||||
func (s Server) ForwardProduction(ctx context.Context, envelope ProductionEnvelope) (ProductionForwardResult, error) {
|
||||
if !s.ProductionForwardingEnabled {
|
||||
return ProductionForwardResult{}, ErrForwardDisabled
|
||||
}
|
||||
if err := ValidateProductionEnvelope(s.Local, envelope, time.Now().UTC()); err != nil {
|
||||
return ProductionForwardResult{}, err
|
||||
}
|
||||
if err := ValidateProductionEnvelopeRouteConfig(s.Local, envelope, s.ProductionRoutes, time.Now().UTC()); err != nil {
|
||||
s.rejectProductionForward(w, envelope, err, forwardStatusCode(err))
|
||||
return
|
||||
return ProductionForwardResult{}, err
|
||||
}
|
||||
s.logProductionForward(productionForwardLogEntry("production_forward_accepted", s.Local, envelope, "", 0))
|
||||
if s.ProductionEnvelopeObserver != nil {
|
||||
observation := NewProductionEnvelopeObservation(envelope, time.Now().UTC())
|
||||
if err := observeProductionEnvelope(r.Context(), s.ProductionEnvelopeObserver, observation); err != nil {
|
||||
if err := observeProductionEnvelope(ctx, s.ProductionEnvelopeObserver, observation); err != nil {
|
||||
s.logProductionForward(productionForwardLogEntry("production_forward_rejected", s.Local, envelope, ErrForwardObservationFailed.Error(), http.StatusInternalServerError))
|
||||
http.Error(w, ErrForwardObservationFailed.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
return ProductionForwardResult{}, ErrForwardObservationFailed
|
||||
}
|
||||
}
|
||||
if envelope.DestinationNodeID == s.Local.NodeID {
|
||||
if err := deliverProductionEnvelope(r.Context(), s.ProductionEnvelopeDelivery, envelope); err != nil {
|
||||
if err := deliverProductionEnvelope(ctx, s.ProductionEnvelopeDelivery, envelope); err != nil {
|
||||
s.logProductionForward(productionForwardLogEntry("production_forward_rejected", s.Local, envelope, ErrForwardDeliveryFailed.Error(), http.StatusInternalServerError))
|
||||
http.Error(w, ErrForwardDeliveryFailed.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
return ProductionForwardResult{}, ErrForwardDeliveryFailed
|
||||
}
|
||||
s.logProductionForward(productionForwardLogEntry("production_forward_delivered", s.Local, envelope, "", http.StatusOK))
|
||||
writeProductionForwardResult(w, ProductionForwardResult{
|
||||
return ProductionForwardResult{
|
||||
Accepted: true,
|
||||
Delivered: true,
|
||||
By: s.Local,
|
||||
MessageID: envelope.MessageID,
|
||||
RouteID: envelope.RouteID,
|
||||
})
|
||||
return
|
||||
}, nil
|
||||
}
|
||||
if envelope.NextHopNodeID == s.Local.NodeID {
|
||||
s.rejectProductionForward(w, envelope, ErrLoopDetected, forwardStatusCode(ErrLoopDetected))
|
||||
return
|
||||
return ProductionForwardResult{}, ErrLoopDetected
|
||||
}
|
||||
if len(envelope.RoutePath) == 0 && envelope.NextHopNodeID != envelope.DestinationNodeID {
|
||||
s.rejectProductionForward(w, envelope, ErrForwardRuntimeUnavailable, http.StatusNotImplemented)
|
||||
return
|
||||
return ProductionForwardResult{}, ErrForwardRuntimeUnavailable
|
||||
}
|
||||
if s.ProductionForwardTransport == nil {
|
||||
s.rejectProductionForward(w, envelope, ErrForwardRuntimeUnavailable, http.StatusNotImplemented)
|
||||
return
|
||||
return ProductionForwardResult{}, ErrForwardRuntimeUnavailable
|
||||
}
|
||||
if envelope.TTL <= 1 {
|
||||
s.rejectProductionForward(w, envelope, ErrTTLExhausted, forwardStatusCode(ErrTTLExhausted))
|
||||
return
|
||||
return ProductionForwardResult{}, ErrTTLExhausted
|
||||
}
|
||||
forwarded := envelope
|
||||
forwarded.CurrentHopNodeID = envelope.NextHopNodeID
|
||||
@@ -2159,10 +2161,9 @@ func (s Server) handleForward(w http.ResponseWriter, r *http.Request) {
|
||||
forwarded.TTL = envelope.TTL - 1
|
||||
forwarded.HopCount = envelope.HopCount + 1
|
||||
forwarded.VisitedNodeIDs = append(append([]string{}, envelope.VisitedNodeIDs...), s.Local.NodeID)
|
||||
result, err := s.ProductionForwardTransport.SendProduction(r.Context(), envelope.NextHopNodeID, forwarded)
|
||||
result, err := s.ProductionForwardTransport.SendProduction(ctx, envelope.NextHopNodeID, forwarded)
|
||||
if err != nil {
|
||||
s.rejectProductionForward(w, envelope, err, forwardStatusCode(err))
|
||||
return
|
||||
return ProductionForwardResult{}, err
|
||||
}
|
||||
s.logProductionForward(productionForwardLogEntry("production_forward_forwarded", s.Local, envelope, "", http.StatusOK))
|
||||
result.Accepted = true
|
||||
@@ -2171,7 +2172,7 @@ func (s Server) handleForward(w http.ResponseWriter, r *http.Request) {
|
||||
result.MessageID = envelope.MessageID
|
||||
result.RouteID = envelope.RouteID
|
||||
result.NextNodeID = envelope.NextHopNodeID
|
||||
writeProductionForwardResult(w, result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s Server) rejectProductionForward(w http.ResponseWriter, envelope ProductionEnvelope, err error, statusCode int) {
|
||||
@@ -2262,6 +2263,10 @@ func (s Server) handleSyntheticProbe(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
if s.DisableHTTPDataPlane {
|
||||
http.Error(w, "mesh synthetic probes require QUIC fabric transport", http.StatusGone)
|
||||
return
|
||||
}
|
||||
if s.SyntheticRuntime == nil {
|
||||
http.Error(w, ErrMeshRuntimeDisabled.Error(), http.StatusServiceUnavailable)
|
||||
return
|
||||
@@ -2307,17 +2312,19 @@ func syntheticStatusCode(err error) int {
|
||||
}
|
||||
|
||||
func forwardStatusCode(err error) int {
|
||||
switch err {
|
||||
case ErrClusterMismatch, ErrNodeMismatch, ErrUnauthorizedChannel, ErrLoopDetected:
|
||||
switch {
|
||||
case errors.Is(err, ErrClusterMismatch), errors.Is(err, ErrNodeMismatch), errors.Is(err, ErrUnauthorizedChannel), errors.Is(err, ErrLoopDetected):
|
||||
return http.StatusForbidden
|
||||
case ErrRouteExpired, ErrTTLExhausted, ErrInvalidRoutePath, ErrRouteIDRequired:
|
||||
case errors.Is(err, ErrRouteExpired), errors.Is(err, ErrTTLExhausted), errors.Is(err, ErrInvalidRoutePath), errors.Is(err, ErrRouteIDRequired), errors.Is(err, ErrForwardEnvelopeInvalid):
|
||||
return http.StatusBadRequest
|
||||
case ErrForwardRuntimeUnavailable:
|
||||
case errors.Is(err, ErrForwardRuntimeUnavailable), errors.Is(err, ErrForwardDisabled):
|
||||
return http.StatusNotImplemented
|
||||
case ErrRouteNotFound:
|
||||
case errors.Is(err, ErrRouteNotFound):
|
||||
return http.StatusNotFound
|
||||
case ErrForwardPeerUnavailable:
|
||||
case errors.Is(err, ErrForwardPeerUnavailable):
|
||||
return http.StatusBadGateway
|
||||
case errors.Is(err, ErrForwardObservationFailed), errors.Is(err, ErrForwardDeliveryFailed):
|
||||
return http.StatusInternalServerError
|
||||
default:
|
||||
return http.StatusBadRequest
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user