2020-05-29 12:37:55 +03:00
|
|
|
package httputilz
|
|
|
|
|
|
|
|
import (
|
2020-08-23 21:42:20 +03:00
|
|
|
"bufio"
|
2020-06-23 20:14:39 +03:00
|
|
|
"fmt"
|
2022-08-17 02:16:06 +03:00
|
|
|
"io"
|
2020-05-29 12:37:55 +03:00
|
|
|
"net/http/httputil"
|
2020-08-23 21:42:20 +03:00
|
|
|
"strings"
|
2020-05-29 12:37:55 +03:00
|
|
|
|
|
|
|
"github.com/projectdiscovery/retryablehttp-go"
|
2021-05-24 14:15:24 +03:00
|
|
|
"github.com/projectdiscovery/urlutil"
|
2020-05-29 12:37:55 +03:00
|
|
|
)
|
|
|
|
|
2020-09-26 20:56:17 +03:00
|
|
|
const (
|
2020-09-26 21:42:32 +03:00
|
|
|
headerParts = 2
|
2020-09-26 20:56:17 +03:00
|
|
|
requestParts = 3
|
|
|
|
)
|
|
|
|
|
2020-05-29 12:37:55 +03:00
|
|
|
// DumpRequest to string
|
|
|
|
func DumpRequest(req *retryablehttp.Request) (string, error) {
|
|
|
|
dump, err := httputil.DumpRequestOut(req.Request, true)
|
|
|
|
|
|
|
|
return string(dump), err
|
|
|
|
}
|
2020-06-23 20:14:39 +03:00
|
|
|
|
2020-08-23 21:42:20 +03:00
|
|
|
// ParseRequest from raw string
|
2020-09-29 23:07:50 +03:00
|
|
|
func ParseRequest(req string, unsafe bool) (method, path string, headers map[string]string, body string, err error) {
|
2020-08-23 21:42:20 +03:00
|
|
|
headers = make(map[string]string)
|
|
|
|
reader := bufio.NewReader(strings.NewReader(req))
|
|
|
|
s, err := reader.ReadString('\n')
|
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("could not read request: %s", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
parts := strings.Split(s, " ")
|
2020-09-26 20:56:17 +03:00
|
|
|
if len(parts) < requestParts {
|
2020-08-23 21:42:20 +03:00
|
|
|
err = fmt.Errorf("malformed request supplied")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
method = parts[0]
|
|
|
|
|
|
|
|
for {
|
2020-09-25 18:54:10 +03:00
|
|
|
line, readErr := reader.ReadString('\n')
|
2020-08-23 21:42:20 +03:00
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
|
2020-09-25 18:54:10 +03:00
|
|
|
if readErr != nil || line == "" {
|
2020-08-23 21:42:20 +03:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:07:50 +03:00
|
|
|
// Unsafe skips all checks
|
2020-09-26 20:56:17 +03:00
|
|
|
p := strings.SplitN(line, ":", headerParts)
|
2020-09-29 23:07:50 +03:00
|
|
|
key := p[0]
|
|
|
|
value := ""
|
|
|
|
if len(p) == headerParts {
|
|
|
|
value = p[1]
|
2020-08-23 21:42:20 +03:00
|
|
|
}
|
|
|
|
|
2020-09-29 23:07:50 +03:00
|
|
|
if !unsafe {
|
|
|
|
if len(p) != headerParts {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.EqualFold(key, "content-length") {
|
|
|
|
continue
|
|
|
|
}
|
2020-08-23 21:42:20 +03:00
|
|
|
|
2020-09-29 23:07:50 +03:00
|
|
|
key = strings.TrimSpace(key)
|
|
|
|
value = strings.TrimSpace(value)
|
|
|
|
}
|
2020-08-23 21:42:20 +03:00
|
|
|
|
2020-09-29 23:07:50 +03:00
|
|
|
headers[key] = value
|
2020-08-23 21:42:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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") {
|
2021-05-24 14:15:24 +03:00
|
|
|
var parsed *urlutil.URL
|
|
|
|
parsed, err = urlutil.Parse(parts[1])
|
2020-08-23 21:42:20 +03:00
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("could not parse request URL: %s", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
path = parts[1]
|
|
|
|
headers["Host"] = parsed.Host
|
|
|
|
} else {
|
|
|
|
path = parts[1]
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the request body
|
2022-08-17 02:16:06 +03:00
|
|
|
b, err := io.ReadAll(reader)
|
2020-08-23 21:42:20 +03:00
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("could not read request body: %s", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
body = string(b)
|
2020-09-25 19:43:13 +03:00
|
|
|
|
|
|
|
return method, path, headers, body, nil
|
2020-08-23 21:42:20 +03:00
|
|
|
}
|