コード例 #1
0
ファイル: request.go プロジェクト: sguzwf/vertex
// parse the client address, based on http headers or the actual ip
func (r *Request) parseAddr() {

	// the default is the originating ip. but we try to find better options because this is almost
	// never the right IP
	if parts := strings.Split(r.Request.RemoteAddr, ":"); len(parts) == 2 {
		r.RemoteIP = parts[0]
	}
	// If we have a forwarded-for header, take the address from there
	if xff := strings.Trim(r.Header.Get("X-Forwarded-For"), ","); len(xff) > 0 {
		addrs := strings.Split(xff, ",")
		lastFwd := addrs[len(addrs)-1]
		if ip := net.ParseIP(lastFwd); ip != nil {
			logging.Debug("Setting IP based on XFF header to %s", ip)
			r.RemoteIP = ip.String()
		}

	} else if xri := r.Header.Get("X-Real-Ip"); len(xri) > 0 {
		if ip := net.ParseIP(xri); ip != nil {
			logging.Debug("Setting IP based on XRI header to %s", ip)
			r.RemoteIP = ip.String()
		}
	}

	logging.Debug("Request ip: %s", r.RemoteIP)

}
コード例 #2
0
ファイル: testing.go プロジェクト: sguzwf/vertex
// FormatUrl returns a fully formatted URL for the context's route, with all path params replaced by
// their respective values in the pathParams map
func (t *TestContext) FormatUrl(pathParams Params) string {

	u := fmt.Sprintf("%s%s", t.serverURl, t.api.FullPath(FormatPath(t.routePath, pathParams)))

	logging.Debug("Formatted url: %s", u)
	return u
}
コード例 #3
0
ファイル: route.go プロジェクト: sguzwf/vertex
func (r *Route) parseInfo(path string) error {

	ri, err := schema.NewRequestInfo(reflect.TypeOf(r.Handler), path, r.Description, r.Returns)
	if err != nil {
		return err
	}

	// search for custom unmarshallers in the request info
	for _, param := range ri.Params {
		if param.Type.Kind() == reflect.Struct {

			logging.Debug("Checking unmarshaller for %s", param.Type)
			val := reflect.Zero(param.Type).Interface()

			if unm, ok := val.(Unmarshaler); ok {
				logging.Info("Registering unmarshaller for %#v", val)

				schemaDecoder.RegisterConverter(val, gorilla.Converter(func(s string) reflect.Value {
					return reflect.ValueOf(unm.UnmarshalRequestData(s))
				}))

			}
		}

	}

	r.requestInfo = ri
	return nil

}
コード例 #4
0
ファイル: config.go プロジェクト: sguzwf/vertex
func ReadConfigs() error {

	if err := autoflag.Load(gofigure.DefaultLoader, &Config); err != nil {
		logging.Error("Error loading configs: %v", err)
		return err
	}
	logging.Info("Read configs: %#v", &Config)

	for k, m := range Config.APIConfigs {

		if conf, found := Config.apiconfs[k]; found && conf != nil {

			b, err := yaml.Marshal(m)
			if err == nil {

				if err := yaml.Unmarshal(b, conf); err != nil {
					logging.Error("Error reading config for API %s: %s", k, err)
				} else {
					logging.Debug("Unmarshaled API config for %s: %#v", k, conf)
				}

			} else {

				logging.Error("Error marshalling config for API %s: %s", k, err)

			}
		} else {
			logging.Warning("API Section %s in config file not registered with server", k)
		}

	}

	return nil

}
コード例 #5
0
ファイル: api.go プロジェクト: sguzwf/vertex
// FullPath returns the calculated full versioned path inside the API of a request.
//
// e.g. if my API name is "myapi" and the version is 1.0, FullPath("/foo") returns "/myapi/1.0/foo"
func (a *API) FullPath(relpath string) string {

	relpath = routeRe.ReplaceAllString(relpath, ":$1")

	ret := path.Join(a.root(), relpath)
	logging.Debug("FullPath for %s => %s", relpath, ret)
	return ret
}
コード例 #6
0
ファイル: api.go プロジェクト: sguzwf/vertex
func (a *API) middlewareHandler(chain *step, security SecurityScheme, renderer Renderer) func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {

	// allow overriding the API's default renderer with a per-route one
	if renderer == nil {
		renderer = a.Renderer
	}

	return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {

		req := NewRequest(r)

		if !a.AllowInsecure && !req.Secure {
			// local requests bypass security
			if req.RemoteIP != "127.0.0.1" {
				http.Error(w, insecureAccessMessage, http.StatusForbidden)
				return
			}
		}

		r.ParseForm()
		// Copy values from the router params to the request params
		for _, v := range p {
			r.Form.Set(v.Key, v.Value)
		}

		var ret interface{}
		var err error

		if security != nil {
			if err = security.Validate(req); err != nil {
				logging.Warning("Error validating security scheme: %s", err)

				if e, ok := err.(*internalError); ok {
					e.Code = ErrUnauthorized
					err = e
				}
			}
		}
		if err == nil {
			ret, err = chain.handle(w, req)
		}

		if err != Hijacked {

			if err = renderer.Render(ret, err, w, req); err != nil {
				logging.Error("Error rendering response: %s", err)
			}
		} else {
			logging.Debug("Not rendering hijacked request %s", r.RequestURI)
		}

	}

}
コード例 #7
0
ファイル: request.go プロジェクト: sguzwf/vertex
// parse the locale based on Accept-Language header. If no header found or the values are invalid,
// we fall back to en-US
func (r *Request) parseLocale() {

	tags, _, err := language.ParseAcceptLanguage(r.Header.Get("Accept-Language"))
	if err != nil {
		logging.Warning("Could not parse accept lang header: %s", err)
		return
	}

	if len(tags) > 0 {
		logging.Debug("Locale for request: %s", tags[0])
		r.Locale = tags[0].String()
	}
}
コード例 #8
0
ファイル: validate.go プロジェクト: sguzwf/vertex
// Create new request validator for a request handler interface.
// This function walks the struct tags of the handler's fields and extracts validation metadata.
//
// You should give it the reflect type of your request handler struct
func NewRequestValidator(ri schema.RequestInfo) *RequestValidator {

	//if the user passes a pointer we walk the actual struct

	ret := &RequestValidator{
		fieldValidators: make([]validator, 0),
	}

	//iterate over the fields and create a validator for each
	for _, pi := range ri.Params {

		var vali validator
		switch pi.Kind {
		//		case reflect.Struct:

		//			//for structs - we add validators recursively
		//			validator := NewRequestValidator(field.Type)
		//			if validator != nil && len(validator.fieldValidators) > 0 {
		//				ret.fieldValidators = append(ret.fieldValidators, validator.fieldValidators...)
		//			}
		//			continue

		case reflect.String:
			vali = newStringValidator(pi)

		case reflect.Int, reflect.Int32, reflect.Int64:
			vali = newIntValidator(pi)

		case reflect.Float32, reflect.Float64:
			vali = newFloatValidator(pi)
		case reflect.Bool:
			vali = newBoolValidator(pi)
		default:
			logging.Error("I don't know how to validate %s", pi.Kind)
			continue
		}

		if vali != nil {
			logging.Debug("Adding validator %v to request validator %v", vali, ri)
			ret.fieldValidators = append(ret.fieldValidators, vali)
		}

	}

	return ret
}
コード例 #9
0
ファイル: basic_auth.go プロジェクト: sguzwf/vertex
func (b BasicAuth) Handle(w http.ResponseWriter, r *vertex.Request, next vertex.HandlerFunc) (interface{}, error) {

	if !r.IsLocal() || !b.BypassForLocal {
		user, pass, ok := r.BasicAuth()
		if !ok {
			logging.Debug("No auth header, denying")
			b.requireAuth(w)
			return nil, vertex.Hijacked
		}

		if user != b.User || pass != b.Password {
			logging.Warning("Unmatching auth: %s/%s", user, pass)
			b.requireAuth(w)
			return nil, vertex.Hijacked
		}
	}

	return next(w, r)
}
コード例 #10
0
ファイル: cache.go プロジェクト: sguzwf/vertex
func (m *CacheMiddleware) Handle(w http.ResponseWriter, r *vertex.Request, next vertex.HandlerFunc) (interface{}, error) {

	// Do not act on request if they have no-cache header
	if strings.ToLower(r.Header.Get("Cache-Control")) == "no-cache" {
		return next(w, r)
	}

	key := m.requestKey(r)
	logging.Debug("CACHING KEY: %s", key)
	entry, err := m.get(key)
	if err == nil && entry != nil {
		logging.Info("Fetched cache response: %#v", entry.value)
		return entry.value, nil
	}

	v, err := next(w, r)
	if err == nil {
		m.put(key, newEntry(v, m.ttl))
	}

	return v, err

}