Last active
August 29, 2021 20:38
-
-
Save KaHBrat/e11fa370e463fb361b19f2154b61ad11 to your computer and use it in GitHub Desktop.
httpencoding
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package httpencoding | |
import ( | |
"bytes" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"net/http" | |
"net/url" | |
"reflect" | |
"strings" | |
"testing" | |
) | |
func TestHttpencoding_Integration_ConvBackAndForth(t *testing.T) { | |
//Arrange | |
const defaultUserAgent = "Go-http-client/1.1" | |
type args struct { | |
req http.Request | |
} | |
tests := []struct { | |
name string | |
args args | |
want http.Request | |
wantErr bool | |
}{ | |
{ | |
name: "Convert a HTTP Request to a byte Array and back to HTTP Request", | |
args: args{http.Request{Method: http.MethodGet, URL: &url.URL{Path: "http://localhost:20000"}}}, | |
want: http.Request{ | |
Method: http.MethodGet, | |
Host: "localhost:20000", | |
RequestURI: "http://localhost:20000", | |
URL: &url.URL{ | |
Scheme: "http", | |
Host: "localhost:20000"}, | |
Proto: "HTTP/1.1", | |
ProtoMajor: 1, | |
ProtoMinor: 1, | |
Header: http.Header{ | |
"User-Agent": []string{defaultUserAgent}}, | |
Body: http.NoBody, | |
Close: false}, | |
}, | |
} | |
for _, tt := range tests { | |
t.Run(tt.name, func(t *testing.T) { | |
//Act | |
b, err := GetHttpRawRequest(tt.args.req) | |
if (err != nil) != tt.wantErr { | |
t.Errorf("GetHttpRawMessage() error = %v, wantErr %v", err, tt.wantErr) | |
return | |
} | |
r := bytes.NewReader(b) | |
if (err != nil) != tt.wantErr { | |
t.Errorf("r.Read() error = %v, wantErr %v", err, tt.wantErr) | |
return | |
} | |
got, err := GetHttpRequest(r) | |
if (err != nil) != tt.wantErr { | |
t.Errorf("ConvByteToHttpReq() error = %v, wantErr %v", err, tt.wantErr) | |
return | |
} | |
//Assert | |
if !reflect.DeepEqual(*got, tt.want) { | |
t.Errorf("GetHttpRawMessage() = %v, want %v", *got, tt.want) | |
} | |
}) | |
} | |
} | |
/* | |
Test Description: | |
RequestB will be encapsulated in the body of RequestA | |
RequestA will be sent to Testserver1 | |
Testserver1 will convert the encapsulated RequestB to an httpRequest | |
Testserver1 will send RequestB to Testserver2 | |
Testserver1 will encapsulate the response of Testserver2 in its response | |
The response of Testserver1 will be converted to a httpResponse | |
The body of the response of Testserver2 will be read | |
send: ReqA{ReqB} -> Testserver1. ReqB -> Testserver2 | |
read: respTestServer1{respTestserver2} | |
*/ | |
func TestHttpEncoding_Integration_Complete(t *testing.T) { | |
//Arrange | |
go runTestServer1() | |
go runTestServer2() | |
type args struct { | |
httpMethod string | |
url string | |
message string | |
} | |
tests := []struct { | |
name string | |
args args | |
want string | |
wantErr bool | |
}{ | |
{ | |
name: "Full Integration test", | |
args: args{httpMethod: http.MethodGet, url: httpEncodingEndpoint2, message: "Hello World"}, | |
want: "Encapsulated HTTP Request received on test-server2 and sent back successfully", | |
}, | |
} | |
for _, tt := range tests { | |
t.Run(tt.name, func(t *testing.T) { | |
//Arrange | |
stringReader := strings.NewReader(tt.args.message) | |
req, err := http.NewRequest(tt.args.httpMethod, tt.args.url, stringReader) | |
if (err != nil) != tt.wantErr { | |
t.Errorf("http.NewRequest() error = %v, wantErr %v", err, tt.wantErr) | |
return | |
} | |
//Act | |
b, err := GetHttpRawRequest(*req) | |
if (err != nil) != tt.wantErr { | |
t.Errorf("GetHttpRawRequest() error = %v, wantErr %v", err, tt.wantErr) | |
return | |
} | |
r := bytes.NewReader(b) | |
resp, err := http.Post(httpEncodingEndpoint, "", r) | |
if (err != nil) != tt.wantErr { | |
t.Errorf("http.Post() error = %v, wantErr %v", err, tt.wantErr) | |
return | |
} | |
encapsulatedResponse, err := GetHttpResponse(resp.Body, req) | |
if (err != nil) != tt.wantErr { | |
t.Errorf("GetHttpResponse() error = %v, wantErr %v", err, tt.wantErr) | |
return | |
} | |
msg, err := ioutil.ReadAll(encapsulatedResponse.Body) | |
if (err != nil) != tt.wantErr { | |
t.Errorf("ioutil.ReadAll() error = %v, wantErr %v", err, tt.wantErr) | |
return | |
} | |
got := string(msg) | |
//Assert | |
if !reflect.DeepEqual(got, tt.want) { | |
t.Errorf("GetHttpRawMessage() = %v, want %v", got, tt.want) | |
} | |
}) | |
} | |
} | |
const httpEncodingEndpoint = "http://localhost:12000/httpEncoding" | |
const httpEncodingEndpoint2 = "http://localhost:20000/httpEncoding2" | |
const msgPath = "/httpEncoding" | |
const msgPath2 = "/httpEncoding2" | |
const msgPort = ":12000" | |
const msgPort2 = ":20000" | |
func runTestServer1() { | |
log.Printf("Starting test http Listener\n serving on endpoint %s", httpEncodingEndpoint) | |
http.HandleFunc(msgPath, httpEncodingHandler) | |
if err := http.ListenAndServe(msgPort, nil); err != nil { | |
log.Fatalf("error: %s", err) | |
} | |
} | |
func httpEncodingHandler(w http.ResponseWriter, r *http.Request) { | |
req, err := GetHttpRequest(r.Body) | |
if err != nil { | |
http.Error(w, fmt.Sprintf("Converting to HTTP Request failed: %s", err), http.StatusBadRequest) | |
return | |
} | |
client := http.Client{} | |
resp, err := client.Do(req) | |
if err != nil { | |
http.Error(w, fmt.Sprintf("calling next HTTP Request failed: %s", err), http.StatusBadRequest) | |
return | |
} | |
rawResponse, err := GetHttpRawResponse(*resp) | |
if err != nil { | |
http.Error(w, fmt.Sprintf("converting to rawp HTTP response failed: %s", err), http.StatusBadRequest) | |
return | |
} | |
fmt.Println(string(rawResponse)) | |
w.Write(rawResponse) | |
} | |
func runTestServer2() { | |
log.Printf("Starting test http Listener\n serving on endpoint %s", httpEncodingEndpoint2) | |
http.HandleFunc(msgPath2, httpEncodingHandler2) | |
if err := http.ListenAndServe(msgPort2, nil); err != nil { | |
log.Fatalf("error: %s", err) | |
} | |
} | |
func httpEncodingHandler2(w http.ResponseWriter, r *http.Request) { | |
w.Write([]byte("Encapsulated HTTP Request received on test-server2 and sent back successfully")) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package httpencoding | |
import ( | |
"bufio" | |
"bytes" | |
"io" | |
"net/http" | |
"net/url" | |
) | |
func GetHttpRawRequest(req http.Request) ([]byte, error) { | |
var b = &bytes.Buffer{} | |
if err := req.Write(b) ; err != nil { | |
return nil, err | |
} | |
return b.Bytes(), nil | |
} | |
func GetHttpRequest(r io.Reader) (*http.Request, error) { | |
bufReader := bufio.NewReader(r) | |
req, err := http.ReadRequest(bufReader) | |
if err != nil { | |
return nil, err | |
} | |
// https://stackoverflow.com/questions/19595860/http-request-requesturi-field-when-making-request-in-go | |
// We can't have this set. And it only contains the msg path anyway. It was set during http.ReadRequest | |
req.RequestURI = "" | |
// Since the req.URL will not have all the information set, | |
// such as protocol scheme and host, we create a new URL | |
u, err := url.Parse("http://"+req.Host+req.URL.Path) | |
if err != nil { | |
return nil, err | |
} | |
req.URL = u | |
return req ,err | |
} | |
func GetHttpRawResponse(resp http.Response) ([]byte, error) { | |
var b = &bytes.Buffer{} | |
if err := resp.Write(b) ; err != nil { | |
return nil, err | |
} | |
return b.Bytes(), nil | |
} | |
func GetHttpResponse(r io.Reader, req *http.Request) (*http.Response, error) { | |
bufReader := bufio.NewReader(r) | |
resp, err := http.ReadResponse(bufReader, req) | |
if err != nil { | |
return nil, err | |
} | |
return resp ,err | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment