Skip to content

Commit

Permalink
Change TCP Socket's connect to take a SocketAddress struct.
Browse files Browse the repository at this point in the history
  • Loading branch information
dom96 committed Feb 14, 2023
1 parent f32d4f2 commit c0ea735
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/workerd/api/global-scope.c++
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ jsg::Promise<jsg::Ref<Response>> ServiceWorkerGlobalScope::fetch(
}

jsg::Ref<Socket> ServiceWorkerGlobalScope::connect(
jsg::Lock& js, kj::String address, jsg::Optional<SocketOptions> options,
jsg::Lock& js, AnySocketAddress address, jsg::Optional<SocketOptions> options,
CompatibilityFlags::Reader featureFlags) {
return connectImpl(js, nullptr, kj::mv(address), featureFlags);
}
Expand Down
2 changes: 1 addition & 1 deletion src/workerd/api/global-scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ class ServiceWorkerGlobalScope: public WorkerGlobalScope {
CompatibilityFlags::Reader featureFlags);

jsg::Ref<Socket> connect(
jsg::Lock& js, kj::String address, jsg::Optional<SocketOptions> options,
jsg::Lock& js, AnySocketAddress address, jsg::Optional<SocketOptions> options,
CompatibilityFlags::Reader featureFlags);

jsg::Ref<ServiceWorkerGlobalScope> getSelf() {
Expand Down
2 changes: 1 addition & 1 deletion src/workerd/api/http.c++
Original file line number Diff line number Diff line change
Expand Up @@ -1878,7 +1878,7 @@ jsg::Promise<jsg::Ref<Response>> fetchImpl(
}

jsg::Ref<Socket> Fetcher::connect(
jsg::Lock& js, kj::String address, jsg::Optional<SocketOptions> options,
jsg::Lock& js, AnySocketAddress address, jsg::Optional<SocketOptions> options,
CompatibilityFlags::Reader featureFlags) {
return connectImpl(js, JSG_THIS, kj::mv(address), featureFlags);
}
Expand Down
4 changes: 3 additions & 1 deletion src/workerd/api/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,8 @@ struct RequestInitializerDict;

class Socket;
struct SocketOptions;
struct SocketAddress;
typedef kj::OneOf<SocketAddress, kj::String> AnySocketAddress;

class Fetcher: public jsg::Object {
// A capability to send HTTP requests to some destination other than the public internet.
Expand Down Expand Up @@ -429,7 +431,7 @@ class Fetcher: public jsg::Object {
// specified on URLs, Fetcher-specific URL decoding options, and error handling.

jsg::Ref<Socket> connect(
jsg::Lock& js, kj::String address, jsg::Optional<SocketOptions> options,
jsg::Lock& js, AnySocketAddress address, jsg::Optional<SocketOptions> options,
CompatibilityFlags::Reader featureFlags);

jsg::Promise<jsg::Ref<Response>> fetch(
Expand Down
44 changes: 26 additions & 18 deletions src/workerd/api/sockets.c++
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,28 @@
namespace workerd::api {


bool isValidAddress(kj::StringPtr address) {
bool isValidHost(kj::StringPtr host) {
// This function performs some basic length and characters checks, it does not guarantee that
// the specified address is a valid domain. It should only be used to reject malicious
// addresses.
if (address.size() > (255 + 6) || address.size() == 0) {
// RFC1035 states that maximum domain name length is 255 octets. But we also add 6 to support
// port numbers in the address.
// the specified host is a valid domain. It should only be used to reject malicious
// hosts.
if (host.size() > 255 || host.size() == 0) {
// RFC1035 states that maximum domain name length is 255 octets.
//
// IP addresses are always shorter, so we take the max domain length instead.
return false;
}

for (int i = 0; i < address.size(); i++) {
switch (address[i]) {
for (int i = 0; i < host.size(); i++) {
switch (host[i]) {
case '-':
case '.':
case ':':
case '_':
case '[': case ']': // For IPv6.
case '[': case ']': case ':': // For IPv6.
break;
default:
if ((address[i] >= 'a' && address[i] <= 'z') ||
(address[i] >= 'A' && address[i] <= 'Z') ||
(address[i] >= '0' && address[i] <= '9')) {
if ((host[i] >= 'a' && host[i] <= 'z') ||
(host[i] >= 'A' && host[i] <= 'Z') ||
(host[i] >= '0' && host[i] <= '9')) {
break;
}
return false;
Expand All @@ -42,21 +40,31 @@ bool isValidAddress(kj::StringPtr address) {
}

jsg::Ref<Socket> connectImplNoOutputLock(
jsg::Lock& js, jsg::Ref<Fetcher> fetcher, kj::String address) {
jsg::Lock& js, jsg::Ref<Fetcher> fetcher, AnySocketAddress address) {

JSG_REQUIRE(isValidAddress(address), TypeError,
auto addressStr = kj::str("");
KJ_SWITCH_ONEOF(address) {
KJ_CASE_ONEOF(str, kj::String) {
addressStr = kj::mv(str);
}
KJ_CASE_ONEOF(record, SocketAddress) {
addressStr = kj::str(record.hostname, ":", record.port);
}
}

JSG_REQUIRE(isValidHost(addressStr), TypeError,
"Specified address is empty string, contains unsupported characters or is too long.");

auto& ioContext = IoContext::current();

auto jsRequest = Request::constructor(js, kj::str(address), nullptr);
auto jsRequest = Request::constructor(js, kj::str(addressStr), nullptr);
kj::Own<WorkerInterface> client = fetcher->getClient(
ioContext, jsRequest->serializeCfBlobJson(js), "connect"_kj);

// Set up the connection.
auto headers = kj::heap<kj::HttpHeaders>(ioContext.getHeaderTable());
auto httpClient = kj::newHttpClient(*client);
auto request = httpClient->connect(address, *headers);
auto request = httpClient->connect(addressStr, *headers);

// Initialise the readable/writable streams with the readable/writable sides of an AsyncIoStream.
auto sysStreams = newSystemMultiStream(kj::mv(request.connection), ioContext);
Expand All @@ -76,7 +84,7 @@ jsg::Ref<Socket> connectImplNoOutputLock(
}

jsg::Ref<Socket> connectImpl(
jsg::Lock& js, kj::Maybe<jsg::Ref<Fetcher>> fetcher, kj::String address,
jsg::Lock& js, kj::Maybe<jsg::Ref<Fetcher>> fetcher, AnySocketAddress address,
CompatibilityFlags::Reader featureFlags) {
// `connect()` should be hidden when the feature flag is off, so we shouldn't even get here.
KJ_ASSERT(featureFlags.getTcpSocketsSupport());
Expand Down
15 changes: 11 additions & 4 deletions src/workerd/api/sockets.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@

namespace workerd::api {

struct SocketAddress {
kj::String hostname;
uint16_t port;
JSG_STRUCT(hostname, port);
};

struct SocketOptions {
jsg::Unimplemented tls; // TODO(later): TCP socket options need to be implemented.
JSG_STRUCT(tls);
Expand Down Expand Up @@ -74,15 +80,16 @@ class Socket: public jsg::Object {
};

jsg::Ref<Socket> connectImplNoOutputLock(
jsg::Lock& js, jsg::Ref<Fetcher> fetcher, kj::String address);
jsg::Lock& js, jsg::Ref<Fetcher> fetcher, AnySocketAddress address);

jsg::Ref<Socket> connectImpl(
jsg::Lock& js, kj::Maybe<jsg::Ref<Fetcher>> fetcher, kj::String address,
jsg::Lock& js, kj::Maybe<jsg::Ref<Fetcher>> fetcher, AnySocketAddress address,
CompatibilityFlags::Reader featureFlags);

#define EW_SOCKETS_ISOLATE_TYPES \
#define EW_SOCKETS_ISOLATE_TYPES \
api::Socket, \
api::SocketOptions
api::SocketOptions, \
api::SocketAddress

// The list of sockets.h types that are added to worker.c++'s JSG_DECLARE_ISOLATE_TYPE
} // namespace workerd::api

0 comments on commit c0ea735

Please sign in to comment.