How can I log every request/response body in Armeria HTTP client - http

I tried two approaches to log every HTTP body produced/received by my armeria client:
using out-of-box LoggingClient decorator
decorator(LoggingClient.newDecorator())
creating custom logging decorator
decorator { delegate, ctx, req ->
ctx.log().whenRequestComplete().thenAccept { log -> logger.trace(log.toStringRequestOnly()) }
ctx.log().whenComplete().thenAccept { log -> logger.trace(log.toStringResponseOnly()) }
delegate.execute(ctx, req)
}
But I see in logs only headers and other technical information. How can I log requestContent/responseContent?
It's said in armeria documentation that these fields are available only for Thrift clients:
the serialization-dependent content object of the request. ThriftCall for Thrift. null otherwise.
the serialization-dependent content object of the response. ThriftReply for Thrift. null otherwise.
It's weird to me.

I had to add com.linecorp.armeria.client.logging.ContentPreviewingClient decorator in addition to logging decorator:
decorator(ContentPreviewingClient.newDecorator(1000))

Related

How to send HTTP request when "log.Fatal()" is executed?

In summary I want to send system information to my HTTP server when the "log.Fatal()" is called without any extra code for every log statement. Changing/overwriting the default behaviour of Info, Fatal etc. would be fantastic.
In Python, there is a way to add HTTP handlers to default logging library which in turn sends a POST HTTP request on log emit.
You can create a wrapper module for builtin log
yourproject/log/log.go
package log
import goLog "log"
func Fatal(v ...interface{}) {
goLog.Fatal(v...)
// send request ...
// reqQueue <- some args
}
replace log module with the wrapper in your project
// import "log"
import "yourproject/log"
func Foo() {
log.Fatal(err)
}
Try creating a type that wraps the standard Logger type, but with your desired enhancement. Then by creating an instance of it called "log" which wraps the default logger, you can continue to use logging in your code in the same way with minimal changes required (since it will have the same name as the log package, and retain *all of the methods).
package main
import _log "log"
type WrappedLogger struct {
// This field has no name, so we retain all the Logger methods
*_log.Logger
}
// here we override the behaviour of log.Fatal
func (l *WrappedLogger) Fatal(v ...interface{}) {
l.Println("doing the HTTP request")
/// do HTTP request
// now call the original Fatal method from the underlying logger
l.Logger.Fatal(v...)
}
// wrapping the default logger, but adding our new method.
var log = WrappedLogger{_log.Default()}
func main() {
// notice we can still use Println
log.Println("hello")
// but now Fatal does the special behaviour
log.Fatal("fatal log")
}
*The only gotcha here is that we've replaced the typical log package with a log instance. In many ways, it behaves the same, since most of the functions in the log package are set up as forwards to the default Logger instance for convenience.
However, this means that our new log won't have access to the "true" functions from the log package, such as log.New. For that, you will need to reference the alias to the original package.
// want to create a new logger?
_log.New(out, prefix, flag)

Spring Webflux: Remove WWW-authenticate header

I am using Spring 5 Webflux with Basic Authentication.
Problem:
When I type a wrong username or password spring reponses with Http Status 401 and includes the www-authenticate: Basic realm="Realm" Http Header which causes the browser to pop up the basic auth box.
How to remove that HTTP Header in Spring 5 Webflux?
Do I have to do a custom Webfilter?
The code below is in Kotlin copied from my project. But the idea can be simply transfered into Java.
So the solution is tied around a custom Webfilter.
#Component
class HttpHeaderWebFilter: WebFilter {
override fun filter(exchange: ServerWebExchange, next: WebFilterChain): Mono<Void> {
return next.filter(exchange).then(Mono.defer {
val headers = exchange.response.headers
if (headers.containsKey("WWW-Authenticate")) {
headers.remove("WWW-Authenticate")
}
Mono.empty<Void>()
})
}
}
We can use the following
if (exchange.getRequest().getHeaders().containsKey("headerKey")) {
exchange.getRequest().mutate().header("headerKey", null, null);
}
We are using the double null, to overcome deprecated Overriding method.
If you are using Spring Framework 5.2, usage of single null is sufficient.
The reason why it sends that header is that the authenticationFailureHandler associated with the default httpBasic() configuration uses the configured entryPoint. If it's not configured, then it uses the default entryPoint (HttpBasicServerAuthenticationEntryPoint) which adds that header to the response.
So, to change this behavior you can set a custom entryPoint, for example:
.httpBasic().authenticationEntryPoint(HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED))

Angular 2 http service. Get detailed error information

Executing Angular2 http call to the offline server doesn't provide much info in it's "error response" object I'm getting in the Observable's .catch(error) operator or subscription error delegate (they are both share the same info actually). But as you can see on the screen shot of the console there's actual error was displayed by zone.js somehow.
So, how can I get this specific error info (net::ERR_CONNECTION_REFUSED)?
Thanks.
Whenever server do not respond, response.status will be always equal to 0 (zero)
{
type: 3, //ResponseType.Error
status: 0, // problem connecting endpoint
}
Also note, when you are performing CORS request, but origin (url in browser) is not authorized (not in allowed list of host names configured in remote endpoint) the response would be similar to above, with exception to type attribute which will be equal to 4 = ResponseType.Opaque...
This means, connection was made, but for instance, OPTIONS request returned with headers which do not contain origin or HTTPS request was performed from HTTP origin.
You can handle the error messages so they are easier to read. This can definitely be expanded on too:
public Get() {
return this.http.get(this.URL).map(this.extractData)
.catch(this.handleError);
}
public extractData(res: Response) {
let body = res.json();
return body || {};
}
public handleError(error: any) {
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg);
return Observable.throw(errMsg);
}
Check out this part of the docs on error handling.
Without digging in the code, my expectation is that if the server is unreachable, then no response can be returned from the server. Therefore the Response object remains its initialized state.

Stop authentication at an early pipeline stage- unless going to /Login?

I'm writing a MessageHandler to authenticate a user.
If a request is not containing a special header , I want to block it at the MessageHandler stage.
But if the user wants to go to the Users/Login method, he will probably have no header (because he is not Login yet ).
The problem is that I don't want to block him at the [authorize] controller level.
It's pretty simple :
If he doesn't have the header and he is not on the way to login — BLOCK
If he doesn't have the header and he is on the way to login — only then - ALLOW
Question
1) At the MessaageHandler stage , how can I know that he is on a way to do login ? ( NB : I don't mention the {action} in the route. e.g. :
--
public class User :ApiController
{
[HttpPost]
public bool CheckLogin (....) //i'm not specifying action in the route
{
}
}
2) Looking at the command to read the header :
AuthenticationHeaderValue auth = actionContext.Request.Headers.Authorization;
But - Authorization != Authentication.
So why does web api reference the authorization header as an Authentication ?
The MessageHandler executes before routing has occurred. So at this stage you don't know yet which controller action will be executed.
One possibility would be to check the verb and the path being requested and perform the custom verification based on that:
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
string path = request.RequestUri.PathAndQuery;
if (request.Method == HttpMethod.Post && path.StartsWith("/api/checklogin", StringComparison.InvariantCultureIgnoreCase))
{
// Do not enforce the presence of the custom header
return base.SendAsync(request, cancellationToken);
}
// Check for the presence of your custom header
}
So why does web api reference the authorization header as an Authentication ?
At HTTP level, the header is called Authorization.
I believe you are trying to reinvent the wheel while it is already there. You have Autorize and AllowAnonymous (for your Login action) and then you could have a custom authentication filter to read the header and set up the Principal for the request lifetime.
The reason for that is that the term authorization header has been always used in the context of HTTP header-based authentication. Someone who used the tern for the first time was probably not aware that authentication header would probably be slightly more appropriate.

Express.js get http method in controller

I am building a registration form (passport-local as authentication, forms as form helper).
Because the registration only knows GET and POST I would like to do the whole handling in one function.
With other words I am searching after something like:
exports.register = function(req, res){
if (req.isPost) {
// do form handling
}
res.render('user/registration.html.swig', { form: form.toHTML() });
};
The answer was quite easy
exports.register = function(req, res) {
if (req.method == "POST") {
// do form handling
}
res.render('user/registration.html.swig', { form: form.toHTML() });
};
But I searched a long time for this approach in the express guide.
Finally the node documentation has such detailed information:
http://nodejs.org/api/http.html#http_http_request_options_callback
Now you can use a package in npm => "method-override", which provides a middle-ware layer that overrides the "req.method" property.
Basically your client can send a POST request with a modified "req.method", something like /registration/passportID?_method=PUT.
The
?_method=XXXXX
portion is for the middle-ware to identify that this is an undercover PUT request.
The flow is that the client sends a POST req with data to your server side, and the middle-ware translates the req and run the corresponding "app.put..." route.
I think this is a way of compromise. For more info: method-override

Resources