Skip to content

feat: Add auto-referer (HTTP header) option - #2245

Merged
Mzack9999 merged 5 commits into
projectdiscovery:devfrom
siamak-amo:auto-referer
Aug 28, 2025
Merged

Mzack9999 merged 5 commits into
projectdiscovery:devfrom
siamak-amo:auto-referer

Conversation

@siamak-amo

@siamak-amo siamak-amo commented Aug 21, 2025

Copy link
Copy Markdown
Contributor

httpx produces better results when the Referer header is set. However, when using stdin, there is currently no built-in way to set the Referer header based on the current URL.

Normally, we achieve this by using a shell while loop:
cat links | while read url; do httpx -H "Referer: $url"; done
This approach is inefficient, as it requires running httpx many times, and also using -threads is not possible.

This feature introduces the -auto-referer option, which eliminates the need for a while loop;
Users can now simply execute: cat links | httpx -auto-referer.

Summary by CodeRabbit

  • New Features

    • Optional Auto-Referer that can auto-set Referer to the current request URL; new CLI flag to toggle (default off). Explicit Referer headers take precedence.
  • Documentation

    • README updated with the new Auto-Referer configuration option.
  • Refactor

    • Internal request URL handling and favicon/request-dump behavior adjusted; minor string/allocation optimizations.
  • Chores

    • Cleanup: many deferred closes and return values now explicitly ignore errors; test handlers updated to discard unused returns.

The option -auto-referer, sets the referer HTTP header
of the current request to it's URL.
@coderabbitai

coderabbitai Bot commented Aug 21, 2025

Copy link
Copy Markdown

Walkthrough

Adds an AutoReferer option (CLI and internal) and logic to auto-populate Referer from the current request string when enabled; also makes widespread error-ignoring defer changes, replaces some string/URL accessors with request.String()/req.Path/req.Params, swaps errorutil→errkit, and small string API modernizations.

Changes

Cohort / File(s) Summary
AutoReferer option & HTTPX behavior
common/httpx/option.go, common/httpx/httpx.go
Adds Options.AutoReferer bool. When AutoReferer is true and no explicit Referer header exists, code sets Referer using the request's String() representation before sending.
Runner CLI & wiring
runner/options.go, runner/runner.go
Exposes Options.AutoReferer and --auto-referer flag; Runner.New passes AutoReferer into httpx options but forces it false when an explicit Referer: is present in CustomHeaders.
Defer/error-consumption and formatting refactors
runner/runner.go, cmd/functional-test/main.go, cmd/integration-test/*.go, cmd/integration-test/library.go, examples/speed_control/main.go, runner/headless.go, runner/healthcheck.go, common/httpx/httpx.go, internal/pdcp/writer.go, common/customports/customport.go, internal/pdcp/*.go
Replaces many defer foo.Close() with defer func() { _ = foo.Close() }(), discards some Close() errors, replaces some fmt.Sprintf with fmt.Fprintf to builders, and updates newline replacement to strings.ReplaceAll. Minor error-message casing changes in custom ports.
Request/URL accessor updates
runner/runner.go, internal/pdcp/writer.go, common/httpx/httpx.go
Several callsites switched from req.URL.* to req.* (e.g., req.String(), req.Path, req.Params, req.Update()), and favicon/request-dump flows now use req.String()/req.Path.
Error wrapping library swap
internal/pdcp/writer.go
Replaces errorutil usage with errkit (errkit.Wrap / errkit.Wrapf) for error wrapping.
Docs
README.md
Documents the new -auto-referer configuration option.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant CLI as CLI
  participant Runner as Runner.New
  participant HTTPX as HTTPX Layer
  participant Request as Request Builder
  participant Server as Remote

  CLI->>Runner: parse flags (--auto-referer)
  Runner->>HTTPX: httpxOptions.AutoReferer = options.AutoReferer
  alt CustomHeaders contains "Referer:"
    Runner->>HTTPX: httpxOptions.AutoReferer = false
    note right of HTTPX #D3E4CD: explicit Referer disables auto
  end

  Request->>HTTPX: build request (headers)
  alt httpxOptions.AutoReferer == true AND header "Referer" empty
    HTTPX->>Request: set "Referer" = req.String()
    note right of Request #FCE1D6: uses req.String() (full request)
  else
    note right of Request #E8F0FE: keep explicit Referer or none
  end

  Request->>Server: send HTTP request
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • ehsandeep

Poem

I twitch my whiskers at headers fair,
A Referer springs from current air—
If you set it first, I step aside,
Else I tuck your URL where headers hide.
Hop, flag, and patch — a quiet guide. 🐇

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbit in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbit in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbit gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbit read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbit ignore or @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbit summary or @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbit or @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
common/httpx/option.go (1)

14-16: Add field doc and confirm default behavior

AutoReferer addition looks fine and defaults to false via DefaultOptions. Consider adding a short doc comment (e.g., “AutoReferer sets the Referer header to the current request URL when not explicitly provided”) to keep exported API self-explanatory.

runner/options.go (1)

488-489: Clarify flag behavior in help text

Minor: consider clarifying that an explicitly provided Referer header disables/overrides auto behavior, e.g., “set the Referer header to the current URL (ignored if Referer is explicitly provided)”.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5f55bfa and f0e464f.

📒 Files selected for processing (4)
  • common/httpx/httpx.go (1 hunks)
  • common/httpx/option.go (1 hunks)
  • runner/options.go (2 hunks)
  • runner/runner.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
common/httpx/httpx.go (1)
common/httpx/option.go (1)
  • Options (13-57)
runner/runner.go (1)
common/customheader/customheader.go (1)
  • CustomHeaders (10-10)
🔇 Additional comments (2)
runner/options.go (1)

264-265: Struct surface looks good; keep CLI/API parity

Exposing AutoReferer on runner.Options mirrors common/httpx.Options. No concerns.

runner/runner.go (1)

171-175: Ensure any explicit Referer header disables AutoReferer

The current check in runner/runner.go only looks for CLI‐provided headers via options.CustomHeaders.Has("Referer:"), so headers injected through the raw-request flag (-rr) won’t be detected here. In that case, httpxOptions.AutoReferer remains set to options.AutoReferer and the default auto-referer logic in common/httpx/httpx.go will still overwrite the user’s Referer (via r.Header.Set("Referer", …)).

Instead of a one-off guard in the runner, delegate this entirely to the centralized hook in common/httpx/httpx.go (see the SetCustomHeaders logic) so that any Referer—no matter the source—is honored. This avoids scattered special-cases and ensures the auto-referer behavior is consistently disabled whenever a Referer header is already present.

Additionally, confirm that CustomHeaders.Has(...) does a case-insensitive match on the header name (e.g. “referer:”) so “referer:” isn’t missed.

– runner/runner.go, lines 171–175
– common/httpx/httpx.go: use SetCustomHeaders guard to disable auto-referer centrally
– Verify CustomHeaders.Has is case-insensitive for header names

Comment thread common/httpx/httpx.go Outdated
@Mzack9999
Mzack9999 self-requested a review August 27, 2025 18:01

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
common/customports/customport.go (2)

63-69: Protocol merge bugs: narrows existing HTTP+HTTPS and leaks across range loop.

  • If a port is already HTTP+HTTPS, new single-protocol input overwrites it to narrower.
  • In ranges, mutating protocol makes all ports after the first conflict become HTTP+HTTPS even when not needed.
-			if existingProtocol, ok := Ports[p]; ok {
-				if existingProtocol == httpx.HTTP && protocol == httpx.HTTPS || existingProtocol == httpx.HTTPS && protocol == httpx.HTTP {
-					protocol = httpx.HTTPandHTTPS
-				}
-			}
-			Ports[p] = protocol
+			if existingProtocol, ok := Ports[p]; ok {
+				if existingProtocol == httpx.HTTPandHTTPS || protocol == httpx.HTTPandHTTPS ||
+					(existingProtocol == httpx.HTTP && protocol == httpx.HTTPS) ||
+					(existingProtocol == httpx.HTTPS && protocol == httpx.HTTP) {
+					Ports[p] = httpx.HTTPandHTTPS
+				} else {
+					// same protocol: preserve existing to avoid churn
+					Ports[p] = existingProtocol
+				}
+			} else {
+				Ports[p] = protocol
+			}
-			for i := lowP; i <= highP; i++ {
-				if existingProtocol, ok := Ports[i]; ok {
-					if existingProtocol == httpx.HTTP && protocol == httpx.HTTPS || existingProtocol == httpx.HTTPS && protocol == httpx.HTTP {
-						protocol = httpx.HTTPandHTTPS
-					}
-				}
-				Ports[i] = protocol
-			}
+			for i := lowP; i <= highP; i++ {
+				finalProtocol := protocol
+				if existingProtocol, ok := Ports[i]; ok {
+					if existingProtocol == httpx.HTTPandHTTPS || finalProtocol == httpx.HTTPandHTTPS ||
+						(existingProtocol == httpx.HTTP && finalProtocol == httpx.HTTPS) ||
+						(existingProtocol == httpx.HTTPS && finalProtocol == httpx.HTTP) {
+						finalProtocol = httpx.HTTPandHTTPS
+					} else {
+						// same protocol: keep existing
+						finalProtocol = existingProtocol
+					}
+				}
+				Ports[i] = finalProtocol
+			}

Also applies to: 90-97


105-110: Reject invalid ports <= 0.

Acceptable ports are 1..65535; current check lets 0/-1 through.

 func checkPortValue(port int) error {
-	if port > 65535 {
-		return errors.New("port value is bigger than 65535")
+	if port < 1 || port > 65535 {
+		return errors.New("port value must be between 1 and 65535")
 	}
 	return nil
 }
internal/pdcp/writer.go (1)

173-181: Bug: record dropped when buffer boundary is crossed.

When buff.Len()+len(line) > MaxChunkSize, the current line is not written after flushing.

Apply this diff:

-      if buff.Len()+len(line) > MaxChunkSize {
-        // flush existing buffer
-        if err := u.uploadChunk(buff); err != nil {
-          gologger.Error().Msgf("Failed to upload asset results on cloud: %v", err)
-        }
-      } else {
-        buff.WriteString(line)
-        buff.WriteString("\n")
-      }
+      if buff.Len()+len(line) > MaxChunkSize {
+        // flush existing buffer
+        if err := u.uploadChunk(buff); err != nil {
+          gologger.Error().Msgf("Failed to upload asset results on cloud: %v", err)
+        }
+      }
+      // write current line (either to emptied buffer or existing one)
+      buff.WriteString(line)
+      buff.WriteString("\n")
🧹 Nitpick comments (12)
common/customports/customport.go (3)

86-88: Clarify the constraint to reflect the actual check (<= allowed).

The code allows equal endpoints; update message accordingly.

-				return fmt.Errorf("first value of port range should be lower than the last port from your range: [%d, %d]", lowP, highP)
+				return fmt.Errorf("first port must be <= last port: [%d, %d]", lowP, highP)

53-56: Guard against malformed inputs with more than one dash.

Limit split to two parts.

-		potentialRange := strings.Split(potentialPort, "-")
+		potentialRange := strings.SplitN(potentialPort, "-", portRangeParts)

56-59: Standardize error casing and remove stray newline.

Align with the lowercase style adopted elsewhere.

-			if err != nil {
-				return errors.Wrap(err, fmt.Sprintf("Could not cast port to integer from your value: %s\n", potentialPort))
-			}
+			if err != nil {
+				return errors.Wrap(err, fmt.Sprintf("could not cast port to integer from your value: %s", potentialPort))
+			}
-			if err != nil {
-				return errors.Wrap(err, fmt.Sprintf("Could not cast first port of your range(%s) to integer from your value: %s", potentialPort, potentialRange[0]))
-			}
+			if err != nil {
+				return errors.Wrap(err, fmt.Sprintf("could not cast first port of your range(%s) to integer from your value: %s", potentialPort, potentialRange[0]))
+			}

Also applies to: 71-76

cmd/functional-test/main.go (1)

44-46: Explicitly ignoring Close error is fine here; consider centralizing the pattern.

LGTM for tests. If this pattern repeats across the repo, a tiny helper (e.g., closeSilently(io.Closer)) can reduce repetition.

runner/headless.go (1)

147-149: Silent cleanup is acceptable; optional: debug-log failures.

If troubleshooting flaky headless runs, logging Close/RemoveAll errors at debug level could help.

internal/pdcp/writer.go (2)

233-241: Mutable shared URL can be a future data race; copy before mutation.

getRequest mutates u.uploadURL.Path. It’s fine with the current single goroutine, but future concurrent use would race. Prefer copying to a local url.URL before setting Path and building the request URL.


194-195: Log level: consider Info instead of Warning.

"Uploaded results chunk" is not a warning condition; Info/Verbose would be more appropriate.

runner/runner.go (5)

42-42: Avoid blanket nolint on import; scope it or drop it.

//nolint at import level hides all linter classes. If needed, target the specific linter(s) and add a short rationale; otherwise remove it.


127-130: Don’t silently ignore RemoveAll errors.

Failures here (permission, ENOENT races, RO FS) are useful for diagnostics. Log at debug and continue.

-        _ = os.RemoveAll(filepath.Join(options.StoreResponseDir, "response", "index.txt"))
-        _ = os.RemoveAll(filepath.Join(options.StoreResponseDir, "screenshot", "index_screenshot.txt"))
+        if err := os.RemoveAll(filepath.Join(options.StoreResponseDir, "response", "index.txt")); err != nil {
+                gologger.Debug().Msgf("cleanup response index failed: %v", err)
+        }
+        if err := os.RemoveAll(filepath.Join(options.StoreResponseDir, "screenshot", "index_screenshot.txt")); err != nil {
+                gologger.Debug().Msgf("cleanup screenshot index failed: %v", err)
+        }

1114-1115: Body stripping by substring risks accidental header mutation.

strings.ReplaceAll(resp.Raw, resp.ResponseBody, "") may remove identical byte sequences outside the body. Prefer slicing raw at the known header/body boundary (e.g., split on \r\n\r\n once) or use the library’s structured fields.


2087-2087: Remove stray //nolint on local variable.

outputHashes is used below; the suppression isn’t needed and hides real issues.

-        outputHashes := !(r.options.JSONOutput || r.options.OutputAll) //nolint
+        outputHashes := !(r.options.JSONOutput || r.options.OutputAll)

2397-2406: Base URL derivation: prefer urlutil.ParseURL for consistency with unsafe parsing.

Minor, but using the project’s parser avoids divergence with Unsafe mode and IDNA handling.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 281ed16 and 2b688a5.

📒 Files selected for processing (10)
  • cmd/functional-test/main.go (1 hunks)
  • cmd/integration-test/http.go (12 hunks)
  • cmd/integration-test/library.go (2 hunks)
  • common/customports/customport.go (1 hunks)
  • common/httpx/httpx.go (4 hunks)
  • examples/speed_control/main.go (1 hunks)
  • internal/pdcp/writer.go (5 hunks)
  • runner/headless.go (2 hunks)
  • runner/healthcheck.go (2 hunks)
  • runner/runner.go (25 hunks)
✅ Files skipped from review due to trivial changes (3)
  • examples/speed_control/main.go
  • runner/healthcheck.go
  • cmd/integration-test/library.go
🔇 Additional comments (14)
common/customports/customport.go (1)

80-81: Lowercased error string — LGTM.

Matches Go style for error messages.

runner/headless.go (1)

118-120: OK to discard page.Close error on deferred cleanup.

Matches the repo-wide convention introduced in this PR.

cmd/integration-test/http.go (1)

52-52: OK to discard write errors in test handlers.

These are test-only responses; explicit ignores keep handlers concise without affecting assertions.

Also applies to: 104-104, 167-167, 195-195, 218-218, 242-242, 269-269, 294-294, 318-318, 345-345, 369-369, 394-394

internal/pdcp/writer.go (3)

21-21: errkit migration acknowledged.

Import switch to errkit is consistent with the PR-wide error-handling refactor.


74-75: Good: wrap parse errors with context.

The error now carries actionable context.


189-190: Consistent error wrapping and cleanup behavior.

Wrapping improves diagnosability; ignoring resp.Body.Close error is appropriate in this path.

Also applies to: 201-202, 205-206, 212-213, 219-220

common/httpx/httpx.go (3)

158-160: Ignoring Setenv error is acceptable.

Matches the intended behavior of forcing http/1.1 without surfacing env errors.


363-366: Using req.String() for the unsafe target is correct.

Ensures path/params mutations are reflected in raw execution.


454-455: ReplaceAll is fine.

Minor readability improvement; equivalent behavior.

runner/runner.go (5)

1665-1669: Verify DumpRequestRaw URL argument change.

Switching to req.String() (vs req.URL.String()) may pass an absolute URL or include host overrides differently than expected by rawhttp. Confirm it still emits a valid start-line and host semantics in unsafe mode.


1688-1699: LGTM: Using req.String() to compute fullURL.

This correctly reflects custom Host/port tweaks before presentation.


1874-1875: LGTM: fmt.Fprintf to builder reduces allocs.

Good micro-optimization across status/headers/metrics blocks.

Also applies to: 1988-1989, 2014-2015, 2019-2019, 2023-2023, 2140-2141, 2151-2151, 2160-2160


2486-2486: LGTM: clone.String() for FaviconURL.

Accurately preserves any per-request header/URL tweaks.


171-175: I’ve searched for the CustomHeaders type and its Has method to confirm how header keys (including casing and colon) are handled. Let me know if you’d like me to inspect the raw‐request merge logic next.

Comment on lines 82 to 84
if err := checkPortValue(highP); err != nil {
return errors.Wrap(err, fmt.Sprintf("last port of your range(%d)", lowP))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Wrong variable in “last port” error context.

Message prints lowP instead of highP.

-				return errors.Wrap(err, fmt.Sprintf("last port of your range(%d)", lowP))
+				return errors.Wrap(err, fmt.Sprintf("last port of your range(%d)", highP))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if err := checkPortValue(highP); err != nil {
return errors.Wrap(err, fmt.Sprintf("last port of your range(%d)", lowP))
}
if err := checkPortValue(highP); err != nil {
return errors.Wrap(err, fmt.Sprintf("last port of your range(%d)", highP))
}
🤖 Prompt for AI Agents
In common/customports/customport.go around lines 82 to 84, the error wrap for
validating the upper bound prints the wrong variable (it uses lowP instead of
highP); update the fmt.Sprintf call to include highP so the error context
correctly identifies the last port value (e.g., change the wrapped message to
reference highP).

Comment thread common/httpx/httpx.go
Comment on lines +438 to +440
if h.Options.AutoReferer && r.Header.Get("Referer") == "" {
r.Header.Set("Referer", r.String())
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Sanitize Referer to avoid credential leakage.

If the URL contains userinfo (user:pass@host), setting it as Referer leaks credentials. Strip userinfo before setting.

Apply this diff:

-  if h.Options.AutoReferer && r.Header.Get("Referer") == "" {
-    r.Header.Set("Referer", r.String())
-  }
+  if h.Options.AutoReferer && r.Header.Get("Referer") == "" {
+    if u, perr := url.Parse(r.String()); perr == nil {
+      u.User = nil // drop potential credentials
+      r.Header.Set("Referer", u.String())
+    } else {
+      r.Header.Set("Referer", r.String())
+    }
+  }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In common/httpx/httpx.go around lines 438 to 440, the current code sets Referer
to r.String() which can leak credentials if the URL contains userinfo; change
the logic to construct a sanitized referer by cloning r.URL (or using a safe
representation), removing any userinfo (set User to nil), and then using the
sanitized URL string when calling r.Header.Set("Referer", ...). Keep the
existing AutoReferer and header-empty checks, and ensure the sanitized URL is
used so no user:pass@host is ever sent in the Referer header.

Comment thread internal/pdcp/writer.go
Comment on lines 214 to 216
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("could not upload results got status code %v on %v", resp.StatusCode, resp.Request.URL.String())
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Accept 201/202 for create/append responses.

Some endpoints return 201 Created (POST) or 202 Accepted. Current strict 200 check may misclassify success as error.

Apply this diff:

-  if resp.StatusCode != http.StatusOK {
+  if resp.StatusCode != http.StatusOK &&
+     resp.StatusCode != http.StatusCreated &&    // 201
+     resp.StatusCode != http.StatusAccepted {    // 202 (async)
     return fmt.Errorf("could not upload results got status code %v on %v", resp.StatusCode, resp.Request.URL.String())
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("could not upload results got status code %v on %v", resp.StatusCode, resp.Request.URL.String())
}
if resp.StatusCode != http.StatusOK &&
resp.StatusCode != http.StatusCreated && // 201
resp.StatusCode != http.StatusAccepted { // 202 (async)
return fmt.Errorf(
"could not upload results got status code %v on %v",
resp.StatusCode,
resp.Request.URL.String(),
)
}
🤖 Prompt for AI Agents
In internal/pdcp/writer.go around lines 214 to 216, the status-code check
currently only accepts 200; update it to treat 200, 201 and 202 as success (or
better, accept any 2xx by checking resp.StatusCode >= 200 && resp.StatusCode <
300) and only return an error for non-2xx codes, preserving the existing error
message but ensuring it uses resp.StatusCode and resp.Request.URL.String() as
before.

Comment thread runner/runner.go
Comment on lines +811 to 813
_ = plainFile.Close()
}()
jsonFile = openOrCreateFile(r.options.Resume, r.options.Output+".json")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Capture and log Close() errors instead of discarding them.

Close can surface buffered-write failures. Prefer a helper that logs and continues.

-            defer func() {
-                _ = plainFile.Close()
-            }()
+            defer closeFile(plainFile, r.options.Output)

Add once in this file:

func closeFile(f *os.File, name string) {
        if f == nil {
                return
        }
        if err := f.Close(); err != nil {
                gologger.Error().Msgf("Could not close file '%s': %s\n", name, err)
        }
}

Apply the helper to all similar defers in this function.

Also applies to: 815-817, 819-821, 828-830, 839-841, 850-852, 1243-1245, 1337-1339, 1362-1364

🤖 Prompt for AI Agents
In runner/runner.go around lines 811-813 (and also update the similar defers at
815-817, 819-821, 828-830, 839-841, 850-852, 1243-1245, 1337-1339, 1362-1364),
the current defers call f.Close() and discard any error; add a helper function
closeFile(f *os.File, name string) that returns early on nil and logs Close()
errors via gologger.Error().Msgf("Could not close file '%s': %s\n", name, err),
then replace each deferred anonymous Close() with defer closeFile(<fileVar>,
"<filename or variable>") so buffered-write failures are captured and logged
while allowing the function to continue.

Comment thread runner/runner.go
Comment on lines +2380 to 2383
if path.Ext(req.Path) == ".ico" {
mmh3, md5h, err := r.calculateFaviconHashWithRaw(currentResp)
return mmh3, md5h, req.URL.Path, currentResp, req.URL.String(), err
return mmh3, md5h, req.Path, currentResp, req.String(), err
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

req.Path may be empty; add fallback to URL.Path.

Some request types won’t populate Path. Guard and return the actual path used.

-    if path.Ext(req.Path) == ".ico" {
-        mmh3, md5h, err := r.calculateFaviconHashWithRaw(currentResp)
-        return mmh3, md5h, req.Path, currentResp, req.String(), err
-    }
+    p := req.Path
+    if p == "" && req.URL != nil {
+        p = req.URL.Path
+    }
+    if path.Ext(p) == ".ico" {
+        mmh3, md5h, err := r.calculateFaviconHashWithRaw(currentResp)
+        return mmh3, md5h, p, currentResp, req.String(), err
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if path.Ext(req.Path) == ".ico" {
mmh3, md5h, err := r.calculateFaviconHashWithRaw(currentResp)
return mmh3, md5h, req.URL.Path, currentResp, req.URL.String(), err
return mmh3, md5h, req.Path, currentResp, req.String(), err
}
// Determine the path, falling back to URL.Path if req.Path is empty
p := req.Path
if p == "" && req.URL != nil {
p = req.URL.Path
}
if path.Ext(p) == ".ico" {
mmh3, md5h, err := r.calculateFaviconHashWithRaw(currentResp)
return mmh3, md5h, p, currentResp, req.String(), err
}
🤖 Prompt for AI Agents
In runner/runner.go around lines 2380 to 2383, the code checks if
path.Ext(req.Path) == ".ico" but req.Path can be empty for some request types;
change the logic to use a safe path variable: set p := req.Path; if p == "" &&
req.URL != nil { p = req.URL.Path } then use path.Ext(p) for the ico check and
return p (not req.Path) as the path value; this ensures a fallback to
req.URL.Path and avoids nil-pointer or empty-path returns.

@Mzack9999
Mzack9999 merged commit 01064f7 into projectdiscovery:dev Aug 28, 2025
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants