Can't make gRPC work with python requests rest api call - python-requests

Need help in wiring the grpc client/server to listen to rest requests. Want to execute a post request
Any help is much appreciated..
digestor.proto
import "google/api/annotations.proto";
service Digestor{
rpc GetDigestor(DigestMessage) returns (DigestedMessage) {}
}
service DigestorRest {
rpc GetDigestor(DigestMessage) returns (DigestedMessage) {
option (google.api.http) = {
get: "/v1/digest"
body: "*"
};
}
}
after the pb2 files get generated.
grpc - request works perfectly ok
curr_client = DigestorClient()
print(curr_client.get_digest("Test Message"))
My rest/get request:
requests.get(url='http://localhost:46001/v1/digest')
should return the correct response however I get
requests.exceptions.ConnectionError: ('Connection aborted.', BadStatusLine('\x00\x00\x18\x04\x00\x00\x00\x00\x00\x00\x04\x00#\x00\x00\x00\x05\x00#\x00\x00\x00\x06\x00\x00 \x00รพ\x03\x00\x00\x00\x01\x00\x00\x04\x08\x00\x00\x00\x00\x00\x00?\x00\x01\x00\x00\x08\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'))

I presume you are using the GCP Transcoding feature. If you haven't tried the tutorial, please try to go through the example steps.
The gRPC protocol is based on HTTP2 instead of HTTP1. The requests library is an HTTP1. The exception reported by requests looks like protocol mismatch. So, it is likely that there is an issue in your GCP Endpoints setting.

Related

How to identify the protocol of the Meteor connection

I've wondered how to identify the current protocol if it's using websocket or polling.
-- in the client. (appended for certainty)
I've found a valid information from the debug console.
Meteor.connection._stream.socket.protocol
and it seems to have one value among...
['websocket',
'xdr-streaming',
'xhr-streaming',
'iframe-eventsource',
'iframe-htmlfile',
'xdr-polling',
'xhr-polling',
'iframe-xhr-polling',
'jsonp-polling'];
is there more grace way to identify the current protocol?
and when would it be the fastest timing to detect the protocol?
By the way, I need it to use a different DDP server when the sticky sessions needed since AWS ELB doesn't support sticky sessions and websocket at the same time.
Meteor uses DDP protocol. To connect to a different Meteor server and call its methods, use DDP.connect as follows.
import { DDP } from 'meteor/ddp-client'
DDP.connect(url)
Unfortunately, there is no graceful to get the protocol. onConnection returns an object which has some info.
Meteor.onConnection(obj =>
{ console.log(obj.httpHeaders.x-forwarded-proto); });
This returns 'ws' for websocket. This way of getting the protocol is not graceful!
Meteor.status() gives a reactive data source.
(https://docs.meteor.com/api/connections.html#DDP-connect)
if (Meteor.isClient) {
Tracker.autorun(() => {
const stat = Meteor.status();
if (stat.status === 'connected') {
console.log(Meteor.connection._stream.socket.protocol);
}
});
}
something like that will give the current protocol in the client side.

Asynchronous WebSockets in Winhttp Windows 8

I want just to add WebSockets to my app that uses WinHTTP in async mode.
When I need a WebSocket I call the following.
Before sending request:
WinHttpSetOption(context->hRequest, WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET, NULL, 0);
In WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
appContext->pIoRequest->hWebSocketHandle = WinHttpWebSocketCompleteUpgrade(appContext->hRequest, NULL);
WinHttpWebSocketReceive(appContext->pIoRequest->hWebSocketHandle, appContext->pszOutBuffer,RESPONSE_BUFFER_SIZE, NULL, NULL);
all without errors.
Now I see in Fiddler that the server sends some data to my WebSocket but there is no WINHTTP_CALLBACK_STATUS_READ_COMPLETE triggered.
Any ideas why this is? How can I read asynchronously from my WebSocket? Sending data to the WebSocket works well.
Omg! I found how its work!
You MUST call additional WinHttpSetStatusCallback to set WebSocket callback for WebSocketHandle returned in WinHttpWebSocketCompleteUpgrade and this callback MUST differ then that from call WinHttpWebSocketCompleteUpgrade was made!
It is no possible to set a context pointer by WinHttpSetOption with WINHTTP_OPTION_CONTEXT_VALUE flag! Its not work. dwContext In WebSocketCallback has wrong data. Call to WinHttpQueryOption in WebSocketCallback return wrong context data. I think that is a BUG in Windows 8.1. I write my own handler to connect my context with WebSocketHandle.
All of this is NOT documented in MSDN! Most of all, I did not google any info about async winhttp websocket usage... So, I am the first=) I will be very glad if my research will help you!
It seems websockets do not get PING and PONG messages to the callback!

Accept post request with iron router

I'm trying to accept a post request from my twilio account to my application to get an xml response back. How do I respond to an incoming post request in iron router? I have read the docs and tried everything in there but I just get (Error: Not implemented on server yet). I have tried putting it on the server, on the client and in lib.:
Router (lib/router.coffee)
Router.route('/api/twilio/voice', where: 'server')
.post -> console.log 'hey'
This is due to having this.subscribe then .wait()s configured for both server and client. Look for .wait within your Router configuration scopes and make sure it only runs at the client.
Look at the code part where this happens at the iron-controller repo:
https://github.com/EventedMind/iron-controller/blob/devel/lib/controller_server.js
Also I think a better way to debug (instead of console.log) is to actually use this.response:
Router.route('/api/twilio/voice', { where: server })
.post(function() {
this.response.end('hey');
});
or even the classic format:
Router.route('/api/twilio/voice', { where: server })
.post(function(req, res, next) {
res.end('hey');
});
Edit: Issue filed here and PR here.

Apigee fault handling for CLASSIFICATION_FAILURE

In Apigee, can fault handling - specifying a FaultRule and a RaiseFault policy be used to handle and provide a custom message for:
{
"fault": {
"faultstring": "Not Found",
"detail": {
"errorcode": "CLASSIFICATION_FAILURE"
}
}
}
If this can be done, should the 'Condition' for the fault rule be 'fault.name = "CLASSIFICATION_FAILURE"'? I tried this and it is not working.
CLASSIFICATION_FAILURE is a system level failure to find an API Proxy for the given URL/URI. The request will not even reach the API proxy(hence the policies) - which is the precise complaint by the system.
So you do not want to handle an error like that.
Another way to approach this case is to have a catch all API proxy with basepath /** which will be invoked when there is no specific URL match. You can generate a custom message in this proxy - this can be the message you wanted to send across in case of classification failure.
Srikanth's answer on 30/05/2014 is only partially correct. Using a basepath /** did not work for us. Instead, we had to create an api proxy with basepath = /
Inside the proxy, we defined a RaiseFault in Preflow and that was it.

Serving non-standard HTTP method with ExpressJS

I would like to write an HTTP server that answer to request using a non-standard HTTP method (verb). For instance, the client would make a request like FOO / HTTP/.1.1. And on the server side, this request would be handled by something like:
var express = require('express');
var app = express.createServer();
app.configure(function(){
app.use(express.logger({ format: ':method :url' }));
app.use(express.methodOverride());
});
app.foo('/', function(req, res){
res.send('Hello World');
});
app.listen(3000);
I appended my non-standard method to the array exported in ExpressJS's lib/router/methods.js. This allow me to write my server code as expected. When using express.methodOverride() and a POST request with _method=foo, it works. But an actual FOO request doesn't work. As soon as the client send the first line of the request the connection is closed by the server:
$telnet localhost 3000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
FOO / HTTP/1.1
Connection closed by foreign host.
I would like to be able to implement this with ExpressJS and without avoid hacking into its core file.
Any idea if this is possible and how?
Short answer: No, it's not possible. Not without implementing your own HTTP module.
To test, start a barebones HTTP server ...
$ node
> require('http').createServer(function(req, res) {
... console.log(req.method);
... res.end();
... }).listen(8080);
Then (as you've already done) telnet to it and issue a GET and FOO request ...
$ telnet localhost 8080
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
HTTP/1.1 200 OK
Connection: keep-alive
Transfer-Encoding: chunked
0
FOO / HTTP/1.1
Connection closed by foreign host.
$
In node console you'll see
GET
... but no FOO. So, node's native HTTP module, which Express uses, does not make these requests available.
Node has a hard-coded whitelist of acceptable HTTP verbs in C.
In order to accept custom verbs, you must modify the HTTP parser and recompile node.
You mentioned that you're trying to implement PURGE, which was added to the whitelist in v0.7.5.
As others have said, Node.js' HTTP server library is configured to accept only specific verbs. Ben Noordius' suggestion of using Parsley doesn't work either, since that library accepts an even smaller whitelist of verbs. (It also hasn't been maintained in quite some time.)
At this stage, if we want to support oddball requests, we have to take more drastic measures. Here's a nice ugly hack for you that involves duck punching some internal behavior. This works on v0.10.x of Node.js, but test carefully on newer versions as they become available.
In my case, I needed to support not only a non-standard verb, but a non-standard protocol version identifier as well, and a missing Content-Length header for Icecast source streams:
SOURCE /live ICE/1.0
The following should get you started:
server.on('connection', function (socket) {
var originalOnDataFunction = socket.ondata;
var newLineOffset;
var receiveBuffer = new Buffer(0);
socket.ondata = function (d, start, end) {
receiveBuffer = Buffer.concat([receiveBuffer, d.slice(start, end)]);
if ((newLineOffset = receiveBuffer.toString('ascii').indexOf('\n')) > -1) {
var firstLineParts = receiveBuffer.slice(0, newLineOffset).toString().split(' ');
firstLineParts[0] = firstLineParts[0].replace(/^SOURCE$/ig, 'PUT');
firstLineParts[2] = firstLineParts[2].replace(/^ICE\//ig, 'HTTP/');
receiveBuffer = Buffer.concat([
new Buffer(
firstLineParts.join(' ') + '\r\n' +
'Content-Length: 9007199254740992\r\n'
),
receiveBuffer.slice(newLineOffset +1)
]);
socket.ondata = originalOnDataFunction;
socket.ondata.apply(this, [receiveBuffer, 0, receiveBuffer.length]);
}
};
}
It's ugly, but works. I'm not particularly happy about it, but when choosing between a rough built-from-the-ground-up HTTP parser or tweaking an existing one, I choose to tweak in this instance.
For anyone who needs it, there is http-parser-js, which replaces Node's built-in HTTP parser.
Their README contains an example of monkey-patching the parser, though I find that it wasn't enough, as both the http-parser-js and the http modules have a hardcoded list of methods.
So, you have to replace the parser and edit the list of methods:
const { HTTPParser } = require('http-parser-js');
HTTPParser.methods.push('FOOBAR');
const binding = process.binding('http_parser');
binding.HTTPParser = HTTPParser;
binding.methods = HTTPParser.methods;
require('http').METHODS = HTTPParser.methods;
Later Node versions may not support process.binding, in which case, you can use the --expose-internals flag for Node (see this issue):
const { internalBinding } = require('internal/test/binding');
const binding = internalBinding('http_parser');
From the looks of it, the http2 module's parser accepts any method, in case that's an option. See this issue about invalid HTTP methods. Unfortunately, express and the likes do not use http2.
And for anyone who was in my shoes, proxying requests to a legacy server in Create React App, use the above snippet in webpack-dev-server, at the top of Server.js, in order to monkey-patch the parser. Hopefully everything switches to http2 soon...

Resources