File: log_replay_socket.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (110 lines) | stat: -rw-r--r-- 3,721 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/test/chromedriver/log_replay/log_replay_socket.h"

#include <memory>

#include "base/files/file_path.h"
#include "base/json/json_reader.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"

namespace {

std::string SessionIdJson(const std::string& session_id) {
  return session_id.empty() ? std::string()
                            : ",\"sessionId\":\"" + session_id + "\"";
}

}  // namespace

LogReplaySocket::LogReplaySocket(const base::FilePath& log_path)
    : connected_(false), log_reader_(log_path) {}

LogReplaySocket::~LogReplaySocket() = default;

void LogReplaySocket::SetId(const std::string& socket_id) {
  socket_id_ = socket_id;
}

bool LogReplaySocket::IsConnected() {
  return connected_;
}

bool LogReplaySocket::Connect(const GURL& url) {
  connected_ = true;
  return true;
}

bool LogReplaySocket::Send(const std::string& message) {
  std::optional<base::Value> json = base::JSONReader::Read(message);
  max_id_ = json->GetDict().FindInt("id").value();
  return true;
}

std::unique_ptr<LogEntry> LogReplaySocket::GetNextSocketEntry(
    bool include_requests) {
  while (true) {
    std::unique_ptr<LogEntry> next = log_reader_.GetNext(LogEntry::kWebSocket);
    if (next == nullptr)
      return nullptr;
    // it's a request (and |include_requests| is false)
    if (!include_requests && next->event_type == LogEntry::kRequest)
      continue;
    return next;
  }
}

SyncWebSocket::StatusCode LogReplaySocket::ReceiveNextMessage(
    std::string* message,
    const Timeout& timeout) {
  if (socket_id_ == "") {
    return SyncWebSocket::StatusCode::kDisconnected;
  }
  std::unique_ptr<LogEntry> next = GetNextSocketEntry(false);
  if (next->event_type == LogEntry::kResponse) {
    // We have to build the messages back up to what they would have been
    // in the actual WebSocket.
    *message = "{\"id\":" + base::NumberToString(next->id) +
               SessionIdJson(next->session_id) +
               ",\"result\":" + next->payload + "}";
    return SyncWebSocket::StatusCode::kOk;
  }
  // it's an event
  *message = "{\"method\":\"" + next->command_name + "\"" +
             SessionIdJson(next->session_id) + ",\"params\":" + next->payload +
             "}";
  return SyncWebSocket::StatusCode::kOk;
}

// Ensures that we are not getting ahead of Chromedriver.
//
// This means not returning events or responses before ChromeDriver has taken
// the action that triggers them.
//
// There is a rare case where the following order of events occurs in the log:
// client-side command
// WebSocket Command (id=X) (resulting from client-side command)
// WebSocket Event
// WebSocket Response (id=X)
// To ensure that we don't fire the second event before the client-side
// command is called (thus probably causing an error), we must block when we
// see the WebSocket Command until that id is sent through the Send method.
// Such a WebSocket Command will always occur after a client-side command.
// If the event occurs between the client-side command and the WebSocket
// Command, it will be fine to fire at that time because ChromeDriver hasn't
// taken any action on the client-side command yet.
bool LogReplaySocket::HasNextMessage() {
  // "Peek" the next entry
  std::unique_ptr<LogEntry> next = GetNextSocketEntry(true);
  if (next == nullptr)
    return false;
  if (next->event_type == LogEntry::kEvent) {
    log_reader_.UndoGetNext(std::move(next));
    return true;
  }
  bool have_message = next->id <= max_id_;
  log_reader_.UndoGetNext(std::move(next));
  return have_message;
}