nuclei/v2/pkg/protocols/http/request.go

670 lines
24 KiB
Go
Raw Normal View History

package http
import (
2021-02-08 01:55:53 +05:30
"bytes"
"encoding/hex"
2021-03-08 19:01:40 +05:30
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"sync"
"time"
"github.com/pkg/errors"
2021-09-07 17:31:46 +03:00
"github.com/remeh/sizedwaitgroup"
"go.uber.org/multierr"
"moul.io/http2curl"
2021-09-07 17:31:46 +03:00
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/operators"
"github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
2021-10-07 01:40:49 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/expressions"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/eventcreator"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/responsehighlighter"
2021-04-18 16:10:10 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
2021-01-01 15:28:28 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/tostring"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/httpclientpool"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/signer"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http/signerpool"
templateTypes "github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/projectdiscovery/rawhttp"
"github.com/projectdiscovery/stringsutil"
)
const defaultMaxWorkers = 150
// Type returns the type of the protocol request
func (request *Request) Type() templateTypes.ProtocolType {
return templateTypes.HTTPProtocol
}
// executeRaceRequest executes race condition request for a URL
func (request *Request) executeRaceRequest(reqURL string, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
var generatedRequests []*generatedRequest
// Requests within race condition should be dumped once and the output prefilled to allow DSL language to work
// This will introduce a delay and will populate in hacky way the field "request" of outputEvent
generator := request.newGenerator()
inputData, payloads, ok := generator.nextValue()
if !ok {
return nil
}
requestForDump, err := generator.Make(reqURL, inputData, payloads, nil)
if err != nil {
return err
}
request.setCustomHeaders(requestForDump)
dumpedRequest, err := dump(requestForDump, reqURL)
if err != nil {
return err
}
if request.options.Options.Debug || request.options.Options.DebugRequests {
gologger.Info().Msgf("[%s] Dumped HTTP request for %s\n\n", request.options.TemplateID, reqURL)
gologger.Print().Msgf("%s", string(dumpedRequest))
}
previous["request"] = string(dumpedRequest)
// Pre-Generate requests
for i := 0; i < request.RaceNumberRequests; i++ {
generator := request.newGenerator()
inputData, payloads, ok := generator.nextValue()
if !ok {
break
}
generatedRequest, err := generator.Make(reqURL, inputData, payloads, nil)
if err != nil {
return err
}
generatedRequests = append(generatedRequests, generatedRequest)
}
wg := sync.WaitGroup{}
var requestErr error
2020-12-30 16:49:45 +05:30
mutex := &sync.Mutex{}
for i := 0; i < request.RaceNumberRequests; i++ {
wg.Add(1)
go func(httpRequest *generatedRequest) {
defer wg.Done()
err := request.executeRequest(reqURL, httpRequest, previous, false, callback, 0)
mutex.Lock()
if err != nil {
requestErr = multierr.Append(requestErr, err)
}
mutex.Unlock()
}(generatedRequests[i])
request.options.Progress.IncrementRequests()
}
wg.Wait()
return requestErr
}
2021-02-04 22:00:09 +05:30
// executeRaceRequest executes parallel requests for a template
func (request *Request) executeParallelHTTP(reqURL string, dynamicValues output.InternalEvent, callback protocols.OutputEventCallback) error {
generator := request.newGenerator()
// Workers that keeps enqueuing new requests
maxWorkers := request.Threads
swg := sizedwaitgroup.New(maxWorkers)
var requestErr error
2020-12-30 16:49:45 +05:30
mutex := &sync.Mutex{}
for {
inputData, payloads, ok := generator.nextValue()
if !ok {
break
}
generatedHttpRequest, err := generator.Make(reqURL, inputData, payloads, dynamicValues)
if err != nil {
if err == io.EOF {
break
}
request.options.Progress.IncrementFailedRequestsBy(int64(generator.Total()))
return err
}
if reqURL == "" {
reqURL = generatedHttpRequest.URL()
}
swg.Add()
go func(httpRequest *generatedRequest) {
defer swg.Done()
request.options.RateLimiter.Take()
2021-07-10 14:54:49 +05:30
previous := make(map[string]interface{})
err := request.executeRequest(reqURL, httpRequest, previous, false, callback, 0)
mutex.Lock()
if err != nil {
requestErr = multierr.Append(requestErr, err)
}
mutex.Unlock()
}(generatedHttpRequest)
request.options.Progress.IncrementRequests()
}
swg.Wait()
return requestErr
}
2021-06-09 11:15:21 +05:30
// executeTurboHTTP executes turbo http request for a URL
func (request *Request) executeTurboHTTP(reqURL string, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
generator := request.newGenerator()
// need to extract the target from the url
URL, err := url.Parse(reqURL)
if err != nil {
return err
}
pipeOptions := rawhttp.DefaultPipelineOptions
pipeOptions.Host = URL.Host
pipeOptions.MaxConnections = 1
if request.PipelineConcurrentConnections > 0 {
pipeOptions.MaxConnections = request.PipelineConcurrentConnections
}
if request.PipelineRequestsPerConnection > 0 {
pipeOptions.MaxPendingRequests = request.PipelineRequestsPerConnection
}
pipeClient := rawhttp.NewPipelineClient(pipeOptions)
// defaultMaxWorkers should be a sufficient value to keep queues always full
maxWorkers := defaultMaxWorkers
// in case the queue is bigger increase the workers
if pipeOptions.MaxPendingRequests > maxWorkers {
maxWorkers = pipeOptions.MaxPendingRequests
}
swg := sizedwaitgroup.New(maxWorkers)
var requestErr error
2020-12-30 16:49:45 +05:30
mutex := &sync.Mutex{}
for {
inputData, payloads, ok := generator.nextValue()
if !ok {
break
}
generatedHttpRequest, err := generator.Make(reqURL, inputData, payloads, dynamicValues)
if err != nil {
request.options.Progress.IncrementFailedRequestsBy(int64(generator.Total()))
return err
}
if reqURL == "" {
reqURL = generatedHttpRequest.URL()
}
generatedHttpRequest.pipelinedClient = pipeClient
swg.Add()
go func(httpRequest *generatedRequest) {
defer swg.Done()
err := request.executeRequest(reqURL, httpRequest, previous, false, callback, 0)
mutex.Lock()
if err != nil {
requestErr = multierr.Append(requestErr, err)
}
mutex.Unlock()
}(generatedHttpRequest)
request.options.Progress.IncrementRequests()
}
swg.Wait()
return requestErr
}
2020-12-29 11:42:46 +05:30
// ExecuteWithResults executes the final request on a URL
func (request *Request) ExecuteWithResults(reqURL string, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
// verify if pipeline was requested
if request.Pipeline {
return request.executeTurboHTTP(reqURL, dynamicValues, previous, callback)
}
// verify if a basic race condition was requested
if request.Race && request.RaceNumberRequests > 0 {
return request.executeRaceRequest(reqURL, previous, callback)
}
// verify if parallel elaboration was requested
if request.Threads > 0 {
return request.executeParallelHTTP(reqURL, dynamicValues, callback)
}
generator := request.newGenerator()
var gotDynamicValues map[string][]string
2021-03-08 19:01:40 +05:30
requestCount := 1
var requestErr error
for {
// returns two values, error and skip, which skips the execution for the request instance.
executeFunc := func(data string, payloads, dynamicValue map[string]interface{}) (bool, error) {
hasInteractMatchers := interactsh.HasMatchers(request.CompiledOperators)
generatedHttpRequest, err := generator.Make(reqURL, data, payloads, dynamicValue)
if err != nil {
if err == io.EOF {
return true, nil
}
request.options.Progress.IncrementFailedRequestsBy(int64(generator.Total()))
return true, err
}
2022-02-01 12:34:12 +01:00
hasInteractMarkers := interactsh.HasMarkers(data) || len(generatedHttpRequest.interactshURLs) > 0
if reqURL == "" {
reqURL = generatedHttpRequest.URL()
}
2021-11-30 16:55:09 +05:30
// Check if hosts keep erroring
if request.options.HostErrorsCache != nil && request.options.HostErrorsCache.Check(reqURL) {
return true, nil
2021-04-16 16:56:41 +05:30
}
var gotMatches bool
request.options.RateLimiter.Take()
err = request.executeRequest(reqURL, generatedHttpRequest, previous, hasInteractMatchers, func(event *output.InternalWrappedEvent) {
// Add the extracts to the dynamic values if any.
if event.OperatorsResult != nil {
gotMatches = event.OperatorsResult.Matched
gotDynamicValues = generators.MergeMapsMany(event.OperatorsResult.DynamicValues, dynamicValues, gotDynamicValues)
}
if hasInteractMarkers && hasInteractMatchers && request.options.Interactsh != nil {
request.options.Interactsh.RequestEvent(generatedHttpRequest.interactshURLs, &interactsh.RequestData{
MakeResultFunc: request.MakeResultEvent,
Event: event,
Operators: request.CompiledOperators,
MatchFunc: request.Match,
ExtractFunc: request.Extract,
})
} else {
callback(event)
}
}, requestCount)
2021-11-30 16:55:09 +05:30
// If a variable is unresolved, skip all further requests
if err == errStopExecution {
return true, nil
}
if err != nil {
if request.options.HostErrorsCache != nil && request.options.HostErrorsCache.CheckError(err) {
request.options.HostErrorsCache.MarkFailed(reqURL)
}
requestErr = err
2021-04-16 16:56:41 +05:30
}
requestCount++
request.options.Progress.IncrementRequests()
// If this was a match, and we want to stop at first match, skip all further requests.
if (generatedHttpRequest.original.options.Options.StopAtFirstMatch || generatedHttpRequest.original.options.StopAtFirstMatch || request.StopAtFirstMatch) && gotMatches {
return true, nil
}
return false, nil
}
inputData, payloads, ok := generator.nextValue()
if !ok {
break
}
var gotErr error
var skip bool
if len(gotDynamicValues) > 0 {
2021-11-24 22:44:43 +05:30
operators.MakeDynamicValuesCallback(gotDynamicValues, request.IterateAll, func(data map[string]interface{}) bool {
if skip, gotErr = executeFunc(inputData, payloads, data); skip || gotErr != nil {
return true
}
return false
})
} else {
skip, gotErr = executeFunc(inputData, payloads, dynamicValues)
}
if gotErr != nil && requestErr == nil {
requestErr = gotErr
}
if skip || gotErr != nil {
break
}
}
return requestErr
}
2021-02-04 22:09:32 +05:30
const drainReqSize = int64(8 * 1024)
var errStopExecution = errors.New("stop execution due to unresolved variables")
2021-02-26 13:13:11 +05:30
// executeRequest executes the actual generated request and returns error if occurred
func (request *Request) executeRequest(reqURL string, generatedRequest *generatedRequest, previousEvent output.InternalEvent, hasInteractMatchers bool, callback protocols.OutputEventCallback, requestCount int) error {
request.setCustomHeaders(generatedRequest)
var (
resp *http.Response
fromCache bool
dumpedRequest []byte
err error
)
2021-02-08 01:43:51 +05:30
// Dump request for variables checks
2021-10-07 01:40:49 +05:30
// For race conditions we can't dump the request body at this point as it's already waiting the open-gate event, already handled with a similar code within the race function
if !generatedRequest.original.Race {
2021-10-07 01:40:49 +05:30
var dumpError error
2021-11-13 03:17:05 +01:00
// TODO: dump is currently not working with post-processors - somehow it alters the signature
dumpedRequest, dumpError = dump(generatedRequest, reqURL)
2021-10-07 01:40:49 +05:30
if dumpError != nil {
return dumpError
}
dumpedRequestString := string(dumpedRequest)
2021-12-18 20:06:51 +01:00
if ignoreList := GetVariablesNamesSkipList(generatedRequest.original.Signature.Value); ignoreList != nil {
if varErr := expressions.ContainsVariablesWithIgnoreList(ignoreList, dumpedRequestString); varErr != nil && !request.SkipVariablesCheck {
gologger.Warning().Msgf("[%s] Could not make http request for %s: %v\n", request.options.TemplateID, reqURL, varErr)
return errStopExecution
}
} else { // Check if are there any unresolved variables. If yes, skip unless overridden by user.
if varErr := expressions.ContainsUnresolvedVariables(dumpedRequestString); varErr != nil && !request.SkipVariablesCheck {
gologger.Warning().Msgf("[%s] Could not make http request for %s: %v\n", request.options.TemplateID, reqURL, varErr)
return errStopExecution
}
2021-10-07 01:40:49 +05:30
}
}
2021-01-11 19:59:12 +05:30
var formedURL string
var hostname string
timeStart := time.Now()
if generatedRequest.original.Pipeline {
if generatedRequest.rawRequest != nil {
formedURL = generatedRequest.rawRequest.FullURL
2021-06-09 11:15:21 +05:30
if parsed, parseErr := url.Parse(formedURL); parseErr == nil {
hostname = parsed.Host
}
resp, err = generatedRequest.pipelinedClient.DoRaw(generatedRequest.rawRequest.Method, reqURL, generatedRequest.rawRequest.Path, generators.ExpandMapValues(generatedRequest.rawRequest.Headers), ioutil.NopCloser(strings.NewReader(generatedRequest.rawRequest.Data)))
} else if generatedRequest.request != nil {
resp, err = generatedRequest.pipelinedClient.Dor(generatedRequest.request)
}
} else if generatedRequest.original.Unsafe && generatedRequest.rawRequest != nil {
formedURL = generatedRequest.rawRequest.FullURL
2021-02-26 13:13:11 +05:30
if parsed, parseErr := url.Parse(formedURL); parseErr == nil {
hostname = parsed.Host
}
options := generatedRequest.original.rawhttpClient.Options
options.FollowRedirects = request.Redirects
options.CustomRawBytes = generatedRequest.rawRequest.UnsafeRawBytes
resp, err = generatedRequest.original.rawhttpClient.DoRawWithOptions(generatedRequest.rawRequest.Method, reqURL, generatedRequest.rawRequest.Path, generators.ExpandMapValues(generatedRequest.rawRequest.Headers), ioutil.NopCloser(strings.NewReader(generatedRequest.rawRequest.Data)), options)
} else {
hostname = generatedRequest.request.URL.Host
formedURL = generatedRequest.request.URL.String()
// if nuclei-project is available check if the request was already sent previously
if request.options.ProjectFile != nil {
// if unavailable fail silently
fromCache = true
resp, err = request.options.ProjectFile.Get(dumpedRequest)
if err != nil {
fromCache = false
}
}
if resp == nil {
2021-12-02 15:57:52 +01:00
if errSignature := request.handleSignature(generatedRequest); errSignature != nil {
return errSignature
2021-11-12 19:29:45 +01:00
}
resp, err = request.httpClient.Do(generatedRequest.request)
}
}
// Dump the requests containing all headers
if !generatedRequest.original.Race {
var dumpError error
dumpedRequest, dumpError = dump(generatedRequest, reqURL)
if dumpError != nil {
return dumpError
}
dumpedRequestString := string(dumpedRequest)
if request.options.Options.Debug || request.options.Options.DebugRequests {
gologger.Info().Msgf("[%s] Dumped HTTP request for %s\n\n", request.options.TemplateID, reqURL)
gologger.Print().Msgf("%s", dumpedRequestString)
}
}
// use request url as matched url if empty
if formedURL == "" {
formedURL = reqURL
}
if err != nil {
2021-09-07 17:31:46 +03:00
// rawhttp doesn't support draining response bodies.
if resp != nil && resp.Body != nil && generatedRequest.rawRequest == nil {
_, _ = io.CopyN(ioutil.Discard, resp.Body, drainReqSize)
resp.Body.Close()
}
request.options.Output.Request(request.options.TemplatePath, formedURL, request.Type().String(), err)
request.options.Progress.IncrementErrorsBy(1)
// If we have interactsh markers and request times out, still send
2021-09-07 17:31:46 +03:00
// a callback event so in case we receive an interaction, correlation is possible.
if hasInteractMatchers {
outputEvent := request.responseToDSLMap(&http.Response{}, reqURL, formedURL, tostring.UnsafeToString(dumpedRequest), "", "", "", 0, generatedRequest.meta)
if i := strings.LastIndex(hostname, ":"); i != -1 {
hostname = hostname[:i]
}
outputEvent["ip"] = httpclientpool.Dialer.GetDialedIP(hostname)
event := &output.InternalWrappedEvent{InternalEvent: outputEvent}
if request.CompiledOperators != nil {
event.InternalEvent = outputEvent
}
callback(event)
}
return err
}
2021-02-26 13:13:11 +05:30
defer func() {
2021-08-30 12:40:38 +05:30
if resp.StatusCode != http.StatusSwitchingProtocols {
_, _ = io.CopyN(ioutil.Discard, resp.Body, drainReqSize)
}
2021-02-26 13:13:11 +05:30
resp.Body.Close()
}()
2021-02-05 12:36:01 +05:30
var curlCommand string
if !request.Unsafe && resp != nil && generatedRequest.request != nil && resp.Request != nil && !request.Race {
bodyBytes, _ := generatedRequest.request.BodyBytes()
resp.Request.Body = ioutil.NopCloser(bytes.NewReader(bodyBytes))
command, _ := http2curl.GetCurlCommand(resp.Request)
if err == nil && command != nil {
curlCommand = command.String()
}
}
gologger.Verbose().Msgf("[%s] Sent HTTP request to %s", request.options.TemplateID, formedURL)
request.options.Output.Request(request.options.TemplatePath, formedURL, request.Type().String(), err)
duration := time.Since(timeStart)
2021-02-05 12:36:01 +05:30
2021-02-08 01:55:53 +05:30
dumpedResponseHeaders, err := httputil.DumpResponse(resp, false)
2021-02-05 12:36:01 +05:30
if err != nil {
return errors.Wrap(err, "could not dump http response")
}
var dumpedResponse []redirectedResponse
2021-11-26 18:51:02 +05:30
var gotData []byte
// If the status code is HTTP 101, we should not proceed with reading body.
if resp.StatusCode != http.StatusSwitchingProtocols {
var bodyReader io.Reader
if request.MaxSize != 0 {
bodyReader = io.LimitReader(resp.Body, int64(request.MaxSize))
} else {
bodyReader = resp.Body
2021-06-09 11:15:21 +05:30
}
data, err := ioutil.ReadAll(bodyReader)
if err != nil {
// Ignore body read due to server misconfiguration errors
if stringsutil.ContainsAny(err.Error(), "gzip: invalid header") {
gologger.Warning().Msgf("[%s] Server sent an invalid gzip header and it was not possible to read the uncompressed body for %s: %s", request.options.TemplateID, formedURL, err.Error())
} else if !stringsutil.ContainsAny(err.Error(), "unexpected EOF", "user canceled") { // ignore EOF and random error
return errors.Wrap(err, "could not read http body")
}
}
2021-11-26 18:51:02 +05:30
gotData = data
resp.Body.Close()
dumpedResponse, err = dumpResponseWithRedirectChain(resp, data)
if err != nil {
return errors.Wrap(err, "could not read http response with redirect chain")
}
} else {
dumpedResponse = []redirectedResponse{{fullResponse: dumpedResponseHeaders, headers: dumpedResponseHeaders}}
}
2021-11-26 18:51:02 +05:30
// if nuclei-project is enabled store the response if not previously done
if request.options.ProjectFile != nil && !fromCache {
if err := request.options.ProjectFile.Set(dumpedRequest, resp, gotData); err != nil {
return errors.Wrap(err, "could not store in project file")
}
2021-11-26 18:51:02 +05:30
}
2021-11-26 18:51:02 +05:30
for _, response := range dumpedResponse {
if response.resp == nil {
continue // Skip nil responses
}
matchedURL := reqURL
if generatedRequest.rawRequest != nil && generatedRequest.rawRequest.FullURL != "" {
matchedURL = generatedRequest.rawRequest.FullURL
2021-09-10 21:19:05 +05:30
}
if generatedRequest.request != nil {
matchedURL = generatedRequest.request.URL.String()
2021-09-10 21:19:05 +05:30
}
finalEvent := make(output.InternalEvent)
outputEvent := request.responseToDSLMap(response.resp, reqURL, matchedURL, tostring.UnsafeToString(dumpedRequest), tostring.UnsafeToString(response.fullResponse), tostring.UnsafeToString(response.body), tostring.UnsafeToString(response.headers), duration, generatedRequest.meta)
if i := strings.LastIndex(hostname, ":"); i != -1 {
hostname = hostname[:i]
}
outputEvent["curl-command"] = curlCommand
outputEvent["ip"] = httpclientpool.Dialer.GetDialedIP(hostname)
if request.options.Interactsh != nil {
request.options.Interactsh.MakePlaceholders(generatedRequest.interactshURLs, outputEvent)
}
for k, v := range previousEvent {
finalEvent[k] = v
}
for k, v := range outputEvent {
finalEvent[k] = v
}
// Add to history the current request number metadata if asked by the user.
if request.ReqCondition {
for k, v := range outputEvent {
key := fmt.Sprintf("%s_%d", k, requestCount)
previousEvent[key] = v
finalEvent[key] = v
}
}
// prune signature internal values if any
request.pruneSignatureInternalValues(generatedRequest.meta)
event := eventcreator.CreateEventWithAdditionalOptions(request, generators.MergeMaps(generatedRequest.dynamicValues, finalEvent), request.options.Options.Debug || request.options.Options.DebugResponse, func(internalWrappedEvent *output.InternalWrappedEvent) {
internalWrappedEvent.OperatorsResult.PayloadValues = generatedRequest.meta
})
if hasInteractMatchers {
event.UsesInteractsh = true
}
responseContentType := resp.Header.Get("Content-Type")
dumpResponse(event, request.options, response.fullResponse, formedURL, responseContentType)
callback(event)
}
return nil
}
2021-12-02 15:57:52 +01:00
// handleSignature of the http request
func (request *Request) handleSignature(generatedRequest *generatedRequest) error {
switch request.Signature.Value {
case AWSSignature:
var awsSigner signer.Signer
vars := request.options.Options.Vars.AsMap()
awsAccessKeyId := types.ToString(vars["aws-id"])
awsSecretAccessKey := types.ToString(vars["aws-secret"])
2021-12-02 15:57:52 +01:00
awsSignerArgs := signer.AwsSignerArgs{AwsId: awsAccessKeyId, AwsSecretToken: awsSecretAccessKey}
service := types.ToString(generatedRequest.dynamicValues["service"])
region := types.ToString(generatedRequest.dynamicValues["region"])
2021-12-18 20:06:51 +01:00
// if region is empty use default value
2021-12-09 08:50:54 +01:00
if region == "" {
2021-12-18 20:06:51 +01:00
region = types.ToString(signer.AwsDefaultVars["region"])
2021-12-09 08:50:54 +01:00
}
2021-12-02 15:57:52 +01:00
awsSignatureArguments := signer.AwsSignatureArguments{
Service: types.ToString(service),
Region: types.ToString(region),
Time: time.Now(),
}
awsSigner, err := signerpool.Get(request.options.Options, &signerpool.Configuration{SignerArgs: awsSignerArgs})
if err != nil {
return err
}
err = awsSigner.SignHTTP(generatedRequest.request.Request, awsSignatureArguments)
if err != nil {
return err
}
}
return nil
}
// setCustomHeaders sets the custom headers for generated request
func (request *Request) setCustomHeaders(req *generatedRequest) {
for k, v := range request.customHeaders {
2021-02-04 22:00:09 +05:30
if req.rawRequest != nil {
req.rawRequest.Headers[k] = v
} else {
kk, vv := strings.TrimSpace(k), strings.TrimSpace(v)
req.request.Header.Set(kk, vv)
if kk == "Host" {
req.request.Host = vv
}
}
}
}
const CRLF = "\r\n"
func dumpResponse(event *output.InternalWrappedEvent, requestOptions *protocols.ExecuterOptions, redirectedResponse []byte, formedURL string, responseContentType string) {
cliOptions := requestOptions.Options
if cliOptions.Debug || cliOptions.DebugResponse {
response := string(redirectedResponse)
var highlightedResult string
if responseContentType == "application/octet-stream" || ((responseContentType == "" || responseContentType == "application/x-www-form-urlencoded") && responsehighlighter.HasBinaryContent(response)) {
highlightedResult = createResponseHexDump(event, response, cliOptions.NoColor)
} else {
highlightedResult = responsehighlighter.Highlight(event.OperatorsResult, response, cliOptions.NoColor, false)
}
gologger.Debug().Msgf("[%s] Dumped HTTP response for %s\n\n%s", requestOptions.TemplateID, formedURL, highlightedResult)
}
}
func createResponseHexDump(event *output.InternalWrappedEvent, response string, noColor bool) string {
CRLFs := CRLF + CRLF
headerEndIndex := strings.Index(response, CRLFs) + len(CRLFs)
if headerEndIndex > 0 {
headers := response[0:headerEndIndex]
responseBodyHexDump := hex.Dump([]byte(response[headerEndIndex:]))
highlightedHeaders := responsehighlighter.Highlight(event.OperatorsResult, headers, noColor, false)
highlightedResponse := responsehighlighter.Highlight(event.OperatorsResult, responseBodyHexDump, noColor, true)
return fmt.Sprintf("%s\n%s", highlightedHeaders, highlightedResponse)
} else {
return responsehighlighter.Highlight(event.OperatorsResult, hex.Dump([]byte(response)), noColor, true)
}
}
func (request *Request) pruneSignatureInternalValues(maps ...map[string]interface{}) {
var signatureFieldsToSkip map[string]interface{}
switch request.Signature.Value {
case AWSSignature:
2022-02-07 16:41:55 +02:00
signatureFieldsToSkip = signer.AwsInternalOnlyVars
default:
return
}
for _, m := range maps {
for fieldName := range signatureFieldsToSkip {
delete(m, fieldName)
}
}
}