Skip to content

Commit e48ac4e

Browse files
authored
Merge pull request #120 from kjin/grpc-js-core-work
grpc-js-core: compiler error and http2-facing fixes
2 parents e397ad5 + b7eb3d6 commit e48ac4e

File tree

5 files changed

+25
-21
lines changed

5 files changed

+25
-21
lines changed

packages/grpc-js-core/src/call-credentials.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {map, reduce} from 'lodash';
33
import {Metadata} from './metadata';
44

55
export type CallMetadataGenerator =
6-
(options: Object, cb: (err: Error|null, metadata?: Metadata) => void) =>
6+
(options: {}, cb: (err: Error|null, metadata?: Metadata) => void) =>
77
void;
88

99
/**
@@ -15,7 +15,7 @@ export interface CallCredentials {
1515
* Asynchronously generates a new Metadata object.
1616
* @param options Options used in generating the Metadata object.
1717
*/
18-
generateMetadata(options: Object): Promise<Metadata>;
18+
generateMetadata(options: {}): Promise<Metadata>;
1919
/**
2020
* Creates a new CallCredentials object from properties of both this and
2121
* another CallCredentials object. This object's metadata generator will be
@@ -28,7 +28,7 @@ export interface CallCredentials {
2828
class ComposedCallCredentials implements CallCredentials {
2929
constructor(private creds: CallCredentials[]) {}
3030

31-
async generateMetadata(options: Object): Promise<Metadata> {
31+
async generateMetadata(options: {}): Promise<Metadata> {
3232
let base: Metadata = new Metadata();
3333
let generated: Metadata[] = await Promise.all(
3434
map(this.creds, (cred) => cred.generateMetadata(options)));
@@ -46,7 +46,7 @@ class ComposedCallCredentials implements CallCredentials {
4646
class SingleCallCredentials implements CallCredentials {
4747
constructor(private metadataGenerator: CallMetadataGenerator) {}
4848

49-
async generateMetadata(options: Object): Promise<Metadata> {
49+
async generateMetadata(options: {}): Promise<Metadata> {
5050
return new Promise<Metadata>((resolve, reject) => {
5151
this.metadataGenerator(options, (err, metadata) => {
5252
if (metadata !== undefined) {
@@ -64,7 +64,7 @@ class SingleCallCredentials implements CallCredentials {
6464
}
6565

6666
class EmptyCallCredentials implements CallCredentials {
67-
async generateMetadata(options: Object): Promise<Metadata> {
67+
async generateMetadata(options: {}): Promise<Metadata> {
6868
return new Metadata();
6969
}
7070

packages/grpc-js-core/src/call-stream.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,10 @@ export class Http2CallStream extends Duplex implements CallStream {
182182
this.cancelWithStatus(Status.UNKNOWN, error.message);
183183
});
184184
});
185-
stream.on('trailers', (headers) => {
185+
stream.on('trailers', (headers: http2.IncomingHttpHeaders) => {
186186
let code: Status = this.mappedStatusCode;
187-
if (headers.hasOwnProperty('grpc-status')) {
187+
let details = '';
188+
if (typeof headers['grpc-status'] === 'string') {
188189
let receivedCode = Number(headers['grpc-status']);
189190
if (receivedCode in Status) {
190191
code = receivedCode;
@@ -193,9 +194,8 @@ export class Http2CallStream extends Duplex implements CallStream {
193194
}
194195
delete headers['grpc-status'];
195196
}
196-
let details = '';
197-
if (headers.hasOwnProperty('grpc-message')) {
198-
details = decodeURI(headers['grpc-message']);
197+
if (typeof headers['grpc-message'] === 'string') {
198+
details = decodeURI(headers['grpc-message'] as string);
199199
}
200200
let metadata: Metadata;
201201
try {
@@ -301,7 +301,7 @@ export class Http2CallStream extends Duplex implements CallStream {
301301
}
302302
this.endCall({code: code, details: details, metadata: new Metadata()});
303303
});
304-
stream.on('error', () => {
304+
stream.on('error', (err: Error) => {
305305
this.endCall({
306306
code: Status.INTERNAL,
307307
details: 'Internal HTTP2 error',
@@ -325,7 +325,9 @@ export class Http2CallStream extends Duplex implements CallStream {
325325

326326
cancelWithStatus(status: Status, details: string): void {
327327
this.endCall({code: status, details: details, metadata: new Metadata()});
328-
if (this.http2Stream !== null) {
328+
// The http2 stream could already have been destroyed if cancelWithStatus
329+
// is called in response to an internal http2 error.
330+
if (this.http2Stream !== null && !this.http2Stream.destroyed) {
329331
/* TODO(murgatroid99): Determine if we want to send different RST_STREAM
330332
* codes based on the status code */
331333
this.http2Stream.rstWithCancel();

packages/grpc-js-core/src/channel.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export interface Channel extends EventEmitter {
7171
}
7272

7373
export class Http2Channel extends EventEmitter implements Channel {
74+
private readonly authority: url.URL;
7475
private connectivityState: ConnectivityState = ConnectivityState.IDLE;
7576
/* For now, we have up to one subchannel, which will exist as long as we are
7677
* connecting or trying to connect */
@@ -134,9 +135,9 @@ export class Http2Channel extends EventEmitter implements Channel {
134135
let subChannel: http2.ClientHttp2Session;
135136
let secureContext = this.credentials.getSecureContext();
136137
if (secureContext === null) {
137-
subChannel = http2.connect(this.address);
138+
subChannel = http2.connect(this.authority);
138139
} else {
139-
subChannel = http2.connect(this.address, {secureContext});
140+
subChannel = http2.connect(this.authority, {secureContext});
140141
}
141142
this.subChannel = subChannel;
142143
let now = new Date();
@@ -165,14 +166,14 @@ export class Http2Channel extends EventEmitter implements Channel {
165166
}
166167

167168
constructor(
168-
private readonly address: url.URL,
169+
address: string,
169170
public readonly credentials: ChannelCredentials,
170171
private readonly options: ChannelOptions) {
171172
super();
172173
if (credentials.getSecureContext() === null) {
173-
address.protocol = 'http';
174+
this.authority = new url.URL(`http://${address}`);
174175
} else {
175-
address.protocol = 'https';
176+
this.authority = new url.URL(`https://${address}`);
176177
}
177178
this.filterStackFactory = new FilterStackFactory([
178179
new CompressionFilterFactory(this),
@@ -193,7 +194,7 @@ export class Http2Channel extends EventEmitter implements Channel {
193194
finalMetadata.then(
194195
(metadataValue) => {
195196
let headers = metadataValue.toHttp2Headers();
196-
headers[HTTP2_HEADER_AUTHORITY] = this.address.hostname;
197+
headers[HTTP2_HEADER_AUTHORITY] = this.authority.hostname;
197198
headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc';
198199
headers[HTTP2_HEADER_METHOD] = 'POST';
199200
headers[HTTP2_HEADER_PATH] = methodName;

packages/grpc-js-core/src/client.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export class Client {
2424
}
2525
// TODO(murgatroid99): Figure out how to get version number
2626
// options['grpc.primary_user_agent'] += 'grpc-node/' + version;
27-
this.channel = new Http2Channel(new URL(address), credentials, options);
27+
this.channel = new Http2Channel(address, credentials, options);
2828
}
2929

3030
close(): void {

packages/grpc-js-core/src/metadata.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ export class Metadata {
166166
* Creates an OutgoingHttpHeaders object that can be used with the http2 API.
167167
*/
168168
toHttp2Headers(): http2.OutgoingHttpHeaders {
169+
// NOTE: Node <8.9 formats http2 headers incorrectly.
169170
const result: http2.OutgoingHttpHeaders = {};
170171
forOwn(this.internalRepr, (values, key) => {
171172
// We assume that the user's interaction with this object is limited to
@@ -194,15 +195,15 @@ export class Metadata {
194195
values.forEach((value) => {
195196
result.add(key, Buffer.from(value, 'base64'));
196197
});
197-
} else {
198+
} else if (values !== undefined) {
198199
result.add(key, Buffer.from(values, 'base64'));
199200
}
200201
} else {
201202
if (Array.isArray(values)) {
202203
values.forEach((value) => {
203204
result.add(key, value);
204205
});
205-
} else {
206+
} else if (values !== undefined) {
206207
result.add(key, values);
207208
}
208209
}

0 commit comments

Comments
 (0)