summaryrefslogtreecommitdiff
path: root/http
AgeCommit message (Collapse)AuthorFilesLines
6 daysRefactor startAsyncWaitForSignal lambdaYuvakumar Selvamani1-21/+22
Extract the long signal handler lambda in startAsyncWaitForSignal() into a named member function, afterWaitForSignal(), bound via std::bind_front(), per the <10 line lambda coding standard in docs/COMMON_ERRORS.md. Tested on AST2600 SoC: - `kill -HUP <bmcweb pid>`, then `GET /redfish/v1/` Expected: cert reload, service stays active, 200 OK Actual: bmcweb.service remained active, GET returned HTTP 200 - `kill -TERM <bmcweb pid>` Expected: clean shutdown Actual: journalctl confirmed "bmcweb.service: Deactivated successfully" - RSV: 5845 Pass / 353 Warn / 0 Fail Change-Id: Id02f26fd680ae34639b521962b0f4e3d67c534bc Signed-off-by: Yuvakumar Selvamani <yuvakumars@ami.com>
10 daysinclude,http: Extract getUserInfo/onRequestRecvYuvakumar Selvamani1-13/+17
Move long lambdas in getUserInfo() and onRequestRecv() into named functions, afterGetUserInfo() and afterCompleteRequest(), per the <10 line lambda rule in docs/COMMON_ERRORS.md. No functional change. Tested: - Tested on AST2600 SoC. - getUserInfo/afterGetUserInfo: sent an authenticated Basic-auth Redfish GET and confirmed a 200 response with no "Failed to populate user information" error in journalctl, proving populateUserInfo() succeeded via the extracted callback. - onRequestRecv/afterCompleteRequest: RSV's client uses HTTP/1.1, so it does not exercise this HTTP/2-only code path. Instead, used "curl --http2" and confirmed ALPN negotiated h2 and the request completed as HTTP/2 200. journalctl -u bmcweb confirmed both "onRequestRecv streamId:1" and the extracted callback's "res.completeRequestHandler called" fired for that stream. - Redfish Service Validator: 5830 Pass / 353 Warn / 0 Fail. Change-Id: I0e6365c682f6acc8d39510ad5f1fe239d747154f Signed-off-by: Yuvakumar Selvamani <yuvakumars@ami.com>
2026-09-11http: Refactor handleMessage lambdaYuvakumar Selvamani1-12/+16
Extract the long completion lambda in handleMessage() into a named member function, afterHandleMessage(), bound via std::bind_front(), per the <10 line lambda coding standard in docs/COMMON_ERRORS.md. Tested: - No functional change. - Build successfully compiled. - Redfish Service Validator passed with no new errors or warnings introduced. Change-Id: I54f4cbee152c04c2bd083e5fbbf6859b8277b887 Signed-off-by: Yuvakumar Selvamani <yuvakumars@ami.com>
2026-09-10Prevent error level prints on disconnect of http2Ed Tanous1-1/+3
Previously, http2 disconnects that weren't cleanly stopped in openssl would result in a log message like: ''' [http2_connection.hpp:998] 0x2bba5e0 Error while reading: stream truncated ''' While it's valid to log that a client disconnected unclealy, clients seem to do this and clog up the logs. Tested: Redfish Service validator passes. I don't have a client that reproduces this; Inspection only. Change-Id: I9205500171912f7d82b31487b7df8d1a293d8c89 Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-07-29Add defensive callback invocationMyung Bae1-2/+8
We have experienced a `std::bad_function_call` exception [1]. The journal entries are showing ``` Jun 17 15:27:21.985663 bmcwebd[1995]: [http_client.hpp:391] recvMessage() failed: asio.ssl error from https://10.5.10.140:17443/redfish/events Jun 17 15:27:22.043798 bmcwebd[1995]: [http_client.hpp:391] recvMessage() failed: stale parser from https://10.5.10.140:17443/redfish/events Jun 17 15:27:22.085644 bmcwebd[1995]: terminate called after throwing an instance of 'std::bad_function_call' Jun 17 15:27:22.086908 bmcwebd[1995]: what(): bad_function_call Jun 17 15:27:22.163520 systemd-coredump[4621]: Process 1995 (bmcwebd) of user 0 terminated abnormally with signal 6/ABRT ``` The matching line is ``` void recvMessage(const std::shared_ptr<ConnectionInfo>& /*self*/, const boost::system::error_code& ec, std::size_t bytesTransferred) { ... callback(parser->keep_alive(), connId, res); ... } ``` This would imply that the callback function pointer became null when it is invoked. ``` void sendNext(bool keepAlive, uint32_t connId) { ... conn->callback = nullptr; ... } ``` This may be happening due to the race condition between multiple async operations where the async call is waiting to be invoked but sendNext is executed first. This commit is to make the defensive checking of `callback` function pointer before invoking like ``` if (callback) { callback(parser->keep_alive(), connId, res); } ``` [1] https://en.cppreference.com/cpp/utility/functional/bad_function_call Change-Id: Ic23e17ea486433e3bb7493e8e3c1e56b1798c8e9 Signed-off-by: Myung Bae <myungbae@us.ibm.com>
2026-07-22Implement Response header countJoel P J1-0/+7
Add Response::headerCount() to return the total number of stored header fields on a response. The implementation counts the current header entries directly from the underlying Beast header container. Added unit coverage to verify the method reports the full header count after headers are added through the normal addHeader() path. Tested with: meson test -C build http_response_test --print-errorlogs This helper is used by response unit tests to verify that only the expected headers are present and that no unexpected headers are added to the response. See also: https://gerrit.openbmc.org/c/openbmc/bmcweb/+/91848 Change-Id: I28432bb4fc982db44cee0688395d04ac513d6749 Signed-off-by: Joel Pullokaran Jesin <joelpj@ami.com>
2026-07-15Fix bug in asio resolverEd Tanous1-2/+2
This regressed when the bypass was added. Fix the code for resolver=asio to properly construct the results object using the built in asio type instead of std::vector. Tested: Code compiles with resolver=asio again. Change-Id: I3d9ddc38b88a392cf82fc81bd5609f3360837393 Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-07-09Updating maxValues to support roughly 200 bmcweb sessionsRick Yazwinski1-1/+1
parseStringAsJson() routes through BmcwebSaxParse, which hard-caps a payload at 500 total JSON values to defend against malicious external HTTP request bodies. The most visible symptom is that bmcweb silently loses every persisted session across a restart once ~50 sessions accumulate (each persisted session is ~11 JSON values, so the file trips the cap and is treated as malformed). Tntegration testing hit this 50 session limit and failed. (Was failing our internal but also the openbmc-test-automation robot suite) I had originally implemented a solution as a "trusted reader" with no limit ( https://gerrit.openbmc.org/c/openbmc/bmcweb/+/90138 ); however, the security implications of "no limit" weren't attractive. This area may be refactored in the near future to represent each session as a distinct json file. This value bump gets us past the immediate needs without introducing a lot of churn in code that will be refactored. Change-Id: Ifd3514bd8ee15c8bdf1b6c2119451a2965801671 Signed-off-by: Rick Yazwinski <rickyaz@meta.com>
2026-07-01Flag long lambdasEd Tanous3-0/+3
Long lambdas have been documented as an anti-pattern for some time.[1] Despite this being generally understood, bmcweb has a long ways to go cleaning these up, and routinely code is submitted in violation of this anti-pattern. Invent an ast-grep rule that can identify when new examples of this anti-pattern are added, and ignore the existing 200+ examples that are in the codebase already using ast-grep ignore. These flags will give us something to search for as we clean this up, and will help to prevent new instances from being added unintentionally. [1] https://github.com/openbmc/docs/blob/master/anti-patterns.md#very-long-lambda-callbacks Tested: Comment only change. ast-grep passes. Manually removing an ast-grep ignore flag shows as a failure in ast-grep scan Change-Id: I77d634a393884969f184d2c39c02cc08288d5a29 Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-06-25Fix socket reuse in HTTP server accept loopKokilambal Varadhan1-11/+11
bmcweb HTTP server accept handling had a critical bug where a single socket pointer was reused across multiple acceptors, causing undefined behavior and potential crashes. 1. Move socket creation into doAcceptOne() to ensure each acceptor creates its own unique socket instance. 2. Pass acceptor pointer to afterAccept() callback to track which acceptor completed the accept operation. 3. Replace doAccept() call with doAcceptOne() in afterAccept() to resume accepting on only the specific acceptor that handled the connection, not all acceptors. This ensures proper socket lifecycle management and prevents race conditions from shared socket instances. Tested: HTTP server accepts connections correctly with multiple acceptors (HTTP/HTTPS) without crashes or undefined behavior. Change-Id: I0540802cdd682e8e7d7312d6edfd5651bf09378a Signed-off-by: Kokilambal Varadhan <kokilavaradhan@gmail.com>
2026-06-16http2: pass client IP address to HTTP/2 requestsVijaysankar Ravi2-4/+8
HTTP/2 connections were not passing the resolved client IP into the per-request ipAddress field, causing sessions to report 0.0.0.0 instead of the actual client address. Additionally, authentication::authenticate() was called with an empty IP, resulting in Basic Auth sessions being created with an incorrect clientIp in the session store. Pass the IP through the HTTP2Connection constructor, use it in the authenticate() call, and assign it to req->ipAddress during request dispatch in onRequestRecv. Tested: - Client IP correctly displayed in Redfish SessionService on HTTP/2 connections. - Before patch: ClientOriginIPAddress showed "0.0.0.0" - After patch: ClientOriginIPAddress shows actual client IP - Redfish Service Validator (v3.1.4) passed on /redfish/v1/SessionService tree: PASS: 44, WARN: 0, FAIL: 0, NOT TESTED: 41 Before: curl -k https://127.0.0.1:2443/redfish/v1/\ SessionService/Sessions/O9gUpSoxbe -u root:0penBmc { "@odata.id": "/redfish/v1/SessionService/Sessions/O9gUpSoxbe", "@odata.type": "#Session.v1_7_0.Session", "ClientOriginIPAddress": "0.0.0.0", "Description": "Manager User Session", "Id": "O9gUpSoxbe", "Name": "User Session", "Roles": [ "Administrator" ], "UserName": "root" } After this patch: curl -k https://172.31.216.225/redfish/v1/\ SessionService/Sessions/LuttjprSGD -u root:0penBmc { "@odata.id": "/redfish/v1/SessionService/Sessions/LuttjprSGD", "@odata.type": "#Session.v1_7_0.Session", "ClientOriginIPAddress": "10.0.136.165", "Description": "Manager User Session", "Id": "LuttjprSGD", "Name": "User Session", "Roles": [ "Administrator" ], "UserName": "root" } Change-Id: I223e5c90448419ba87b690de38cc5e69ffb6a0c3 Signed-off-by: Vijaysankar Ravi <vijaysankarr@ami.com>
2026-06-12OpenSSL cleanupEd Tanous4-48/+20
Continue moving OpenSSL into reusable RAII classes that can be used in unit tests and other places. This is slightly more code, but as we're adding unit tests, it allows reuse between unit tests rather than writing C directly. It also encapsulates the complexity of parsing openssl output (usually in bytes) into standard types (string) that can be compared/modified. Functionally this adds two new classes to the "wrappers" functions, OpenSSLSSLCtx and OpenSSLSSL, which each wrap SSL_CTX and SSL objects respectively from openssl. These are rough approximations of the boost equivalents. Change-Id: Id87ac4ccde88890bd70861deffdb256188ec0e39 Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-06-10http: improve JSON parse error loggingAKash A0071-2/+4
Add specific warning for empty or missing Content-Type header to help debug malformed Redfish requests. Keep existing warning for invalid content types. Avoid reflecting user-controlled input such as URL or header values in log messages to prevent log flooding from malicious requests. Tested: Verified log message appears when Content-Type header is empty. Confirmed no user input is reflected in logs. Verified warning still appears for invalid content types like text/plain. Tested on Ubuntu 24.04.1 LTS. Change-Id: I6b873e8f7517aaea1a010bf9cbb5533a410e1b21 Signed-off-by: Akash Arunkumar <mirrorghost007@gmail.com>
2026-06-02http: zstd: do not attempt compressing already opened filesTan Siewert1-0/+5
Commit 2d7dc991 changed the body storage from being saved in a separate field to a std::variant. Calling str() calls emplace<std::string>(), which destroys the active FileBody in-place on file-backed bodies (e.g. the Web UI) and closes the FD. Any subsequent action now tries to access a non-existing FD (dummy handle returning -1 as FD.) Fix by returning early from `attemptZstdCompression` when the body is file-backed, as file-backed bodies are already handled by the streaming zstdCompressor in the writer. Tested: cURL with "Accept-Encoding: zstd" to favicon.ico, ensuring that it returns data again. Fixes: 2d7dc991 ("Optimize bmcweb memory usage for multipart fw update") Change-Id: Ia54712f89d8c5f7dc9ce7c5d040aed06e8f6fded Signed-off-by: Tan Siewert <tan.siewert@9elements.com>
2026-05-29Fix coredump in http_client during rapid connection destructionMyung Bae1-4/+16
Issue: BMCWeb crashes with segmentation fault when HTTP client connections are rapidly created and destroyed while async operations are pending. This occurs during event subscription deletion, BMCWeb shutdown, or network timeout scenarios where ConnectionPool is destroyed while callbacks are still executing. Root Cause: Race condition between async callback execution and ConnectionPool destruction leads to three failure modes: 1. Out-of-bounds vector access in sendNext() when connId is invalid 2. Null pointer dereference when connection pointer is null 3. Use-after-free when callback executes after pool destruction The issue manifests as: - Segmentation fault in sendNext() - Crash in afterSendData() when accessing destroyed pool - Invalid memory access during callback execution Key Fixes: 1. Bounds Checking - Validate connId < connections.size() before vector access - Prevents segmentation fault from out-of-bounds access - Returns early with error log if connId invalid 2. Null Pointer Validation - Check if connection pointer is null before dereferencing - Provides graceful error handling instead of crash - Logs error and returns safely 3. Reordered afterSendData() - Check ConnectionPool validity BEFORE calling user callback - Prevents callback execution if pool has been destroyed - Ensures safe early return if pool no longer exists Testing: Reproduced coredump by simulating aggressive client behavior: - Client rapidly creates HTTP connections to BMCWeb - Client sends POST requests to create event subscriptions - Client abruptly closes connections during SSL handshake - Client destroys sessions while async operations are pending - This triggers race condition where callbacks execute after ConnectionPool destruction Example Python code that reproduces the issue: ``` for i in range(100): session = requests.Session() session.post('https://bmc/redfish/v1/EventService/Subscriptions', json={'Destination': 'http://192.0.2.1:8080/events'}) time.sleep(0.01) # Brief delay session.close() # Abrupt destruction while request pending del session ``` Before fix: - Segmentation fault in sendNext() - BMCWeb process crashes - Coredump generated After fix: - No coredumps detected - BMCWeb process remains stable - Graceful error handling with log messages: "Invalid connId: X (size: Y)" "Connection at index X is null" "Failed to capture connection" Expected logs during aggressive client testing (normal behavior): - SSL handshake failures (client abruptly disconnects) - Authentication failures (connections close during auth) - No segmentation faults or process crashes Verification: coredumpctl list bmcweb # No new coredumps systemctl status bmcweb # Process still running dmesg | grep segfault # No segmentation faults Change-Id: I7b7a61aa8fcce1e32b5e3893da5ff0d5b3e3344f Signed-off-by: Myung Bae <myungbae@us.ibm.com>
2026-05-26Print IP address on max connectionsGunnar Mills1-3/+4
Have seen this a few times where the BMC is spammed by some client and bmcweb hits its max connections. Have also gotten feedback that the current "Max connection count exceeded." isn't very useful since it doesn't tell you who is spamming the BMC. These cases have not been malicious, instead an automated malfunctioning network agent. Even if they were malicious recording/printing the IP address of the attacker is referenced by several documents on detecting and responding to a DoS attack. "see a surge in web traffic, seemingly out of nowhere, that’s coming from the same IP address or range." [1] "An IP address makes x requests over y seconds" [2] OpenBMC's security considerations document discusses DoS.[3] bmcweb doesn't claim to have DoS protection and a best practice is for the BMC to be on a dedicated management network. Network Analysis could be used to identify the offending client(s) but specially for after the fact, having the ip address recorded is more reliable. The downside of this change is now when bmcweb is at the max connections, it is reading the IP Address and keeping the connection open slightly longer. In practice, did not see a measurable difference. [1]: https://www.microsoft.com/en-us/security/business/security-101/what-is-a-ddos-attack [2]: https://www.loggly.com/blog/ddos-monitoring-how-to-know-youre-under-attack/ [3]: https://github.com/openbmc/docs/blob/643e73605907251d80166d3d3c984456fc7fd599/security/network-security-considerations.md Tested: 200+ concurrent connections with keep-alive true to leave connections. Sent ``` curl -v -k https://${bmc}/redfish/v1 ``` Saw in logs ``` [http_connection.hpp:214] 0x1ab4c70 Max connection count exceeded. Request <IP> ``` Change-Id: Ib9225e0ee67caafe90b958eb89534adfb0831646 Signed-off-by: Gunnar Mills <gmills@us.ibm.com> Signed-off-by: Justin Nguyen <justinnanguyen@gmail.com>
2026-05-13Fix bad merge resolutionEd Tanous1-0/+4
There was a regression on json parsing due to a merge conflict resolution on 2d7dc991600297d04e50d7958fe9611f9ac42bcf. Update the connection unit tests to test the body catching this case, and fix the error. Tested: Unit tests pass. Redfish service validator passes Change-Id: I4ad8802b7c75001ca7a2b1619af2f368bfe448ee Signed-off-by: Ed Tanous <etanous@nvidia.com> Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
2026-05-01Make parser errors warningsEd Tanous1-2/+2
Users (or attackers) may give bad input to the frontend socket. Reducing these to warnings means the they will no longer print logs if given randomized byte input. Change-Id: Ic78427242bb01e2a1c23a62cbb90af807ed19312 Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-04-29Optimize bmcweb memory usage for multipart fw updateEd Tanous3-31/+147
Previously, firmware updates via multipart/form-data stored two copies of the entire upload in memory (200MB+ for a 100MB image). This change reduces memory usage by incrementally processing multipart data in chunks, running through the parser as required. This avoids a copy into the http body. With this change, bmcweb no longer retains any duplicate copy of the image in memory, thereby limiting memory consumption to roughly the size of the image itself. To accomplish this, the multipart parser is rewritten to support incremental parsing. This should be 100% compatible with the old parser, with one exception, bytes at the end of the payload are no longer accepted and ignored. Tests: Multipart FW Update using a 114.2MB file shows bmcweb memory usage in line with one copy of the image, not two. Unit tests pass. Change-Id: Id18e20004059bfbc7de62f4f6c9542430c7943b0 Signed-off-by: Rajeev Ranjan <ranjan.rajeev1609@gmail.com> Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-04-29Make request non constEd Tanous6-13/+12
In preparation for allowing handlers to "steal" the input (thus saving memory), make the router pass a non-const Request down the pipeline. Tested: Redfish service validator passes. No functional changes. Change-Id: Ic2f44081bc7b6a0e4a82c6ac498eb040574e79be Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-04-27RAII OpenSSLEd Tanous3-26/+24
bmcweb openssl usage is a mess. Start cleaning it up. 1. Make RAII objects for any held memory. 2. Move methods from hostname monitor into the ssl namespace, so not all compile units need to pull in openssl headers 3. Move methods to static where functions can be encapsulated. Because we're now testing openssl, we need to register memory init so that the sanitizers don't cause issues when mallocing from non bootstrapped openssl binaries. Openssl provides a handle for this, so use it in those unit tests. Tested: Unit tests pass. bmcweb launches and can open ssl with curl as it did previously. Change-Id: If0340692d2c56a6c45bb8d661d654a4b58ff3d2c Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-04-27Update and add unit tests for date string functionEd Tanous1-24/+16
To do this, refactor the date string function to a single method that can be unit tested easily. While we're here, deprecate our usage of time_t and move to std::chrono Tested: Redifsh service validator passes Change-Id: I67d4fe66d40b06ed0a0b60286adc75394c34ea1e Signed-off-by: Ed Tanous <ed@tanous.net>
2026-04-23http: Make UPN domain matching case-insensitiveIgor Kanyuka1-1/+5
Domain names are case-insensitive per RFC standards [1]. Update isUPNMatch() to perform case-insensitive comparison of domain labels. This ensures UPNs like user@DOMAIN.COM match hostnames like host.domain.com, as per DNS standards. Tested: 1. Unit tests 2. Built an image, flashed to real BMC, made sure curl requests that use mTLS auth with certs that use UPN work 3. Redfish service validator [1] https://datatracker.ietf.org/doc/html/rfc4343 Change-Id: Ibf5715fdddace4263d0aeef54e518457cf03dfcc Signed-off-by: Igor Kanyuka <ifelmail@gmail.com> Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-04-21Use methods that don't throwEd Tanous1-1/+8
Per common error #5 failing to catch thrown exceptions can lead to a crash. It turns out that the boost::beast::http::fields::set call can throw in extreme circumstances (large headers). There are two uses to clean up. Port these to using an overload that returns an error code to make sure that we don't accidentally set headers or throw an uncaught exception. [1] https://github.com/openbmc/bmcweb/blob/master/docs/COMMON_ERRORS.md#5-using-methods-that-throw-or-not-handling-bad-inputs Tested: Verified unit test coverage on both of these. Change-Id: I996b64ebb34c4ff7f4e582506d1acfabea05d72e Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-04-21HTTP/2: Reject over limit Content-LengthGunnar Mills1-0/+12
Reject requests whose Content-Length exceeds BMCWEB_HTTP_BODY_LIMIT before calling reserve(). BMCWEB_HTTP_BODY_LIMIT is defaulted to 30 Mebibyte (MiB). Make the unit clear in the meson.option too. Tested: See the trace. The reserve doesn't happen. Not sending a RST_STREAM / 413 based on how init() works today. WIP. Change-Id: Ie1e0ba19e2999c2f6c9e18f2b98e49c4bd100bcc Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
2026-04-21Move body limit enforcementGunnar Mills1-7/+7
Make sure the body limit enforcement happens before the Expect: 100-continue check. Tested: Verified the body limit check happens first, even when Expect: 100-continue is used. Now rejects with 413 Payload Too Large. Normal operations such as the Redfish Validator still work. Change-Id: I185dab82c75b3c44d89102750fd03666659a57a6 Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
2026-04-21http_client: Add TLS hostname verification on outbound connectionsGary Beihl1-17/+35
setCipherSuiteTLSext() sets SNI via SSL_set_tlsext_host_name() but never verifies that the peer certificate matches the destination hostname. The existing verify_peer mode validates the certificate chain to a trusted CA but does not check the certificate's Subject Alternative Name against the hostname. Any certificate signed by a CA in the BMC's trust store passes the handshake, regardless of which host it was issued for. This allows MITM on outbound connections (Redfish Event subscriptions, firmware downloads) by an attacker holding any valid certificate signed by a trusted CA, even one issued for a completely different domain. Register Boost Asio's ssl::host_name_verification as the SSL stream's verify_callback, gated on verifyCert != NoVerify to preserve the existing operator opt-out. host_name_verification is Boost Asio's wrapper around X509_check_host(), the OpenSSL 1.0.2+ hostname-matching API. Boost's SSL documentation uses this pattern in its "Verified connection" example. This patch uses ssl::host_name_verification (registered via set_verify_callback), rather than calling SSL_set1_host directly on the native handle as an earlier version of this change did. Both reach the same OpenSSL primitive (X509_check_host); Asio's wrapper is the idiomatic form, and is what Boost documentation points at for hostname verification. libcurl reaches the same check via X509_VERIFY_PARAM_set1_host on its verify parameters, which SSL_set1_host is a thin alias for -- libcurl is not skipping the check. This fix requires the VerifyCertificate enum inversion fix (change 89409) to be effective: verify_peer must actually be enabled for host_name_verification to run its check. Depends-On: Iecf1d03d2caee141f6eb4a6a4f284e4e36a3b693 Tested: Docker CI passes (format, build, all tests). Booted OpenBMC on AST2600 (evb-ast2600-renode) in Renode 1.16, drove Redfish subscriptions through bmcweb's outbound TLS path to a test HTTPS server presenting a cert with either a matching (good.example.com) or mismatching (evil.example.com) SAN. The test CA was installed in the BMC trust store. Phase 1 (upstream/master, no patch applied): Benign (good SAN, VerifyCertificate=true) PASS delivers because chain validates. MITM (wrong SAN, VerifyCertificate=true) FAIL "Event was delivered despite a cert that should have caused rejection." Reproduces the bug: bmcweb accepts any CA-signed cert regardless of hostname. NoVerify (wrong SAN, VerifyCertificate=false) PASS opt-out delivers regardless of cert. Phase 2 (upstream/master + this patch): Benign (good SAN, VerifyCertificate=true) PASS chain + SAN both check. MITM (wrong SAN, VerifyCertificate=true) PASS host_name_verification rejects at the verify_callback; event is NOT delivered. NoVerify (wrong SAN, VerifyCertificate=false) PASS opt-out path unchanged. The MITM PASS in phase 2 is specifically a hostname-verification result: Benign's PASS in the same run confirms the chain itself validates cleanly, so MITM's rejection is exactly the hostname check doing its job. Change-Id: Ia1178e4ce662b88d76b4649cf39797e8ede7f42f Signed-off-by: Gary Beihl <garybeihl@microsoft.com>
2026-04-21Remove static variablesEd Tanous2-2/+0
These static variables have the potential to cause reentrancy issues. In practice, the conditions to cause issues would require someone to basically write incorrect code, but it makes sense to wrap this into a state tracker anyway to clean up the code. While we're here, convert to using std::chrono. Note, this changes the behavior such that the values produced are now no longer dependent on timezone. Functionally, Redfish only recently got the ability to set a timezone, so this is not expected to have any user facing impact, even though the unit tests need to change. Tested: RSV Passes Change-Id: Icb7cff1d289ae23790a5fb1db6604abd73dd68fd Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-04-02Remove chatty log statementsEd Tanous1-6/+6
Very few people actually need to debug the connection classes, so having lots of logs clogs up debugging for most people. Comment out the log lines, but leave them in place such that if someone (possibly me) needs to they can be re-enabled easily. Tested: With logging enabled, running queries on the bmc doesn't result in logs printed per timer arm. Change-Id: Idcba1111091dab45e417a118c9eb093d84f8b2ec Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-03-31Port nlohmann::json::parse uses to saxEd Tanous1-1/+2
We should have a single entry point where we do json parsing. There are configurations for nlohmmann that we had previously documented, but were not well enforced. Move all uses to using the helper parse functions. Tested: Unit tests pass. Redfish service validator passes. Change-Id: I2a8aed9327b6b15219dc9b4d6db146b69bcd8eb3 Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-03-25Upgrade to Boost 1.90Ed Tanous1-1/+1
Boost seems to have removed some of the enums that were previously in the enumeration[1]. We relied on two of these Http2-Settings and Content-Tranfer-Encoding. It's not clear why they were removed, but move those to using inline strings. [1] https://github.com/boostorg/beast/pull/3042/changes/db31a880525fe84b0e17b80015049363106c5b61 Change-Id: I233f103531de1361f903bae5c2981845143983d1 Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-03-19Add TLS session resumption support to mTLSIgor Kanyuka3-42/+31
TLS session resumption allows to bypass full TLS handshake in subsequent connections, it's enabled in OpenSSL, so clients that support it use it. One of the optimizations is, the client passes Session ID in subsequent request and does not pass certificates. Since client certificate is not passed, the callback that populates user session out of the certificate is not called, and as result, auth fails for requests sents in subsequent connections. This change enables session ID in memory cache, lookup of the certificate in the cache by the session ID received from the client and constructing user session out of it for subsequent connections. The cache is stored in RAM [1]. According to Nginx doc [2], size of one session is about 250 bytes. If sessions use mTLS, they will also contain a cert which is typically up 2kb. A client establishes connections as part of a session, so a session can be associated with multiple connections. In the worst case, when many clients establish a single connection at a time, or a client always uses a new session for every established connection, there will be number of session entries in the cache equals to the number of connections. While OpenSSL limits cache size to SSL_SESSION_CACHE_MAX_SIZE_DEFAULT which is 20480 [3], OpenBMC limits number of established connections to 200 [4], so in the worst case, memory usage will be ~50kb for non mTLS clients, and ~440kb for mTLS clients. Typically, when there are just 2-3 clients connected, even if them maintain multiple connections within their sessions, the cache size will be less than 10kb for mTLS. To prevent high memory usage by the cache, the change sets cache size to 100 entries. Expired sessions are automatically removed on every 255th session [5]. Tested: Deployed on one of our envs and ran client that quickly sends multiple requests to the BMC (so the client created several connections), and make sure the 401 auth problem had been observed before gone. Also, made sure BMCWeb logged debug messages about existing session detection. Ran tests from the openbmc-test-automation repository, esp related to certificate and user management. They do session auth and not mTLS/multi-connection, so they could not detect/confirm the problem is fixed, but they confirm the change does not break the primary use case. [1] https://docs.openssl.org/3.6/man3/SSL_CTX_set_session_cache_mode/#notes [2] https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_session_cache [3] https://github.com/openssl/openssl/blob/5869303daaecf037f0d00dc33a00f9bdc1e71f2f/include/openssl/ssl.h.in#L670 [4] https://github.com/openbmc/bmcweb/blob/master/http/http_connection.hpp#L219C13-L219C28 [5] https://docs.openssl.org/3.6/man3/SSL_CTX_flush_sessions/#notes Change-Id: Ia94d1e323cd464cc7ca5b0f9c7d6a76e4c780e9a Signed-off-by: Igor Kanyuka <ifelmail@gmail.com>
2026-03-11Fix socket startup when mode is httpEd Tanous1-3/+29
When starting up in http mode, the socket needs to be of type http to allow the flow to work correctly. As is, enabling insecure-disable-ssl results in a non functional api due to hardcoded https. Teted: enabled insecure-disable-ssl; Verify that curl to http port 80 works Change-Id: I2958d6f39b642a02b6ce5f1c69d1da409dafc70d Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-02-27zstd: downgrade the encoding log levelHaiyue Wang1-1/+1
This isn't an error message, change it for making the command output of 'journalctl -u bmcweb' clean. Change-Id: Iff3af323b863776e2e49abcda51198f6b571007d Signed-off-by: Haiyue Wang <haiyuewa@163.com>
2026-02-24Be more paranoid in json parsingEd Tanous1-4/+190
When taking json directly from a user, we should set some limits on parsing depth as well as total number of value elements. Value elements are considered any individual value, the start of an array, the start of a dictionary, or null. This is to prevent flooding type attacks creating large number of objects, while still keeping under the depth 10 cap. This commit makes use of the nlohmann sax parse to handle this by injecting a new error handler in between that will impose new limits. Currently this sets the depth limit to 10 and the total number of keys to 500; These are intentionally high, and could be tuned or expanded on in the future. Tested: Unit tests pass. Change-Id: I789543679e22b0b0ce0b2b0b71f31377b0759cd7 Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-02-17Make sure init is called on http2Ed Tanous1-1/+21
The body object seems to work properly when init isn't called, but to make things efficient, init can call std::string::reserve when appropriate and avoid mallocs. Tested: Unit tests pass. Good coverage for http2. Change-Id: I7abba9640ad711678f1ca2ed6d1b42d9aba22dcc Signed-off-by: Ed Tanous <etanous@nvidia.com> Signed-off-by: Rajeev Ranjan <ranjan.rajeev1609@gmail.com>
2026-02-10zstd compressionEd Tanous5-41/+311
zstd compression allows for reducing the size of payloads with repeating elements. Pretty printed json is one very specific case where we would prefer to not change the behavior, but would also like to avoid the overhead of TLS compression. When ztd is present, the webserver will look for the Accepts-Encoding header to contain zstd, and if it does, compress the payload before sending. Tested: Webui loads correctly, and shows zstd being used for download. Redfish service validator runs. (does not support zstd) Unit tests pass. Change-Id: Ic575911fea70d218d1efb4df030d3cc098f1ecd0 Signed-off-by: Ed Tanous <etanous@nvidia.com>
2026-01-13Fix Bmcweb crash due to HTTP2 connection resetChandramohan Harkude1-4/+8
Changes added : handle dangling pointer in response completion handler Problem : When high number of connections made to BMC and suddenly reset those connections, crash was observed in bmcweb. Fix : Since the connection already torn but bmcweb trying to close those connections in response completion handler causing the crash. Added code to handle the closed or reset connections Tested : made around 200 connections and reset them immediately, repeated these steps around 15 times no crash observed Change-Id: I03b5fd563275c4138a6eb004e09d277547af9692 Signed-off-by: Chandra Harkude <chandramohan.harkude@gmail.com>
2026-01-13Lower severity of HTTP logs from INFO to DEBUGAmithash Prasad1-2/+2
Couple of these logs are heavy hitters and fill up the journal especially with external entities constantly hitting the redfish endpoints. This change moves the largest two logs we saw (on a yosemite4 machine) from INFO to DEBUG. Change-Id: Iac7337e3040e0348e41bba79c8200320e8ba12ef Signed-off-by: Amithash Prasad <amithash@meta.com>
2026-01-07Enable TCP keepalives for HTTP connectionsJoey Berkovitz1-5/+23
This fix enables TCP keepalives at the OS layer. It also enables a 15 minute deadline timer at the bmcweb level when waiting on an idle HTTP keepalive connection. Tested: romulus image running bmcweb, start connections with keepalive, block incoming connections `iptables -P INPUT DROP`, validate that sockets eventually die and are tracked with keepalives `ss -nto` Change-Id: I8f5040440348c060dae1d0516ec202a0e4dc349e Signed-off-by: Joey Berkovitz <joey@berkovitz.us>
2025-11-17Use std::format for hex conversionsEd Tanous1-1/+1
Deprecate intoToHex handler now that we can do everything using std::format. Tested: RSV passes Redfish protocol validator passes Change-Id: I71000506573314d6c9326c4677f5fbca1ca02b46 Signed-off-by: Ed Tanous <etanous@nvidia.com>
2025-11-14Don't log EOF as error in HTTP/2Amy Chang1-2/+7
EOF occurs when HTTP/2 clients close connection after completing requests (e.g., curl). This is normal for multiplexed connections. EOF indicates graceful shutdown, not an error condition. Change-Id: I3291b23c7784a2273f2de05afc71ddb57dd0c28a Signed-off-by: Amy Chang <yahanc@nvidia.com> Signed-off-by: Ed Tanous <etanous@nvidia.com>
2025-11-04Fix websocket error log handlingMyung Bae1-4/+5
The commit b0ae71c[1] mishandles the error handling branches which cause `operation_aborted` to be reported as an error. ``` else if (ec != <error-cases>) { BMCWEB_LOG_ERROR("doRead error {}", ec); } else if (ec == boost::asio::error::operation_aborted) { BMCWEB_LOG_WARNING("doRead operation is aborted: {}", ec); } ``` This needs to handle `operation_aborted` first. Tested: - Unit test passes [1] https://github.com/openbmc/bmcweb/commit/b0ae71c8f503b9e56a5bf88549346b15e7961e26 Change-Id: Ie4b0eafabcf41adf661ab3abc1fe1282c13d1d82 Signed-off-by: Myung Bae <myungbae@us.ibm.com>
2025-11-01Suppress websocket aborted error logMyung Bae1-8/+18
When websocket is aborted under some situations like GUI console is aborted earlier before websocket write is still waiting for completion, it is currently logged as ERROR. However, it may not need to be an error. This commit will change it as WARNING. For example, ``` Oct 31 10:40:29 balco10 bmcwebd[1230]: [websocket_impl.hpp:305] Error in ws.async_write Operation canceled [system:125 at /usr/include/boost/beast/websocket/impl/stream_impl.hpp:355:13 in function 'bool boost::beast::websocket::stream< <template-parameter-1-1>, <anonymous> >::impl_type::check_stop_now(boost::beast::error_code&)'] ``` Tested: - While GUI page is loading pages (e.g. pcie topology), close web-browser and check the bmcweb journal records. Change-Id: I4b16c21d2784ec0b9774ab256f833bb38fc34a27 Signed-off-by: Myung Bae <myungbae@us.ibm.com>
2025-11-01Break out lambdas in websocketMyung Bae1-43/+51
Move out the large lambdas into normal methods to maintain more easily. Tested: - Unit tests pass Change-Id: I9450af36d45b2b17e8a063f383d91026db581d27 Signed-off-by: Myung Bae <myungbae@us.ibm.com>
2025-10-10Bypass resolverEd Tanous1-3/+25
If we are given an ip address to the http client, there's no reason to call the dns resolver. Implement a procedure to "skip" resolution if the http client is an ip address. Tested: Using an ipv4 address from a system not running OpenBMC dbus (in this case an Ubuntu system) now can resolve an IP address. Redfish works with later patches. Change-Id: I094ec7b3015e1e31cb83f0e1c25f6c1fb6685219 Signed-off-by: Ed Tanous <etanous@nvidia.com>
2025-10-08Aggregation: Add basic authentication supportKamran Hasan1-0/+12
Add support for basic authentication when connecting to aggregation sources. This allows satellite BMCs to be authenticated using username and password credentials. The implementation: - Stores credentials alongside URLs in AggregationSource struct - Validates credentials: no colons, max 40 chars, not empty strings - Creates Basic Auth headers using base64 encoding - Only sends Authorization header when both username and password exist - Adds PATCH handler for updating credentials independently - Prevents duplicate aggregation sources with same hostname - Cleans up credentials when aggregation sources are deleted Tested: Manual testing with authenticated aggregation sources Change-Id: Ide17a3c08a4a8f6b90a2ffcd2c798cbbec578db8 Signed-off-by: Kamran Hasan <khasan@nvidia.com>
2025-10-03Remove getNthStringFromPath functionEd Tanous1-10/+36
This utility function is being removed for several reasons. First, it does not verify the full string on URIs and paths, so things like /foo/bar/baz/valid_id would still pass this check. Second, it is used for both URIs and dbus paths, both of which we have better utility functions these days respectively, boost::url for urls and sdbusplus::message::object_path for dbus paths. Neither of the two is escaped properly when this function is used. Therefore, remove it and replace it with the appropriate alternatives. The existing URI functions were found to not accept fragments (given they are rarely used in PATCH). Add support for fragments to cover the getNthStringFromPath use cases. Tested: Redfish service validator passes. Change-Id: Ibc6755ad69397123d7fef0e0b764042bbb48888b Signed-off-by: Ed Tanous <etanous@nvidia.com>
2025-10-03Fix the corrupted Trie routing treeMyung Bae1-6/+13
The routing table may potentially become corrupted during the routing table construction as the vector element pointer becomes invalid if the vector is resized [1]. http/routing/trie.hpp#L241: ``` ContainedType& node = nodes[idx]; size_t* param = &node.stringParamChild; if (str1 == "<path>") { param = &node.pathParamChild; } if (*param == 0U) { L249: *param = newNode(); // <--- } idx = *param; ``` Here, `newNodes()` at L249 may resize the vector of `nodes[]` and thus the reference of `nodes[idx]` becomes invalid and thus the previously saved the pointer of `param` is invalid. The similar issue is also at sub_route_trie construction [5]. This problem may be shown during CI/valgrind test depending on the order of route setups in [2]. For example, for the commit 39574 [3], if `requestsRoutesAssembly()` is added earlier than `requestRoutesProcessorCollection()`, it causes CI/valgrind test fails [3]. The error looks like [4]. [1] https://github.com/openbmc/bmcweb/blob/master/http/routing/trie.hpp#L241 [2] https://github.com/openbmc/bmcweb/blob/master/redfish-core/src/redfish.cpp [3] https://gerrit.openbmc.org/c/openbmc/bmcweb/+/39574 [4] https://gerrit.openbmc.org/c/openbmc/bmcweb/+/39574/comment/15e652e0_f8881ffc/ [5] https://github.com/openbmc/bmcweb/blob/master/redfish-core/include/sub_route_trie.hpp#L160 Tested: - CI with https://gerrit.openbmc.org/c/openbmc/bmcweb/+/39574 passes after rebase of having earlier `requestsRoutesAssembly()`. - Redfish Service Validator passes Change-Id: I349777dfab65f2d41eb5db25796d82322b3c36cc Signed-off-by: Myung Bae <myungbae@us.ibm.com>
2025-10-03Tune http2 window and frame sizesEd Tanous2-5/+31
http2 maintains its own frame ACK window per stream. While the defaults work well in most cases, for large binary uploads, like Redfish UpdateService, the relatively small default window size of 16KB leads to slower performance than http1. While it's not expected to see a performance improvement, we would prefer to not see a regression for a normal use case. Update the HTTP2 max frame size to 16KB. Setting the internal buffer to the same size + the http2 header allows clocking in the entire frame in one async read. Note, setting the value higher than 16KB doesn't appear to allow curl to send larger frames. Also update the HTTP window size to 512KB, or 32 times the max frame size. Note, all streams including the control stream are set to this value, which, while somewhat arbitrary, allows for continued UpdateService pushing without pauses for window ACK. Tested: POST /redfish/v1/UpdateService/update-multipart Of an arbitrary 100MB file through curl shows that --http1.1 option and --http2 option are within 5% of the same upload time. Change-Id: I7ff6296a9cc0794aad63f5058620c0f1fb9299e3 Signed-off-by: Ed Tanous <etanous@nvidia.com>