Path: blob/dev/pkg/protocols/offlinehttp/request.go
2070 views
package offlinehttp12import (3"fmt"4"io"5"net/http"6"net/http/httputil"7"os"89"github.com/pkg/errors"1011"github.com/projectdiscovery/gologger"12"github.com/projectdiscovery/nuclei/v3/pkg/output"13"github.com/projectdiscovery/nuclei/v3/pkg/protocols"14"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"15"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"16"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/eventcreator"17"github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"18templateTypes "github.com/projectdiscovery/nuclei/v3/pkg/templates/types"19"github.com/projectdiscovery/utils/conversion"20syncutil "github.com/projectdiscovery/utils/sync"21unitutils "github.com/projectdiscovery/utils/unit"22)2324var _ protocols.Request = &Request{}2526const maxSize = 5 * unitutils.Mega2728// Type returns the type of the protocol request29func (request *Request) Type() templateTypes.ProtocolType {30return templateTypes.OfflineHTTPProtocol31}3233// RawInputMode is a flag to indicate if the input is raw input34// rather than a file path35var RawInputMode = false3637// ExecuteWithResults executes the protocol requests and returns results instead of writing them.38func (request *Request) ExecuteWithResults(input *contextargs.Context, metadata, previous output.InternalEvent, callback protocols.OutputEventCallback) error {39if RawInputMode {40return request.executeRawInput(input.MetaInput.Input, "", input, callback)41}4243wg, err := syncutil.New(syncutil.WithSize(request.options.Options.BulkSize))44if err != nil {45return err46}4748err = request.getInputPaths(input.MetaInput.Input, func(data string) {49wg.Add()5051go func(data string) {52defer wg.Done()5354file, err := os.Open(data)55if err != nil {56gologger.Error().Msgf("Could not open file path %s: %s\n", data, err)57return58}59defer func() {60_ = file.Close()61}()6263stat, err := file.Stat()64if err != nil {65gologger.Error().Msgf("Could not stat file path %s: %s\n", data, err)66return67}68if stat.Size() >= int64(maxSize) {69gologger.Verbose().Msgf("Could not process path %s: exceeded max size\n", data)70return71}7273buffer, err := io.ReadAll(file)74if err != nil {75gologger.Error().Msgf("Could not read file path %s: %s\n", data, err)76return77}78dataStr := conversion.String(buffer)7980if err := request.executeRawInput(dataStr, data, input, callback); err != nil {81gologger.Error().Msgf("Could not execute raw input %s: %s\n", data, err)82return83}84}(data)85})86wg.Wait()87if err != nil {88request.options.Output.Request(request.options.TemplatePath, input.MetaInput.Input, "file", err)89request.options.Progress.IncrementFailedRequestsBy(1)90return errors.Wrap(err, "could not send file request")91}92request.options.Progress.IncrementRequests()93return nil94}9596func (request *Request) executeRawInput(data, inputString string, input *contextargs.Context, callback protocols.OutputEventCallback) error {97resp, err := readResponseFromString(data)98if err != nil {99return errors.Wrap(err, "could not read raw response")100}101102if request.options.Options.Debug || request.options.Options.DebugRequests {103gologger.Info().Msgf("[%s] Dumped offline-http request for %s", request.options.TemplateID, data)104gologger.Print().Msgf("%s", data)105}106gologger.Verbose().Msgf("[%s] Sent OFFLINE-HTTP request to %s", request.options.TemplateID, data)107108dumpedResponse, err := httputil.DumpResponse(resp, true)109if err != nil {110return errors.Wrap(err, "could not dump raw http response")111}112113body, err := io.ReadAll(resp.Body)114if err != nil {115return errors.Wrap(err, "could not read raw http response body")116}117reqURL := inputString118if inputString == "" {119reqURL = getURLFromRequest(resp.Request)120}121122outputEvent := request.responseToDSLMap(resp, data, reqURL, data, conversion.String(dumpedResponse), conversion.String(body), utils.HeadersToString(resp.Header), 0, nil)123// add response fields to template context and merge templatectx variables to output event124request.options.AddTemplateVars(input.MetaInput, request.Type(), request.GetID(), outputEvent)125if request.options.HasTemplateCtx(input.MetaInput) {126outputEvent = generators.MergeMaps(outputEvent, request.options.GetTemplateCtx(input.MetaInput).GetAll())127}128outputEvent["ip"] = ""129130event := eventcreator.CreateEvent(request, outputEvent, request.options.Options.Debug || request.options.Options.DebugResponse)131callback(event)132return nil133}134135func getURLFromRequest(req *http.Request) string {136if req.URL.Scheme == "" {137req.URL.Scheme = "https"138}139return fmt.Sprintf("%s://%s%s", req.URL.Scheme, req.Host, req.URL.Path)140}141142// UpdateOptions replaces this request's options with a new copy143func (r *Request) UpdateOptions(opts *protocols.ExecutorOptions) {144r.options = opts145}146147148