Crafter.Network master now carries, in their final shape, the pieces the HTTP layer and the SQL broker were written against on a side branch: ClientHTTP1::Fetch follows redirects by RFC 9110 §15.4 on a URL type of its own, and SocketErrorException is a std::system_error with the phase that failed. The broker and the HTTP layer read the errno or the resolver code from code() and the phase from the field, instead of matching message prefixes, and the pin moves to that commit, so the build no longer needs --local against a checkout of the side branch. The messages the run log, the preflight detail and the SQL helper show are unchanged, but for the wording of a refused URL.
49 lines
2 KiB
C++
49 lines
2 KiB
C++
// SPDX-License-Identifier: AGPL-3.0-only
|
|
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
|
|
|
export module Crafter.Review:Http;
|
|
import std;
|
|
import :Json;
|
|
|
|
// The HTTP the driver needs: app_ready's preflight, the OpenRouter catalogue
|
|
// and key probe. On Crafter.Network's ClientHTTP1::Fetch, which follows redirects; on
|
|
// top of it a status outside 2xx thrown as HttpError, and every other failure
|
|
// as Error with a fixed text, because those texts reach the run log and
|
|
// app_ready's detail. Proxies are not consulted (AGENTS.md).
|
|
export namespace Crafter::Review::Http {
|
|
struct Response {
|
|
std::int32_t status = 0;
|
|
std::string body;
|
|
};
|
|
|
|
// A status outside 2xx. what(): "HTTP Error 404: Not Found", with the
|
|
// standard reason phrase rather than the server's.
|
|
class HttpError : public std::runtime_error {
|
|
public:
|
|
HttpError(std::int32_t code, const std::string& message);
|
|
explicit HttpError(std::int32_t code);
|
|
std::int32_t Code() const;
|
|
|
|
private:
|
|
std::int32_t code;
|
|
};
|
|
|
|
// Every other failure. What fails while the request goes out reads
|
|
// "<urlopen error [Errno 111] Connection refused>" or "<urlopen error
|
|
// timed out>"; what fails while the response comes in reads as it is:
|
|
// "timed out".
|
|
class Error : public std::runtime_error {
|
|
public:
|
|
using std::runtime_error::runtime_error;
|
|
};
|
|
|
|
// A GET of `url`, read whole. Header names in any case; Accept-Encoding:
|
|
// identity and Connection: close always go out, and a User-Agent unless
|
|
// one is given.
|
|
Response UrlOpen(std::string_view url, const std::map<std::string, std::string>& headers, double timeout);
|
|
// The body as JSON: Dyn::Error JSONDecodeError (or UnicodeDecodeError)
|
|
// with the scanner's message for a body that is not.
|
|
Json JsonBody(const Response& response);
|
|
// http.HTTPStatus(code).phrase, "" for a code it does not know.
|
|
std::string_view Reason(std::int32_t code);
|
|
}
|