I am developing C modules in nginx
I want to issue a sub request and get a response(header,body)
The code I am writing now is as as follows
How can I get a response (heade, body) after executing the ngx_http_subrequest method?
ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
if (ps == NULL) {
return NGX_ERROR;
}
ps->handler = ngx_http_auth_request_done;
ps->data = "foo";
if (ngx_http_subrequest(r, &uri, NULL, &sr, ps, NGX_HTTP_SUBREQUEST_IN_MEMORY) != NGX_OK)
{
ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "subrequest is failed!!");
return NGX_ERROR;
}
ngx_http_auth_request_done is the handler you have defined which is the callback that handles the response of the subrequest. You are supposed to implement this function. If you look at it's signature, it has the request structure you have sent out. The request structure's upstream variable contains a buffer where the response is stored. r->upstream->buffer. You can look at nginx's own modules for how to parse the response.
Related
I'm having an issue in gRPC that's been driving me crazy. I have a .NET gRPC service that my ReactJS client is connecting to - this works fine. I'm subscribing to my stream, and I get data over the stream as expected. I'm having an issue deserializing "google.protobuf.Any" types that exist in my messages. The one I'm receiving looks like this:
message PointNotification {
KindsOfPointNotification Kind = 1;
google.protobuf.Any NotificationData = 2;
}
Inside of the ReactJS client I am doing the following:
useEffect(() => {
console.log("Subscribing to point stream");
var pointStream = client.subscribeToNotificationStream(new Empty(), {});
pointStream.on("data", (response) => {
switch (response.getKind())
{
case KindsOfPointNotification.KINDS_OF_POINT_NOTIFICATION_POINT_ADDED_OR_UPDATED:
const any = response.getNotificationdata();
console.log(any);
const bar = any.unpack(NotificationPointAddedOrUpdated.deserializeBinary, any.getTypeName());
console.log(bar);
break;
case KindsOfPointNotification.KINDS_OF_POINT_NOTIFICATION_POINT_REMOVED:
console.log("Point removed");
break;
}
});
The "any" variable looks right in the browser logs. The payload, and the typeName are correct. However when I go to unpack "any" I get the following error (screenshot):
TypeError in browser
Uncaught TypeError: deserialize is not a function
This is despite the fact that the generated _pb file has the following method:
/**
* Deserializes binary data (in protobuf wire format).
* #param {jspb.ByteSource} bytes The bytes to deserialize.
* #return {!proto.Point.NotificationPointAddedOrUpdated}
*/
proto.Point.NotificationPointAddedOrUpdated.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.Point.NotificationPointAddedOrUpdated;
return proto.Point.NotificationPointAddedOrUpdated.deserializeBinaryFromReader(msg,
reader);
};
According to The documentation this is correct way to do it. What am I missing? Why am I getting a deserialize error?
Edit: I have one other thing to add. If I change the following line:
const bar = any.unpack(NotificationPointAddedOrUpdated.deserializeBinary, any.getTypeName());
To:
const bar = any.unpack(NotificationPointAddedOrUpdated.deserializeBinary(), any.getTypeName());
The error I get in the browser changes to:
Uncaught TypeError: _proto_pointdata_pb_js__WEBPACK_IMPORTED_MODULE_3___default(...).deserializeBinary is not a function
The following issue led me to the solution: https://github.com/protocolbuffers/protobuf/issues/5482
The previous dev was not encoding data in base64, and that was causing deserialize issues in JavaScript.
In the Flutter/Dart app that I am currently working on need to download large files from my servers. However, instead of storing the file in local storage what I need to do is to parse its contents and consume it one-off. I thought the best way to accomplish this was by implementing my own StreamConsumer and overriding the relvant methods. Here is what I have done thus far
import 'dart:io';
import 'dart:async';
class Accumulator extends StreamConsumer<List<int>>
{
String text = '';
#override
Future<void> addStream(Stream<List<int>> s) async
{
print('Adding');
//print(s.length);
return;
}
#override
Future<dynamic> close() async
{
print('closed');
return Future.value(text);
}
}
Future<String> fileFetch() async
{
String url = 'https://file.io/bse4moAYc7gW';
final HttpClientRequest request = await HttpClient().getUrl(Uri.parse(url));
final HttpClientResponse response = await request.close();
return await response.pipe(Accumulator());
}
Future<void> simpleFetch() async
{
String url = 'https://file.io/bse4moAYc7gW';
final HttpClientRequest request = await HttpClient().getUrl(Uri.parse(url));
final HttpClientResponse response = await request.close();
await response.pipe(File('sample.txt').openWrite());
print('Simple done!!');
}
void main() async
{
print('Starting');
await simpleFetch();
String text = await fileFetch();
print('Finished! $text');
}
When I run this in VSCode here is the output I get
Starting
Simple done!! //the contents of the file at https://file.io/bse4moAYc7gW are duly saved in the file
sample.txt
Adding //clearly addStream is being called
Instance of 'Future<int>' //I had expected to see the length of the available data here
closed //close is clearly being called BUT
Finished! //back in main()
My understanding of the underlying issues here is still rather limited. My expectation
I had thought that I would use addStream to accumulate the contents being downloaded until
There is nothing more to download at which point close would be called and the program would display exited
Why is addStream showing instance of... rather than the length of available content?
Although the VSCode debug console does display exited this happens several seconds after closed is displayed. I thought this might be an issue with having to call super.close() but not so. What am I doing wrong here?
I was going to delete this question but decided to leave it here with an answer for the benefit of anyone else trying to do something similar.
The key point to note is that the call to Accumulator.addStream does just that - it furnishes a stream to be listened to, no actual data to be read. What you do next is this
void whenData(List<int> data)
{
//you will typically get a sequence of one or more bytes here.
for(int value in data)
{
//accumulate the incoming data here
}
return;
}
function void whenDone()
{
//now that you have all the file data *accumulated* do what you like with it
}
#override
Future<void> addStream(Stream<List<int>> s) async
{
s.listen(whenData,onDone:whenDone);
//you can optionally ahandler for `onError`
}
I have method
Mono<ReceiptResponse> a01(Mono<DefaultBeneficiaryBankRequest> request)
and aspect
#Around("callAtMyServiceSecurityAnnotation(request)")
#Order(1)
public Object scheduleTimeout(ProceedingJoinPoint joinPoint, Mono<?> request) {
Mono<?> retVal = (Mono)joinPoint.proceed();
return retVal.doOnSuccess(i -> {
...
someMethod(<request.value>)// <-- How I can get requets value here?
...
});
}
How I can get request value as someMethod argument?
The information in your question is incomplete, but to me it seems your pointcut callAtMyServiceSecurityAnnotation(request) already captures the request and forwards it to your advice method as Mono<?> request parameter. So the answer to your question is simple: Just use request in order to get access to the request argument.
You do not show your actual pointcut, but assuming it is something like (untested, writing just freestyle because I do not have a test case from you to try it on)
#Pointcut("within(my.package.MyTargetClass) && execution(* a01(*)) && args(request)")
public void callAtMyServiceSecurityAnnotation(Mono<?> request) {}
it should just work.
I'm create a website using ReactJS and I want get my local IP address. I've tried few ways to do that but I was confused with result.
First, I use module on npm is local-ip-url, then use localIpUrl() to get my ip address and display with console.log(). If i use a terminal to run this .js file (eg: node index.js), it print exact result i want (192.168.x.x). But if i use browser to see console log, it shows a different result 127.0.0.0.
I've tried another ways, create my own function:
const os = require('os');
function getAvailableIp() {
let ifaces = os.networkInterfaces();
let result = {};
for (let ifname in ifaces) {
ifaces[ifname].forEach(function (iface) {
if ('IPv4' !== iface.family || iface.internal !== false) return;
result[ifname] = iface.address;
});
};
return result;
}
function getIp() {
let ips = getAvailableIp();
return ips.WiFi || 'localhost';
}
Same like above, when I ran code in terminal, it showed perfect result. But on browser, function os.networkInterfaces() return a empty object {}(It has a property is proto, i think it doesn't cause problem). So, it always return localhost.
Anyone can explain?
Now I can parse all http connection stream by http-parser. I want get url where content-type is text/html or text/xml.
How to get it? Url is in request, but content-type is always in response header.
I dont known response how to match the request.
I have tied this way, use the url suffix to ensure the url is a html, but failed.
const char *strSuffix[] = {
".html",
".htm",
".xml",
".jsp",
".shtml"
};
for(i = 0;i < ARRAY_SIZE(strSuffix);i++)
if((tmp = strstr(messages[0].request_url,strSuffix[i])) != NULL)
Basically, you need to check the REQUEST_METHOD and the CONTENT_TYPE in your environments.
Something like this (not tested):
char *request_method = getenv("REQUEST_METHOD") ;
if (strcmp(request_method, "POST") == 0) {
if (strstr(getenv("CONTENT_TYPE"), "text/xml")) {
...
} else
if (strstr(getenv("CONTENT_TYPE"), "text/html")) {
...
} ...