mirror of
https://github.com/gravitational/teleport
synced 2024-10-21 17:53:28 +00:00
144 lines
4.3 KiB
Go
144 lines
4.3 KiB
Go
/*
|
|
Copyright 2015 Gravitational, Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
// Package httplib implements common utility functions for writing
|
|
// classic HTTP handlers
|
|
package httplib
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"regexp"
|
|
"strconv"
|
|
|
|
"github.com/gravitational/roundtrip"
|
|
"github.com/gravitational/trace"
|
|
"github.com/julienschmidt/httprouter"
|
|
)
|
|
|
|
// HandlerFunc specifies HTTP handler function that returns error
|
|
type HandlerFunc func(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error)
|
|
|
|
// StdHandlerFunc specifies HTTP handler function that returns error
|
|
type StdHandlerFunc func(w http.ResponseWriter, r *http.Request) (interface{}, error)
|
|
|
|
// MakeHandler returns a new httprouter.Handle func from a handler func
|
|
func MakeHandler(fn HandlerFunc) httprouter.Handle {
|
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
|
out, err := fn(w, r, p)
|
|
if err != nil {
|
|
trace.WriteError(w, err)
|
|
return
|
|
}
|
|
if out != nil {
|
|
roundtrip.ReplyJSON(w, http.StatusOK, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MakeStdHandler returns a new http.Handle func from http.HandlerFunc
|
|
func MakeStdHandler(fn StdHandlerFunc) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
out, err := fn(w, r)
|
|
if err != nil {
|
|
trace.WriteError(w, err)
|
|
return
|
|
}
|
|
if out != nil {
|
|
roundtrip.ReplyJSON(w, http.StatusOK, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
// ReadJSON reads HTTP json request and unmarshals it
|
|
// into passed interface{} obj
|
|
func ReadJSON(r *http.Request, val interface{}) error {
|
|
data, err := ioutil.ReadAll(r.Body)
|
|
if err != nil {
|
|
return trace.Wrap(err)
|
|
}
|
|
if err := json.Unmarshal(data, &val); err != nil {
|
|
return trace.BadParameter("request: %v", err.Error())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ConvertResponse converts http error to internal error type
|
|
// based on HTTP response code and HTTP body contents
|
|
func ConvertResponse(re *roundtrip.Response, err error) (*roundtrip.Response, error) {
|
|
if err != nil {
|
|
if uerr, ok := err.(*url.Error); ok && uerr != nil && uerr.Err != nil {
|
|
return nil, trace.Wrap(uerr.Err)
|
|
}
|
|
return nil, trace.Wrap(err)
|
|
}
|
|
return re, trace.ReadError(re.Code(), re.Bytes())
|
|
}
|
|
|
|
// InsecureSetDevmodeHeaders allows cross-origin requests, used in dev mode only
|
|
func InsecureSetDevmodeHeaders(w http.ResponseWriter) {
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS")
|
|
w.Header().Set("Access-Control-Allow-Headers", "Accept, Origin, Content-type, Authorization")
|
|
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
w.Header().Set("Access-Control-Max-Age", "1728000")
|
|
}
|
|
|
|
// ParseBool will parse boolean variable from url query
|
|
// returns value, ok, error
|
|
func ParseBool(q url.Values, name string) (bool, bool, error) {
|
|
stringVal := q.Get(name)
|
|
if stringVal == "" {
|
|
return false, false, nil
|
|
}
|
|
|
|
val, err := strconv.ParseBool(stringVal)
|
|
if err != nil {
|
|
return false, false, trace.BadParameter(
|
|
"'%v': expected 'true' or 'false', got %v", name, stringVal)
|
|
}
|
|
return val, true, nil
|
|
}
|
|
|
|
// RewritePair is a rewrite expression
|
|
type RewritePair struct {
|
|
// Expr is matching expression
|
|
Expr *regexp.Regexp
|
|
// Replacement is replacement
|
|
Replacement string
|
|
}
|
|
|
|
// Rewrite creates a rewrite pair, panics if in epxression
|
|
// is not a valid regular expressoin
|
|
func Rewrite(in, out string) RewritePair {
|
|
return RewritePair{
|
|
Expr: regexp.MustCompile(in),
|
|
Replacement: out,
|
|
}
|
|
}
|
|
|
|
// RewritePaths creates a middleware that rewrites paths in incoming request
|
|
func RewritePaths(next http.Handler, rewrites ...RewritePair) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
for _, rewrite := range rewrites {
|
|
req.URL.Path = rewrite.Expr.ReplaceAllString(req.URL.Path, rewrite.Replacement)
|
|
}
|
|
next.ServeHTTP(w, req)
|
|
})
|
|
}
|