2

I would like to implement an HTTP request and response system of this for

client ------> A ----------> B --------> (request) HTTPserver
client <------ A <---------- B <-------- (response) HTTPserver
  1. client send HTTP request with any HTTP method (POST,PUT, etc) to A
  2. A then reads the request body encrypt it and then forward it to B 3 B then decrypt the reads the HTTP request body
  3. B then with the received decrypt body as payload prepare an HTTP request and and send to the HTTP server. 5 The HTTP server then respond to B.
  4. B then encrypt the response from the HTTP server and then forward to A.
  5. A also decrypt the response from B and then and send the response back to the client.

I have implements the following base on earlier suggestions.

ProxyA:

const (
  ServerB = "<address of B>"
  Port = "<proxy A port>"
)

func main() {
  // start server
  http.HandleFunc("/", proxyPass)
  log.Fatal(http.ListenAndServe(":" + Port, nil))
}

func proxyPass(res http.ResponseWriter, req  *http.Request) {
 
 // read request body from client
bodybytes, _ := ioutil.ReadAll(req.Body)

defer req.Body.Close()

// encrypt req.Body
object, _ := enc.Encrypt(bodybytes)

// serialize object
serialized, _ := object.CompactSerialize()

// prepare forwarding message
msg := message{reformatedData: serialized}

// encode message 
msgbytes, _ := json.Marshal(&msg)

req.ContentLength = int64(len(msgbytes))
req.Body = ioutil.NopCloser(bytes.NewBuffer(msgbytes))


// How do I read the response data from proxy server B and then send
// response to the client
....
 
  url, _ := url.Parse(ServerB)
  proxy := httputil.NewSingleHostReverseProxy(url)
  proxy.ServeHTTP(res, req)
}

For proxy B:

const (
  Server = "<address of server>"
  Port = "<proxy B port>"
)

func main() {
  // start server
  http.HandleFunc("/", proxyPass)
  log.Fatal(http.ListenAndServe(":" + Port, nil))
}

func proxyPass(res http.ResponseWriter, req  *http.Request) {

  var msg message
  HTTPServerurl := http://xxxxx

  // read request body
  bodybytes, _ := ioutil.ReadAll(req.Body)
  
  req.ContentLength = int64(len(bodybytes))
  req.Body = ioutil.NopCloser(bytes.NewBuffer(bodybytes))


// decode message 
err = json.Unmarshal(bodybytes, &msg)

// decrypt message
object, _ := jose.ParseEncrypted(msg)
decrypted, _ := object.Decrypt("phrasetodecryptmessage")

//send HTTP request to HTTP server
resp, _ := HandlemessageToHTTPServer(decrypted, "POST", HTTPServerurl)

//read response body
RespBody, _ := ioutil.ReadAll(resp.Body)

// encrypt response body
object, _ = enc.Encrypt(producerRespBody)
serialized, _ := object.CompactSerialize()

// prepare response JSON message 
resmsg := resmessage {resmessage: serialized}

// marshall response message 
respmsgbytes, _ := json.Marshal(&resmsg)


// How do I write the "respmsgbytes" to proxyServHTTP "res" back to proxy A


  url, _ := url.Parse(Server)
  proxy := httputil.NewSingleHostReverseProxy(url)
  proxy.ServeHTTP(res, req)
} 

My question is

  1. How do I write the "respmsgbytes" to proxyServHTTP "res" in proxy B back to proxy A ?

  2. How do I read the response data from proxy server B and then send response to the client?

Any help? I have left error checking to make the code short.

1
  • 4
    You may find the stdlib httputil.ReverseProxy useful Commented Apr 22, 2021 at 12:40

1 Answer 1

4

You can use httputil
You can do something like following.
For proxy A:

const (
  ServerB = "<address of B>"
  Port = "<proxy A port>"
)

func main() {
  // start server
  http.HandleFunc("/", proxyPass)
  log.Fatal(http.ListenAndServe(":" + Port, nil))
}

func proxyPass(res http.ResponseWriter, req  *http.Request) {
  // Encrypt Request here
  // ...

  url, _ := url.Parse(ServerB)
  proxy := httputil.NewSingleHostReverseProxy(url)
  proxy.ServeHTTP(res, req)
} 

For proxy B:

const (
  Server = "<address of server>"
  Port = "<proxy B port>"
)

func main() {
  // start server
  http.HandleFunc("/", proxyPass)
  log.Fatal(http.ListenAndServe(":" + Port, nil))
}

func proxyPass(res http.ResponseWriter, req  *http.Request) {
  // Decrypt Request here
  // ...

  url, _ := url.Parse(Server)
  proxy := httputil.NewSingleHostReverseProxy(url)
  proxy.ServeHTTP(res, req)
} 

EDIT:
To handle the request body at each proxy, you can have a look at this. Alternatively, I think there should be no harm in construction of new req based on current req as following:

func proxyPass(res http.ResponseWriter, req  *http.Request) {
    body, _ := ioutil.ReadAll(req.Body)
    data := string(body)

    // process data here

    req, _ = http.NewRequest(req.Method, req.URL.String(), strings.NewReader(data))
    
    u, _ := url.Parse(Server)
    proxy := httputil.NewSingleHostReverseProxy(u)
    proxy.ServeHTTP(res, req)
}

This can be done at both proxies.

EDIT:
The proxy response can be updated using ReverseProxy.ModifyResponse.
You can use it like this:

func proxyPass(res http.ResponseWriter, req *http.Request) {
    ....
    
    proxy := httputil.NewSingleHostReverseProxy(url)
    
    proxy.ModifyResponse = func(response *http.Response) error {
        // Read and update the response here

        // The response here is response from server (proxy B if this is at proxy A)
        // It is a pointer, so can be modified to update in place
        // It will not be called if Proxy B is unreachable
    }

    proxy.ServeHTTP(res, req)
}
Sign up to request clarification or add additional context in comments.

8 Comments

Am getting error: httputil: ReverseProxy read error during body copy: read tcp 127.0.0.1:52484->127.0.0.1:2020: read: connection reset by peer
how are you trying to connect? the error is connection reset by peer meaning for some reason, the client seems to send RST
Sorry it was my fault to use http.ListenAndServeTLS instead of http.ListenAndServe.
However, after encryption of the request, how do i send it to proxy B?
You'll have to use the request body and update the request itself. I would directly update the current request.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.