github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/mw_js_plugin.go (about)

     1  package gateway
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/tls"
     6  	"encoding/base64"
     7  	"encoding/json"
     8  	"errors"
     9  	"io/ioutil"
    10  	"net/http"
    11  	"net/url"
    12  	"os"
    13  	"path/filepath"
    14  	"reflect"
    15  	"strings"
    16  	"sync"
    17  	"time"
    18  
    19  	"github.com/robertkrimen/otto"
    20  	_ "github.com/robertkrimen/otto/underscore"
    21  
    22  	"github.com/TykTechnologies/tyk/config"
    23  	"github.com/TykTechnologies/tyk/user"
    24  
    25  	"github.com/sirupsen/logrus"
    26  )
    27  
    28  // Lets the user override and return a response from middleware
    29  type ReturnOverrides struct {
    30  	ResponseCode    int
    31  	ResponseError   string
    32  	ResponseBody    string
    33  	ResponseHeaders map[string]string
    34  	OverrideError   bool
    35  }
    36  
    37  // MiniRequestObject is marshalled to JSON string and passed into JSON middleware
    38  type MiniRequestObject struct {
    39  	Headers         map[string][]string
    40  	SetHeaders      map[string]string
    41  	DeleteHeaders   []string
    42  	Body            []byte
    43  	URL             string
    44  	Params          map[string][]string
    45  	AddParams       map[string]string
    46  	ExtendedParams  map[string][]string
    47  	DeleteParams    []string
    48  	ReturnOverrides ReturnOverrides
    49  	IgnoreBody      bool
    50  	Method          string
    51  	RequestURI      string
    52  	Scheme          string
    53  }
    54  
    55  func (mr *MiniRequestObject) ReconstructParams(r *http.Request) {
    56  	updatedValues := r.URL.Query()
    57  
    58  	for _, k := range mr.DeleteParams {
    59  		updatedValues.Del(k)
    60  	}
    61  
    62  	for p, v := range mr.AddParams {
    63  		updatedValues.Set(p, v)
    64  	}
    65  
    66  	for p, v := range mr.ExtendedParams {
    67  		for _, val := range v {
    68  			updatedValues.Add(p, val)
    69  		}
    70  	}
    71  
    72  	if !reflect.DeepEqual(r.URL.Query(), updatedValues) {
    73  		r.URL.RawQuery = updatedValues.Encode()
    74  	}
    75  }
    76  
    77  type VMReturnObject struct {
    78  	Request     MiniRequestObject
    79  	SessionMeta map[string]string
    80  	Session     user.SessionState
    81  	AuthValue   string
    82  }
    83  
    84  // DynamicMiddleware is a generic middleware that will execute JS code before continuing
    85  type DynamicMiddleware struct {
    86  	BaseMiddleware
    87  	MiddlewareClassName string
    88  	Pre                 bool
    89  	UseSession          bool
    90  	Auth                bool
    91  }
    92  
    93  func (d *DynamicMiddleware) Name() string {
    94  	return "DynamicMiddleware"
    95  }
    96  
    97  func specToJson(spec *APISpec) string {
    98  	m := map[string]interface{}{
    99  		"OrgID": spec.OrgID,
   100  		"APIID": spec.APIID,
   101  		// For backwards compatibility within 2.x.
   102  		// TODO: simplify or refactor in 3.x or later.
   103  		"config_data": spec.ConfigData,
   104  	}
   105  	bs, err := json.Marshal(m)
   106  	if err != nil {
   107  		log.Error("Failed to encode configuration data: ", err)
   108  		return ""
   109  	}
   110  	return string(bs)
   111  }
   112  
   113  // ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
   114  func (d *DynamicMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
   115  	t1 := time.Now().UnixNano()
   116  	logger := d.Logger()
   117  
   118  	// Create the proxy object
   119  	originalBody, err := ioutil.ReadAll(r.Body)
   120  	if err != nil {
   121  		logger.WithError(err).Error("Failed to read request body")
   122  		return nil, http.StatusOK
   123  	}
   124  	defer r.Body.Close()
   125  
   126  	headers := r.Header
   127  	host := r.Host
   128  	if host == "" && r.URL != nil {
   129  		host = r.URL.Host
   130  	}
   131  	if host != "" {
   132  		headers = make(http.Header)
   133  		for k, v := range r.Header {
   134  			headers[k] = v
   135  		}
   136  		headers.Set("Host", host)
   137  	}
   138  	scheme := "http"
   139  	if r.TLS != nil {
   140  		scheme = "https"
   141  	}
   142  
   143  	requestData := MiniRequestObject{
   144  		Headers:        headers,
   145  		SetHeaders:     map[string]string{},
   146  		DeleteHeaders:  []string{},
   147  		Body:           originalBody,
   148  		URL:            r.URL.String(),
   149  		Params:         r.URL.Query(),
   150  		AddParams:      map[string]string{},
   151  		ExtendedParams: map[string][]string{},
   152  		DeleteParams:   []string{},
   153  		Method:         r.Method,
   154  		RequestURI:     r.RequestURI,
   155  		Scheme:         scheme,
   156  	}
   157  
   158  	requestAsJson, err := json.Marshal(requestData)
   159  	if err != nil {
   160  		logger.WithError(err).Error("Failed to encode request object for dynamic middleware")
   161  		return nil, http.StatusOK
   162  	}
   163  
   164  	specAsJson := specToJson(d.Spec)
   165  
   166  	session := new(user.SessionState)
   167  	session.Mutex = &sync.RWMutex{}
   168  	// Encode the session object (if not a pre-process)
   169  	if !d.Pre && d.UseSession {
   170  		session = ctxGetSession(r)
   171  	}
   172  
   173  	sessionAsJson, err := json.Marshal(session)
   174  	if err != nil {
   175  		logger.WithError(err).Error("Failed to encode session for VM")
   176  		return nil, http.StatusOK
   177  	}
   178  
   179  	// Run the middleware
   180  	middlewareClassname := d.MiddlewareClassName
   181  	vm := d.Spec.JSVM.VM.Copy()
   182  	vm.Interrupt = make(chan func(), 1)
   183  	logger.Debug("Running: ", middlewareClassname)
   184  	// buffered, leaving no chance of a goroutine leak since the
   185  	// spawned goroutine will send 0 or 1 values.
   186  	ret := make(chan otto.Value, 1)
   187  	errRet := make(chan error, 1)
   188  	go func() {
   189  		defer func() {
   190  			// the VM executes the panic func that gets it
   191  			// to stop, so we must recover here to not crash
   192  			// the whole Go program.
   193  			recover()
   194  		}()
   195  		returnRaw, err := vm.Run(middlewareClassname + `.DoProcessRequest(` + string(requestAsJson) + `, ` + string(sessionAsJson) + `, ` + specAsJson + `);`)
   196  		ret <- returnRaw
   197  		errRet <- err
   198  	}()
   199  	var returnRaw otto.Value
   200  	t := time.NewTimer(d.Spec.JSVM.Timeout)
   201  	select {
   202  	case returnRaw = <-ret:
   203  		if err := <-errRet; err != nil {
   204  			logger.WithError(err).Error("Failed to run JS middleware")
   205  			return nil, http.StatusOK
   206  		}
   207  		t.Stop()
   208  	case <-t.C:
   209  		t.Stop()
   210  		logger.Error("JS middleware timed out after ", d.Spec.JSVM.Timeout)
   211  		vm.Interrupt <- func() {
   212  			// only way to stop the VM is to send it a func
   213  			// that panics.
   214  			panic("stop")
   215  		}
   216  		return nil, http.StatusOK
   217  	}
   218  	returnDataStr, _ := returnRaw.ToString()
   219  
   220  	// Decode the return object
   221  	newRequestData := VMReturnObject{}
   222  	if err := json.Unmarshal([]byte(returnDataStr), &newRequestData); err != nil {
   223  		logger.WithError(err).Error("Failed to decode middleware request data on return from VM. Returned data: ", returnDataStr)
   224  		return nil, http.StatusOK
   225  	}
   226  
   227  	// Reconstruct the request parts
   228  	if newRequestData.Request.IgnoreBody {
   229  		r.ContentLength = int64(len(originalBody))
   230  		r.Body = ioutil.NopCloser(bytes.NewReader(originalBody))
   231  	} else {
   232  		r.ContentLength = int64(len(newRequestData.Request.Body))
   233  		r.Body = ioutil.NopCloser(bytes.NewReader(newRequestData.Request.Body))
   234  	}
   235  
   236  	r.URL, err = url.Parse(newRequestData.Request.URL)
   237  	if err != nil {
   238  		return nil, http.StatusOK
   239  	}
   240  
   241  	// Delete and set headers
   242  	for _, dh := range newRequestData.Request.DeleteHeaders {
   243  		r.Header.Del(dh)
   244  	}
   245  
   246  	for h, v := range newRequestData.Request.SetHeaders {
   247  		r.Header.Set(h, v)
   248  	}
   249  
   250  	// Delete and set request parameters
   251  	newRequestData.Request.ReconstructParams(r)
   252  
   253  	// Save the session data (if modified)
   254  	if !d.Pre && d.UseSession {
   255  		newMeta := mapStrsToIfaces(newRequestData.SessionMeta)
   256  		if !reflect.DeepEqual(session.GetMetaData(), newMeta) {
   257  			session.SetMetaData(newMeta)
   258  			ctxScheduleSessionUpdate(r)
   259  		}
   260  	}
   261  
   262  	logger.Debug("JSVM middleware execution took: (ns) ", time.Now().UnixNano()-t1)
   263  
   264  	if newRequestData.Request.ReturnOverrides.ResponseError != "" {
   265  		newRequestData.Request.ReturnOverrides.ResponseBody = newRequestData.Request.ReturnOverrides.ResponseError
   266  	}
   267  
   268  	if newRequestData.Request.ReturnOverrides.ResponseCode >= http.StatusBadRequest && !newRequestData.Request.ReturnOverrides.OverrideError {
   269  
   270  		for header, value := range newRequestData.Request.ReturnOverrides.ResponseHeaders {
   271  			w.Header().Set(header, value)
   272  		}
   273  
   274  		return errors.New(newRequestData.Request.ReturnOverrides.ResponseBody), newRequestData.Request.ReturnOverrides.ResponseCode
   275  	}
   276  
   277  	if newRequestData.Request.ReturnOverrides.ResponseCode != 0 {
   278  		responseObject := VMResponseObject{
   279  			Response: ResponseObject{
   280  				Body:    newRequestData.Request.ReturnOverrides.ResponseBody,
   281  				Code:    newRequestData.Request.ReturnOverrides.ResponseCode,
   282  				Headers: newRequestData.Request.ReturnOverrides.ResponseHeaders,
   283  			},
   284  		}
   285  
   286  		forceResponse(w, r, &responseObject, d.Spec, session, d.Pre, logger)
   287  		return nil, mwStatusRespond
   288  	}
   289  
   290  	if d.Auth {
   291  		ctxSetSession(r, &newRequestData.Session, newRequestData.AuthValue, true)
   292  	}
   293  
   294  	return nil, http.StatusOK
   295  }
   296  
   297  func mapStrsToIfaces(m map[string]string) map[string]interface{} {
   298  	// TODO: do we really need this conversion? note that we can't
   299  	// make user.SessionState.MetaData a map[string]string, however.
   300  	m2 := make(map[string]interface{}, len(m))
   301  	for k, v := range m {
   302  		m2[k] = v
   303  	}
   304  	return m2
   305  }
   306  
   307  // --- Utility functions during startup to ensure a sane VM is present for each API Def ----
   308  
   309  type JSVM struct {
   310  	Spec    *APISpec
   311  	VM      *otto.Otto
   312  	Timeout time.Duration
   313  	Log     *logrus.Entry  // logger used by the JS code
   314  	RawLog  *logrus.Logger // logger used by `rawlog` func to avoid formatting
   315  }
   316  
   317  const defaultJSVMTimeout = 5
   318  
   319  // Init creates the JSVM with the core library and sets up a default
   320  // timeout.
   321  func (j *JSVM) Init(spec *APISpec, logger *logrus.Entry) {
   322  	vm := otto.New()
   323  	logger = logger.WithField("prefix", "jsvm")
   324  
   325  	// Init TykJS namespace, constructors etc.
   326  	if _, err := vm.Run(coreJS); err != nil {
   327  		logger.WithError(err).Error("Could not load TykJS")
   328  		return
   329  	}
   330  
   331  	// Load user's TykJS on top, if any
   332  	if path := config.Global().TykJSPath; path != "" {
   333  		f, err := os.Open(path)
   334  		if err == nil {
   335  			_, err = vm.Run(f)
   336  			f.Close()
   337  
   338  			if err != nil {
   339  				logger.WithError(err).Error("Could not load user's TykJS")
   340  			}
   341  		}
   342  	}
   343  
   344  	j.VM = vm
   345  	j.Spec = spec
   346  
   347  	// Add environment API
   348  	j.LoadTykJSApi()
   349  
   350  	if jsvmTimeout := config.Global().JSVMTimeout; jsvmTimeout <= 0 {
   351  		j.Timeout = time.Duration(defaultJSVMTimeout) * time.Second
   352  		logger.Debugf("Default JSVM timeout used: %v", j.Timeout)
   353  	} else {
   354  		j.Timeout = time.Duration(jsvmTimeout) * time.Second
   355  		logger.Debugf("Custom JSVM timeout: %v", j.Timeout)
   356  	}
   357  
   358  	j.Log = logger // use the global logger by default
   359  	j.RawLog = rawLog
   360  }
   361  
   362  // LoadJSPaths will load JS classes and functionality in to the VM by file
   363  func (j *JSVM) LoadJSPaths(paths []string, prefix string) {
   364  	for _, mwPath := range paths {
   365  		if prefix != "" {
   366  			mwPath = filepath.Join(prefix, mwPath)
   367  		}
   368  		j.Log.Info("Loading JS File: ", mwPath)
   369  		f, err := os.Open(mwPath)
   370  		if err != nil {
   371  			j.Log.WithError(err).Error("Failed to open JS middleware file")
   372  			continue
   373  		}
   374  		if _, err := j.VM.Run(f); err != nil {
   375  			j.Log.WithError(err).Error("Failed to load JS middleware")
   376  		}
   377  		f.Close()
   378  	}
   379  }
   380  
   381  type TykJSHttpRequest struct {
   382  	Method   string
   383  	Body     string
   384  	Headers  map[string]string
   385  	Domain   string
   386  	Resource string
   387  	FormData map[string]string
   388  }
   389  
   390  type TykJSHttpResponse struct {
   391  	Code    int
   392  	Body    string
   393  	Headers map[string][]string
   394  
   395  	// Make this compatible with BatchReplyUnit
   396  	CodeComp    int                 `json:"code"`
   397  	BodyComp    string              `json:"body"`
   398  	HeadersComp map[string][]string `json:"headers"`
   399  }
   400  
   401  func (j *JSVM) LoadTykJSApi() {
   402  	// Enable a log
   403  	j.VM.Set("log", func(call otto.FunctionCall) otto.Value {
   404  		j.Log.WithFields(logrus.Fields{
   405  			"type": "log-msg",
   406  		}).Info(call.Argument(0).String())
   407  		return otto.Value{}
   408  	})
   409  	j.VM.Set("rawlog", func(call otto.FunctionCall) otto.Value {
   410  		j.RawLog.Print(call.Argument(0).String() + "\n")
   411  		return otto.Value{}
   412  	})
   413  
   414  	// these two needed for non-utf8 bodies
   415  	j.VM.Set("b64dec", func(call otto.FunctionCall) otto.Value {
   416  		in := call.Argument(0).String()
   417  		out, err := base64.StdEncoding.DecodeString(in)
   418  
   419  		// Fallback to RawStdEncoding:
   420  		if err != nil {
   421  			out, err = base64.RawStdEncoding.DecodeString(in)
   422  			if err != nil {
   423  				j.Log.WithError(err).Error("Failed to base64 decode")
   424  				return otto.Value{}
   425  			}
   426  		}
   427  		returnVal, err := j.VM.ToValue(string(out))
   428  		if err != nil {
   429  			j.Log.WithError(err).Error("Failed to base64 decode")
   430  			return otto.Value{}
   431  		}
   432  		return returnVal
   433  	})
   434  	j.VM.Set("b64enc", func(call otto.FunctionCall) otto.Value {
   435  		in := []byte(call.Argument(0).String())
   436  		out := base64.StdEncoding.EncodeToString(in)
   437  		returnVal, err := j.VM.ToValue(out)
   438  		if err != nil {
   439  			j.Log.WithError(err).Error("Failed to base64 encode")
   440  			return otto.Value{}
   441  		}
   442  		return returnVal
   443  	})
   444  
   445  	j.VM.Set("rawb64dec", func(call otto.FunctionCall) otto.Value {
   446  		in := call.Argument(0).String()
   447  		out, err := base64.RawStdEncoding.DecodeString(in)
   448  		if err != nil {
   449  			if err != nil {
   450  				j.Log.WithError(err).Error("Failed to base64 decode")
   451  				return otto.Value{}
   452  			}
   453  		}
   454  		returnVal, err := j.VM.ToValue(string(out))
   455  		if err != nil {
   456  			j.Log.WithError(err).Error("Failed to base64 decode")
   457  			return otto.Value{}
   458  		}
   459  		return returnVal
   460  	})
   461  	j.VM.Set("rawb64enc", func(call otto.FunctionCall) otto.Value {
   462  		in := []byte(call.Argument(0).String())
   463  		out := base64.RawStdEncoding.EncodeToString(in)
   464  		returnVal, err := j.VM.ToValue(out)
   465  		if err != nil {
   466  			j.Log.WithError(err).Error("Failed to base64 encode")
   467  			return otto.Value{}
   468  		}
   469  		return returnVal
   470  	})
   471  
   472  	// Enable the creation of HTTP Requsts
   473  	j.VM.Set("TykMakeHttpRequest", func(call otto.FunctionCall) otto.Value {
   474  		jsonHRO := call.Argument(0).String()
   475  		if jsonHRO == "undefined" {
   476  			// Nope, return nothing
   477  			return otto.Value{}
   478  		}
   479  		hro := TykJSHttpRequest{}
   480  		if err := json.Unmarshal([]byte(jsonHRO), &hro); err != nil {
   481  			j.Log.WithError(err).Error("JSVM: Failed to deserialise HTTP Request object")
   482  			return otto.Value{}
   483  		}
   484  
   485  		// Make the request
   486  		domain := hro.Domain
   487  		data := url.Values{}
   488  		for k, v := range hro.FormData {
   489  			data.Set(k, v)
   490  		}
   491  
   492  		u, _ := url.ParseRequestURI(domain + hro.Resource)
   493  		urlStr := u.String() // "https://api.com/user/"
   494  
   495  		var d string
   496  		if hro.Body != "" {
   497  			d = hro.Body
   498  		} else if len(hro.FormData) > 0 {
   499  			d = data.Encode()
   500  		}
   501  
   502  		r, _ := http.NewRequest(hro.Method, urlStr, nil)
   503  
   504  		if d != "" {
   505  			r, _ = http.NewRequest(hro.Method, urlStr, strings.NewReader(d))
   506  		}
   507  
   508  		for k, v := range hro.Headers {
   509  			r.Header.Set(k, v)
   510  		}
   511  		r.Close = true
   512  
   513  		tr := &http.Transport{TLSClientConfig: &tls.Config{}}
   514  		if cert := getUpstreamCertificate(r.Host, j.Spec); cert != nil {
   515  			tr.TLSClientConfig.Certificates = []tls.Certificate{*cert}
   516  		}
   517  
   518  		if config.Global().ProxySSLInsecureSkipVerify {
   519  			tr.TLSClientConfig.InsecureSkipVerify = true
   520  		}
   521  
   522  		if j.Spec.Proxy.Transport.SSLInsecureSkipVerify {
   523  			tr.TLSClientConfig.InsecureSkipVerify = true
   524  		}
   525  
   526  		tr.DialTLS = customDialTLSCheck(j.Spec, tr.TLSClientConfig)
   527  
   528  		tr.Proxy = proxyFromAPI(j.Spec)
   529  
   530  		// using new Client each time should be ok, since we closing connection every time
   531  		client := &http.Client{Transport: tr}
   532  		resp, err := client.Do(r)
   533  		if err != nil {
   534  			j.Log.WithError(err).Error("Request failed")
   535  			return otto.Value{}
   536  		}
   537  
   538  		body, _ := ioutil.ReadAll(resp.Body)
   539  		bodyStr := string(body)
   540  		tykResp := TykJSHttpResponse{
   541  			Code:        resp.StatusCode,
   542  			Body:        bodyStr,
   543  			Headers:     resp.Header,
   544  			CodeComp:    resp.StatusCode,
   545  			BodyComp:    bodyStr,
   546  			HeadersComp: resp.Header,
   547  		}
   548  
   549  		retAsStr, _ := json.Marshal(tykResp)
   550  		returnVal, err := j.VM.ToValue(string(retAsStr))
   551  		if err != nil {
   552  			j.Log.WithError(err).Error("Failed to encode return value")
   553  			return otto.Value{}
   554  		}
   555  
   556  		return returnVal
   557  	})
   558  
   559  	// Expose Setters and Getters in the REST API for a key:
   560  	j.VM.Set("TykGetKeyData", func(call otto.FunctionCall) otto.Value {
   561  		apiKey := call.Argument(0).String()
   562  		apiId := call.Argument(1).String()
   563  
   564  		obj, _ := handleGetDetail(apiKey, apiId, false)
   565  		bs, _ := json.Marshal(obj)
   566  
   567  		returnVal, err := j.VM.ToValue(string(bs))
   568  		if err != nil {
   569  			j.Log.WithError(err).Error("Failed to encode return value")
   570  			return otto.Value{}
   571  		}
   572  
   573  		return returnVal
   574  	})
   575  
   576  	j.VM.Set("TykSetKeyData", func(call otto.FunctionCall) otto.Value {
   577  		apiKey := call.Argument(0).String()
   578  		encoddedSession := call.Argument(1).String()
   579  		suppressReset := call.Argument(2).String()
   580  
   581  		newSession := user.SessionState{Mutex: &sync.RWMutex{}}
   582  		err := json.Unmarshal([]byte(encoddedSession), &newSession)
   583  		if err != nil {
   584  			j.Log.WithError(err).Error("Failed to decode the sesison data")
   585  			return otto.Value{}
   586  		}
   587  
   588  		doAddOrUpdate(apiKey, &newSession, suppressReset == "1", false)
   589  
   590  		return otto.Value{}
   591  	})
   592  
   593  	// Batch request method
   594  	unsafeBatchHandler := BatchRequestHandler{}
   595  	j.VM.Set("TykBatchRequest", func(call otto.FunctionCall) otto.Value {
   596  		requestSet := call.Argument(0).String()
   597  		j.Log.Debug("Batch input is: ", requestSet)
   598  
   599  		bs, err := unsafeBatchHandler.ManualBatchRequest([]byte(requestSet))
   600  		if err != nil {
   601  			j.Log.WithError(err).Error("Batch request error")
   602  			return otto.Value{}
   603  		}
   604  
   605  		returnVal, err := j.VM.ToValue(string(bs))
   606  		if err != nil {
   607  			j.Log.WithError(err).Error("Failed to encode return value")
   608  			return otto.Value{}
   609  		}
   610  
   611  		return returnVal
   612  	})
   613  
   614  	j.VM.Run(`function TykJsResponse(response, session_meta) {
   615  		return JSON.stringify({Response: response, SessionMeta: session_meta})
   616  	}`)
   617  }
   618  
   619  const coreJS = `
   620  var TykJS = {
   621  	TykMiddleware: {
   622  		MiddlewareComponentMeta: function(configuration) {
   623  			this.configuration = configuration
   624  		}
   625  	},
   626  	TykEventHandlers: {
   627  		EventHandlerComponentMeta: function() {}
   628  	}
   629  }
   630  
   631  TykJS.TykMiddleware.MiddlewareComponentMeta.prototype.ProcessRequest = function(request, session, config) {
   632  	log("Process Request Not Implemented")
   633  	return request
   634  }
   635  
   636  TykJS.TykMiddleware.MiddlewareComponentMeta.prototype.DoProcessRequest = function(request, session, config) {
   637  	request.Body = b64dec(request.Body)
   638  	var processed_request = this.ProcessRequest(request, session, config)
   639  
   640  	if (!processed_request) {
   641  		log("Middleware didn't return request object!")
   642  		return
   643  	}
   644  
   645  	// Reset the headers object
   646  	processed_request.Request.Headers = {}
   647  	processed_request.Request.Body = b64enc(processed_request.Request.Body)
   648  
   649  	return JSON.stringify(processed_request)
   650  }
   651  
   652  // The user-level middleware component
   653  TykJS.TykMiddleware.NewMiddleware = function(configuration) {
   654  	TykJS.TykMiddleware.MiddlewareComponentMeta.call(this, configuration)
   655  }
   656  
   657  // Set up object inheritance
   658  TykJS.TykMiddleware.NewMiddleware.prototype = Object.create(TykJS.TykMiddleware.MiddlewareComponentMeta.prototype)
   659  TykJS.TykMiddleware.NewMiddleware.prototype.constructor = TykJS.TykMiddleware.NewMiddleware
   660  
   661  TykJS.TykMiddleware.NewMiddleware.prototype.NewProcessRequest = function(callback) {
   662  	this.ProcessRequest = callback
   663  }
   664  
   665  TykJS.TykMiddleware.NewMiddleware.prototype.ReturnData = function(request, session) {
   666  	return {Request: request, SessionMeta: session}
   667  }
   668  
   669  TykJS.TykMiddleware.NewMiddleware.prototype.ReturnAuthData = function(request, session) {
   670  	return {Request: request, Session: session}
   671  }
   672  
   673  // Event Handler implementation
   674  
   675  TykJS.TykEventHandlers.EventHandlerComponentMeta.prototype.DoProcessEvent = function(event, context) {
   676  	// call the handler
   677  	log("Calling built - in handle")
   678  	this.Handle(event, context)
   679  	return
   680  }
   681  
   682  TykJS.TykEventHandlers.EventHandlerComponentMeta.prototype.Handle = function(request, context) {
   683  	log("Handler not implemented!")
   684  	return request
   685  }
   686  
   687  // The user-level event handler component
   688  TykJS.TykEventHandlers.NewEventHandler = function() {
   689  	TykJS.TykEventHandlers.EventHandlerComponentMeta.call(this)
   690  }
   691  
   692  // Set up object inheritance for events
   693  TykJS.TykEventHandlers.NewEventHandler.prototype = Object.create(TykJS.TykEventHandlers.EventHandlerComponentMeta.prototype)
   694  TykJS.TykEventHandlers.NewEventHandler.prototype.constructor = TykJS.TykEventHandlers.NewEventHandler
   695  
   696  TykJS.TykEventHandlers.NewEventHandler.prototype.NewHandler = function(callback) {
   697  	this.Handle = callback
   698  };`