// url generates the absolute URL that will be used to make // this request. func (r *Request) url() (*url.URL, error) { urlString := stewstrings.MergeStrings(r.session.host(), common.PathSeparator, r.path) theURL, urlErr := url.Parse(urlString) if urlErr != nil { return nil, urlErr } // set the query values theURL.RawQuery = r.queryValues.Encode() urlString = theURL.String() if strings.Contains(urlString, "?") { urlString = stewstrings.MergeStrings(urlString, "&", common.ParameterAPIKey, "=", r.session.apiKey) } else { urlString = stewstrings.MergeStrings(urlString, "?", common.ParameterAPIKey, "=", r.session.apiKey) } theURL, urlErr = url.Parse(urlString) if urlErr != nil { return nil, urlErr } return theURL, nil }
// GetSignedURL gets the URL with the sign parameter added based on the given parameters. func GetSignedURLWithTrace(method, requestUrl, body, privateKey string, tracer *tracer.Tracer) (string, error) { trace(tracer, "GetSignedURL: method=%s", method) trace(tracer, "GetSignedURL: requestUrl=%s", requestUrl) trace(tracer, "GetSignedURL: body=%s", body) trace(tracer, "GetSignedURL: privateKey=%s", privateKey) hash, hashErr := GetSignatureWithTrace(method, requestUrl, body, privateKey, tracer) if hashErr != nil { trace(tracer, "GetSignedURL: FAILED to get the signature: %s", hashErr) return FailedSignature, hashErr } var signedUrl string if strings.Contains(requestUrl, "?") { signedUrl = stewstrings.MergeStrings(requestUrl, "&", url.QueryEscape(SignatureKey), "=", url.QueryEscape(hash)) } else { signedUrl = stewstrings.MergeStrings(requestUrl, "?", url.QueryEscape(SignatureKey), "=", url.QueryEscape(hash)) } trace(tracer, "GetSignedURL: Output: %s", signedUrl) return signedUrl, nil }
// Marshal converts an object to JSONP. func (c *JsonPCodec) Marshal(object interface{}, options map[string]interface{}) ([]byte, error) { if len(options) == 0 { return nil, ErrorMissingCallback } json, err := jsonEncoding.Marshal(object) if err != nil { return nil, err } // #codec-context-options // the assumption is options[0] is the callback parameter, // and options[1] is the client-context (NB: not *Context) string. var callbackFunctionName string var callbackString string var clientContextString string var ok bool if callbackFunctionName, ok = options[constants.OptionKeyClientCallback].(string); !ok { panic("stretchrcom/codecs: JSONP requires the options to contain the constants.OptionKeyClientCallback value.") } clientContextString, hasClientContext := options[constants.OptionKeyClientContext].(string) if !hasClientContext { callbackString = stewstrings.MergeStrings(callbackFunctionName, "(", string(json), ");") } else { callbackString = stewstrings.MergeStrings(options[constants.OptionKeyClientCallback].(string), "(", string(json), `,"`, clientContextString, `"`, ");") } return []byte(callbackString), nil }
// OrderParams gets the parameters ordered by key, then by values as a URL string. func OrderParams(values url.Values) string { // get the keys var keys []string for k, _ := range values { keys = append(keys, k) } // sort the keys sort.Strings(keys) // ordered items var ordered []string // sort the values for _, key := range keys { sort.Strings(values[key]) for _, val := range values[key] { ordered = append(ordered, stewstrings.MergeStrings(key, "=", val)) } } joined := stewstrings.JoinStrings("&", ordered...) return joined }
// host gets the host to make requests to. func (s *Session) host() string { // get the protocol var protocol string if s.UseSSL { protocol = common.HTTPProtocolSecure } else { protocol = common.HTTPProtocol } host := stewstrings.MergeStrings(protocol, common.ProtocolSeparator, s.account, common.HostSeparator, common.TopLevelHostName, common.APIVersionPathPrefix, s.apiVersion, common.PathSeparator, s.project, ) Tracer.TraceInfo("Host string: %s", host) return host }
// String gets a nicely formatted string of the trace data. func (t *Tracer) String() string { if t == nil { return "" } t.Process() return strings.MergeStrings("\n", strings.JoinStrings("\n", t.StringData()...)) }
// GetSignatureWithTrace gets the signature of a request based on the given parameters. func GetSignatureWithTrace(method, requestUrl, body, privateKey string, tracer *tracer.Tracer) (string, error) { trace(tracer, "GetSignature: method=%s", method) trace(tracer, "GetSignature: requestUrl=%s", requestUrl) trace(tracer, "GetSignature: body=%s", body) trace(tracer, "GetSignature: privateKey=%s", privateKey) // parse the URL u, parseErr := url.ParseRequestURI(requestUrl) if parseErr != nil { trace(tracer, "GetSignature: FAILED to parse the URL: %s", parseErr) return FailedSignature, parseErr } trace(tracer, "GetSignature: Parsed the URL as: %s", u.String()) // get the query values values := u.Query() // add the private key parameter values.Set(PrivateKeyKey, privateKey) trace(tracer, "GetSignature: Set the private key (%s): %s", PrivateKeyKey, privateKey) if len(body) > 0 { bodyHash := Hash(body) trace(tracer, "GetSignature: Set the body hash (%s): %s", BodyHashKey, bodyHash) values.Set(BodyHashKey, bodyHash) } else { trace(tracer, "GetSignature: Skipping body hash as there's no body (%s).", BodyHashKey) } // get the ordered params orderedParams := OrderParams(values) trace(tracer, "GetSignature: Ordered parameters: %s", orderedParams) base := strings.Split(u.String(), "?")[0] combined := stewstrings.MergeStrings(strings.ToUpper(method), "&", base, "?", orderedParams) trace(tracer, "GetSignature: Base : %s", base) trace(tracer, "GetSignature: Combined: %s", combined) theHash := Hash(combined) trace(tracer, "GetSignature: Output: %s", theHash) return theHash, nil }
// trace writes some trace (if there is a Tracer set). func trace(t *tracer.Tracer, format string, args ...interface{}) { if t.Should(tracer.LevelDebug) { // add the 'signature' prefix to trace if len(format) > 0 { format = stewstrings.MergeStrings("signature: ", format) } // trace this t.Trace(tracer.LevelDebug, format, args...) } }
func (p *PathPattern) String() string { return stewstrings.MergeStrings("{PathPattern:\"", p.RawPath, "\"}") }
// MapController maps a controller to a specified path prefix. // // For more information, see goweb.MapController. func (h *HttpHandler) MapController(options ...interface{}) error { var matcherFuncStartPos int = -1 var path string var controller interface{} if len(options) == 0 { // no arguments is an error panic("goweb: Cannot call MapController with no arguments") } switch options[0].(type) { case string: // (path, controller) if len(options) == 1 { // we need more than just a string panic("goweb: Cannot call MapController without a Controller") } path = options[0].(string) controller = options[1] matcherFuncStartPos = 2 default: // (controller) if restfulController, ok := options[0].(controllers.RestfulController); ok { controller = restfulController path = restfulController.Path() } else { // use the default path controller = options[0] path = paths.PathPrefixForClass(options[0]) } matcherFuncStartPos = 1 } // store the matcher function slice var matcherFuncs []MatcherFunc = findMatcherFuncs(options[matcherFuncStartPos:]...) // get the specialised paths that we might need pathWithID := stewstrings.MergeStrings(path, "/{", RestfulIDParameterName, "}") // e.g. people/123 pathWithOptionalID := stewstrings.MergeStrings(path, "/[", RestfulIDParameterName, "]") // e.g. people/[123] // get the HTTP methods that we will end up mapping collectiveMethods := controllers.OptionsListForResourceCollection(controller) singularMethods := controllers.OptionsListForSingleResource(controller) // BeforeHandler if beforeController, ok := controller.(controllers.BeforeHandler); ok { // map the collective before handler h.MapBefore(collectiveMethods, path, beforeController.Before, matcherFuncs) // map the singular before handler h.MapBefore(singularMethods, pathWithID, beforeController.Before, matcherFuncs) } // AfterHandler if afterController, ok := controller.(controllers.AfterHandler); ok { // map the collective after handler h.MapAfter(collectiveMethods, path, afterController.After, matcherFuncs) // map the singular after handler h.MapAfter(singularMethods, pathWithID, afterController.After, matcherFuncs) } // POST /resource - Create if restfulController, ok := controller.(controllers.RestfulCreator); ok { h.Map(http.MethodPost, path, restfulController.Create, matcherFuncs) } // GET /resource/{id} - Read if restfulController, ok := controller.(controllers.RestfulReader); ok { h.Map(http.MethodGet, pathWithID, func(ctx context.Context) error { return restfulController.Read(ctx.PathParams().Get(RestfulIDParameterName).Str(), ctx) }, matcherFuncs) } // GET /resource - ReadMany if restfulController, ok := controller.(controllers.RestfulManyReader); ok { h.Map(http.MethodGet, path, restfulController.ReadMany, matcherFuncs) } // DELETE /resource/{id} - Delete if restfulController, ok := controller.(controllers.RestfulDeletor); ok { h.Map(http.MethodDelete, pathWithID, func(ctx context.Context) error { return restfulController.Delete(ctx.PathParams().Get(RestfulIDParameterName).Str(), ctx) }, matcherFuncs) } // DELETE /resource - DeleteMany if restfulController, ok := controller.(controllers.RestfulManyDeleter); ok { h.Map(http.MethodDelete, path, restfulController.DeleteMany, matcherFuncs) } // PUT /resource/{id} - Update if restfulController, ok := controller.(controllers.RestfulUpdater); ok { h.Map(http.MethodPut, pathWithID, func(ctx context.Context) error { return restfulController.Update(ctx.PathParams().Get(RestfulIDParameterName).Str(), ctx) }, matcherFuncs) } // PUT /resource - UpdateMany if restfulController, ok := controller.(controllers.RestfulManyUpdater); ok { h.Map(http.MethodPut, path, restfulController.UpdateMany, matcherFuncs) } // POST /resource/{id} - Replace if restfulController, ok := controller.(controllers.RestfulReplacer); ok { h.Map(http.MethodPost, pathWithID, func(ctx context.Context) error { return restfulController.Replace(ctx.PathParams().Get(RestfulIDParameterName).Str(), ctx) }, matcherFuncs) } // HEAD /resource/[id] - Head if restfulController, ok := controller.(controllers.RestfulHead); ok { h.Map(http.MethodHead, pathWithOptionalID, restfulController.Head, matcherFuncs) } // OPTIONS /resource/[id] - Options if restfulController, ok := controller.(controllers.RestfulOptions); ok { h.Map(http.MethodOptions, pathWithOptionalID, restfulController.Options, matcherFuncs) } else { // use the default options implementation h.Map(http.MethodOptions, path, func(ctx context.Context) error { ctx.HttpResponseWriter().Header().Set("Allow", strings.Join(collectiveMethods, ",")) ctx.HttpResponseWriter().WriteHeader(200) return nil }, matcherFuncs) h.Map(http.MethodOptions, pathWithID, func(ctx context.Context) error { ctx.HttpResponseWriter().Header().Set("Allow", strings.Join(singularMethods, ",")) ctx.HttpResponseWriter().WriteHeader(200) return nil }, matcherFuncs) } // everything ok return nil }
// Where adds a filter to the request. func (r *Request) Where(field, match string) *Request { return r.WithParam(stewstrings.MergeStrings(common.FilterFieldPrefix, field), match) }