mirror of https://github.com/grpc/grpc-web.git
GrpcWebClientReadableStream: keep falsy data (#1230)
This commit is contained in:
parent
b0ea9c7c45
commit
e11903b337
|
@ -123,10 +123,10 @@ class GrpcWebClientBase {
|
|||
let unaryStatus;
|
||||
let unaryMsg;
|
||||
GrpcWebClientBase.setCallback_(
|
||||
stream, (error, response, status, metadata) => {
|
||||
stream, (error, response, status, metadata, unaryResponseReceived) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else if (response) {
|
||||
} else if (unaryResponseReceived) {
|
||||
unaryMsg = response;
|
||||
} else if (status) {
|
||||
unaryStatus = status;
|
||||
|
@ -222,9 +222,16 @@ class GrpcWebClientBase {
|
|||
* @static
|
||||
* @template RESPONSE
|
||||
* @param {!ClientReadableStream<RESPONSE>} stream
|
||||
* @param {function(?RpcError, ?RESPONSE, ?Status=, ?Object<string, string>=)|
|
||||
* @param {function(?RpcError, ?RESPONSE, ?Status=, ?Object<string, string>=, ?boolean)|
|
||||
* function(?RpcError,?RESPONSE)} callback
|
||||
* @param {boolean} useUnaryResponse
|
||||
* @param {boolean} useUnaryResponse Pass true to have the client make
|
||||
* multiple calls to the callback, using (error, response, status,
|
||||
* metadata, unaryResponseReceived) arguments. One of error, status,
|
||||
* metadata, or unaryResponseReceived will be truthy to indicate which piece
|
||||
* of information the client is providing in that call. After the stream
|
||||
* ends, it will call the callback an additional time with all falsy
|
||||
* arguments. Pass false to have the client make one call to the callback
|
||||
* using (error, response) arguments.
|
||||
*/
|
||||
static setCallback_(stream, callback, useUnaryResponse) {
|
||||
let isResponseReceived = false;
|
||||
|
@ -272,11 +279,11 @@ class GrpcWebClientBase {
|
|||
message: 'Incomplete response',
|
||||
});
|
||||
} else {
|
||||
callback(null, responseReceived);
|
||||
callback(null, responseReceived, null, null, /* unaryResponseReceived= */ true);
|
||||
}
|
||||
}
|
||||
if (useUnaryResponse) {
|
||||
callback(null, null); // trigger unaryResponse
|
||||
callback(null, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -75,6 +75,77 @@ testSuite({
|
|||
assertElementsEquals(DEFAULT_UNARY_HEADER_VALUES, Object.values(headers));
|
||||
},
|
||||
|
||||
async testRpcFalsyResponse_ForNonProtobufDescriptor() {
|
||||
const xhr = new XhrIo();
|
||||
const client = new GrpcWebClientBase(/* options= */ {}, xhr);
|
||||
const methodDescriptor = createMethodDescriptor((bytes) => {
|
||||
assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));
|
||||
return 0;
|
||||
});
|
||||
|
||||
const response = await new Promise((resolve, reject) => {
|
||||
client.rpcCall(
|
||||
'url', new MockRequest(), /* metadata= */ {}, methodDescriptor,
|
||||
(error, response) => {
|
||||
assertNull(error);
|
||||
resolve(response);
|
||||
});
|
||||
xhr.simulatePartialResponse(
|
||||
googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),
|
||||
DEFAULT_RESPONSE_HEADERS);
|
||||
xhr.simulateReadyStateChange(ReadyState.COMPLETE);
|
||||
});
|
||||
|
||||
assertEquals(0, response);
|
||||
const headers = /** @type {!Object} */ (xhr.getLastRequestHeaders());
|
||||
assertElementsEquals(DEFAULT_UNARY_HEADERS, Object.keys(headers));
|
||||
assertElementsEquals(DEFAULT_UNARY_HEADER_VALUES, Object.values(headers));
|
||||
},
|
||||
|
||||
async testRpcResponseThenableCall() {
|
||||
const xhr = new XhrIo();
|
||||
const client = new GrpcWebClientBase(/* options= */ {}, xhr);
|
||||
const methodDescriptor = createMethodDescriptor((bytes) => {
|
||||
assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));
|
||||
return new MockReply('value');
|
||||
});
|
||||
|
||||
const responsePromise = client.thenableCall(
|
||||
'url', new MockRequest(), /* metadata= */ {}, methodDescriptor);
|
||||
xhr.simulatePartialResponse(
|
||||
googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),
|
||||
DEFAULT_RESPONSE_HEADERS);
|
||||
xhr.simulateReadyStateChange(ReadyState.COMPLETE);
|
||||
const response = await responsePromise;
|
||||
|
||||
assertEquals('value', response.data);
|
||||
const headers = /** @type {!Object} */ (xhr.getLastRequestHeaders());
|
||||
assertElementsEquals(DEFAULT_UNARY_HEADERS, Object.keys(headers));
|
||||
assertElementsEquals(DEFAULT_UNARY_HEADER_VALUES, Object.values(headers));
|
||||
},
|
||||
|
||||
async testRpcFalsyResponseThenableCall_ForNonProtobufDescriptor() {
|
||||
const xhr = new XhrIo();
|
||||
const client = new GrpcWebClientBase(/* options= */ {}, xhr);
|
||||
const methodDescriptor = createMethodDescriptor((bytes) => {
|
||||
assertElementsEquals(DEFAULT_RPC_RESPONSE_DATA, [].slice.call(bytes));
|
||||
return 0;
|
||||
});
|
||||
|
||||
const responsePromise = client.thenableCall(
|
||||
'url', new MockRequest(), /* metadata= */ {}, methodDescriptor);
|
||||
xhr.simulatePartialResponse(
|
||||
googCrypt.encodeByteArray(new Uint8Array(DEFAULT_RPC_RESPONSE)),
|
||||
DEFAULT_RESPONSE_HEADERS);
|
||||
xhr.simulateReadyStateChange(ReadyState.COMPLETE);
|
||||
const response = await responsePromise;
|
||||
|
||||
assertEquals(0, response);
|
||||
const headers = /** @type {!Object} */ (xhr.getLastRequestHeaders());
|
||||
assertElementsEquals(DEFAULT_UNARY_HEADERS, Object.keys(headers));
|
||||
assertElementsEquals(DEFAULT_UNARY_HEADER_VALUES, Object.values(headers));
|
||||
},
|
||||
|
||||
async testDeadline() {
|
||||
const xhr = new XhrIo();
|
||||
const client = new GrpcWebClientBase(/* options= */ {}, xhr);
|
||||
|
|
|
@ -170,16 +170,18 @@ class GrpcWebClientReadableStream {
|
|||
if (FrameType.DATA in messages[i]) {
|
||||
const data = messages[i][FrameType.DATA];
|
||||
if (data) {
|
||||
let isResponseDeserialized = false;
|
||||
let response;
|
||||
try {
|
||||
response = self.responseDeserializeFn_(data);
|
||||
isResponseDeserialized = true;
|
||||
} catch (err) {
|
||||
self.handleError_(new RpcError(
|
||||
StatusCode.INTERNAL,
|
||||
`Error when deserializing response data; error: ${err}` +
|
||||
`, response: ${response}`));
|
||||
}
|
||||
if (response) {
|
||||
if (isResponseDeserialized) {
|
||||
self.sendDataCallbacks_(response);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue