Merge pull request #111 from fengli79/master

Supports base64 encoded gRPC-Web with content-type: application/grpc-web-text and content-type: application/grpc-web-text+proto.
This commit is contained in:
Feng Li 2017-11-21 15:18:06 -08:00 committed by GitHub
commit 6abade580b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 160 additions and 6 deletions

View File

@ -0,0 +1,25 @@
#include "net/grpc/gateway/codec/grpc_web_text_decoder.h"
namespace grpc {
namespace gateway {
GrpcWebTextDecoder::GrpcWebTextDecoder() {}
GrpcWebTextDecoder::~GrpcWebTextDecoder() {}
Status GrpcWebTextDecoder::Decode() {
std::vector<Slice> buffer;
if (!base64_.Decode(*inputs(), &buffer)) {
return Status(StatusCode::INVALID_ARGUMENT, "Invalid base64 inputs.");
}
inputs()->clear();
for (Slice& s : buffer) {
Append(s);
}
return GrpcWebDecoder::Decode();
}
} // namespace gateway
} // namespace grpc

View File

@ -0,0 +1,26 @@
#ifndef NET_GRPC_GATEWAY_CODEC_GRPC_WEB_TEXT_DECODER_H_
#define NET_GRPC_GATEWAY_CODEC_GRPC_WEB_TEXT_DECODER_H_
#include "net/grpc/gateway/codec/base64.h"
#include "net/grpc/gateway/codec/grpc_web_decoder.h"
namespace grpc {
namespace gateway {
class GrpcWebTextDecoder : public GrpcWebDecoder {
public:
GrpcWebTextDecoder();
~GrpcWebTextDecoder() override;
GrpcWebTextDecoder(const GrpcWebTextDecoder&) = delete;
GrpcWebTextDecoder& operator=(const GrpcWebTextDecoder&) = delete;
Status Decode() override;
private:
Base64 base64_;
};
} // namespace gateway
} // namespace grpc
#endif // NET_GRPC_GATEWAY_CODEC_GRPC_WEB_TEXT_DECODER_H_

View File

@ -0,0 +1,26 @@
#include "net/grpc/gateway/codec/grpc_web_text_encoder.h"
namespace grpc {
namespace gateway {
GrpcWebTextEncoder::GrpcWebTextEncoder() {}
GrpcWebTextEncoder::~GrpcWebTextEncoder() {}
void GrpcWebTextEncoder::Encode(grpc::ByteBuffer* input,
std::vector<Slice>* result) {
std::vector<Slice> buffer;
GrpcWebEncoder::Encode(input, &buffer);
base64_.Encode(buffer, result);
}
void GrpcWebTextEncoder::EncodeStatus(const grpc::Status& status,
const Trailers* trailers,
std::vector<Slice>* result) {
std::vector<Slice> buffer;
GrpcWebEncoder::EncodeStatus(status, trailers, &buffer);
base64_.Encode(buffer, result);
}
} // namespace gateway
} // namespace grpc

View File

@ -0,0 +1,28 @@
#ifndef NET_GRPC_GATEWAY_CODEC_GRPC_WEB_TEXT_ENCODER_H_
#define NET_GRPC_GATEWAY_CODEC_GRPC_WEB_TEXT_ENCODER_H_
#include "net/grpc/gateway/codec/base64.h"
#include "net/grpc/gateway/codec/grpc_web_encoder.h"
namespace grpc {
namespace gateway {
class GrpcWebTextEncoder : public GrpcWebEncoder {
public:
GrpcWebTextEncoder();
~GrpcWebTextEncoder() override;
GrpcWebTextEncoder(const GrpcWebTextEncoder&) = delete;
GrpcWebTextEncoder& operator=(const GrpcWebTextEncoder&) = delete;
void Encode(grpc::ByteBuffer* input, std::vector<Slice>* result) override;
void EncodeStatus(const grpc::Status& status, const Trailers* trailers,
std::vector<Slice>* result) override;
private:
Base64 base64_;
};
} // namespace gateway
} // namespace grpc
#endif // NET_GRPC_GATEWAY_CODEC_GRPC_WEB_TEXT_ENCODER_H_

View File

@ -512,6 +512,9 @@ void NginxHttpFrontend::SendResponseHeadersToClient(Response *response) {
case GRPC_WEB:
AddHTTPHeader(http_request_, kContentType, kContentTypeGrpcWeb);
break;
case GRPC_WEB_TEXT:
AddHTTPHeader(http_request_, kContentType, kContentTypeGrpcWebText);
break;
case JSON_STREAM_BODY:
AddHTTPHeader(http_request_, kContentType, kContentTypeJson);
break;

View File

@ -78,6 +78,9 @@ const char kContentLength[] = "content-length";
// The metadata name of content-transfer-encoding.
const char kContentTransferEncoding[] = "content-transfer-encoding";
// The metadata name of accept.
const char kAccept[] = "accept";
// The metadata value of content-transfer-encoding for base64.
const char kContentTransferEncoding_Base64[] = "base64";
const size_t kContentTransferEncoding_Base64_Length =
@ -103,6 +106,7 @@ enum Protocol {
UNKNOWN = 0,
GRPC,
GRPC_WEB,
GRPC_WEB_TEXT,
JSON_STREAM_BODY,
PROTO_STREAM_BODY,
B64_PROTO_STREAM_BODY,

View File

@ -14,6 +14,8 @@
#include "net/grpc/gateway/codec/grpc_encoder.h"
#include "net/grpc/gateway/codec/grpc_web_decoder.h"
#include "net/grpc/gateway/codec/grpc_web_encoder.h"
#include "net/grpc/gateway/codec/grpc_web_text_decoder.h"
#include "net/grpc/gateway/codec/grpc_web_text_encoder.h"
#include "net/grpc/gateway/codec/json_decoder.h"
#include "net/grpc/gateway/codec/json_encoder.h"
#include "net/grpc/gateway/codec/proto_decoder.h"
@ -62,6 +64,19 @@ bool IsResponseB64(ngx_http_request_t* http_request) {
}
return false;
}
bool IsResponseGrpcWebText(ngx_http_request_t* http_request) {
string_ref value =
GetHTTPHeader(&http_request->headers_in.headers.part, kAccept);
if ((kContentTypeGrpcWebTextLength == value.size() &&
strncasecmp(kContentTypeGrpcWebText, value.data(), value.size()) == 0) ||
(kContentTypeGrpcWebTextProtoLength == value.size() &&
strncasecmp(kContentTypeGrpcWebTextProto, value.data(), value.size()) ==
0)) {
return true;
}
return false;
}
} // namespace
Runtime::Runtime() {
@ -116,6 +131,8 @@ std::unique_ptr<Encoder> Runtime::CreateEncoder(
return std::unique_ptr<Encoder>(new GrpcEncoder());
case GRPC_WEB:
return std::unique_ptr<Encoder>(new GrpcWebEncoder());
case GRPC_WEB_TEXT:
return std::unique_ptr<Encoder>(new GrpcWebTextEncoder());
case JSON_STREAM_BODY:
return std::unique_ptr<Encoder>(new JsonEncoder());
case PROTO_STREAM_BODY:
@ -151,6 +168,8 @@ std::unique_ptr<Decoder> Runtime::CreateDecoder(
}
case GRPC_WEB:
return std::unique_ptr<Decoder>(new GrpcWebDecoder());
case GRPC_WEB_TEXT:
return std::unique_ptr<Decoder>(new GrpcWebTextDecoder());
case JSON_STREAM_BODY:
return std::unique_ptr<Decoder>(new JsonDecoder());
case PROTO_STREAM_BODY:
@ -208,11 +227,22 @@ Protocol Runtime::DetectRequestProtocol(ngx_http_request_t* http_request) {
0) {
return GRPC;
}
if (content_type_length == kContentTypeGrpcWebLength &&
if ((content_type_length == kContentTypeGrpcWebLength &&
strncasecmp(kContentTypeGrpcWeb, content_type,
kContentTypeGrpcWebLength) == 0) {
kContentTypeGrpcWebLength) == 0) ||
(content_type_length == kContentTypeGrpcWebProtoLength &&
strncasecmp(kContentTypeGrpcWebProto, content_type,
kContentTypeGrpcWebProtoLength) == 0)) {
return GRPC_WEB;
}
if ((content_type_length == kContentTypeGrpcWebTextLength &&
strncasecmp(kContentTypeGrpcWebText, content_type,
kContentTypeGrpcWebTextLength) == 0) ||
(content_type_length == kContentTypeGrpcWebTextProtoLength &&
strncasecmp(kContentTypeGrpcWebTextProto, content_type,
kContentTypeGrpcWebTextProtoLength) == 0)) {
return GRPC_WEB_TEXT;
}
return UNKNOWN;
}
@ -252,9 +282,21 @@ Protocol Runtime::DetectResponseProtocol(ngx_http_request_t* http_request) {
0) {
return GRPC;
}
if (content_type_length == kContentTypeGrpcWebLength &&
if ((content_type_length == kContentTypeGrpcWebLength &&
strncasecmp(kContentTypeGrpcWeb, content_type,
kContentTypeGrpcWebLength) == 0) {
kContentTypeGrpcWebLength) == 0) ||
(content_type_length == kContentTypeGrpcWebProtoLength &&
strncasecmp(kContentTypeGrpcWebProto, content_type,
kContentTypeGrpcWebProtoLength) == 0) ||
(content_type_length == kContentTypeGrpcWebTextLength &&
strncasecmp(kContentTypeGrpcWebText, content_type,
kContentTypeGrpcWebTextLength) == 0) ||
(content_type_length == kContentTypeGrpcWebTextProtoLength &&
strncasecmp(kContentTypeGrpcWebTextProto, content_type,
kContentTypeGrpcWebTextProtoLength) == 0)) {
if (IsResponseGrpcWebText(http_request)) {
return GRPC_WEB_TEXT;
}
return GRPC_WEB;
}
return UNKNOWN;