Reputation: 11
I am trying to use the http-client plugin to set a cookie on KrakenD and send it to the client. This cookie should be sent after retrieving the response from the backend. Unfortunately it does not work. The cookie is created successfully in the plugin but somehow not sent to the client. Pls check the code below for further details. Thank you!
// SPDX-License-Identifier: Apache-2.0
package main
import (
"context"
"errors"
"fmt"
"html"
"io"
"net/http"
"time"
)
// ClientRegisterer is the symbol the plugin loader will try to load. It must implement the RegisterClient interface
var ClientRegisterer = registerer("aci-http-client-plugin")
type registerer string
var logger Logger = nil
func (registerer) RegisterLogger(v interface{}) {
l, ok := v.(Logger)
if !ok {
return
}
logger = l
logger.Debug(fmt.Sprintf("[PLUGIN: %s] Logger loaded", ClientRegisterer))
}
func (r registerer) RegisterClients(f func(
name string,
handler func(context.Context, map[string]interface{}) (http.Handler, error),
)) {
f(string(r), r.registerClients)
}
func (r registerer) registerClients(_ context.Context, extra map[string]interface{}) (http.Handler, error) {
// check the passed configuration and initialize the plugin
name, ok := extra["name"].(string)
if !ok {
return nil, errors.New("wrong config")
}
if name != string(r) {
return nil, fmt.Errorf("unknown register %s", name)
}
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
cookie := http.Cookie{
Name: "exampleCookie",
Value: "Hi there!",
Path: "/",
Domain: "localhost",
Expires: time.Now().Add(3600 * 24 * time.Second),
HttpOnly: true,
}
err := cookie.Valid()
if err != nil {
logger.Error("invalid cookie:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
} else {
logger.Debug("cookie is valid", cookie.String())
}
http.SetCookie(w, &cookie)
logger.Debug(fmt.Sprintf("request host: %s, request path: %s", html.EscapeString(req.URL.Host), html.EscapeString(req.URL.Path)))
values := req.URL.Query()
for k, v := range values {
fmt.Println(k, " => ", v)
}
//forword first the request to the backend
logger.Debug("before sending this request: %s", req.URL.String())
resp, err := http.DefaultClient.Do(req)
logger.Debug("request sent")
if err != nil {
logger.Critical("Exception thrown when sending the request!")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Copy headers, status codes, and body from the backend to the response writer
for k, hs := range resp.Header {
for _, h := range hs {
w.Header().Add(k, h)
}
}
w.WriteHeader(resp.StatusCode)
if resp.Body == nil {
return
}
io.Copy(w, resp.Body)
resp.Body.Close()
fmt.Println("\nPrinting all cookies")
for _, c := range resp.Cookies() {
fmt.Println(c)
}
w.WriteHeader(200)
}), nil
}
func main() {}
type Logger interface {
Debug(v ...interface{})
Info(v ...interface{})
Warning(v ...interface{})
Error(v ...interface{})
Critical(v ...interface{})
Fatal(v ...interface{})
}
{
"version": 3,
"plugin": {
"pattern": ".so",
"folder": "."
},
"endpoints": [
{
"endpoint": "/v1/get-server-cookie",
"backend": [
{
"host": [
"http://dummy.restapiexample.com"
],
"url_pattern": "/api/v1/employees",
"extra_config": {
"plugin/http-client": {
"name": "aci-http-client-plugin"
}
}
}
]
}
]
}
The cookie should be sent to the client and displayed in the curl response
Upvotes: 1
Views: 676
Reputation: 1440
when you do not declare an output_encoding, the default (json) is used. With the default, the headers of the backend are not sent to the client (neither the status codes). If you want the backend (with plugin or not) to have the ability of setting headers (such as the Cookie
header) you need to use the no-op
encoding. Your krakend configuration would look like this:
{
"version": 3,
"plugin": {
"pattern": ".so",
"folder": "."
},
"endpoints": [
{
"endpoint": "/v1/get-server-cookie",
"output_encoding": "no-op",
"backend": [
{
"encoding": "no-op",
"host": [
"http://dummy.restapiexample.com"
],
"url_pattern": "/api/v1/employees",
"extra_config": {
"plugin/http-client": {
"name": "aci-http-client-plugin"
}
}
}
]
}
]
}
This is a very interesting reading that complements this answer: https://www.krakend.io/docs/endpoints/content-types/
Upvotes: 0