mirror of
https://github.com/projectdiscovery/httpx
synced 2026-06-08 16:50:17 +00:00
72 lines
1.6 KiB
Go
72 lines
1.6 KiB
Go
package httpx
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
stringsutil "github.com/projectdiscovery/utils/strings"
|
|
)
|
|
|
|
// SupportPipeline checks if the target host supports HTTP1.1 pipelining by sending x probes
|
|
// and reading back responses expecting at least 2 with HTTP/1.1 or HTTP/1.0
|
|
func (h *HTTPX) SupportPipeline(protocol, method, host string, port int) bool {
|
|
addr := host
|
|
if port == 0 {
|
|
port = 80
|
|
if protocol == "https" {
|
|
port = 443
|
|
}
|
|
}
|
|
if _, _, err := net.SplitHostPort(host); err != nil && port > 0 {
|
|
addr = fmt.Sprintf("%s:%d", host, port)
|
|
}
|
|
// dummy method while awaiting for full rawhttp implementation
|
|
dummyReq := fmt.Sprintf("%s / HTTP/1.1\nHost: %s\n\n", method, addr)
|
|
conn, err := pipelineDial(protocol, addr)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
// send some probes
|
|
nprobes := 10
|
|
for i := 0; i < nprobes; i++ {
|
|
if _, err = conn.Write([]byte(dummyReq)); err != nil {
|
|
return false
|
|
}
|
|
}
|
|
gotReplies := 0
|
|
reply := make([]byte, 1024)
|
|
for i := 0; i < nprobes; i++ {
|
|
err := conn.SetReadDeadline(time.Now().Add(1 * time.Second))
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
if _, err := conn.Read(reply); err != nil {
|
|
break
|
|
}
|
|
|
|
// The check is very naive, but it works most of the times
|
|
for _, s := range strings.Split(string(reply), "\n\n") {
|
|
if stringsutil.ContainsAnyI(s, "HTTP/1.1", "HTTP/1.0") {
|
|
gotReplies++
|
|
}
|
|
}
|
|
}
|
|
|
|
// expect at least 2 replies
|
|
return gotReplies >= 2 //nolint
|
|
}
|
|
|
|
func pipelineDial(protocol, addr string) (net.Conn, error) {
|
|
// http
|
|
if protocol == "http" {
|
|
return net.Dial("tcp", addr)
|
|
}
|
|
|
|
// https
|
|
return tls.Dial("tcp", addr, &tls.Config{InsecureSkipVerify: true})
|
|
}
|