mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-05-10 18:56:34 +00:00

To help accommodate web browser interactions with websockets, when a streaming logs session is requested for the same actor while already serving a session for that user in a separate request, the original request will be closed and the new request start streaming logs instead. This should help with rogue sessions holding on for too long with no client on the other side (before idle timeout or connection close).
77 lines
2.1 KiB
Go
77 lines
2.1 KiB
Go
package management
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
type ctxKey int
|
|
|
|
const (
|
|
accessClaimsCtxKey ctxKey = iota
|
|
)
|
|
|
|
const (
|
|
connectorIDQuery = "connector_id"
|
|
accessTokenQuery = "access_token"
|
|
)
|
|
|
|
var (
|
|
errMissingAccessToken = managementError{Code: 1001, Message: "missing access_token query parameter"}
|
|
)
|
|
|
|
// HTTP middleware setting the parsed access_token claims in the request context
|
|
func ValidateAccessTokenQueryMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
// Validate access token
|
|
accessToken := r.URL.Query().Get("access_token")
|
|
if accessToken == "" {
|
|
writeHTTPErrorResponse(w, errMissingAccessToken)
|
|
return
|
|
}
|
|
token, err := parseToken(accessToken)
|
|
if err != nil {
|
|
writeHTTPErrorResponse(w, errMissingAccessToken)
|
|
return
|
|
}
|
|
r = r.WithContext(context.WithValue(r.Context(), accessClaimsCtxKey, token))
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// Middleware validation error struct for returning to the eyeball
|
|
type managementError struct {
|
|
Code int `json:"code,omitempty"`
|
|
Message string `json:"message,omitempty"`
|
|
}
|
|
|
|
func (m *managementError) Error() string {
|
|
return m.Message
|
|
}
|
|
|
|
// Middleware validation error HTTP response JSON for returning to the eyeball
|
|
type managementErrorResponse struct {
|
|
Success bool `json:"success,omitempty"`
|
|
Errors []managementError `json:"errors,omitempty"`
|
|
}
|
|
|
|
// writeErrorResponse will respond to the eyeball with basic HTTP JSON payloads with validation failure information
|
|
func writeHTTPErrorResponse(w http.ResponseWriter, errResp managementError) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
err := json.NewEncoder(w).Encode(managementErrorResponse{
|
|
Success: false,
|
|
Errors: []managementError{errResp},
|
|
})
|
|
// we have already written the header, so write a basic error response if unable to encode the error
|
|
if err != nil {
|
|
// fallback to text message
|
|
http.Error(w, fmt.Sprintf(
|
|
"%d %s",
|
|
http.StatusBadRequest,
|
|
http.StatusText(http.StatusBadRequest),
|
|
), http.StatusBadRequest)
|
|
}
|
|
}
|