Commit 097fef76 authored by miket@chromium.org's avatar miket@chromium.org

- Changed the data structure being passed around in the socket API from a...

- Changed the data structure being passed around in the socket API from a string to an array of longs. This is a stepping stone to get us to ArrayBuffers.

- Changed "message" key to "data" for consistency.

BUG=120567
TEST=no new ones, but existing, as updated, still pass.

Review URL: http://codereview.chromium.org/10095020

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132512 0039d316-1c4b-4281-b951-d872f2087c98
parent 882898c6
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/json/json_writer.h" #include "base/json/json_writer.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
...@@ -50,18 +51,20 @@ void APIResourceEventNotifier::OnConnectComplete(int result_code) { ...@@ -50,18 +51,20 @@ void APIResourceEventNotifier::OnConnectComplete(int result_code) {
} }
void APIResourceEventNotifier::OnDataRead(int result_code, void APIResourceEventNotifier::OnDataRead(int result_code,
const std::string& data) { base::ListValue* data) {
// Do we have a destination for this event? There will be one if a source id // Do we have a destination for this event? There will be one if a source id
// was injected by the request handler for the resource's create method in // was injected by the request handler for the resource's create method in
// schema_generated_bindings.js, which will in turn be the case if the caller // schema_generated_bindings.js, which will in turn be the case if the caller
// of the create method provided an onEvent closure. // of the create method provided an onEvent closure.
if (src_id_ < 0) if (src_id_ < 0) {
delete data;
return; return;
}
DictionaryValue* event = CreateAPIResourceEvent( DictionaryValue* event = CreateAPIResourceEvent(
API_RESOURCE_EVENT_DATA_READ); API_RESOURCE_EVENT_DATA_READ);
event->SetInteger(kResultCodeKey, result_code); event->SetInteger(kResultCodeKey, result_code);
event->SetString(kDataKey, data); event->Set(kDataKey, data);
DispatchEvent(event); DispatchEvent(event);
} }
......
...@@ -16,6 +16,10 @@ ...@@ -16,6 +16,10 @@
class ExtensionEventRouter; class ExtensionEventRouter;
class Profile; class Profile;
namespace base {
class ListValue;
}
namespace extensions { namespace extensions {
enum APIResourceEventType { enum APIResourceEventType {
...@@ -47,7 +51,10 @@ class APIResourceEventNotifier ...@@ -47,7 +51,10 @@ class APIResourceEventNotifier
virtual ~APIResourceEventNotifier(); virtual ~APIResourceEventNotifier();
virtual void OnConnectComplete(int result_code); virtual void OnConnectComplete(int result_code);
virtual void OnDataRead(int result_code, const std::string& data);
// Takes ownership of data.
virtual void OnDataRead(int result_code, base::ListValue* data);
virtual void OnWriteComplete(int result_code); virtual void OnWriteComplete(int result_code);
static std::string APIResourceEventTypeToString( static std::string APIResourceEventTypeToString(
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
namespace extensions { namespace extensions {
const char kConnectionIdKey[] = "connectionId"; const char kConnectionIdKey[] = "connectionId";
const char kMessageKey[] = "message"; const char kDataKey[] = "data";
const char kBytesReadKey[] = "bytesRead"; const char kBytesReadKey[] = "bytesRead";
const char kBytesWrittenKey[] = "bytesWritten"; const char kBytesWrittenKey[] = "bytesWritten";
...@@ -81,19 +81,19 @@ bool SerialReadFunction::Prepare() { ...@@ -81,19 +81,19 @@ bool SerialReadFunction::Prepare() {
void SerialReadFunction::Work() { void SerialReadFunction::Work() {
int bytes_read = -1; int bytes_read = -1;
std::string message; std::string data;
SerialConnection* serial_connection = SerialConnection* serial_connection =
controller()->GetSerialConnection(connection_id_); controller()->GetSerialConnection(connection_id_);
if (serial_connection) { if (serial_connection) {
unsigned char byte = '\0'; unsigned char byte = '\0';
bytes_read = serial_connection->Read(&byte); bytes_read = serial_connection->Read(&byte);
if (bytes_read == 1) if (bytes_read == 1)
message = byte; data = byte;
} }
DictionaryValue* result = new DictionaryValue(); DictionaryValue* result = new DictionaryValue();
result->SetInteger(kBytesReadKey, bytes_read); result->SetInteger(kBytesReadKey, bytes_read);
result->SetString(kMessageKey, message); result->SetString(kDataKey, data);
result_.reset(result); result_.reset(result);
} }
......
...@@ -18,8 +18,7 @@ Socket::Socket(const std::string& address, int port, ...@@ -18,8 +18,7 @@ Socket::Socket(const std::string& address, int port,
: APIResource(APIResource::SocketResource, event_notifier), : APIResource(APIResource::SocketResource, event_notifier),
address_(address), address_(address),
port_(port), port_(port),
is_connected_(false), is_connected_(false) {
read_buffer_(new net::IOBufferWithSize(kMaxRead)) {
} }
Socket::~Socket() { Socket::~Socket() {
...@@ -27,47 +26,34 @@ Socket::~Socket() { ...@@ -27,47 +26,34 @@ Socket::~Socket() {
DCHECK(!is_connected_); DCHECK(!is_connected_);
} }
void Socket::OnDataRead(int result) { void Socket::OnDataRead(scoped_refptr<net::IOBuffer> io_buffer, int result) {
std::string message; // OnDataRead will take ownership of data_value.
if (result >= 0) ListValue* data_value = new ListValue();
message = std::string(read_buffer_->data(), result); if (result >= 0) {
event_notifier()->OnDataRead(result, message); size_t bytes_size = static_cast<size_t>(result);
const char* io_buffer_start = io_buffer->data();
for (size_t i = 0; i < bytes_size; ++i) {
data_value->Set(i, Value::CreateIntegerValue(io_buffer_start[i]));
}
}
event_notifier()->OnDataRead(result, data_value);
} }
void Socket::OnWriteComplete(int result) { void Socket::OnWriteComplete(int result) {
event_notifier()->OnWriteComplete(result); event_notifier()->OnWriteComplete(result);
} }
std::string Socket::Read() { int Socket::Read(scoped_refptr<net::IOBuffer> io_buffer, int io_buffer_len) {
int result = socket()->Read( return socket()->Read(
read_buffer_, kMaxRead, io_buffer.get(),
base::Bind(&Socket::OnDataRead, base::Unretained(this))); io_buffer_len,
if (result == net::ERR_IO_PENDING) base::Bind(&Socket::OnDataRead, base::Unretained(this), io_buffer));
return "";
if (result < 0)
return "";
return std::string(read_buffer_->data(), result);
} }
int Socket::Write(const std::string& message) { int Socket::Write(scoped_refptr<net::IOBuffer> io_buffer, int byte_count) {
int length = message.length(); return socket()->Write(
scoped_refptr<net::StringIOBuffer> io_buffer( io_buffer.get(), byte_count,
new net::StringIOBuffer(message)); base::Bind(&Socket::OnWriteComplete, base::Unretained(this)));
scoped_refptr<net::DrainableIOBuffer> buffer(
new net::DrainableIOBuffer(io_buffer, length));
int bytes_sent = 0;
while (buffer->BytesRemaining()) {
int result = socket()->Write(
buffer, buffer->BytesRemaining(),
base::Bind(&Socket::OnWriteComplete, base::Unretained(this)));
if (result <= 0)
// We pass all errors, including ERROR_IO_PENDING, back to the caller.
return bytes_sent > 0 ? bytes_sent : result;
bytes_sent += result;
buffer->DidConsume(result);
}
return bytes_sent;
} }
} // namespace extensions } // namespace extensions
...@@ -31,21 +31,18 @@ class Socket : public APIResource { ...@@ -31,21 +31,18 @@ class Socket : public APIResource {
virtual int Connect() = 0; virtual int Connect() = 0;
virtual void Disconnect() = 0; virtual void Disconnect() = 0;
// Returns a string representing what was able to be read without blocking. // Returns the number of bytes read into the buffer, or a negative number if
// If it reads an empty string, or blocks... the behavior is // an error occurred.
// indistinguishable! TODO(miket): this is awful. We should be returning a virtual int Read(scoped_refptr<net::IOBuffer> io_buffer, int io_buffer_size);
// blob, and we should be giving the caller all needed information about
// what's happening with the read operation.
virtual std::string Read();
// Returns the number of bytes successfully written, or a negative error // Returns the number of bytes successfully written, or a negative error
// code. Note that ERR_IO_PENDING means that the operation blocked, in which // code. Note that ERR_IO_PENDING means that the operation blocked, in which
// case |event_notifier| will eventually be called with the final result // case |event_notifier| (supplied at socket creation) will eventually be
// (again, either a nonnegative number of bytes written, or a negative // called with the final result (again, either a nonnegative number of bytes
// error). // written, or a negative error).
virtual int Write(const std::string& message); virtual int Write(scoped_refptr<net::IOBuffer> io_buffer, int bytes);
virtual void OnDataRead(int result); virtual void OnDataRead(scoped_refptr<net::IOBuffer> io_buffer, int result);
virtual void OnWriteComplete(int result); virtual void OnWriteComplete(int result);
protected: protected:
...@@ -56,10 +53,6 @@ class Socket : public APIResource { ...@@ -56,10 +53,6 @@ class Socket : public APIResource {
const std::string address_; const std::string address_;
int port_; int port_;
bool is_connected_; bool is_connected_;
private:
static const int kMaxRead = 1024;
scoped_refptr<net::IOBufferWithSize> read_buffer_;
}; };
} // namespace extensions } // namespace extensions
......
...@@ -5,17 +5,17 @@ ...@@ -5,17 +5,17 @@
#include "chrome/browser/extensions/api/socket/socket_api.h" #include "chrome/browser/extensions/api/socket/socket_api.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/values.h"
#include "chrome/browser/extensions/api/api_resource_controller.h" #include "chrome/browser/extensions/api/api_resource_controller.h"
#include "chrome/browser/extensions/api/socket/socket.h" #include "chrome/browser/extensions/api/socket/socket.h"
#include "chrome/browser/extensions/api/socket/tcp_socket.h" #include "chrome/browser/extensions/api/socket/tcp_socket.h"
#include "chrome/browser/extensions/api/socket/udp_socket.h" #include "chrome/browser/extensions/api/socket/udp_socket.h"
#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service.h"
#include "net/base/io_buffer.h"
namespace extensions { namespace extensions {
const char kBytesWrittenKey[] = "bytesWritten"; const char kBytesWrittenKey[] = "bytesWritten";
const char kMessageKey[] = "message"; const char kDataKey[] = "data";
const char kSocketIdKey[] = "socketId"; const char kSocketIdKey[] = "socketId";
const char kTCPOption[] = "tcp"; const char kTCPOption[] = "tcp";
const char kUDPOption[] = "udp"; const char kUDPOption[] = "udp";
...@@ -125,13 +125,29 @@ bool SocketReadFunction::Prepare() { ...@@ -125,13 +125,29 @@ bool SocketReadFunction::Prepare() {
} }
void SocketReadFunction::Work() { void SocketReadFunction::Work() {
std::string message; // TODO(miket): this is an arbitrary number. Can we come up with one that
// makes sense?
const int buffer_len = 2048;
scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(buffer_len));
Socket* socket = controller()->GetSocket(socket_id_); Socket* socket = controller()->GetSocket(socket_id_);
int bytes_read = -1;
if (socket) if (socket)
message = socket->Read(); bytes_read = socket->Read(io_buffer, buffer_len);
// TODO(miket): the buffer-to-array functionality appears twice, once here
// and once in socket.cc. When serial etc. is converted over, it'll appear
// there, too. What's a good single place for it to live? Keep in mind that
// this is short-term code, to be replaced with ArrayBuffer code.
DictionaryValue* result = new DictionaryValue(); DictionaryValue* result = new DictionaryValue();
result->SetString(kMessageKey, message); ListValue* data_value = new ListValue();
if (bytes_read > 0) {
size_t bytes_size = static_cast<size_t>(bytes_read);
const char* io_buffer_start = io_buffer->data();
for (size_t i = 0; i < bytes_size; ++i) {
data_value->Set(i, Value::CreateIntegerValue(io_buffer_start[i]));
}
}
result->Set(kDataKey, data_value);
result_.reset(result); result_.reset(result);
} }
...@@ -139,9 +155,33 @@ bool SocketReadFunction::Respond() { ...@@ -139,9 +155,33 @@ bool SocketReadFunction::Respond() {
return true; return true;
} }
SocketWriteFunction::SocketWriteFunction()
: socket_id_(0),
io_buffer_(NULL) {
}
SocketWriteFunction::~SocketWriteFunction() {
}
bool SocketWriteFunction::Prepare() { bool SocketWriteFunction::Prepare() {
EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &socket_id_)); EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &socket_id_));
EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &message_)); base::ListValue *data_list_value;
EXTENSION_FUNCTION_VALIDATE(args_->GetList(1, &data_list_value));
size_t size = data_list_value->GetSize();
if (size != 0) {
io_buffer_ = new net::IOBufferWithSize(size);
uint8* data_buffer =
reinterpret_cast<uint8*>(io_buffer_->data());
for (size_t i = 0; i < size; ++i) {
int int_value = -1;
data_list_value->GetInteger(i, &int_value);
DCHECK(int_value < 256);
DCHECK(int_value >= 0);
uint8 truncated_int = static_cast<uint8>(int_value);
*data_buffer++ = truncated_int;
}
}
return true; return true;
} }
...@@ -149,8 +189,8 @@ void SocketWriteFunction::Work() { ...@@ -149,8 +189,8 @@ void SocketWriteFunction::Work() {
int bytes_written = -1; int bytes_written = -1;
Socket* socket = controller()->GetSocket(socket_id_); Socket* socket = controller()->GetSocket(socket_id_);
if (socket) if (socket)
bytes_written = socket->Write(message_); bytes_written = socket->Write(io_buffer_, io_buffer_->size());
else else
error_ = kSocketNotFoundError; error_ = kSocketNotFoundError;
DictionaryValue* result = new DictionaryValue(); DictionaryValue* result = new DictionaryValue();
......
...@@ -6,7 +6,9 @@ ...@@ -6,7 +6,9 @@
#define CHROME_BROWSER_EXTENSIONS_API_SOCKET_SOCKET_API_H_ #define CHROME_BROWSER_EXTENSIONS_API_SOCKET_SOCKET_API_H_
#pragma once #pragma once
#include "base/memory/ref_counted.h"
#include "chrome/browser/extensions/api/api_function.h" #include "chrome/browser/extensions/api/api_function.h"
#include "net/base/io_buffer.h"
#include <string> #include <string>
...@@ -99,6 +101,10 @@ class SocketReadFunction : public AsyncIOAPIFunction { ...@@ -99,6 +101,10 @@ class SocketReadFunction : public AsyncIOAPIFunction {
}; };
class SocketWriteFunction : public AsyncIOAPIFunction { class SocketWriteFunction : public AsyncIOAPIFunction {
public:
SocketWriteFunction();
virtual ~SocketWriteFunction();
protected: protected:
virtual bool Prepare() OVERRIDE; virtual bool Prepare() OVERRIDE;
virtual void Work() OVERRIDE; virtual void Work() OVERRIDE;
...@@ -106,7 +112,7 @@ class SocketWriteFunction : public AsyncIOAPIFunction { ...@@ -106,7 +112,7 @@ class SocketWriteFunction : public AsyncIOAPIFunction {
private: private:
int socket_id_; int socket_id_;
std::string message_; scoped_refptr<net::IOBufferWithSize> io_buffer_;
DECLARE_EXTENSION_FUNCTION_NAME("experimental.socket.write") DECLARE_EXTENSION_FUNCTION_NAME("experimental.socket.write")
}; };
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "chrome/browser/extensions/api/api_resource_event_notifier.h" #include "chrome/browser/extensions/api/api_resource_event_notifier.h"
#include "net/base/address_list.h" #include "net/base/address_list.h"
#include "net/base/completion_callback.h" #include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/base/rand_callback.h" #include "net/base/rand_callback.h"
#include "net/socket/tcp_client_socket.h" #include "net/socket/tcp_client_socket.h"
...@@ -56,7 +57,9 @@ TEST(SocketTest, TestTCPSocketRead) { ...@@ -56,7 +57,9 @@ TEST(SocketTest, TestTCPSocketRead) {
EXPECT_CALL(*tcp_client_socket, Read(_, _, _)) EXPECT_CALL(*tcp_client_socket, Read(_, _, _))
.Times(1); .Times(1);
std::string message = socket->Read(); scoped_refptr<net::IOBufferWithSize> io_buffer(
new net::IOBufferWithSize(512));
socket->Read(io_buffer.get(), io_buffer->size());
} }
TEST(SocketTest, TestTCPSocketWrite) { TEST(SocketTest, TestTCPSocketWrite) {
...@@ -70,7 +73,9 @@ TEST(SocketTest, TestTCPSocketWrite) { ...@@ -70,7 +73,9 @@ TEST(SocketTest, TestTCPSocketWrite) {
EXPECT_CALL(*tcp_client_socket, Write(_, _, _)) EXPECT_CALL(*tcp_client_socket, Write(_, _, _))
.Times(1); .Times(1);
socket->Write("foo"); scoped_refptr<net::IOBufferWithSize> io_buffer(
new net::IOBufferWithSize(256));
socket->Write(io_buffer.get(), io_buffer->size());
} }
TEST(SocketTest, TestTCPSocketBlockedWrite) { TEST(SocketTest, TestTCPSocketBlockedWrite) {
...@@ -87,7 +92,10 @@ TEST(SocketTest, TestTCPSocketBlockedWrite) { ...@@ -87,7 +92,10 @@ TEST(SocketTest, TestTCPSocketBlockedWrite) {
.WillOnce(testing::DoAll(SaveArg<2>(&callback), .WillOnce(testing::DoAll(SaveArg<2>(&callback),
Return(net::ERR_IO_PENDING))); Return(net::ERR_IO_PENDING)));
ASSERT_EQ(net::ERR_IO_PENDING, socket->Write("foo")); scoped_refptr<net::IOBufferWithSize> io_buffer(new net::IOBufferWithSize(
1));
ASSERT_EQ(net::ERR_IO_PENDING, socket->Write(io_buffer.get(),
io_buffer->size()));
// Good. Original call came back unable to complete. Now pretend the socket // Good. Original call came back unable to complete. Now pretend the socket
// finished, and confirm that we passed the error back. // finished, and confirm that we passed the error back.
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "chrome/browser/extensions/api/api_resource_event_notifier.h" #include "chrome/browser/extensions/api/api_resource_event_notifier.h"
#include "net/base/completion_callback.h" #include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/base/rand_callback.h" #include "net/base/rand_callback.h"
#include "net/udp/udp_client_socket.h" #include "net/udp/udp_client_socket.h"
...@@ -56,7 +57,9 @@ TEST(SocketTest, TestUDPSocketRead) { ...@@ -56,7 +57,9 @@ TEST(SocketTest, TestUDPSocketRead) {
EXPECT_CALL(*udp_client_socket, Read(_, _, _)) EXPECT_CALL(*udp_client_socket, Read(_, _, _))
.Times(1); .Times(1);
std::string message = socket->Read(); scoped_refptr<net::IOBufferWithSize> io_buffer(
new net::IOBufferWithSize(512));
socket->Read(io_buffer.get(), io_buffer->size());
} }
TEST(SocketTest, TestUDPSocketWrite) { TEST(SocketTest, TestUDPSocketWrite) {
...@@ -69,7 +72,9 @@ TEST(SocketTest, TestUDPSocketWrite) { ...@@ -69,7 +72,9 @@ TEST(SocketTest, TestUDPSocketWrite) {
EXPECT_CALL(*udp_client_socket, Write(_, _, _)) EXPECT_CALL(*udp_client_socket, Write(_, _, _))
.Times(1); .Times(1);
socket->Write("foo"); scoped_refptr<net::IOBufferWithSize> io_buffer(
new net::IOBufferWithSize(512));
socket->Write(io_buffer.get(), io_buffer->size());
} }
TEST(SocketTest, TestUDPSocketBlockedWrite) { TEST(SocketTest, TestUDPSocketBlockedWrite) {
...@@ -85,7 +90,9 @@ TEST(SocketTest, TestUDPSocketBlockedWrite) { ...@@ -85,7 +90,9 @@ TEST(SocketTest, TestUDPSocketBlockedWrite) {
.WillOnce(testing::DoAll(SaveArg<2>(&callback), .WillOnce(testing::DoAll(SaveArg<2>(&callback),
Return(net::ERR_IO_PENDING))); Return(net::ERR_IO_PENDING)));
ASSERT_EQ(net::ERR_IO_PENDING, socket->Write("foo")); scoped_refptr<net::IOBufferWithSize> io_buffer(new net::IOBufferWithSize(1));
ASSERT_EQ(net::ERR_IO_PENDING, socket->Write(io_buffer.get(),
io_buffer->size()));
// Good. Original call came back unable to complete. Now pretend the socket // Good. Original call came back unable to complete. Now pretend the socket
// finished, and confirm that we passed the error back. // finished, and confirm that we passed the error back.
......
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
long? resultCode; long? resultCode;
// The data read, if the event type is dataRead. // The data read, if the event type is dataRead.
DOMString? data; // TODO(miket): [instanceOf=ArrayBuffer]object? data;
long[]? data;
// Whether this is the final event that this socket will send. // Whether this is the final event that this socket will send.
[nodoc] boolean isFinalEvent; [nodoc] boolean isFinalEvent;
...@@ -53,7 +54,8 @@ ...@@ -53,7 +54,8 @@
dictionary ReadInfo { dictionary ReadInfo {
// The data received. Warning: will probably become a blob or other // The data received. Warning: will probably become a blob or other
// appropriate binary-friendly type. // appropriate binary-friendly type.
DOMString message; // TODO(miket): [instanceOf=ArrayBuffer]object data;
long[] data;
}; };
callback ReadCallback = void (ReadInfo readInfo); callback ReadCallback = void (ReadInfo readInfo);
...@@ -111,8 +113,9 @@ ...@@ -111,8 +113,9 @@
// write operation completes without blocking, the write operation blocked // write operation completes without blocking, the write operation blocked
// before completion (in which case onEvent() will eventually be called with // before completion (in which case onEvent() will eventually be called with
// a <code>writeComplete</code> event), or an error occurred. // a <code>writeComplete</code> event), or an error occurred.
// TODO(miket): [instanceOf=ArrayBuffer]object data;
static void write(long socketId, static void write(long socketId,
DOMString data, long[] data,
WriteCallback callback); WriteCallback callback);
}; };
......
...@@ -2,47 +2,63 @@ ...@@ -2,47 +2,63 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// net/tools/testserver/testserver.py is picky about the format of what it
// calls its "echo" messages. One might go so far as to mutter to oneself that
// it isn't an echo server at all.
//
// The response is based on the request but obfuscated using a random key.
const request = "0100000005320000005hello";
var expectedResponsePattern = /0100000005320000005.{11}/;
const socket = chrome.experimental.socket; const socket = chrome.experimental.socket;
const message = "helloECHO"; var address;
const address = "127.0.0.1"; var bytesWritten = 0;
var protocol = "none"; var dataAsString;
var dataRead = [];
var port = -1; var port = -1;
var protocol = "none";
var socketId = 0; var socketId = 0;
var dataRead = "";
var succeeded = false; var succeeded = false;
var waitCount = 0; var waitCount = 0;
var testSocketCreation = function() { // Many thanks to Dennis for his StackOverflow answer: http://goo.gl/UDanx
function onCreate(socketInfo) { function string2ArrayBuffer(string, callback) {
chrome.test.assertTrue(socketInfo.socketId > 0); var bb = new WebKitBlobBuilder();
bb.append(string);
var f = new FileReader();
f.onload = function(e) {
callback(e.target.result);
};
f.readAsArrayBuffer(bb.getBlob());
}
// TODO(miket): this doesn't work yet. It's possible this will become function arrayBuffer2String(buf, callback) {
// automatic, but either way we can't forget to clean up. var bb = new WebKitBlobBuilder();
//socket.destroy(socketInfo.socketId); bb.append(buf);
var f = new FileReader();
f.onload = function(e) {
callback(e.target.result);
};
f.readAsText(bb.getBlob());
}
chrome.test.succeed(); function arrayBufferToArrayOfLongs(arrayBuffer) {
var longs = [];
var arrayBufferView = new Uint8Array(arrayBuffer);
for (var i = 0; i < arrayBufferView.length; ++i) {
longs[i] = arrayBufferView[i];
} }
return longs;
}
socket.create(protocol, address, port, {}, onCreate); function arrayOfLongsToArrayBuffer(longs) {
}; var arrayBuffer = new ArrayBuffer(longs.length);
var arrayBufferView = new Uint8Array(arrayBuffer);
// net/tools/testserver/testserver.py is picky about the format of what for (var i = 0; i < longs.length; ++i) {
// it calls its "echo" messages. One might go so far as to mutter to arrayBufferView[i] = longs[i];
// oneself that it isn't an echo server at all. }
// return arrayBuffer;
// The response is based on the request but obfuscated using a random }
// key.
const request = "0100000005320000005hello";
var expectedResponsePattern = /0100000005320000005.{11}/;
var address;
var protocol;
var port;
var socketId = 0;
var bytesWritten = 0;
var dataRead = "";
var succeeded = false;
var waitCount = 0;
var testSocketCreation = function() { var testSocketCreation = function() {
function onCreate(socketInfo) { function onCreate(socketInfo) {
...@@ -50,6 +66,7 @@ var testSocketCreation = function() { ...@@ -50,6 +66,7 @@ var testSocketCreation = function() {
// TODO(miket): this doesn't work yet. It's possible this will become // TODO(miket): this doesn't work yet. It's possible this will become
// automatic, but either way we can't forget to clean up. // automatic, but either way we can't forget to clean up.
//
//socket.destroy(socketInfo.socketId); //socket.destroy(socketInfo.socketId);
chrome.test.succeed(); chrome.test.succeed();
...@@ -59,11 +76,14 @@ var testSocketCreation = function() { ...@@ -59,11 +76,14 @@ var testSocketCreation = function() {
}; };
function onDataRead(readInfo) { function onDataRead(readInfo) {
dataRead += readInfo.message; // TODO(miket): this isn't correct for multiple calls of onDataRead.
if (dataRead.match(expectedResponsePattern)) { arrayBuffer2String(arrayOfLongsToArrayBuffer(readInfo.data), function(s) {
succeeded = true; dataAsString = s; // save this for error reporting
chrome.test.succeed(); if (s.match(expectedResponsePattern)) {
} succeeded = true;
chrome.test.succeed();
}
});
// Blocked. Wait for onEvent. // Blocked. Wait for onEvent.
} }
...@@ -77,7 +97,10 @@ function onWriteComplete(writeInfo) { ...@@ -77,7 +97,10 @@ function onWriteComplete(writeInfo) {
function onConnectComplete(connectResult) { function onConnectComplete(connectResult) {
if (connectResult == 0) { if (connectResult == 0) {
socket.write(socketId, request, onWriteComplete); string2ArrayBuffer(request, function(arrayBuffer) {
var longs = arrayBufferToArrayOfLongs(arrayBuffer);
socket.write(socketId, longs, onWriteComplete);
});
} }
// Blocked. Wait for onEvent. // Blocked. Wait for onEvent.
} }
...@@ -92,8 +115,7 @@ function onEvent(socketEvent) { ...@@ -92,8 +115,7 @@ function onEvent(socketEvent) {
if (socketEvent.type == "connectComplete") { if (socketEvent.type == "connectComplete") {
onConnectComplete(socketEvent.resultCode); onConnectComplete(socketEvent.resultCode);
} else if (socketEvent.type == "dataRead") { } else if (socketEvent.type == "dataRead") {
// TODO(miket): why one "message" and the other "data"? onDataRead({data: socketEvent.data});
onDataRead({message: socketEvent.data});
} else if (socketEvent.type == "writeComplete") { } else if (socketEvent.type == "writeComplete") {
onWriteComplete(socketEvent.resultCode); onWriteComplete(socketEvent.resultCode);
} else { } else {
...@@ -101,33 +123,13 @@ function onEvent(socketEvent) { ...@@ -101,33 +123,13 @@ function onEvent(socketEvent) {
} }
}; };
function onRead(readInfo) {
if (readInfo.message == message) {
succeeded = true;
chrome.test.succeed();
} else {
// The read blocked. Save what we've got so far, and wait for onEvent.
dataRead = readInfo.message;
}
}
function onWrite(writeInfo) {
chrome.test.assertTrue(writeInfo.bytesWritten == message.length);
socket.read(socketId, onRead);
}
function onConnect(connectResult) {
chrome.test.assertTrue(connectResult);
socket.write(socketId, message, onWrite);
}
function waitForBlockingOperation() { function waitForBlockingOperation() {
if (++waitCount < 10) { if (++waitCount < 10) {
setTimeout(waitForBlockingOperation, 1000); setTimeout(waitForBlockingOperation, 1000);
} else { } else {
// We weren't able to succeed in the given time. // We weren't able to succeed in the given time.
chrome.test.fail("Operations didn't complete after " + waitCount + " " + chrome.test.fail("Operations didn't complete after " + waitCount + " " +
"seconds. Response so far was <" + dataRead + ">."); "seconds. Response so far was <" + dataAsString + ">.");
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment