2020-04-04 00:17:57 +05:30
|
|
|
package requests
|
|
|
|
|
|
|
|
|
|
import (
|
2020-04-28 23:02:07 +02:00
|
|
|
"bufio"
|
2020-04-29 02:57:18 +02:00
|
|
|
"fmt"
|
2020-04-04 02:50:32 +05:30
|
|
|
"io/ioutil"
|
|
|
|
|
"net/http"
|
2020-04-04 03:26:11 +05:30
|
|
|
"net/url"
|
2020-05-04 23:24:59 +02:00
|
|
|
"regexp"
|
2020-04-04 02:50:32 +05:30
|
|
|
"strings"
|
|
|
|
|
|
2020-05-04 23:24:59 +02:00
|
|
|
"github.com/Knetic/govaluate"
|
2020-07-01 16:17:24 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/extractors"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/generators"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/matchers"
|
2020-04-04 17:12:29 +05:30
|
|
|
retryablehttp "github.com/projectdiscovery/retryablehttp-go"
|
2020-04-04 00:17:57 +05:30
|
|
|
)
|
|
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
// BulkHTTPRequest contains a request to be made from a template
|
|
|
|
|
type BulkHTTPRequest struct {
|
2020-07-10 09:04:38 +02:00
|
|
|
Name string `yaml:"Name,omitempty"`
|
2020-05-04 23:24:59 +02:00
|
|
|
// AttackType is the attack type
|
|
|
|
|
// Sniper, PitchFork and ClusterBomb. Default is Sniper
|
|
|
|
|
AttackType string `yaml:"attack,omitempty"`
|
|
|
|
|
// attackType is internal attack type
|
|
|
|
|
attackType generators.Type
|
|
|
|
|
// Path contains the path/s for the request variables
|
2020-07-13 03:30:07 +02:00
|
|
|
Payloads map[string]interface{} `yaml:"payloads,omitempty"`
|
2020-04-04 00:17:57 +05:30
|
|
|
// Method is the request method, whether GET, POST, PUT, etc
|
|
|
|
|
Method string `yaml:"method"`
|
|
|
|
|
// Path contains the path/s for the request
|
|
|
|
|
Path []string `yaml:"path"`
|
|
|
|
|
// Headers contains headers to send with the request
|
|
|
|
|
Headers map[string]string `yaml:"headers,omitempty"`
|
|
|
|
|
// Body is an optional parameter which contains the request body for POST methods, etc
|
|
|
|
|
Body string `yaml:"body,omitempty"`
|
2020-07-16 16:15:24 +02:00
|
|
|
// CookieReuse is an optional setting that makes cookies shared within requests
|
|
|
|
|
CookieReuse bool `yaml:"cookie-reuse,omitempty"`
|
2020-04-04 00:17:57 +05:30
|
|
|
// Matchers contains the detection mechanism for the request to identify
|
|
|
|
|
// whether the request was successful
|
2020-04-05 23:58:22 +05:30
|
|
|
Matchers []*matchers.Matcher `yaml:"matchers,omitempty"`
|
2020-04-26 05:50:33 +05:30
|
|
|
// MatchersCondition is the condition of the matchers
|
|
|
|
|
// whether to use AND or OR. Default is OR.
|
|
|
|
|
MatchersCondition string `yaml:"matchers-condition,omitempty"`
|
2020-04-26 06:33:59 +05:30
|
|
|
// matchersCondition is internal condition for the matchers.
|
|
|
|
|
matchersCondition matchers.ConditionType
|
2020-04-05 23:58:22 +05:30
|
|
|
// Extractors contains the extraction mechanism for the request to identify
|
|
|
|
|
// and extract parts of the response.
|
2020-04-06 00:44:45 +05:30
|
|
|
Extractors []*extractors.Extractor `yaml:"extractors,omitempty"`
|
2020-04-23 03:56:41 +05:30
|
|
|
// Redirects specifies whether redirects should be followed.
|
|
|
|
|
Redirects bool `yaml:"redirects,omitempty"`
|
|
|
|
|
// MaxRedirects is the maximum number of redirects that should be followed.
|
|
|
|
|
MaxRedirects int `yaml:"max-redirects,omitempty"`
|
2020-04-29 21:19:35 +02:00
|
|
|
// Raw contains raw requests
|
2020-07-18 21:42:23 +02:00
|
|
|
Raw []string `yaml:"raw,omitempty"`
|
|
|
|
|
positionPath int
|
|
|
|
|
positionRaw int
|
|
|
|
|
generator func(payloads map[string][]string) (out chan map[string]interface{})
|
|
|
|
|
currentPayloads map[string]interface{}
|
|
|
|
|
basePayloads map[string][]string
|
|
|
|
|
generatorChan chan map[string]interface{}
|
|
|
|
|
currentGeneratorValue map[string]interface{}
|
2020-04-04 00:17:57 +05:30
|
|
|
}
|
2020-04-04 02:50:32 +05:30
|
|
|
|
2020-04-26 06:33:59 +05:30
|
|
|
// GetMatchersCondition returns the condition for the matcher
|
2020-07-18 21:42:23 +02:00
|
|
|
func (r *BulkHTTPRequest) GetMatchersCondition() matchers.ConditionType {
|
2020-04-26 06:33:59 +05:30
|
|
|
return r.matchersCondition
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetMatchersCondition sets the condition for the matcher
|
2020-07-18 21:42:23 +02:00
|
|
|
func (r *BulkHTTPRequest) SetMatchersCondition(condition matchers.ConditionType) {
|
2020-04-26 06:33:59 +05:30
|
|
|
r.matchersCondition = condition
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-04 23:24:59 +02:00
|
|
|
// GetAttackType returns the attack
|
2020-07-18 21:42:23 +02:00
|
|
|
func (r *BulkHTTPRequest) GetAttackType() generators.Type {
|
2020-05-04 23:24:59 +02:00
|
|
|
return r.attackType
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetAttackType sets the attack
|
2020-07-18 21:42:23 +02:00
|
|
|
func (r *BulkHTTPRequest) SetAttackType(attack generators.Type) {
|
2020-05-04 23:24:59 +02:00
|
|
|
r.attackType = attack
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-19 03:14:19 +02:00
|
|
|
func (r *BulkHTTPRequest) MakeHTTPRequest(baseURL string, dynamicValues map[string]interface{}, data string) (*HttpRequest, error) {
|
2020-04-04 03:26:11 +05:30
|
|
|
parsed, err := url.Parse(baseURL)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2020-07-20 00:41:31 +02:00
|
|
|
hostname := parsed.Host
|
2020-04-04 02:50:32 +05:30
|
|
|
|
2020-07-19 03:14:19 +02:00
|
|
|
values := generators.MergeMaps(dynamicValues, map[string]interface{}{
|
2020-04-29 02:57:18 +02:00
|
|
|
"BaseURL": baseURL,
|
|
|
|
|
"Hostname": hostname,
|
2020-07-19 03:14:19 +02:00
|
|
|
})
|
2020-04-29 02:57:18 +02:00
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
// if data contains \n it's a raw request
|
|
|
|
|
if strings.Contains(data, "\n") {
|
|
|
|
|
return r.makeHTTPRequestFromRaw(baseURL, data, values)
|
2020-04-29 02:57:18 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
return r.makeHTTPRequestFromModel(baseURL, data, values)
|
2020-04-29 02:57:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MakeHTTPRequestFromModel creates a *http.Request from a request template
|
2020-07-18 21:42:23 +02:00
|
|
|
func (r *BulkHTTPRequest) makeHTTPRequestFromModel(baseURL string, data string, values map[string]interface{}) (*HttpRequest, error) {
|
|
|
|
|
replacer := newReplacer(values)
|
|
|
|
|
URL := replacer.Replace(data)
|
2020-04-04 17:12:29 +05:30
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
// Build a request on the specified URL
|
|
|
|
|
req, err := http.NewRequest(r.Method, URL, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2020-05-04 23:24:59 +02:00
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
request, err := r.fillRequest(req, values)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2020-05-04 23:24:59 +02:00
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
return &HttpRequest{Request: request}, nil
|
|
|
|
|
}
|
2020-05-04 23:24:59 +02:00
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
func (r *BulkHTTPRequest) StartGenerator() {
|
|
|
|
|
r.generatorChan = r.generator(r.basePayloads)
|
|
|
|
|
}
|
2020-04-04 02:50:32 +05:30
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
func (r *BulkHTTPRequest) PickOne() {
|
|
|
|
|
var ok bool
|
|
|
|
|
r.currentGeneratorValue, ok = <-r.generatorChan
|
|
|
|
|
if !ok {
|
|
|
|
|
r.generator = nil
|
|
|
|
|
}
|
2020-04-04 02:50:32 +05:30
|
|
|
}
|
2020-04-28 23:02:07 +02:00
|
|
|
|
|
|
|
|
// makeHTTPRequestFromRaw creates a *http.Request from a raw request
|
2020-07-18 21:42:23 +02:00
|
|
|
func (r *BulkHTTPRequest) makeHTTPRequestFromRaw(baseURL string, data string, values map[string]interface{}) (*HttpRequest, error) {
|
|
|
|
|
// Add trailing line
|
|
|
|
|
data += "\n"
|
|
|
|
|
if len(r.Payloads) > 0 {
|
|
|
|
|
if r.generator == nil {
|
|
|
|
|
r.basePayloads = generators.LoadPayloads(r.Payloads)
|
|
|
|
|
generatorFunc := generators.SniperGenerator
|
|
|
|
|
switch r.attackType {
|
|
|
|
|
case generators.PitchFork:
|
|
|
|
|
generatorFunc = generators.PitchforkGenerator
|
|
|
|
|
case generators.ClusterBomb:
|
|
|
|
|
generatorFunc = generators.ClusterbombGenerator
|
2020-05-05 21:42:28 +02:00
|
|
|
}
|
2020-07-18 21:42:23 +02:00
|
|
|
r.generator = generatorFunc
|
|
|
|
|
r.StartGenerator()
|
2020-05-05 21:42:28 +02:00
|
|
|
}
|
2020-05-04 23:24:59 +02:00
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
r.PickOne()
|
|
|
|
|
|
|
|
|
|
return r.handleRawWithPaylods(data, baseURL, values, r.currentGeneratorValue)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// otherwise continue with normal flow
|
2020-07-19 19:25:05 +02:00
|
|
|
return r.handleRawWithPaylods(data, baseURL, values, nil)
|
2020-05-05 21:42:28 +02:00
|
|
|
}
|
2020-05-04 23:24:59 +02:00
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
func (r *BulkHTTPRequest) handleRawWithPaylods(raw string, baseURL string, values, genValues map[string]interface{}) (*HttpRequest, error) {
|
2020-05-05 21:42:28 +02:00
|
|
|
baseValues := generators.CopyMap(values)
|
|
|
|
|
finValues := generators.MergeMaps(baseValues, genValues)
|
2020-05-04 23:24:59 +02:00
|
|
|
|
2020-05-05 21:42:28 +02:00
|
|
|
replacer := newReplacer(finValues)
|
|
|
|
|
|
|
|
|
|
// Replace the dynamic variables in the URL if any
|
|
|
|
|
raw = replacer.Replace(raw)
|
2020-05-04 23:24:59 +02:00
|
|
|
|
2020-05-05 21:42:28 +02:00
|
|
|
dynamicValues := make(map[string]interface{})
|
|
|
|
|
// find all potentials tokens between {{}}
|
|
|
|
|
var re = regexp.MustCompile(`(?m)\{\{.+}}`)
|
|
|
|
|
for _, match := range re.FindAllString(raw, -1) {
|
|
|
|
|
// check if the match contains a dynamic variable
|
|
|
|
|
if generators.StringContainsAnyMapItem(finValues, match) {
|
|
|
|
|
expr := generators.TrimDelimiters(match)
|
|
|
|
|
compiled, err := govaluate.NewEvaluableExpressionWithFunctions(expr, generators.HelperFunctions())
|
|
|
|
|
if err != nil {
|
2020-07-18 21:42:23 +02:00
|
|
|
return nil, err
|
2020-05-05 21:42:28 +02:00
|
|
|
}
|
|
|
|
|
result, err := compiled.Evaluate(finValues)
|
|
|
|
|
if err != nil {
|
2020-07-18 21:42:23 +02:00
|
|
|
return nil, err
|
2020-05-04 23:24:59 +02:00
|
|
|
}
|
2020-05-05 21:42:28 +02:00
|
|
|
dynamicValues[expr] = result
|
2020-05-04 23:24:59 +02:00
|
|
|
}
|
2020-05-05 21:42:28 +02:00
|
|
|
}
|
2020-04-28 23:02:07 +02:00
|
|
|
|
2020-05-05 21:42:28 +02:00
|
|
|
// replace dynamic values
|
|
|
|
|
dynamicReplacer := newReplacer(dynamicValues)
|
|
|
|
|
raw = dynamicReplacer.Replace(raw)
|
|
|
|
|
|
2020-07-04 14:34:41 +07:00
|
|
|
compiledRequest, err := r.parseRawRequest(raw, baseURL)
|
2020-05-05 21:42:28 +02:00
|
|
|
if err != nil {
|
2020-07-18 21:42:23 +02:00
|
|
|
return nil, err
|
2020-05-05 21:42:28 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-04 14:34:41 +07:00
|
|
|
req, err := http.NewRequest(compiledRequest.Method, compiledRequest.FullURL, strings.NewReader(compiledRequest.Data))
|
2020-05-05 21:42:28 +02:00
|
|
|
if err != nil {
|
2020-07-18 21:42:23 +02:00
|
|
|
return nil, err
|
2020-05-05 21:42:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// copy headers
|
2020-06-29 19:50:11 +05:30
|
|
|
for key, value := range compiledRequest.Headers {
|
2020-07-17 16:04:13 +02:00
|
|
|
req.Header[key] = []string{value}
|
2020-06-29 19:50:11 +05:30
|
|
|
}
|
2020-05-05 21:42:28 +02:00
|
|
|
|
|
|
|
|
request, err := r.fillRequest(req, values)
|
|
|
|
|
if err != nil {
|
2020-07-18 21:42:23 +02:00
|
|
|
return nil, err
|
2020-05-05 21:42:28 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
return &HttpRequest{Request: request, Meta: genValues}, nil
|
2020-04-29 02:57:18 +02:00
|
|
|
}
|
2020-04-28 23:02:07 +02:00
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
func (r *BulkHTTPRequest) fillRequest(req *http.Request, values map[string]interface{}) (*retryablehttp.Request, error) {
|
2020-05-05 21:42:28 +02:00
|
|
|
req.Header.Set("Connection", "close")
|
|
|
|
|
req.Close = true
|
2020-04-30 17:39:33 +02:00
|
|
|
replacer := newReplacer(values)
|
2020-07-04 14:34:41 +07:00
|
|
|
|
2020-04-29 02:57:18 +02:00
|
|
|
// Check if the user requested a request body
|
|
|
|
|
if r.Body != "" {
|
|
|
|
|
req.Body = ioutil.NopCloser(strings.NewReader(r.Body))
|
|
|
|
|
}
|
2020-04-28 23:02:07 +02:00
|
|
|
|
2020-04-29 02:57:18 +02:00
|
|
|
// Set the header values requested
|
|
|
|
|
for header, value := range r.Headers {
|
2020-07-17 16:04:13 +02:00
|
|
|
req.Header[header] = []string{replacer.Replace(value)}
|
2020-04-29 02:57:18 +02:00
|
|
|
}
|
2020-04-28 23:02:07 +02:00
|
|
|
|
2020-04-29 02:57:18 +02:00
|
|
|
// Set some headers only if the header wasn't supplied by the user
|
2020-04-29 23:07:19 +02:00
|
|
|
if _, ok := req.Header["User-Agent"]; !ok {
|
2020-05-26 13:55:39 +05:30
|
|
|
req.Header.Set("User-Agent", "Nuclei - Open-source project (github.com/projectdiscovery/nuclei)")
|
2020-04-29 02:57:18 +02:00
|
|
|
}
|
2020-04-29 23:07:19 +02:00
|
|
|
|
2020-07-04 14:34:41 +07:00
|
|
|
// raw requests are left untouched
|
|
|
|
|
if len(r.Raw) > 0 {
|
|
|
|
|
return retryablehttp.FromRequest(req)
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-29 23:07:19 +02:00
|
|
|
if _, ok := req.Header["Accept"]; !ok {
|
2020-04-29 02:57:18 +02:00
|
|
|
req.Header.Set("Accept", "*/*")
|
|
|
|
|
}
|
2020-04-29 23:07:19 +02:00
|
|
|
if _, ok := req.Header["Accept-Language"]; !ok {
|
2020-04-29 02:57:18 +02:00
|
|
|
req.Header.Set("Accept-Language", "en")
|
2020-04-28 23:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-29 02:57:18 +02:00
|
|
|
return retryablehttp.FromRequest(req)
|
2020-04-28 23:02:07 +02:00
|
|
|
}
|
2020-05-05 21:42:28 +02:00
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
type HttpRequest struct {
|
2020-05-05 21:42:28 +02:00
|
|
|
Request *retryablehttp.Request
|
2020-05-14 18:09:36 +02:00
|
|
|
Meta map[string]interface{}
|
2020-05-05 21:42:28 +02:00
|
|
|
}
|
2020-05-22 00:23:38 +02:00
|
|
|
|
|
|
|
|
// CustomHeaders valid for all requests
|
|
|
|
|
type CustomHeaders []string
|
|
|
|
|
|
|
|
|
|
// String returns just a label
|
|
|
|
|
func (c *CustomHeaders) String() string {
|
|
|
|
|
return "Custom Global Headers"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set a new global header
|
|
|
|
|
func (c *CustomHeaders) Set(value string) error {
|
|
|
|
|
*c = append(*c, value)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2020-06-29 19:50:11 +05:30
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
type RawRequest struct {
|
2020-07-04 14:34:41 +07:00
|
|
|
FullURL string
|
2020-06-29 19:50:11 +05:30
|
|
|
Method string
|
|
|
|
|
Path string
|
|
|
|
|
Data string
|
|
|
|
|
Headers map[string]string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// parseRawRequest parses the raw request as supplied by the user
|
2020-07-18 21:42:23 +02:00
|
|
|
func (r *BulkHTTPRequest) parseRawRequest(request string, baseURL string) (*RawRequest, error) {
|
2020-06-29 19:50:11 +05:30
|
|
|
reader := bufio.NewReader(strings.NewReader(request))
|
|
|
|
|
|
2020-07-18 21:42:23 +02:00
|
|
|
rawRequest := RawRequest{
|
2020-06-29 19:50:11 +05:30
|
|
|
Headers: make(map[string]string),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s, err := reader.ReadString('\n')
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("could not read request: %s", err)
|
|
|
|
|
}
|
|
|
|
|
parts := strings.Split(s, " ")
|
|
|
|
|
if len(parts) < 3 {
|
|
|
|
|
return nil, fmt.Errorf("malformed request supplied")
|
|
|
|
|
}
|
|
|
|
|
// Set the request Method
|
|
|
|
|
rawRequest.Method = parts[0]
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
line, err := reader.ReadString('\n')
|
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
|
|
|
|
|
|
if err != nil || line == "" {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p := strings.SplitN(line, ":", 2)
|
|
|
|
|
if len(p) != 2 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if strings.EqualFold(p[0], "content-length") {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rawRequest.Headers[strings.TrimSpace(p[0])] = strings.TrimSpace(p[1])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handle case with the full http url in path. In that case,
|
|
|
|
|
// ignore any host header that we encounter and use the path as request URL
|
|
|
|
|
if strings.HasPrefix(parts[1], "http") {
|
|
|
|
|
parsed, err := url.Parse(parts[1])
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("could not parse request URL: %s", err)
|
|
|
|
|
}
|
|
|
|
|
rawRequest.Path = parts[1]
|
|
|
|
|
rawRequest.Headers["Host"] = parsed.Host
|
|
|
|
|
} else {
|
|
|
|
|
rawRequest.Path = parts[1]
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-04 14:34:41 +07:00
|
|
|
// If raw request doesn't have a Host header and/ path,
|
|
|
|
|
// this will be generated from the parsed baseURL
|
|
|
|
|
parsedURL, err := url.Parse(baseURL)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("could not parse request URL: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var hostURL string
|
|
|
|
|
if len(rawRequest.Headers["Host"]) == 0 {
|
|
|
|
|
hostURL = parsedURL.Host
|
|
|
|
|
} else {
|
|
|
|
|
hostURL = rawRequest.Headers["Host"]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(rawRequest.Path) == 0 {
|
|
|
|
|
rawRequest.Path = parsedURL.Path
|
|
|
|
|
} else {
|
|
|
|
|
// requests generated from http.ReadRequest have incorrect RequestURI, so they
|
|
|
|
|
// cannot be used to perform another request directly, we need to generate a new one
|
|
|
|
|
// with the new target url
|
|
|
|
|
if strings.HasPrefix(rawRequest.Path, "?") {
|
|
|
|
|
rawRequest.Path = fmt.Sprintf("%s%s", parsedURL.Path, rawRequest.Path)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rawRequest.FullURL = fmt.Sprintf("%s://%s%s", parsedURL.Scheme, hostURL, rawRequest.Path)
|
|
|
|
|
|
2020-06-29 19:50:11 +05:30
|
|
|
// Set the request body
|
|
|
|
|
b, err := ioutil.ReadAll(reader)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("could not read request body: %s", err)
|
|
|
|
|
}
|
|
|
|
|
rawRequest.Data = string(b)
|
|
|
|
|
return &rawRequest, nil
|
|
|
|
|
}
|
2020-07-18 21:42:23 +02:00
|
|
|
|
|
|
|
|
func (r *BulkHTTPRequest) Next() bool {
|
|
|
|
|
if r.positionPath+r.positionRaw >= len(r.Path)+len(r.Raw) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
func (r *BulkHTTPRequest) Position() int {
|
|
|
|
|
return r.positionPath + r.positionRaw
|
|
|
|
|
}
|
|
|
|
|
func (r *BulkHTTPRequest) Reset() {
|
|
|
|
|
r.positionPath = 0
|
|
|
|
|
r.positionRaw = 0
|
|
|
|
|
}
|
|
|
|
|
func (r *BulkHTTPRequest) Current() string {
|
|
|
|
|
if r.positionPath <= len(r.Path) && len(r.Path) != 0 && r.positionRaw == 0 {
|
|
|
|
|
return r.Path[r.positionPath]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r.Raw[r.positionRaw]
|
|
|
|
|
}
|
|
|
|
|
func (r *BulkHTTPRequest) Total() int {
|
|
|
|
|
return len(r.Path) + len(r.Raw)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *BulkHTTPRequest) Increment() int {
|
|
|
|
|
if r.positionPath <= len(r.Path) && len(r.Path) != 0 && r.positionRaw == 0 {
|
|
|
|
|
r.positionPath++
|
|
|
|
|
return r.positionPath
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if we have payloads increment only when the generators are done
|
|
|
|
|
if r.generator == nil {
|
|
|
|
|
r.positionRaw++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r.positionPath + r.positionRaw
|
|
|
|
|
}
|