github.com/anuvu/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/tracing.go (about)

     1  package gateway
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"net/http/httputil"
     9  	"strings"
    10  
    11  	"github.com/sirupsen/logrus"
    12  	"github.com/gorilla/mux"
    13  
    14  	"github.com/TykTechnologies/tyk/apidef"
    15  )
    16  
    17  type traceHttpRequest struct {
    18  	Method  string      `json:"method"`
    19  	Path    string      `json:"path"`
    20  	Body    string      `json:"body"`
    21  	Headers http.Header `json:"headers"`
    22  }
    23  
    24  func (tr *traceHttpRequest) toRequest() *http.Request {
    25  	r := httptest.NewRequest(tr.Method, tr.Path, strings.NewReader(tr.Body))
    26  	r.Header = tr.Headers
    27  	ctxSetTrace(r)
    28  
    29  	return r
    30  }
    31  
    32  // TraceRequest is for tracing an HTTP request
    33  // swagger:model TraceRequest
    34  type traceRequest struct {
    35  	Request *traceHttpRequest     `json:"request"`
    36  	Spec    *apidef.APIDefinition `json:"spec"`
    37  }
    38  
    39  // TraceResponse is for tracing an HTTP response
    40  // swagger:model TraceResponse
    41  type traceResponse struct {
    42  	Message  string `json:"message"`
    43  	Response string `json:"response"`
    44  	Logs     string `json:"logs"`
    45  }
    46  
    47  // Tracing request
    48  // Used to test API definition by sending sample request,
    49  // and analysisng output of both response and logs
    50  //
    51  //---
    52  // requestBody:
    53  //   content:
    54  //     application/json:
    55  //       schema:
    56  //         "$ref": "#/definitions/traceRequest"
    57  //       examples:
    58  //         request:
    59  //           method: GET
    60  //           path: /get
    61  //           headers:
    62  //              Authorization: key
    63  //         spec:
    64  //           api_name: "Test"
    65  // responses:
    66  //   200:
    67  //     description: Success tracing request
    68  //     schema:
    69  //       "$ref": "#/definitions/traceResponse"
    70  //     examples:
    71  //       message: "ok"
    72  //       response:
    73  //         code: 200
    74  //         headers:
    75  //           Header: value
    76  //         body: body-value
    77  //       logs: {...}\n{...}
    78  func traceHandler(w http.ResponseWriter, r *http.Request) {
    79  	var traceReq traceRequest
    80  	if err := json.NewDecoder(r.Body).Decode(&traceReq); err != nil {
    81  		log.Error("Couldn't decode trace request: ", err)
    82  
    83  		doJSONWrite(w, http.StatusBadRequest, apiError("Request malformed"))
    84  		return
    85  	}
    86  
    87  	if traceReq.Spec == nil {
    88  		log.Error("Spec field is missing")
    89  		doJSONWrite(w, http.StatusBadRequest, apiError("Spec field is missing"))
    90  		return
    91  	}
    92  
    93  	if traceReq.Request == nil {
    94  		log.Error("Request field is missing")
    95  		doJSONWrite(w, http.StatusBadRequest, apiError("Request field is missing"))
    96  		return
    97  	}
    98  
    99  	var logStorage bytes.Buffer
   100  	logger := logrus.New()
   101  	logger.Formatter = &logrus.JSONFormatter{}
   102  	logger.Level = logrus.DebugLevel
   103  	logger.Out = &logStorage
   104  
   105  	redisStore, redisOrgStore, healthStore, rpcAuthStore, rpcOrgStore := prepareStorage()
   106  	subrouter := mux.NewRouter()
   107  
   108  	loader := &APIDefinitionLoader{}
   109  	spec := loader.MakeSpec(traceReq.Spec, logrus.NewEntry(logger))
   110  
   111  	chainObj := processSpec(spec, nil, &redisStore, &redisOrgStore, &healthStore, &rpcAuthStore, &rpcOrgStore, subrouter, logrus.NewEntry(logger))
   112  	spec.middlewareChain = chainObj.ThisHandler
   113  
   114  	if chainObj.ThisHandler == nil {
   115  		doJSONWrite(w, http.StatusBadRequest, traceResponse{Message: "error", Logs: logStorage.String()})
   116  		return
   117  	}
   118  
   119  	wr := httptest.NewRecorder()
   120  	chainObj.ThisHandler.ServeHTTP(wr, traceReq.Request.toRequest())
   121  
   122  	var response string
   123  	if dump, err := httputil.DumpResponse(wr.Result(), true); err == nil {
   124  		response = string(dump)
   125  	} else {
   126  		response = err.Error()
   127  	}
   128  
   129  	doJSONWrite(w, http.StatusOK, traceResponse{Message: "ok", Response: response, Logs: logStorage.String()})
   130  }