<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/common/socket_stream_dispatcher.h"

#include <vector>

#include "base/id_map.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop.h"
#include "base/task.h"
#include "content/common/child_thread.h"
#include "content/common/socket_stream.h"
#include "content/common/socket_stream_messages.h"
#include "googleurl/src/gurl.h"
#include "webkit/glue/websocketstreamhandle_bridge.h"
#include "webkit/glue/websocketstreamhandle_delegate.h"

// IPCWebSocketStreamHandleBridge is owned by each SocketStreamHandle.
// It communicates with the main browser process via SocketStreamDispatcher.
class IPCWebSocketStreamHandleBridge
    : public webkit_glue::WebSocketStreamHandleBridge {
 public:
  IPCWebSocketStreamHandleBridge(
      ChildThread* child_thread,
      WebKit::WebSocketStreamHandle* handle,
      webkit_glue::WebSocketStreamHandleDelegate* delegate)
      : socket_id_(content_common::kNoSocketId),
        child_thread_(child_thread),
        handle_(handle),
        delegate_(delegate) {}

  // Returns the handle having given id or NULL if there is no such handle.
  static IPCWebSocketStreamHandleBridge* FromSocketId(int id);

  // webkit_glue::WebSocketStreamHandleBridge methods.
  virtual void Connect(const GURL& url);
  virtual bool Send(const std::vector<char>& data);
  virtual void Close();

  // Called by SocketStreamDispatcher.
  void OnConnected(int max_amount_send_allowed);
  void OnSentData(int amount_sent);
  void OnReceivedData(const std::vector<char>& data);
  void OnClosed();

 private:
  virtual ~IPCWebSocketStreamHandleBridge();

  void DoConnect(const GURL& url);
  int socket_id_;

  ChildThread* child_thread_;
  WebKit::WebSocketStreamHandle* handle_;
  webkit_glue::WebSocketStreamHandleDelegate* delegate_;

  static IDMap<IPCWebSocketStreamHandleBridge> all_bridges;
};

IDMap<IPCWebSocketStreamHandleBridge>
IPCWebSocketStreamHandleBridge::all_bridges;

/* static */
IPCWebSocketStreamHandleBridge* IPCWebSocketStreamHandleBridge::FromSocketId(
    int id) {
  return all_bridges.Lookup(id);
}

IPCWebSocketStreamHandleBridge::~IPCWebSocketStreamHandleBridge() {
  DVLOG(1) << "IPCWebSocketStreamHandleBridge destructor socket_id="
           << socket_id_;
  if (socket_id_ != content_common::kNoSocketId) {
    child_thread_->Send(new SocketStreamHostMsg_Close(socket_id_));
    socket_id_ = content_common::kNoSocketId;
  }
}

void IPCWebSocketStreamHandleBridge::Connect(const GURL& url) {
  DCHECK(child_thread_);
  DVLOG(1) << "Connect url=" << url;
  child_thread_->message_loop()->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &IPCWebSocketStreamHandleBridge::DoConnect,
                        url));
}

bool IPCWebSocketStreamHandleBridge::Send(
    const std::vector<char>& data) {
  DVLOG(1) << "Send data.size=" << data.size();
  if (child_thread_->Send(
      new SocketStreamHostMsg_SendData(socket_id_, data))) {
    if (delegate_)
      delegate_->WillSendData(handle_, &data[0], data.size());
    return true;
  }
  return false;
}

void IPCWebSocketStreamHandleBridge::Close() {
  DVLOG(1) << "Close socket_id" << socket_id_;
  child_thread_->Send(new SocketStreamHostMsg_Close(socket_id_));
}

void IPCWebSocketStreamHandleBridge::OnConnected(int max_pending_send_allowed) {
  DVLOG(1) << "IPCWebSocketStreamHandleBridge::OnConnected socket_id="
           << socket_id_;
  if (delegate_)
    delegate_->DidOpenStream(handle_, max_pending_send_allowed);
}

void IPCWebSocketStreamHandleBridge::OnSentData(int amount_sent) {
  if (delegate_)
    delegate_->DidSendData(handle_, amount_sent);
}

void IPCWebSocketStreamHandleBridge::OnReceivedData(
    const std::vector<char>& data) {
  if (delegate_)
    delegate_->DidReceiveData(handle_, &data[0], data.size());
}

void IPCWebSocketStreamHandleBridge::OnClosed() {
  DVLOG(1) << "IPCWebSocketStreamHandleBridge::OnClosed";
  if (socket_id_ != content_common::kNoSocketId) {
    all_bridges.Remove(socket_id_);
    socket_id_ = content_common::kNoSocketId;
  }
  if (delegate_)
    delegate_->DidClose(handle_);
  delegate_ = NULL;
  Release();
}

void IPCWebSocketStreamHandleBridge::DoConnect(const GURL& url) {
  DCHECK(child_thread_);
  DCHECK_EQ(socket_id_, content_common::kNoSocketId);
  if (delegate_)
    delegate_->WillOpenStream(handle_, url);

  socket_id_ = all_bridges.Add(this);
  DCHECK_NE(socket_id_, content_common::kNoSocketId);
  AddRef();  // Released in OnClosed().
  if (child_thread_->Send(new SocketStreamHostMsg_Connect(url, socket_id_))) {
    DVLOG(1) << "Connect socket_id=" << socket_id_;
    // TODO(ukai): timeout to OnConnected.
  } else {
    LOG(ERROR) << "IPC SocketStream_Connect failed.";
    OnClosed();
  }
}

SocketStreamDispatcher::SocketStreamDispatcher() {
}

/* static */
webkit_glue::WebSocketStreamHandleBridge*
SocketStreamDispatcher::CreateBridge(
    WebKit::WebSocketStreamHandle* handle,<commit_msg>When JavaScript call WebSocket.close() before onopen event happens, IPCWebSocketStreamHandleBridge::Close() run ahead of DoConnect(). In this case, DoClose() do nothing because the object doesn't have a correct socket_id_. This change move actual Close() handling to DoClose(), then make Close() post DoClose() as delayed task to keep execution ordering.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/common/socket_stream_dispatcher.h"

#include <vector>

#include "base/id_map.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop.h"
#include "base/task.h"
#include "content/common/child_thread.h"
#include "content/common/socket_stream.h"
#include "content/common/socket_stream_messages.h"
#include "googleurl/src/gurl.h"
#include "webkit/glue/websocketstreamhandle_bridge.h"
#include "webkit/glue/websocketstreamhandle_delegate.h"

// IPCWebSocketStreamHandleBridge is owned by each SocketStreamHandle.
// It communicates with the main browser process via SocketStreamDispatcher.
class IPCWebSocketStreamHandleBridge
    : public webkit_glue::WebSocketStreamHandleBridge {
 public:
  IPCWebSocketStreamHandleBridge(
      ChildThread* child_thread,
      WebKit::WebSocketStreamHandle* handle,
      webkit_glue::WebSocketStreamHandleDelegate* delegate)
      : socket_id_(content_common::kNoSocketId),
        child_thread_(child_thread),
        handle_(handle),
        delegate_(delegate) {}

  // Returns the handle having given id or NULL if there is no such handle.
  static IPCWebSocketStreamHandleBridge* FromSocketId(int id);

  // webkit_glue::WebSocketStreamHandleBridge methods.
  virtual void Connect(const GURL& url);
  virtual bool Send(const std::vector<char>& data);
  virtual void Close();

  // Called by SocketStreamDispatcher.
  void OnConnected(int max_amount_send_allowed);
  void OnSentData(int amount_sent);
  void OnReceivedData(const std::vector<char>& data);
  void OnClosed();

 private:
  virtual ~IPCWebSocketStreamHandleBridge();

  void DoConnect(const GURL& url);
  void DoClose();
  int socket_id_;

  ChildThread* child_thread_;
  WebKit::WebSocketStreamHandle* handle_;
  webkit_glue::WebSocketStreamHandleDelegate* delegate_;

  static IDMap<IPCWebSocketStreamHandleBridge> all_bridges;
};

IDMap<IPCWebSocketStreamHandleBridge>
IPCWebSocketStreamHandleBridge::all_bridges;

/* static */
IPCWebSocketStreamHandleBridge* IPCWebSocketStreamHandleBridge::FromSocketId(
    int id) {
  return all_bridges.Lookup(id);
}

IPCWebSocketStreamHandleBridge::~IPCWebSocketStreamHandleBridge() {
  DVLOG(1) << "IPCWebSocketStreamHandleBridge destructor socket_id="
           << socket_id_;
  if (socket_id_ != content_common::kNoSocketId) {
    child_thread_->Send(new SocketStreamHostMsg_Close(socket_id_));
    socket_id_ = content_common::kNoSocketId;
  }
}

void IPCWebSocketStreamHandleBridge::Connect(const GURL& url) {
  DCHECK(child_thread_);
  DVLOG(1) << "Connect url=" << url;
  child_thread_->message_loop()->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &IPCWebSocketStreamHandleBridge::DoConnect,
                        url));
}

bool IPCWebSocketStreamHandleBridge::Send(
    const std::vector<char>& data) {
  DVLOG(1) << "Send data.size=" << data.size();
  if (child_thread_->Send(
      new SocketStreamHostMsg_SendData(socket_id_, data))) {
    if (delegate_)
      delegate_->WillSendData(handle_, &data[0], data.size());
    return true;
  }
  return false;
}

void IPCWebSocketStreamHandleBridge::Close() {
  DVLOG(1) << "Close socket_id" << socket_id_;
  AddRef();  // Released in DoClose().
  child_thread_->message_loop()->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &IPCWebSocketStreamHandleBridge::DoClose));
}

void IPCWebSocketStreamHandleBridge::OnConnected(int max_pending_send_allowed) {
  DVLOG(1) << "IPCWebSocketStreamHandleBridge::OnConnected socket_id="
           << socket_id_;
  if (delegate_)
    delegate_->DidOpenStream(handle_, max_pending_send_allowed);
}

void IPCWebSocketStreamHandleBridge::OnSentData(int amount_sent) {
  if (delegate_)
    delegate_->DidSendData(handle_, amount_sent);
}

void IPCWebSocketStreamHandleBridge::OnReceivedData(
    const std::vector<char>& data) {
  if (delegate_)
    delegate_->DidReceiveData(handle_, &data[0], data.size());
}

void IPCWebSocketStreamHandleBridge::OnClosed() {
  DVLOG(1) << "IPCWebSocketStreamHandleBridge::OnClosed";
  if (socket_id_ != content_common::kNoSocketId) {
    all_bridges.Remove(socket_id_);
    socket_id_ = content_common::kNoSocketId;
  }
  if (delegate_)
    delegate_->DidClose(handle_);
  delegate_ = NULL;
  Release();
}

void IPCWebSocketStreamHandleBridge::DoConnect(const GURL& url) {
  DCHECK(child_thread_);
  DCHECK_EQ(socket_id_, content_common::kNoSocketId);
  if (delegate_)
    delegate_->WillOpenStream(handle_, url);

  socket_id_ = all_bridges.Add(this);
  DCHECK_NE(socket_id_, content_common::kNoSocketId);
  AddRef();  // Released in OnClosed().
  if (child_thread_->Send(new SocketStreamHostMsg_Connect(url, socket_id_))) {
    DVLOG(1) << "Connect socket_id=" << socket_id_;
    // TODO(ukai): timeout to OnConnected.
  } else {
    LOG(ERROR) << "IPC SocketStream_Connect failed.";
    OnClosed();
  }
}

void IPCWebSocketStreamHandleBridge::DoClose() {
  child_thread_->Send(new SocketStreamHostMsg_Close(socket_id_));
  Release();
}

SocketStreamDispatcher::SocketStreamDispatcher() {
}

/* static */
webkit_glue::WebSocketStreamHandleBridge*
SocketStreamDispatcher::CreateBridge(
    WebKit::WebSocketStreamHandle* handle,
{'fraction_non_alphanumeric': 0.11163653222067686, 'fraction_numerical': 0.002410755679184052, 'mean_word_length': 5.474189675870348, 'pattern_counts': {'":': 0, '<': 73, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4657889', 'n_tokens_mistral': 3486, 'n_tokens_neox': 3355, 'n_words': 666}