Skip to content

Releases: Lemric/BatchRequest

3.1.4

Choose a tag to compare

@labudzinski labudzinski released this 26 Sep 12:50
2cdba00
  • Removed an invalid generator
  • Added tests
  • Updated the documentation
  • Fixed validator errors and potential log leaks.

3.1.3

Choose a tag to compare

@labudzinski labudzinski released this 26 Sep 12:05
49dd427

The license has been changed to a more useful one. It is now the MIT license.

v3.1.2

Choose a tag to compare

@labudzinski labudzinski released this 25 Apr 09:30

Full Changelog: 3.1.1...3.1.2

v3.1.1

Choose a tag to compare

@labudzinski labudzinski released this 25 Apr 09:21

Symfony profiler

v3.1.0

Choose a tag to compare

@labudzinski labudzinski released this 25 Apr 09:06

Security

  • Parser: byte-accurate strlen payload limit (was mb_strlen); per-
    transaction body cap (default 256 KiB); strict whitelist of forwarded
    parent headers (default: accept, accept-language, content-type,
    user-agent); blacklist now drops cookie, set-cookie, authorization,
    x-csrf-token; $_SERVER filtered through whitelist; parse_str
    guarded against array-bomb (max 1000 fields).
  • Validator: combined path-traversal regex; URI re-checked after
    iterative rawurldecode (defeats double-encoded %2e%2e%2f,
    protocol-relative variants); per-transaction content-length guard;
    recursive sub-batch SSRF guard via metadata flag.
  • ResponseFormatter: strips set-cookie, authorization, proxy-auth*,
    server, x-powered-by from sub-responses to prevent session/header
    leakage through the batch envelope.
  • Facades: parent Authorization header never propagated; new top-level
    "authorization" field in each sub-request injects a per-transaction
    bearer token; trace logs redact authorization|password|token|secret| api_key and truncate to 4 KiB; rate-limit decoding done once.

Performance

  • Handler: optional ExecutionStrategyInterface (default sequential,
    BC-safe). New FiberExecutionStrategy parallelises contiguous read-
    only blocks (GET/HEAD only, write ops always serialised) via PHP
    Fibers with bounded maxConcurrency (default 8).
  • Parser: generator-driven transaction yielding; pre-flipped O(1) header
    maps; single-pass header/cookie/server filtering.
  • ResponseFormatter: BinaryFileResponse streamed in 8190-byte chunks
    (peak RAM ≈ chunk size instead of full file); pre-compiled regex/map
    constants.
  • BatchResponse: manual loop in getFailureCount (no array_filter
    closure allocation).

Testing

  • Add FiberVsSequentialBenchmarkTest covering pure-CPU, blocking I/O
    and cooperative I/O scenarios with deterministic assertions.
  • Update LaravelTransactionExecutorTest to assert Set-Cookie is
    stripped from sub-responses (new secure default).

BREAKING CHANGE: Set-Cookie headers are no longer forwarded from sub-
responses into the batch envelope; parent-request Authorization /
Cookie headers are no longer forwarded into sub-requests. Use the new
top-level "authorization" payload field per sub-request, or override
forwardedHeadersWhitelist in the facade constructor.

v3.0.2

Choose a tag to compare

@labudzinski labudzinski released this 25 Apr 08:22

A single batch can now safely mix sub-requests that return any
Content-Type (JSON, problem+json, vendor +json, HTML, text, XML/SVG,
PDF, PNG, octet-stream, BinaryFileResponse, StreamedResponse, 204).
Previously binary bodies corrupted the outer JsonResponse envelope and
BinaryFileResponse/StreamedResponse payloads were silently dropped.

Changes

  • New Lemric\BatchRequest\Bridge\ResponseFormatter (framework-agnostic,
    shared by both bridges — works for Laravel too because
    Illuminate\Http\Response extends Symfony's and Laravel reuses
    Symfony's BinaryFileResponse/StreamedResponse).

    • JSON / */*+json → decoded array.
    • text/* and application/{xml,*+xml,javascript,yaml,…} → raw string.
    • Anything else → base64-encoded body + body_encoding: "base64".
    • BinaryFileResponse materialised via getFile().
    • StreamedResponse captured via output buffering.
    • Malformed JSON with a JSON content type stays as raw string
      (server claimed text, no base64).
    • Empty/no-content responses return "" (consistent string typing).
  • Symfony/SymfonyTransactionExecutor and
    Laravel/LaravelTransactionExecutor delegate response shaping to the
    new formatter; duplicated formatResponse/extractHeaders/
    isJsonContentType removed.

  • README: new "Mixed content types in a single batch" section with the
    Content-Type → body-shape table and an example mixed response.

Tests

  • New tests/Bridge/ResponseFormatterTest.php (17 cases) covers every
    branch and a mixed-batch round-trip through json_encode.
  • New tests/Bridge/ResponseFormatterLaravelTest.php (9 cases) proves
    the formatter handles Illuminate\Http\{Response,JsonResponse} and
    Symfony BinaryFileResponse/StreamedResponse returned by Laravel
    helpers.
  • SymfonyTransactionExecutorTest::testExecuteHandlesResponseWithoutContent
    updated: empty body is now "" instead of [].

v3.0.1

Choose a tag to compare

@labudzinski labudzinski released this 25 Apr 07:37

Security

  • Validator/TransactionValidator

    • Reject CRLF, percent-encoded CRLF and NULL bytes in URI; fix the
      previously broken backslash regex (/\\\/) that matched nothing
      relevant. Mitigates HTTP Response Splitting / smuggling (A03).
    • Reject protocol-relative URIs (//host, /\host) which Symfony's
      Request::create() interprets as having host as authority.
      Mitigates SSRF / Open Redirect (A10).
    • New validateHeaders(): enforce RFC 7230 §3.2.6 tchar header names
      and forbid CR/LF/NULL in header values (A03).
  • Validator/BatchRequestValidator

    • Drop the "skip per-transaction validation for batches >1000" path.
      Security must not depend on batch size; the maxBatchSize cap is the
      only correct performance lever (A04 Insecure Design).
  • Parser/JsonBatchRequestParser

    • json_decode now uses depth=32 and JSON_THROW_ON_ERROR, plus a
      configurable maxContentLength (default 5 MiB) checked before
      decoding. Mitigates billion-laughs / memory-exhaustion DoS (A04).
    • Add a denylist of sensitive context headers that must not be
      propagated from the parent request to sub-requests: Host,
      X-Forwarded-*, X-Real-IP, Forwarded, and RFC 7230 §6.1
      hop-by-hop headers (A01 BAC + A03 spoofing).
  • Bridge facades and executors

    • SymfonyBatchRequestFacade / LaravelBatchRequestFacade: replace raw
      $e->getMessage() in 500 responses with a generic
      "Internal server error" message; full context is still logged
      (A09 Information Disclosure).
    • SymfonyTransactionExecutor: keep informative error type/message for
      HttpExceptionInterface (NotFound, etc.) but return a generic
      payload for all other Throwable (A09).
    • LaravelTransactionExecutor: stop returning get_class($e) and the
      raw exception message in the per-transaction response (A09).

Bugs

  • Parser/JsonBatchRequestParser::extractParameters

    • parse_str is no longer applied to JSON-looking bodies. Previously
      a body like {"a":1} was silently mangled into
      ['{"a":1}' => '']. The raw body still flows through
      prepareContent.
  • Bridge/Symfony/SymfonyBatchRequestFacade

    • Remove the redundant "isLargeBatch" branch in extractContext that
      decoded the entire payload a second time, and remove the rate-limit
      decode that ran without depth/throw flags. Rate-limit decode is now
      safe and tolerant of invalid input (count=1 fallback).
    • Remove the unused getErrorType() method (dead code).
    • logError no longer allocates a fresh NullLogger on each call.
  • Handler/BatchRequestHandler

    • Stop disabling the logger for batches >1000. Silently dropping
      validation-error logs hid both bugs and DoS attempts.
  • Bridge/Laravel/LaravelServiceProvider

    • Actually load config/batch-request.php via mergeConfigFrom,
      publish it under the batch-request-config tag, and read
      batch-request.max_batch_size (with a safe fallback to 50 when the
      config repository is not bound, so test containers keep working).
      The config file existed and was documented but had no effect.
    • Mark the provider as final.

Tests

  • Update Symfony/LaravelTransactionExecutor tests to assert the new
    generic error contract.
  • Replace the PHPUnit-12 $this->isType('callable') (removed in
    PHPUnit 13) with a callback constraint in
    LaravelServiceProviderTest.

v.3.0.0

Choose a tag to compare

@labudzinski labudzinski released this 12 Oct 11:09
removed unused directory

v2.1.4

Choose a tag to compare

@labudzinski labudzinski released this 21 Jan 09:58
remove fiber and stream

v2.1.3

Choose a tag to compare

@labudzinski labudzinski released this 29 Dec 10:20
Fibers