github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/middleware.go (about) 1 package gateway 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "net/http" 9 "strconv" 10 "sync" 11 "time" 12 13 "github.com/TykTechnologies/tyk/headers" 14 15 "github.com/gocraft/health" 16 "github.com/justinas/alice" 17 newrelic "github.com/newrelic/go-agent" 18 "github.com/paulbellamy/ratecounter" 19 "github.com/pmylund/go-cache" 20 "github.com/sirupsen/logrus" 21 22 "github.com/TykTechnologies/tyk/apidef" 23 "github.com/TykTechnologies/tyk/config" 24 "github.com/TykTechnologies/tyk/request" 25 "github.com/TykTechnologies/tyk/storage" 26 "github.com/TykTechnologies/tyk/trace" 27 "github.com/TykTechnologies/tyk/user" 28 ) 29 30 const mwStatusRespond = 666 31 32 const authTokenType = "authToken" 33 const jwtType = "jwt" 34 const hmacType = "hmac" 35 const basicType = "basic" 36 const coprocessType = "coprocess" 37 const oauthType = "oauth" 38 const oidcType = "oidc" 39 40 var GlobalRate = ratecounter.NewRateCounter(1 * time.Second) 41 42 type TykMiddleware interface { 43 Init() 44 Base() *BaseMiddleware 45 SetName(string) 46 SetRequestLogger(*http.Request) 47 Logger() *logrus.Entry 48 Config() (interface{}, error) 49 ProcessRequest(w http.ResponseWriter, r *http.Request, conf interface{}) (error, int) // Handles request 50 EnabledForSpec() bool 51 Name() string 52 } 53 54 type TraceMiddleware struct { 55 TykMiddleware 56 } 57 58 func (tr TraceMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, conf interface{}) (error, int) { 59 if trace.IsEnabled() { 60 span, ctx := trace.Span(r.Context(), 61 tr.Name(), 62 ) 63 defer span.Finish() 64 setContext(r, ctx) 65 return tr.TykMiddleware.ProcessRequest(w, r, conf) 66 } 67 return tr.TykMiddleware.ProcessRequest(w, r, conf) 68 } 69 70 func createDynamicMiddleware(name string, isPre, useSession bool, baseMid BaseMiddleware) func(http.Handler) http.Handler { 71 dMiddleware := &DynamicMiddleware{ 72 BaseMiddleware: baseMid, 73 MiddlewareClassName: name, 74 Pre: isPre, 75 UseSession: useSession, 76 } 77 78 return createMiddleware(dMiddleware) 79 } 80 81 // Generic middleware caller to make extension easier 82 func createMiddleware(actualMW TykMiddleware) func(http.Handler) http.Handler { 83 mw := &TraceMiddleware{ 84 TykMiddleware: actualMW, 85 } 86 // construct a new instance 87 mw.Init() 88 mw.SetName(mw.Name()) 89 mw.Logger().Debug("Init") 90 91 // Pull the configuration 92 mwConf, err := mw.Config() 93 if err != nil { 94 mw.Logger().Fatal("[Middleware] Configuration load failed") 95 } 96 97 return func(h http.Handler) http.Handler { 98 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 99 mw.SetRequestLogger(r) 100 101 if config.Global().NewRelic.AppName != "" { 102 if txn, ok := w.(newrelic.Transaction); ok { 103 defer newrelic.StartSegment(txn, mw.Name()).End() 104 } 105 } 106 107 job := instrument.NewJob("MiddlewareCall") 108 meta := health.Kvs{} 109 eventName := mw.Name() + "." + "executed" 110 111 if instrumentationEnabled { 112 meta = health.Kvs{ 113 "from_ip": request.RealIP(r), 114 "method": r.Method, 115 "endpoint": r.URL.Path, 116 "raw_url": r.URL.String(), 117 "size": strconv.Itoa(int(r.ContentLength)), 118 "mw_name": mw.Name(), 119 } 120 job.EventKv("executed", meta) 121 job.EventKv(eventName, meta) 122 } 123 124 startTime := time.Now() 125 mw.Logger().WithField("ts", startTime.UnixNano()).Debug("Started") 126 127 if mw.Base().Spec.CORS.OptionsPassthrough && r.Method == "OPTIONS" { 128 h.ServeHTTP(w, r) 129 return 130 } 131 err, errCode := mw.ProcessRequest(w, r, mwConf) 132 if err != nil { 133 // GoPluginMiddleware are expected to send response in case of error 134 // but we still want to record error 135 _, isGoPlugin := actualMW.(*GoPluginMiddleware) 136 137 handler := ErrorHandler{*mw.Base()} 138 handler.HandleError(w, r, err.Error(), errCode, !isGoPlugin) 139 140 meta["error"] = err.Error() 141 142 finishTime := time.Since(startTime) 143 144 if instrumentationEnabled { 145 job.TimingKv("exec_time", finishTime.Nanoseconds(), meta) 146 job.TimingKv(eventName+".exec_time", finishTime.Nanoseconds(), meta) 147 } 148 149 mw.Logger().WithError(err).WithField("code", errCode).WithField("ns", finishTime.Nanoseconds()).Debug("Finished") 150 return 151 } 152 153 finishTime := time.Since(startTime) 154 155 if instrumentationEnabled { 156 job.TimingKv("exec_time", finishTime.Nanoseconds(), meta) 157 job.TimingKv(eventName+".exec_time", finishTime.Nanoseconds(), meta) 158 } 159 160 mw.Logger().WithField("code", errCode).WithField("ns", finishTime.Nanoseconds()).Debug("Finished") 161 162 // Special code, bypasses all other execution 163 if errCode != mwStatusRespond { 164 // No error, carry on... 165 meta["bypass"] = "1" 166 h.ServeHTTP(w, r) 167 } else { 168 mw.Base().UpdateRequestSession(r) 169 } 170 }) 171 } 172 } 173 174 func mwAppendEnabled(chain *[]alice.Constructor, mw TykMiddleware) bool { 175 if mw.EnabledForSpec() { 176 *chain = append(*chain, createMiddleware(mw)) 177 return true 178 } 179 return false 180 } 181 182 func mwList(mws ...TykMiddleware) []alice.Constructor { 183 var list []alice.Constructor 184 for _, mw := range mws { 185 mwAppendEnabled(&list, mw) 186 } 187 return list 188 } 189 190 // BaseMiddleware wraps up the ApiSpec and Proxy objects to be included in a 191 // middleware handler, this can probably be handled better. 192 type BaseMiddleware struct { 193 Spec *APISpec 194 Proxy ReturningHttpHandler 195 logger *logrus.Entry 196 } 197 198 func (t BaseMiddleware) Base() *BaseMiddleware { return &t } 199 200 func (t BaseMiddleware) Logger() (logger *logrus.Entry) { 201 if t.logger == nil { 202 t.logger = logrus.NewEntry(log) 203 } 204 205 return t.logger 206 } 207 208 func (t *BaseMiddleware) SetName(name string) { 209 t.logger = t.Logger().WithField("mw", name) 210 } 211 212 func (t *BaseMiddleware) SetRequestLogger(r *http.Request) { 213 t.logger = getLogEntryForRequest(t.Logger(), r, ctxGetAuthToken(r), nil) 214 } 215 216 func (t BaseMiddleware) Init() {} 217 func (t BaseMiddleware) EnabledForSpec() bool { 218 return true 219 } 220 func (t BaseMiddleware) Config() (interface{}, error) { 221 return nil, nil 222 } 223 224 func (t BaseMiddleware) OrgSession(key string) (user.SessionState, bool) { 225 // Try and get the session from the session store 226 session, found := t.Spec.OrgSessionManager.SessionDetail(key, false) 227 if found && t.Spec.GlobalConfig.EnforceOrgDataAge { 228 // If exists, assume it has been authorized and pass on 229 // We cache org expiry data 230 t.Logger().Debug("Setting data expiry: ", session.OrgID) 231 go t.SetOrgExpiry(session.OrgID, session.DataExpires) 232 } 233 234 session.SetKeyHash(storage.HashKey(key)) 235 return session, found 236 } 237 238 func (t BaseMiddleware) SetOrgExpiry(orgid string, expiry int64) { 239 ExpiryCache.Set(orgid, expiry, cache.DefaultExpiration) 240 } 241 242 func (t BaseMiddleware) OrgSessionExpiry(orgid string) int64 { 243 t.Logger().Debug("Checking: ", orgid) 244 cachedVal, found := ExpiryCache.Get(orgid) 245 if !found { 246 // Cache failed attempt 247 t.SetOrgExpiry(orgid, 604800) 248 go t.OrgSession(orgid) 249 t.Logger().Debug("no cached entry found, returning 7 days") 250 return 604800 251 } 252 253 return cachedVal.(int64) 254 } 255 256 func (t BaseMiddleware) UpdateRequestSession(r *http.Request) bool { 257 session := ctxGetSession(r) 258 token := ctxGetAuthToken(r) 259 260 if session == nil || token == "" { 261 return false 262 } 263 264 if !ctxSessionUpdateScheduled(r) { 265 return false 266 } 267 268 lifetime := session.Lifetime(t.Spec.SessionLifetime) 269 if err := t.Spec.SessionManager.UpdateSession(token, session, lifetime, false); err != nil { 270 t.Logger().WithError(err).Error("Can't update session") 271 return false 272 } 273 274 // Set context state back 275 // Useful for benchmarks when request object stays same 276 ctxDisableSessionUpdate(r) 277 278 if !t.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState { 279 SessionCache.Set(session.GetKeyHash(), *session, cache.DefaultExpiration) 280 } 281 282 return true 283 } 284 285 // ApplyPolicies will check if any policies are loaded. If any are, it 286 // will overwrite the session state to use the policy values. 287 func (t BaseMiddleware) ApplyPolicies(session *user.SessionState) error { 288 rights := make(map[string]user.AccessDefinition) 289 tags := make(map[string]bool) 290 if session.GetMetaData() == nil { 291 session.SetMetaData(make(map[string]interface{})) 292 } 293 294 didQuota, didRateLimit, didACL := make(map[string]bool), make(map[string]bool), make(map[string]bool) 295 policies := session.GetPolicyIDs() 296 297 for _, polID := range policies { 298 policiesMu.RLock() 299 policy, ok := policiesByID[polID] 300 policiesMu.RUnlock() 301 if !ok { 302 err := fmt.Errorf("policy not found: %q", polID) 303 t.Logger().Error(err) 304 return err 305 } 306 // Check ownership, policy org owner must be the same as API, 307 // otherwise youcould overwrite a session key with a policy from a different org! 308 if t.Spec != nil && policy.OrgID != t.Spec.OrgID { 309 err := fmt.Errorf("attempting to apply policy from different organisation to key, skipping") 310 t.Logger().Error(err) 311 return err 312 } 313 314 if policy.Partitions.PerAPI && 315 (policy.Partitions.Quota || policy.Partitions.RateLimit || policy.Partitions.Acl) { 316 err := fmt.Errorf("cannot apply policy %s which has per_api and any of partitions set", policy.ID) 317 log.Error(err) 318 return err 319 } 320 321 if policy.Partitions.PerAPI { 322 for apiID, accessRights := range policy.AccessRights { 323 // new logic when you can specify quota or rate in more than one policy but for different APIs 324 if didQuota[apiID] || didRateLimit[apiID] || didACL[apiID] { // no other partitions allowed 325 err := fmt.Errorf("cannot apply multiple policies when some have per_api set and some are partitioned") 326 log.Error(err) 327 return err 328 } 329 330 // check if we already have limit on API level specified when policy was created 331 if accessRights.Limit == nil || *accessRights.Limit == (user.APILimit{}) { 332 // limit was not specified on API level so we will populate it from policy 333 accessRights.Limit = &user.APILimit{ 334 QuotaMax: policy.QuotaMax, 335 QuotaRenewalRate: policy.QuotaRenewalRate, 336 Rate: policy.Rate, 337 Per: policy.Per, 338 ThrottleInterval: policy.ThrottleInterval, 339 ThrottleRetryLimit: policy.ThrottleRetryLimit, 340 } 341 } 342 343 // respect current quota renews (on API limit level) 344 if r, ok := session.GetAccessRightByAPIID(apiID); ok && r.Limit != nil { 345 accessRights.Limit.QuotaRenews = r.Limit.QuotaRenews 346 } 347 348 accessRights.AllowanceScope = apiID 349 accessRights.Limit.SetBy = apiID 350 351 // overwrite session access right for this API 352 rights[apiID] = accessRights 353 354 // identify that limit for that API is set (to allow set it only once) 355 didACL[apiID] = true 356 didQuota[apiID] = true 357 didRateLimit[apiID] = true 358 } 359 } else { 360 usePartitions := policy.Partitions.Quota || policy.Partitions.RateLimit || policy.Partitions.Acl 361 362 for k, v := range policy.AccessRights { 363 ar := &v 364 365 if v.Limit == nil { 366 v.Limit = &user.APILimit{} 367 } 368 369 if !usePartitions || policy.Partitions.Acl { 370 didACL[k] = true 371 372 // Merge ACLs for the same API 373 if r, ok := rights[k]; ok { 374 r.Versions = appendIfMissing(rights[k].Versions, v.Versions...) 375 376 for _, u := range v.AllowedURLs { 377 found := false 378 for ai, au := range r.AllowedURLs { 379 if u.URL == au.URL { 380 found = true 381 r.AllowedURLs[ai].Methods = append(au.Methods, u.Methods...) 382 } 383 } 384 385 if !found { 386 r.AllowedURLs = append(r.AllowedURLs, v.AllowedURLs...) 387 } 388 } 389 390 ar = &r 391 } 392 393 ar.Limit.SetBy = policy.ID 394 } 395 396 if !usePartitions || policy.Partitions.Quota { 397 didQuota[k] = true 398 399 // -1 is special "unlimited" case 400 if ar.Limit.QuotaMax != -1 && policy.QuotaMax > ar.Limit.QuotaMax { 401 ar.Limit.QuotaMax = policy.QuotaMax 402 } 403 404 if policy.QuotaRenewalRate > ar.Limit.QuotaRenewalRate { 405 ar.Limit.QuotaRenewalRate = policy.QuotaRenewalRate 406 session.QuotaRenewalRate = policy.QuotaRenewalRate 407 } 408 } 409 410 if !usePartitions || policy.Partitions.RateLimit { 411 didRateLimit[k] = true 412 413 if ar.Limit.Rate != -1 && policy.Rate > ar.Limit.Rate { 414 ar.Limit.Rate = policy.Rate 415 session.Rate = policy.Rate 416 } 417 418 if policy.Per > ar.Limit.Per { 419 ar.Limit.Per = policy.Per 420 session.Per = policy.Per 421 } 422 423 if policy.ThrottleInterval > ar.Limit.ThrottleInterval { 424 ar.Limit.ThrottleInterval = policy.ThrottleInterval 425 } 426 427 if policy.ThrottleRetryLimit > ar.Limit.ThrottleRetryLimit { 428 ar.Limit.ThrottleRetryLimit = policy.ThrottleRetryLimit 429 } 430 } 431 432 // Respect existing QuotaRenews 433 if r, ok := session.GetAccessRightByAPIID(k); ok && r.Limit != nil { 434 ar.Limit.QuotaRenews = r.Limit.QuotaRenews 435 } 436 437 rights[k] = *ar 438 } 439 440 // Master policy case 441 if len(policy.AccessRights) == 0 { 442 if !usePartitions || policy.Partitions.RateLimit { 443 session.Rate = policy.Rate 444 session.Per = policy.Per 445 session.ThrottleInterval = policy.ThrottleInterval 446 session.ThrottleRetryLimit = policy.ThrottleRetryLimit 447 } 448 449 if !usePartitions || policy.Partitions.Quota { 450 session.QuotaMax = policy.QuotaMax 451 session.QuotaRenewalRate = policy.QuotaRenewalRate 452 } 453 } 454 455 if !session.HMACEnabled { 456 session.HMACEnabled = policy.HMACEnabled 457 } 458 459 if !session.EnableHTTPSignatureValidation { 460 session.EnableHTTPSignatureValidation = policy.EnableHTTPSignatureValidation 461 } 462 } 463 464 session.IsInactive = session.IsInactive || policy.IsInactive 465 466 for _, tag := range policy.Tags { 467 tags[tag] = true 468 } 469 470 for k, v := range policy.MetaData { 471 session.SetMetaDataKey(k, v) 472 } 473 474 if policy.LastUpdated > session.LastUpdated { 475 session.LastUpdated = policy.LastUpdated 476 } 477 } 478 479 for _, tag := range session.Tags { 480 tags[tag] = true 481 } 482 483 // set tags 484 session.Tags = []string{} 485 for tag := range tags { 486 session.Tags = append(session.Tags, tag) 487 } 488 489 distinctACL := map[string]bool{} 490 for _, v := range rights { 491 if v.Limit.SetBy != "" { 492 distinctACL[v.Limit.SetBy] = true 493 } 494 } 495 496 // If some APIs had only ACL partitions, inherit rest from session level 497 for k, v := range rights { 498 if !didRateLimit[k] { 499 v.Limit.Rate = session.Rate 500 v.Limit.Per = session.Per 501 v.Limit.ThrottleInterval = session.ThrottleInterval 502 v.Limit.ThrottleRetryLimit = session.ThrottleRetryLimit 503 } 504 505 if !didQuota[k] { 506 v.Limit.QuotaMax = session.QuotaMax 507 v.Limit.QuotaRenewalRate = session.QuotaRenewalRate 508 v.Limit.QuotaRenews = session.QuotaRenews 509 } 510 511 // If multime ACL 512 if len(distinctACL) > 1 { 513 if v.AllowanceScope == "" && v.Limit.SetBy != "" { 514 v.AllowanceScope = v.Limit.SetBy 515 } 516 } 517 518 v.Limit.SetBy = "" 519 520 rights[k] = v 521 } 522 523 // If we have policies defining rules for one single API, update session root vars (legacy) 524 if len(didQuota) == 1 && len(didRateLimit) == 1 { 525 for _, v := range rights { 526 if len(didRateLimit) == 1 { 527 session.Rate = v.Limit.Rate 528 session.Per = v.Limit.Per 529 } 530 531 if len(didQuota) == 1 { 532 session.QuotaMax = v.Limit.QuotaMax 533 session.QuotaRenews = v.Limit.QuotaRenews 534 session.QuotaRenewalRate = v.Limit.QuotaRenewalRate 535 } 536 } 537 } 538 539 // Override session ACL if at least one policy define it 540 if len(didACL) > 0 { 541 session.SetAccessRights(rights) 542 } 543 544 return nil 545 } 546 547 // CheckSessionAndIdentityForValidKey will check first the Session store for a valid key, if not found, it will try 548 // the Auth Handler, if not found it will fail 549 func (t BaseMiddleware) CheckSessionAndIdentityForValidKey(originalKey *string, r *http.Request) (user.SessionState, bool) { 550 key := *originalKey 551 minLength := t.Spec.GlobalConfig.MinTokenLength 552 if minLength == 0 { 553 // See https://github.com/TykTechnologies/tyk/issues/1681 554 minLength = 3 555 } 556 557 if len(key) <= minLength { 558 return user.SessionState{IsInactive: true, Mutex: &sync.RWMutex{}}, false 559 } 560 561 // Try and get the session from the session store 562 t.Logger().Debug("Querying local cache") 563 keyHash := key 564 cacheKey := key 565 if t.Spec.GlobalConfig.HashKeys { 566 keyHash = storage.HashStr(key) 567 cacheKey = storage.HashStr(key, storage.HashMurmur64) // always hash cache keys with murmur64 to prevent collisions 568 } 569 570 // Check in-memory cache 571 if !t.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState { 572 cachedVal, found := SessionCache.Get(cacheKey) 573 if found { 574 t.Logger().Debug("--> Key found in local cache") 575 session := cachedVal.(user.SessionState) 576 if err := t.ApplyPolicies(&session); err != nil { 577 t.Logger().Error(err) 578 return session, false 579 } 580 return session, true 581 } 582 } 583 584 // Check session store 585 t.Logger().Debug("Querying keystore") 586 session, found := t.Spec.SessionManager.SessionDetail(key, false) 587 if found { 588 session.SetKeyHash(keyHash) 589 // If exists, assume it has been authorized and pass on 590 // cache it 591 if !t.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState { 592 go SessionCache.Set(cacheKey, session, cache.DefaultExpiration) 593 } 594 595 // Check for a policy, if there is a policy, pull it and overwrite the session values 596 if err := t.ApplyPolicies(&session); err != nil { 597 t.Logger().Error(err) 598 return session, false 599 } 600 t.Logger().Debug("Got key") 601 return session, true 602 } 603 604 t.Logger().Debug("Querying authstore") 605 // 2. If not there, get it from the AuthorizationHandler 606 session, found = t.Spec.AuthManager.SessionDetail(key, false) 607 if found { 608 // update value of originalKey, as for custom-keys it might get updated (the key is generated again using alias) 609 *originalKey = key 610 611 session.SetKeyHash(keyHash) 612 // If not in Session, and got it from AuthHandler, create a session with a new TTL 613 t.Logger().Info("Recreating session for key: ", obfuscateKey(key)) 614 615 // cache it 616 if !t.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState { 617 go SessionCache.Set(cacheKey, session, cache.DefaultExpiration) 618 } 619 620 // Check for a policy, if there is a policy, pull it and overwrite the session values 621 if err := t.ApplyPolicies(&session); err != nil { 622 t.Logger().Error(err) 623 return session, false 624 } 625 626 t.Logger().Debug("Lifetime is: ", session.Lifetime(t.Spec.SessionLifetime)) 627 ctxScheduleSessionUpdate(r) 628 } 629 630 return session, found 631 } 632 633 // FireEvent is added to the BaseMiddleware object so it is available across the entire stack 634 func (t BaseMiddleware) FireEvent(name apidef.TykEvent, meta interface{}) { 635 fireEvent(name, meta, t.Spec.EventPaths) 636 } 637 638 func (b BaseMiddleware) getAuthType() string { 639 return "" 640 } 641 642 func (b BaseMiddleware) getAuthToken(authType string, r *http.Request) (string, apidef.AuthConfig) { 643 config, ok := b.Base().Spec.AuthConfigs[authType] 644 // Auth is deprecated. To maintain backward compatibility authToken and jwt cases are added. 645 if !ok && (authType == authTokenType || authType == jwtType) { 646 config = b.Base().Spec.Auth 647 } 648 649 if config.AuthHeaderName == "" { 650 config.AuthHeaderName = headers.Authorization 651 } 652 653 key := r.Header.Get(config.AuthHeaderName) 654 655 paramName := config.ParamName 656 if config.UseParam || paramName != "" { 657 if paramName == "" { 658 paramName = config.AuthHeaderName 659 } 660 661 paramValue := r.URL.Query().Get(paramName) 662 663 // Only use the paramValue if it has an actual value 664 if paramValue != "" { 665 key = paramValue 666 } 667 } 668 669 cookieName := config.CookieName 670 if config.UseCookie || cookieName != "" { 671 if cookieName == "" { 672 cookieName = config.AuthHeaderName 673 } 674 675 authCookie, err := r.Cookie(cookieName) 676 cookieValue := "" 677 if err == nil { 678 cookieValue = authCookie.Value 679 } 680 681 if cookieValue != "" { 682 key = cookieValue 683 } 684 } 685 686 return key, config 687 } 688 689 type TykResponseHandler interface { 690 Init(interface{}, *APISpec) error 691 Name() string 692 HandleResponse(http.ResponseWriter, *http.Response, *http.Request, *user.SessionState) error 693 } 694 695 func responseProcessorByName(name string) TykResponseHandler { 696 switch name { 697 case "header_injector": 698 return &HeaderInjector{} 699 case "response_body_transform": 700 return &ResponseTransformMiddleware{} 701 case "response_body_transform_jq": 702 return &ResponseTransformJQMiddleware{} 703 case "header_transform": 704 return &HeaderTransform{} 705 } 706 return nil 707 } 708 709 func handleResponseChain(chain []TykResponseHandler, rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState) error { 710 traceIsEnabled := trace.IsEnabled() 711 for _, rh := range chain { 712 if err := handleResponse(rh, rw, res, req, ses, traceIsEnabled); err != nil { 713 return err 714 } 715 } 716 return nil 717 } 718 719 func handleResponse(rh TykResponseHandler, rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState, shouldTrace bool) error { 720 if shouldTrace { 721 span, ctx := trace.Span(req.Context(), rh.Name()) 722 defer span.Finish() 723 req = req.WithContext(ctx) 724 } 725 return rh.HandleResponse(rw, res, req, ses) 726 } 727 728 func parseForm(r *http.Request) { 729 // https://golang.org/pkg/net/http/#Request.ParseForm 730 // ParseForm drains the request body for a request with Content-Type of 731 // application/x-www-form-urlencoded 732 if r.Header.Get("Content-Type") == "application/x-www-form-urlencoded" && r.Form == nil { 733 var b bytes.Buffer 734 r.Body = ioutil.NopCloser(io.TeeReader(r.Body, &b)) 735 736 r.ParseForm() 737 738 r.Body = ioutil.NopCloser(&b) 739 return 740 } 741 742 r.ParseForm() 743 }