From 8bf9dffe0f1c944193cc8b2264cfa32eadd06c8b Mon Sep 17 00:00:00 2001 From: Dominic Breuker Date: Thu, 21 Jul 2022 21:07:39 +0200 Subject: [PATCH 1/3] add support for custom HTTP response headers --- internal/runner/options.go | 62 ++++++++++++++++++++++++----------- internal/runner/runner.go | 1 + pkg/httpserver/headerlayer.go | 20 +++++++++++ pkg/httpserver/httpserver.go | 2 ++ 4 files changed, 65 insertions(+), 20 deletions(-) create mode 100644 pkg/httpserver/headerlayer.go diff --git a/internal/runner/options.go b/internal/runner/options.go index 5086d8a..8a96c3d 100644 --- a/internal/runner/options.go +++ b/internal/runner/options.go @@ -2,37 +2,40 @@ package runner import ( "flag" + "fmt" "os" "path/filepath" "strings" "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger/levels" + "github.com/projectdiscovery/simplehttpserver/pkg/httpserver" ) // Options of the tool type Options struct { - ListenAddress string - Folder string - BasicAuth string - username string - password string - Realm string - TLSCertificate string - TLSKey string - TLSDomain string - HTTPS bool - Verbose bool - EnableUpload bool - EnableTCP bool - RulesFile string - TCPWithTLS bool - Version bool - Silent bool - Sandbox bool - MaxFileSize int - HTTP1Only bool + ListenAddress string + Folder string + BasicAuth string + username string + password string + Realm string + TLSCertificate string + TLSKey string + TLSDomain string + HTTPS bool + Verbose bool + EnableUpload bool + EnableTCP bool + RulesFile string + TCPWithTLS bool + Version bool + Silent bool + Sandbox bool + MaxFileSize int + HTTP1Only bool MaxDumpBodySize int + HTTPHeaders HTTPHeaders } // ParseOptions parses the command line options for application @@ -61,6 +64,7 @@ func ParseOptions() *Options { flag.BoolVar(&options.HTTP1Only, "http1", false, "Enable only HTTP1") flag.IntVar(&options.MaxFileSize, "max-file-size", 50, "Max Upload File Size") flag.IntVar(&options.MaxDumpBodySize, "max-dump-body-size", -1, "Max Dump Body Size") + flag.Var(&options.HTTPHeaders, "header", "Add HTTP Response Header (name: value), can be used multiple times") flag.Parse() // Read the inputs and configure the logging @@ -113,3 +117,21 @@ func (options *Options) FolderAbsPath() string { } return abspath } + +// HTTPHeaders is a slice of HTTPHeader structs +type HTTPHeaders []httpserver.HTTPHeader + +func (h *HTTPHeaders) String() string { + return fmt.Sprint(*h) +} + +// Set sets a new header, which must be a string of the form 'name: value' +func (h *HTTPHeaders) Set(value string) error { + tokens := strings.SplitN(value, ":", 2) + if len(tokens) != 2 { + return fmt.Errorf("header '%s' not in format 'name: value'", value) + } + + *h = append(*h, httpserver.HTTPHeader{Name: tokens[0], Value: tokens[1]}) + return nil +} diff --git a/internal/runner/runner.go b/internal/runner/runner.go index 59c28e3..de0c266 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -68,6 +68,7 @@ func New(options *Options) (*Runner, error) { MaxFileSize: r.options.MaxFileSize, HTTP1Only: r.options.HTTP1Only, MaxDumpBodySize: unit.ToMb(r.options.MaxDumpBodySize), + HTTPHeaders: r.options.HTTPHeaders, }) if err != nil { return nil, err diff --git a/pkg/httpserver/headerlayer.go b/pkg/httpserver/headerlayer.go new file mode 100644 index 0000000..0a0dac7 --- /dev/null +++ b/pkg/httpserver/headerlayer.go @@ -0,0 +1,20 @@ +package httpserver + +import ( + "net/http" +) + +// HTTPHeader represents an HTTP header +type HTTPHeader struct { + Name string + Value string +} + +func (t *HTTPServer) headerlayer(handler http.Handler, headers []HTTPHeader) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + for _, header := range headers { + w.Header().Set(header.Name, header.Value) + } + handler.ServeHTTP(w, r) + }) +} diff --git a/pkg/httpserver/httpserver.go b/pkg/httpserver/httpserver.go index 94c050e..a41e9eb 100644 --- a/pkg/httpserver/httpserver.go +++ b/pkg/httpserver/httpserver.go @@ -27,6 +27,7 @@ type Options struct { HTTP1Only bool MaxFileSize int // 50Mb MaxDumpBodySize int64 + HTTPHeaders []HTTPHeader } // HTTPServer instance @@ -72,6 +73,7 @@ func New(options *Options) (*HTTPServer, error) { } httpHandler = h.loglayer(httpHandler) + httpHandler = h.headerlayer(httpHandler, options.HTTPHeaders) // add handler h.layers = httpHandler From bbc02b0af3084b3ceefa993ee0fcb5fac1469c9a Mon Sep 17 00:00:00 2001 From: Dominic Breuker Date: Thu, 21 Jul 2022 21:25:55 +0200 Subject: [PATCH 2/3] update flag list in readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0363d59..b2e69a9 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ This will display help for the tool. Here are all the switches it supports. | `-realm` | Basic auth message | `simplehttpserver -realm "insert the credentials"` | | `-version` | Show version | `simplehttpserver -version` | | `-silent` | Show only results | `simplehttpserver -silent` | +| `-header` | dd HTTP Response Header (can be used multiple times) | `simplehttpserver -header 'X-Powered-By: Go'` | ### Running simplehttpserver in the current folder From b8349e98ab9e94a1a2a1b58d7340cc116b357a8d Mon Sep 17 00:00:00 2001 From: Dominic Breuker Date: Fri, 22 Jul 2022 21:05:46 +0200 Subject: [PATCH 3/3] fix readme typo and adjust cases of words --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b2e69a9..bea47b3 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ This will display help for the tool. Here are all the switches it supports. | `-realm` | Basic auth message | `simplehttpserver -realm "insert the credentials"` | | `-version` | Show version | `simplehttpserver -version` | | `-silent` | Show only results | `simplehttpserver -silent` | -| `-header` | dd HTTP Response Header (can be used multiple times) | `simplehttpserver -header 'X-Powered-By: Go'` | +| `-header` | HTTP response header (can be used multiple times) | `simplehttpserver -header 'X-Powered-By: Go'` | ### Running simplehttpserver in the current folder