#pragma once // Estado del panel Network — log de peticiones HTTP/WS por sesion CDP. // // Una NetworkSession por (port + tab_id) activa. Mantiene WebSocket vivo, // drena eventos en background, los procesa en el UI thread cuando se llama // `pump()`, y los guarda en `requests` para mostrar en la tabla. // // Eventos consumidos: // Network.requestWillBeSent -> crea/actualiza request // Network.requestWillBeSentExtraInfo -> headers crudos request // Network.responseReceived -> response headers, status, mime, type // Network.responseReceivedExtraInfo -> headers crudos response // Network.dataReceived -> bytes recibidos (acumulado) // Network.loadingFinished -> request terminada OK + tamaño total // Network.loadingFailed -> request fallo + errorText // Network.webSocketCreated -> nueva conexion WS // Network.webSocketFrameSent -> frame WS saliente // Network.webSocketFrameReceived -> frame WS entrante // Network.webSocketClosed -> WS cerrado // Page.frameNavigated -> permite limpiar log si "preserve_log" off #include "cdp_ws.h" #include #include #include #include #include #include namespace navegator { enum class ResourceType { Document, Stylesheet, Image, Media, Font, Script, TextTrack, XHR, Fetch, EventSource, WebSocket, Manifest, SignedExchange, Ping, CSPViolationReport, Preflight, Other }; const char* resource_type_label(ResourceType t); ResourceType parse_resource_type(const std::string& s); struct HeaderKV { std::string name; std::string value; }; struct WsFrame { bool outgoing = false; int opcode = 1; // 1=text, 2=binary double time = 0.0; // wall clock seconds std::string payload; // text or "(binary N bytes)" int masked = 0; }; struct NetworkRequest { std::string id; // requestId std::string loader_id; std::string frame_id; std::string document_url; std::string url; std::string url_fragment; std::string method; ResourceType type = ResourceType::Other; int status = 0; std::string status_text; std::string mime_type; std::string remote_ip; int remote_port = 0; std::string protocol; std::string initiator_type; // parser, script, preload, ... std::string initiator_url; int initiator_line = 0; std::vector request_headers; std::vector response_headers; std::string post_data; bool has_post_data = false; bool from_cache = false; bool from_disk_cache = false; bool from_service_worker = false; int64_t encoded_data_length = 0; // bytes on the wire int64_t data_received_bytes = 0; // sum of dataReceived int64_t response_body_length = 0; bool finished = false; bool failed = false; std::string error_text; bool canceled = false; // Timestamps en CDP "MonotonicTime" (segundos desde un origen arbitrario). double ts_request_will_be_sent = 0.0; double ts_response_received = 0.0; double ts_loading_finished = 0.0; double ts_loading_failed = 0.0; // Wallclock cuando se vio cada cosa (steady_clock seconds since session start). double t_started = 0.0; double t_response = 0.0; double t_finished = 0.0; // Lazy-fetched response body (Network.getResponseBody). Vacio si no se ha pedido. bool body_fetched = false; bool body_base64 = false; std::string body_text; // WS frames si type == WebSocket std::vector ws_frames; }; struct NetworkStats { int total_requests = 0; int64_t transferred = 0; // suma encoded_data_length int64_t resources = 0; // suma response_body_length double finish_time = 0.0; // ultimo t_finished double dom_content_loaded = -1; // Page.domContentLoaded eventFired double load_event = -1; // Page.loadEventFired }; class NetworkSession { public: NetworkSession() = default; ~NetworkSession(); // Abre WS a `ws_url` y emite Network.enable + Page.enable. Devuelve false si fallo. bool open(const std::string& ws_url, std::string* err = nullptr); void close(); bool is_open() const { return ws_ && ws_->is_connected(); } const std::string& ws_url() const { return ws_url_; } const std::string& last_error() const { return last_err_; } // Drena eventos del WS y actualiza el estado interno. Llamar cada frame UI. void pump(); // Reset log preservando socket (Clear button con preserve_log=false). void clear_log(); // Pide cuerpo de respuesta para un request (Network.getResponseBody). Async: // cuando llega lo actualiza en NetworkRequest. Idempotente. void request_body(const std::string& request_id); // Toggle: al navegar limpia o no. void set_preserve_log(bool v) { preserve_log_.store(v); } bool preserve_log() const { return preserve_log_.load(); } // Toggle: Network.setCacheDisabled. void set_cache_disabled(bool v); bool cache_disabled() const { return cache_disabled_.load(); } // Lectura del log (UI thread). Devuelve copia-snapshot (vector de punteros // estables porque almacenamos shared_ptr). std::vector> snapshot() const; NetworkStats stats() const; // Drag-and-drop import/export HAR. std::string export_har_json() const; // Envia Page.reload via CDP. ignore_cache=true equivalente a Ctrl+Shift+R. bool reload_page(bool ignore_cache = false); // Stats del WebSocket subyacente — utiles para diagnosticar si el canal // CDP esta vivo aunque la tabla siga vacia. uint64_t ws_frames_in() const { return ws_ ? ws_->frames_in() : 0; } uint64_t ws_bytes_in() const { return ws_ ? ws_->bytes_in() : 0; } uint64_t ws_bytes_out() const { return ws_ ? ws_->bytes_out() : 0; } private: std::unique_ptr ws_; std::string ws_url_; std::string last_err_; std::atomic preserve_log_{true}; std::atomic cache_disabled_{false}; mutable std::mutex mu_; std::vector> requests_; std::unordered_map> by_id_; NetworkStats stats_; std::chrono::steady_clock::time_point t0_ = std::chrono::steady_clock::now(); // Procesa una linea JSON entrante. void on_message(const std::string& json); // Reset clear_log() implementacion privada. void clear_log_locked(); }; } // namespace navegator