grpc-js: reject invalid Content-Type requests

This commit implements the following portion of the spec:

If Content-Type does not begin with "application/grpc",
gRPC servers SHOULD respond with HTTP status of
415 (Unsupported Media Type). This will prevent other
HTTP/2 clients from interpreting a gRPC error response,
which uses status 200 (OK), as successful.
This commit is contained in:
cjihrig 2019-06-04 11:53:20 -04:00
parent 9c274034d0
commit a4b3a7fbae
No known key found for this signature in database
GPG Key ID: 7434390BDBE9B9C5
2 changed files with 59 additions and 0 deletions

View File

@ -288,6 +288,22 @@ export class Server {
return;
}
const contentType = headers[http2.constants.HTTP2_HEADER_CONTENT_TYPE];
if (
typeof contentType !== 'string' ||
!contentType.startsWith('application/grpc')
) {
stream.respond(
{
[http2.constants.HTTP2_HEADER_STATUS]:
http2.constants.HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,
},
{ endStream: true }
);
return;
}
try {
const path = headers[http2.constants.HTTP2_HEADER_PATH] as string;
const handler = this.handlers.get(path);

View File

@ -19,6 +19,7 @@
// tslint:disable no-any
import * as assert from 'assert';
import * as fs from 'fs';
import * as http2 from 'http2';
import * as path from 'path';
import * as grpc from '../src';
@ -450,4 +451,46 @@ describe('Generic client and server', () => {
});
});
});
it('responds with HTTP status of 415 on invalid content-type', done => {
const server = new Server();
const creds = ServerCredentials.createInsecure();
server.bindAsync('localhost:0', creds, (err, port) => {
assert.ifError(err);
const client = http2.connect(`http://localhost:${port}`);
let count = 0;
function makeRequest(headers: http2.IncomingHttpHeaders) {
const req = client.request(headers);
let statusCode: string;
req.on('response', headers => {
statusCode = headers[http2.constants.HTTP2_HEADER_STATUS] as string;
assert.strictEqual(
statusCode,
http2.constants.HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE
);
});
req.on('end', () => {
assert(statusCode);
count++;
if (count === 2) {
client.close();
server.tryShutdown(done);
}
});
req.end();
}
server.start();
// Missing Content-Type header.
makeRequest({ ':path': '/' });
// Invalid Content-Type header.
makeRequest({ ':path': '/', 'content-type': 'application/not-grpc' });
});
});
});