Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions pkg/input/types/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ func (rr *RequestResponse) Clone() *RequestResponse {
// BuildRequest builds a retryablehttp request from the request response
func (rr *RequestResponse) BuildRequest() (*retryablehttp.Request, error) {
rr.once.Do(func() {
// Request is optional: UnmarshalJSON only populates it when a "request"
// key is present, so an entry carrying just a "url" leaves it nil.
// Dereferencing it below would panic with a nil pointer instead of
// surfacing a usable error, taking the whole scan down.
if rr.Request == nil {
rr.reqErr = fmt.Errorf("could not create request: no request in request response")
return
}
urlx := rr.URL.Clone()
var body io.Reader = nil
if rr.Request.Body != "" {
Expand Down
31 changes: 31 additions & 0 deletions pkg/input/types/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,34 @@ func TestUnmarshalJSON(t *testing.T) {
})
}
}

// BuildRequest used to dereference rr.Request unconditionally. Request is
// optional — UnmarshalJSON only sets it when a "request" key is present — so an
// entry carrying just a "url" (see TestUnmarshalJSON above, which relies on
// exactly that shape) panicked with a nil pointer dereference instead of
// returning an error, taking down the caller in pkg/protocols/http/request_fuzz.go.
func TestBuildRequestWithoutRequest(t *testing.T) {
var rr RequestResponse
err := rr.UnmarshalJSON([]byte(`{"url": "https://example.com/path"}`))
require.NoError(t, err)
require.Nil(t, rr.Request)

require.NotPanics(t, func() {
req, err := rr.BuildRequest()
require.Error(t, err)
require.Nil(t, req)
})
}

// Guard rail: a request response that does carry a request must still build
// normally, so the nil check above can't be satisfied by refusing everything.
func TestBuildRequestWithRequestStillWorks(t *testing.T) {
rr, err := ParseRawRequest("GET /path HTTP/1.1\r\nHost: example.com\r\n\r\n")
require.NoError(t, err)
require.NotNil(t, rr.Request)

req, err := rr.BuildRequest()
require.NoError(t, err)
require.NotNil(t, req)
require.Equal(t, "GET", req.Method)
}
Loading