github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/util/proxy/upgradeaware_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package proxy 18 19 import ( 20 "bufio" 21 "bytes" 22 "compress/gzip" 23 "context" 24 "crypto/tls" 25 "crypto/x509" 26 "errors" 27 "fmt" 28 "io" 29 "io/ioutil" 30 "net" 31 "net/http" 32 "net/http/httptest" 33 "net/http/httputil" 34 "net/url" 35 "reflect" 36 "strconv" 37 "strings" 38 "testing" 39 "time" 40 41 "github.com/stretchr/testify/assert" 42 "github.com/stretchr/testify/require" 43 44 "golang.org/x/net/websocket" 45 46 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/httpstream" 47 utilnet "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/net" 48 ) 49 50 const fakeStatusCode = 567 51 52 type fakeResponder struct { 53 t *testing.T 54 called bool 55 err error 56 // called chan error 57 w http.ResponseWriter 58 } 59 60 func (r *fakeResponder) Error(w http.ResponseWriter, req *http.Request, err error) { 61 if r.called { 62 r.t.Errorf("Error responder called again!\nprevious error: %v\nnew error: %v", r.err, err) 63 } 64 65 w.WriteHeader(fakeStatusCode) 66 _, writeErr := w.Write([]byte(err.Error())) 67 assert.NoError(r.t, writeErr) 68 69 r.called = true 70 r.err = err 71 } 72 73 type fakeConn struct { 74 err error // The error to return when io is performed over the connection. 75 } 76 77 func (f *fakeConn) Read([]byte) (int, error) { return 0, f.err } 78 func (f *fakeConn) Write([]byte) (int, error) { return 0, f.err } 79 func (f *fakeConn) Close() error { return nil } 80 func (fakeConn) LocalAddr() net.Addr { return nil } 81 func (fakeConn) RemoteAddr() net.Addr { return nil } 82 func (fakeConn) SetDeadline(t time.Time) error { return nil } 83 func (fakeConn) SetReadDeadline(t time.Time) error { return nil } 84 func (fakeConn) SetWriteDeadline(t time.Time) error { return nil } 85 86 type SimpleBackendHandler struct { 87 requestURL url.URL 88 requestHost string 89 requestHeader http.Header 90 requestBody []byte 91 requestMethod string 92 responseBody string 93 responseHeader map[string]string 94 t *testing.T 95 } 96 97 func (s *SimpleBackendHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { 98 s.requestURL = *req.URL 99 s.requestHost = req.Host 100 s.requestHeader = req.Header 101 s.requestMethod = req.Method 102 var err error 103 s.requestBody, err = ioutil.ReadAll(req.Body) 104 if err != nil { 105 s.t.Errorf("Unexpected error: %v", err) 106 return 107 } 108 109 if s.responseHeader != nil { 110 for k, v := range s.responseHeader { 111 w.Header().Add(k, v) 112 } 113 } 114 w.Write([]byte(s.responseBody)) 115 } 116 117 func validateParameters(t *testing.T, name string, actual url.Values, expected map[string]string) { 118 for k, v := range expected { 119 actualValue, ok := actual[k] 120 if !ok { 121 t.Errorf("%s: Expected parameter %s not received", name, k) 122 continue 123 } 124 if actualValue[0] != v { 125 t.Errorf("%s: Parameter %s values don't match. Actual: %#v, Expected: %s", 126 name, k, actualValue, v) 127 } 128 } 129 } 130 131 func validateHeaders(t *testing.T, name string, actual http.Header, expected map[string]string, notExpected []string) { 132 for k, v := range expected { 133 actualValue, ok := actual[k] 134 if !ok { 135 t.Errorf("%s: Expected header %s not received", name, k) 136 continue 137 } 138 if actualValue[0] != v { 139 t.Errorf("%s: Header %s values don't match. Actual: %s, Expected: %s", 140 name, k, actualValue, v) 141 } 142 } 143 if notExpected == nil { 144 return 145 } 146 for _, h := range notExpected { 147 if _, present := actual[h]; present { 148 t.Errorf("%s: unexpected header: %s", name, h) 149 } 150 } 151 } 152 153 func TestServeHTTP(t *testing.T) { 154 tests := []struct { 155 name string 156 method string 157 requestPath string 158 expectedPath string 159 requestBody string 160 requestParams map[string]string 161 requestHeader map[string]string 162 responseHeader map[string]string 163 expectedRespHeader map[string]string 164 notExpectedRespHeader []string 165 upgradeRequired bool 166 appendLocationPath bool 167 expectError func(err error) bool 168 useLocationHost bool 169 }{ 170 { 171 name: "root path, simple get", 172 method: "GET", 173 requestPath: "/", 174 expectedPath: "/", 175 }, 176 { 177 name: "no upgrade header sent", 178 method: "GET", 179 requestPath: "/", 180 upgradeRequired: true, 181 expectError: func(err error) bool { 182 return err != nil && strings.Contains(err.Error(), "Upgrade request required") 183 }, 184 }, 185 { 186 name: "simple path, get", 187 method: "GET", 188 requestPath: "/path/to/test", 189 expectedPath: "/path/to/test", 190 }, 191 { 192 name: "request params", 193 method: "POST", 194 requestPath: "/some/path/", 195 expectedPath: "/some/path/", 196 requestParams: map[string]string{"param1": "value/1", "param2": "value%2"}, 197 requestBody: "test request body", 198 }, 199 { 200 name: "request headers", 201 method: "PUT", 202 requestPath: "/some/path", 203 expectedPath: "/some/path", 204 requestHeader: map[string]string{"Header1": "value1", "Header2": "value2"}, 205 }, 206 { 207 name: "empty path - slash should be added", 208 method: "GET", 209 requestPath: "", 210 expectedPath: "/", 211 }, 212 { 213 name: "remove CORS headers", 214 method: "GET", 215 requestPath: "/some/path", 216 expectedPath: "/some/path", 217 responseHeader: map[string]string{ 218 "Header1": "value1", 219 "Access-Control-Allow-Origin": "some.server", 220 "Access-Control-Allow-Methods": "GET"}, 221 expectedRespHeader: map[string]string{ 222 "Header1": "value1", 223 }, 224 notExpectedRespHeader: []string{ 225 "Access-Control-Allow-Origin", 226 "Access-Control-Allow-Methods", 227 }, 228 }, 229 { 230 name: "use location host", 231 method: "GET", 232 requestPath: "/some/path", 233 expectedPath: "/some/path", 234 useLocationHost: true, 235 }, 236 { 237 name: "use location host - invalid upgrade", 238 method: "GET", 239 upgradeRequired: true, 240 requestHeader: map[string]string{ 241 httpstream.HeaderConnection: httpstream.HeaderUpgrade, 242 }, 243 expectError: func(err error) bool { 244 return err != nil && strings.Contains(err.Error(), "invalid upgrade response: status code 200") 245 }, 246 requestPath: "/some/path", 247 expectedPath: "/some/path", 248 useLocationHost: true, 249 }, 250 { 251 name: "append server path to request path", 252 method: "GET", 253 requestPath: "/base", 254 expectedPath: "/base/base", 255 appendLocationPath: true, 256 }, 257 { 258 name: "append server path to request path with ending slash", 259 method: "GET", 260 requestPath: "/base/", 261 expectedPath: "/base/base/", 262 appendLocationPath: true, 263 }, 264 { 265 name: "don't append server path to request path", 266 method: "GET", 267 requestPath: "/base", 268 expectedPath: "/base", 269 appendLocationPath: false, 270 }, 271 } 272 273 for i, test := range tests { 274 func() { 275 backendResponse := "<html><head></head><body><a href=\"/test/path\">Hello</a></body></html>" 276 backendResponseHeader := test.responseHeader 277 // Test a simple header if not specified in the test 278 if backendResponseHeader == nil && test.expectedRespHeader == nil { 279 backendResponseHeader = map[string]string{"Content-Type": "text/html"} 280 test.expectedRespHeader = map[string]string{"Content-Type": "text/html"} 281 } 282 backendHandler := &SimpleBackendHandler{ 283 responseBody: backendResponse, 284 responseHeader: backendResponseHeader, 285 } 286 backendServer := httptest.NewServer(backendHandler) 287 defer backendServer.Close() 288 289 responder := &fakeResponder{t: t} 290 backendURL, _ := url.Parse(backendServer.URL) 291 backendURL.Path = test.requestPath 292 proxyHandler := NewUpgradeAwareHandler(backendURL, nil, false, test.upgradeRequired, responder) 293 proxyHandler.UseLocationHost = test.useLocationHost 294 proxyHandler.AppendLocationPath = test.appendLocationPath 295 proxyServer := httptest.NewServer(proxyHandler) 296 defer proxyServer.Close() 297 proxyURL, _ := url.Parse(proxyServer.URL) 298 proxyURL.Path = test.requestPath 299 paramValues := url.Values{} 300 for k, v := range test.requestParams { 301 paramValues[k] = []string{v} 302 } 303 proxyURL.RawQuery = paramValues.Encode() 304 var requestBody io.Reader 305 if test.requestBody != "" { 306 requestBody = bytes.NewBufferString(test.requestBody) 307 } 308 req, err := http.NewRequest(test.method, proxyURL.String(), requestBody) 309 if test.requestHeader != nil { 310 header := http.Header{} 311 for k, v := range test.requestHeader { 312 header.Add(k, v) 313 } 314 req.Header = header 315 } 316 if err != nil { 317 t.Errorf("Error creating client request: %v", err) 318 } 319 client := &http.Client{} 320 res, err := client.Do(req) 321 if err != nil { 322 t.Errorf("Error from proxy request: %v", err) 323 } 324 325 // Host 326 if test.useLocationHost && backendHandler.requestHost != backendURL.Host { 327 t.Errorf("Unexpected request host: %s", backendHandler.requestHost) 328 } else if !test.useLocationHost && backendHandler.requestHost == backendURL.Host { 329 t.Errorf("Unexpected request host: %s", backendHandler.requestHost) 330 } 331 332 if test.expectError != nil { 333 if !responder.called { 334 t.Errorf("%d: responder was not invoked", i) 335 return 336 } 337 if !test.expectError(responder.err) { 338 t.Errorf("%d: unexpected error: %v", i, responder.err) 339 } 340 return 341 } 342 343 // Validate backend request 344 // Method 345 if backendHandler.requestMethod != test.method { 346 t.Errorf("Unexpected request method: %s. Expected: %s", 347 backendHandler.requestMethod, test.method) 348 } 349 350 // Body 351 if string(backendHandler.requestBody) != test.requestBody { 352 t.Errorf("Unexpected request body: %s. Expected: %s", 353 string(backendHandler.requestBody), test.requestBody) 354 } 355 356 // Path 357 if backendHandler.requestURL.Path != test.expectedPath { 358 t.Errorf("Unexpected request path: %s", backendHandler.requestURL.Path) 359 } 360 // Parameters 361 validateParameters(t, test.name, backendHandler.requestURL.Query(), test.requestParams) 362 363 // Headers 364 validateHeaders(t, test.name+" backend request", backendHandler.requestHeader, 365 test.requestHeader, nil) 366 367 // Validate proxy response 368 369 // Response Headers 370 validateHeaders(t, test.name+" backend headers", res.Header, test.expectedRespHeader, test.notExpectedRespHeader) 371 372 // Validate Body 373 responseBody, err := ioutil.ReadAll(res.Body) 374 if err != nil { 375 t.Errorf("Unexpected error reading response body: %v", err) 376 } 377 if rb := string(responseBody); rb != backendResponse { 378 t.Errorf("Did not get expected response body: %s. Expected: %s", rb, backendResponse) 379 } 380 381 // Error 382 if responder.called { 383 t.Errorf("Unexpected proxy handler error: %v", responder.err) 384 } 385 }() 386 } 387 } 388 389 type RoundTripperFunc func(req *http.Request) (*http.Response, error) 390 391 func (fn RoundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { 392 return fn(req) 393 } 394 395 func TestProxyUpgrade(t *testing.T) { 396 397 localhostPool := x509.NewCertPool() 398 if !localhostPool.AppendCertsFromPEM(localhostCert) { 399 t.Errorf("error setting up localhostCert pool") 400 } 401 var d net.Dialer 402 403 testcases := map[string]struct { 404 ServerFunc func(http.Handler) *httptest.Server 405 ProxyTransport http.RoundTripper 406 UpgradeTransport UpgradeRequestRoundTripper 407 ExpectedAuth string 408 }{ 409 "http": { 410 ServerFunc: httptest.NewServer, 411 ProxyTransport: nil, 412 }, 413 "both client and server support http2, but force to http/1.1 for upgrade": { 414 ServerFunc: func(h http.Handler) *httptest.Server { 415 cert, err := tls.X509KeyPair(exampleCert, exampleKey) 416 if err != nil { 417 t.Errorf("https (invalid hostname): proxy_test: %v", err) 418 } 419 ts := httptest.NewUnstartedServer(h) 420 ts.TLS = &tls.Config{ 421 Certificates: []tls.Certificate{cert}, 422 NextProtos: []string{"http2", "http/1.1"}, 423 } 424 ts.StartTLS() 425 return ts 426 }, 427 ProxyTransport: utilnet.SetTransportDefaults(&http.Transport{TLSClientConfig: &tls.Config{ 428 NextProtos: []string{"http2", "http/1.1"}, 429 InsecureSkipVerify: true, 430 }}), 431 }, 432 "https (invalid hostname + InsecureSkipVerify)": { 433 ServerFunc: func(h http.Handler) *httptest.Server { 434 cert, err := tls.X509KeyPair(exampleCert, exampleKey) 435 if err != nil { 436 t.Errorf("https (invalid hostname): proxy_test: %v", err) 437 } 438 ts := httptest.NewUnstartedServer(h) 439 ts.TLS = &tls.Config{ 440 Certificates: []tls.Certificate{cert}, 441 } 442 ts.StartTLS() 443 return ts 444 }, 445 ProxyTransport: utilnet.SetTransportDefaults(&http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}), 446 }, 447 "https (valid hostname + RootCAs)": { 448 ServerFunc: func(h http.Handler) *httptest.Server { 449 cert, err := tls.X509KeyPair(localhostCert, localhostKey) 450 if err != nil { 451 t.Errorf("https (valid hostname): proxy_test: %v", err) 452 } 453 ts := httptest.NewUnstartedServer(h) 454 ts.TLS = &tls.Config{ 455 Certificates: []tls.Certificate{cert}, 456 } 457 ts.StartTLS() 458 return ts 459 }, 460 ProxyTransport: utilnet.SetTransportDefaults(&http.Transport{TLSClientConfig: &tls.Config{RootCAs: localhostPool}}), 461 }, 462 "https (valid hostname + RootCAs + custom dialer)": { 463 ServerFunc: func(h http.Handler) *httptest.Server { 464 cert, err := tls.X509KeyPair(localhostCert, localhostKey) 465 if err != nil { 466 t.Errorf("https (valid hostname): proxy_test: %v", err) 467 } 468 ts := httptest.NewUnstartedServer(h) 469 ts.TLS = &tls.Config{ 470 Certificates: []tls.Certificate{cert}, 471 } 472 ts.StartTLS() 473 return ts 474 }, 475 ProxyTransport: utilnet.SetTransportDefaults(&http.Transport{DialContext: d.DialContext, TLSClientConfig: &tls.Config{RootCAs: localhostPool}}), 476 }, 477 "https (valid hostname + RootCAs + custom dialer + bearer token)": { 478 ServerFunc: func(h http.Handler) *httptest.Server { 479 cert, err := tls.X509KeyPair(localhostCert, localhostKey) 480 if err != nil { 481 t.Errorf("https (valid hostname): proxy_test: %v", err) 482 } 483 ts := httptest.NewUnstartedServer(h) 484 ts.TLS = &tls.Config{ 485 Certificates: []tls.Certificate{cert}, 486 } 487 ts.StartTLS() 488 return ts 489 }, 490 ProxyTransport: utilnet.SetTransportDefaults(&http.Transport{DialContext: d.DialContext, TLSClientConfig: &tls.Config{RootCAs: localhostPool}}), 491 UpgradeTransport: NewUpgradeRequestRoundTripper( 492 utilnet.SetOldTransportDefaults(&http.Transport{DialContext: d.DialContext, TLSClientConfig: &tls.Config{RootCAs: localhostPool}}), 493 RoundTripperFunc(func(req *http.Request) (*http.Response, error) { 494 req = utilnet.CloneRequest(req) 495 req.Header.Set("Authorization", "Bearer 1234") 496 return MirrorRequest.RoundTrip(req) 497 }), 498 ), 499 ExpectedAuth: "Bearer 1234", 500 }, 501 } 502 503 for k, tc := range testcases { 504 tcName := k 505 backendPath := "/hello" 506 func() { // Cleanup after each test case. 507 backend := http.NewServeMux() 508 backend.Handle("/hello", websocket.Handler(func(ws *websocket.Conn) { 509 if ws.Request().Header.Get("Authorization") != tc.ExpectedAuth { 510 t.Errorf("%s: unexpected headers on request: %v", k, ws.Request().Header) 511 defer ws.Close() 512 ws.Write([]byte("you failed")) 513 return 514 } 515 defer ws.Close() 516 body := make([]byte, 5) 517 ws.Read(body) 518 ws.Write([]byte("hello " + string(body))) 519 })) 520 backend.Handle("/redirect", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 521 http.Redirect(w, r, "/hello", http.StatusFound) 522 })) 523 backendServer := tc.ServerFunc(backend) 524 defer backendServer.Close() 525 526 serverURL, _ := url.Parse(backendServer.URL) 527 serverURL.Path = backendPath 528 proxyHandler := NewUpgradeAwareHandler(serverURL, tc.ProxyTransport, false, false, &noErrorsAllowed{t: t}) 529 proxyHandler.UpgradeTransport = tc.UpgradeTransport 530 proxy := httptest.NewServer(proxyHandler) 531 defer proxy.Close() 532 533 ws, err := websocket.Dial("ws://"+proxy.Listener.Addr().String()+"/some/path", "", "http://127.0.0.1/") 534 if err != nil { 535 t.Fatalf("%s: websocket dial err: %s", tcName, err) 536 } 537 defer ws.Close() 538 539 if _, err := ws.Write([]byte("world")); err != nil { 540 t.Fatalf("%s: write err: %s", tcName, err) 541 } 542 543 response := make([]byte, 20) 544 n, err := ws.Read(response) 545 if err != nil { 546 t.Fatalf("%s: read err: %s", tcName, err) 547 } 548 if e, a := "hello world", string(response[0:n]); e != a { 549 t.Fatalf("%s: expected '%#v', got '%#v'", tcName, e, a) 550 } 551 }() 552 } 553 } 554 555 type noErrorsAllowed struct { 556 t *testing.T 557 } 558 559 func (r *noErrorsAllowed) Error(w http.ResponseWriter, req *http.Request, err error) { 560 r.t.Error(err) 561 } 562 563 func TestProxyUpgradeConnectionErrorResponse(t *testing.T) { 564 var ( 565 responder *fakeResponder 566 expectedErr = errors.New("EXPECTED") 567 ) 568 proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 569 transport := &http.Transport{ 570 Proxy: http.ProxyFromEnvironment, 571 DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { 572 return &fakeConn{err: expectedErr}, nil 573 }, 574 MaxIdleConns: 100, 575 IdleConnTimeout: 90 * time.Second, 576 TLSHandshakeTimeout: 10 * time.Second, 577 ExpectContinueTimeout: 1 * time.Second, 578 } 579 responder = &fakeResponder{t: t, w: w} 580 proxyHandler := NewUpgradeAwareHandler( 581 &url.URL{ 582 Host: "fake-backend", 583 }, 584 transport, 585 false, 586 true, 587 responder, 588 ) 589 proxyHandler.ServeHTTP(w, r) 590 })) 591 defer proxy.Close() 592 593 // Send request to proxy server. 594 req, err := http.NewRequest("POST", "http://"+proxy.Listener.Addr().String()+"/some/path", nil) 595 require.NoError(t, err) 596 req.Header.Set(httpstream.HeaderConnection, httpstream.HeaderUpgrade) 597 resp, err := http.DefaultClient.Do(req) 598 require.NoError(t, err) 599 defer resp.Body.Close() 600 601 // Expect error response. 602 assert.True(t, responder.called) 603 assert.Equal(t, fakeStatusCode, resp.StatusCode) 604 msg, err := ioutil.ReadAll(resp.Body) 605 require.NoError(t, err) 606 assert.Contains(t, string(msg), expectedErr.Error()) 607 } 608 609 func TestProxyUpgradeErrorResponseTerminates(t *testing.T) { 610 for _, code := range []int{400, 500} { 611 t.Run(fmt.Sprintf("code=%v", code), func(t *testing.T) { 612 // Set up a backend server 613 backend := http.NewServeMux() 614 backend.Handle("/hello", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 615 w.WriteHeader(code) 616 w.Write([]byte(`some data`)) 617 })) 618 backend.Handle("/there", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 619 t.Error("request to /there") 620 })) 621 backendServer := httptest.NewServer(backend) 622 defer backendServer.Close() 623 backendServerURL, _ := url.Parse(backendServer.URL) 624 backendServerURL.Path = "/hello" 625 626 // Set up a proxy pointing to a specific path on the backend 627 proxyHandler := NewUpgradeAwareHandler(backendServerURL, nil, false, false, &noErrorsAllowed{t: t}) 628 proxy := httptest.NewServer(proxyHandler) 629 defer proxy.Close() 630 proxyURL, _ := url.Parse(proxy.URL) 631 632 conn, err := net.Dial("tcp", proxyURL.Host) 633 require.NoError(t, err) 634 bufferedReader := bufio.NewReader(conn) 635 636 // Send upgrade request resulting in a non-101 response from the backend 637 req, _ := http.NewRequest("GET", "/", nil) 638 req.Header.Set(httpstream.HeaderConnection, httpstream.HeaderUpgrade) 639 require.NoError(t, req.Write(conn)) 640 // Verify we get the correct response and full message body content 641 resp, err := http.ReadResponse(bufferedReader, nil) 642 require.NoError(t, err) 643 data, err := ioutil.ReadAll(resp.Body) 644 require.NoError(t, err) 645 require.Equal(t, resp.StatusCode, code) 646 require.Equal(t, data, []byte(`some data`)) 647 resp.Body.Close() 648 649 // try to read from the connection to verify it was closed 650 b := make([]byte, 1) 651 conn.SetReadDeadline(time.Now().Add(time.Second)) 652 if _, err := conn.Read(b); err != io.EOF { 653 t.Errorf("expected EOF, got %v", err) 654 } 655 656 // Send another request to another endpoint to verify it is not received 657 req, _ = http.NewRequest("GET", "/there", nil) 658 req.Write(conn) 659 // wait to ensure the handler does not receive the request 660 time.Sleep(time.Second) 661 662 // clean up 663 conn.Close() 664 }) 665 } 666 } 667 668 func TestProxyUpgradeErrorResponse(t *testing.T) { 669 for _, code := range []int{200, 300, 302, 307} { 670 t.Run(fmt.Sprintf("code=%v", code), func(t *testing.T) { 671 // Set up a backend server 672 backend := http.NewServeMux() 673 backend.Handle("/hello", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 674 http.Redirect(w, r, "https://example.com/there", code) 675 })) 676 backendServer := httptest.NewServer(backend) 677 defer backendServer.Close() 678 backendServerURL, _ := url.Parse(backendServer.URL) 679 backendServerURL.Path = "/hello" 680 681 // Set up a proxy pointing to a specific path on the backend 682 proxyHandler := NewUpgradeAwareHandler(backendServerURL, nil, false, false, &fakeResponder{t: t}) 683 proxy := httptest.NewServer(proxyHandler) 684 defer proxy.Close() 685 proxyURL, _ := url.Parse(proxy.URL) 686 687 conn, err := net.Dial("tcp", proxyURL.Host) 688 require.NoError(t, err) 689 bufferedReader := bufio.NewReader(conn) 690 691 // Send upgrade request resulting in a non-101 response from the backend 692 req, _ := http.NewRequest("GET", "/", nil) 693 req.Header.Set(httpstream.HeaderConnection, httpstream.HeaderUpgrade) 694 require.NoError(t, req.Write(conn)) 695 // Verify we get the correct response and full message body content 696 resp, err := http.ReadResponse(bufferedReader, nil) 697 require.NoError(t, err) 698 assert.Equal(t, fakeStatusCode, resp.StatusCode) 699 resp.Body.Close() 700 701 // clean up 702 conn.Close() 703 }) 704 } 705 } 706 707 func TestRejectForwardingRedirectsOption(t *testing.T) { 708 originalBody := []byte(`some data`) 709 testCases := []struct { 710 name string 711 rejectForwardingRedirects bool 712 serverStatusCode int 713 redirect string 714 expectStatusCode int 715 expectBody []byte 716 }{ 717 { 718 name: "reject redirection enabled in proxy, backend server sending 200 response", 719 rejectForwardingRedirects: true, 720 serverStatusCode: 200, 721 expectStatusCode: 200, 722 expectBody: originalBody, 723 }, 724 { 725 name: "reject redirection enabled in proxy, backend server sending 301 response", 726 rejectForwardingRedirects: true, 727 serverStatusCode: 301, 728 redirect: "/", 729 expectStatusCode: 502, 730 expectBody: []byte(`the backend attempted to redirect this request, which is not permitted`), 731 }, 732 { 733 name: "reject redirection enabled in proxy, backend server sending 304 response with a location header", 734 rejectForwardingRedirects: true, 735 serverStatusCode: 304, 736 redirect: "/", 737 expectStatusCode: 502, 738 expectBody: []byte(`the backend attempted to redirect this request, which is not permitted`), 739 }, 740 { 741 name: "reject redirection enabled in proxy, backend server sending 304 response with no location header", 742 rejectForwardingRedirects: true, 743 serverStatusCode: 304, 744 expectStatusCode: 304, 745 expectBody: []byte{}, // client doesn't read the body for 304 responses 746 }, 747 { 748 name: "reject redirection disabled in proxy, backend server sending 200 response", 749 rejectForwardingRedirects: false, 750 serverStatusCode: 200, 751 expectStatusCode: 200, 752 expectBody: originalBody, 753 }, 754 { 755 name: "reject redirection disabled in proxy, backend server sending 301 response", 756 rejectForwardingRedirects: false, 757 serverStatusCode: 301, 758 redirect: "/", 759 expectStatusCode: 301, 760 expectBody: originalBody, 761 }, 762 } 763 for _, tc := range testCases { 764 t.Run(tc.name, func(t *testing.T) { 765 // Set up a backend server 766 backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 767 if tc.redirect != "" { 768 w.Header().Set("Location", tc.redirect) 769 } 770 w.WriteHeader(tc.serverStatusCode) 771 w.Write(originalBody) 772 })) 773 defer backendServer.Close() 774 backendServerURL, _ := url.Parse(backendServer.URL) 775 776 // Set up a proxy pointing to the backend 777 proxyHandler := NewUpgradeAwareHandler(backendServerURL, nil, false, false, &fakeResponder{t: t}) 778 proxyHandler.RejectForwardingRedirects = tc.rejectForwardingRedirects 779 proxy := httptest.NewServer(proxyHandler) 780 defer proxy.Close() 781 proxyURL, _ := url.Parse(proxy.URL) 782 783 conn, err := net.Dial("tcp", proxyURL.Host) 784 require.NoError(t, err) 785 bufferedReader := bufio.NewReader(conn) 786 787 req, _ := http.NewRequest("GET", proxyURL.String(), nil) 788 require.NoError(t, req.Write(conn)) 789 // Verify we get the correct response and message body content 790 resp, err := http.ReadResponse(bufferedReader, nil) 791 require.NoError(t, err) 792 assert.Equal(t, tc.expectStatusCode, resp.StatusCode) 793 data, err := ioutil.ReadAll(resp.Body) 794 require.NoError(t, err) 795 assert.Equal(t, tc.expectBody, data) 796 assert.Equal(t, int64(len(tc.expectBody)), resp.ContentLength) 797 resp.Body.Close() 798 799 // clean up 800 conn.Close() 801 }) 802 } 803 } 804 805 func TestDefaultProxyTransport(t *testing.T) { 806 tests := []struct { 807 name, 808 url, 809 location, 810 expectedScheme, 811 expectedHost, 812 expectedPathPrepend string 813 }{ 814 { 815 name: "simple path", 816 url: "http://test.server:8080/a/test/location", 817 location: "http://localhost/location", 818 expectedScheme: "http", 819 expectedHost: "test.server:8080", 820 expectedPathPrepend: "/a/test", 821 }, 822 { 823 name: "empty path", 824 url: "http://test.server:8080/a/test/", 825 location: "http://localhost", 826 expectedScheme: "http", 827 expectedHost: "test.server:8080", 828 expectedPathPrepend: "/a/test", 829 }, 830 { 831 name: "location ending in slash", 832 url: "http://test.server:8080/a/test/", 833 location: "http://localhost/", 834 expectedScheme: "http", 835 expectedHost: "test.server:8080", 836 expectedPathPrepend: "/a/test", 837 }, 838 } 839 840 for _, test := range tests { 841 locURL, _ := url.Parse(test.location) 842 URL, _ := url.Parse(test.url) 843 h := NewUpgradeAwareHandler(locURL, nil, false, false, nil) 844 result := h.defaultProxyTransport(URL, nil) 845 transport := result.(*corsRemovingTransport).RoundTripper.(*Transport) 846 if transport.Scheme != test.expectedScheme { 847 t.Errorf("%s: unexpected scheme. Actual: %s, Expected: %s", test.name, transport.Scheme, test.expectedScheme) 848 } 849 if transport.Host != test.expectedHost { 850 t.Errorf("%s: unexpected host. Actual: %s, Expected: %s", test.name, transport.Host, test.expectedHost) 851 } 852 if transport.PathPrepend != test.expectedPathPrepend { 853 t.Errorf("%s: unexpected path prepend. Actual: %s, Expected: %s", test.name, transport.PathPrepend, test.expectedPathPrepend) 854 } 855 } 856 } 857 858 func TestProxyRequestContentLengthAndTransferEncoding(t *testing.T) { 859 chunk := func(data []byte) []byte { 860 out := &bytes.Buffer{} 861 chunker := httputil.NewChunkedWriter(out) 862 for _, b := range data { 863 if _, err := chunker.Write([]byte{b}); err != nil { 864 panic(err) 865 } 866 } 867 chunker.Close() 868 out.Write([]byte("\r\n")) 869 return out.Bytes() 870 } 871 872 zip := func(data []byte) []byte { 873 out := &bytes.Buffer{} 874 zipper := gzip.NewWriter(out) 875 if _, err := zipper.Write(data); err != nil { 876 panic(err) 877 } 878 zipper.Close() 879 return out.Bytes() 880 } 881 882 sampleData := []byte("abcde") 883 884 table := map[string]struct { 885 reqHeaders http.Header 886 reqBody []byte 887 888 expectedHeaders http.Header 889 expectedBody []byte 890 }{ 891 "content-length": { 892 reqHeaders: http.Header{ 893 "Content-Length": []string{"5"}, 894 }, 895 reqBody: sampleData, 896 897 expectedHeaders: http.Header{ 898 "Content-Length": []string{"5"}, 899 "Content-Encoding": nil, // none set 900 "Transfer-Encoding": nil, // none set 901 }, 902 expectedBody: sampleData, 903 }, 904 905 "content-length + gzip content-encoding": { 906 reqHeaders: http.Header{ 907 "Content-Length": []string{strconv.Itoa(len(zip(sampleData)))}, 908 "Content-Encoding": []string{"gzip"}, 909 }, 910 reqBody: zip(sampleData), 911 912 expectedHeaders: http.Header{ 913 "Content-Length": []string{strconv.Itoa(len(zip(sampleData)))}, 914 "Content-Encoding": []string{"gzip"}, 915 "Transfer-Encoding": nil, // none set 916 }, 917 expectedBody: zip(sampleData), 918 }, 919 920 "chunked transfer-encoding": { 921 reqHeaders: http.Header{ 922 "Transfer-Encoding": []string{"chunked"}, 923 }, 924 reqBody: chunk(sampleData), 925 926 expectedHeaders: http.Header{ 927 "Content-Length": nil, // none set 928 "Content-Encoding": nil, // none set 929 "Transfer-Encoding": nil, // Transfer-Encoding gets removed 930 }, 931 expectedBody: sampleData, // sample data is unchunked 932 }, 933 934 "chunked transfer-encoding + gzip content-encoding": { 935 reqHeaders: http.Header{ 936 "Content-Encoding": []string{"gzip"}, 937 "Transfer-Encoding": []string{"chunked"}, 938 }, 939 reqBody: chunk(zip(sampleData)), 940 941 expectedHeaders: http.Header{ 942 "Content-Length": nil, // none set 943 "Content-Encoding": []string{"gzip"}, 944 "Transfer-Encoding": nil, // gets removed 945 }, 946 expectedBody: zip(sampleData), // sample data is unchunked, but content-encoding is preserved 947 }, 948 949 // "Transfer-Encoding: gzip" is not supported by go 950 // See http/transfer.go#fixTransferEncoding (https://golang.org/src/net/http/transfer.go#L427) 951 // Once it is supported, this test case should succeed 952 // 953 // "gzip+chunked transfer-encoding": { 954 // reqHeaders: http.Header{ 955 // "Transfer-Encoding": []string{"chunked,gzip"}, 956 // }, 957 // reqBody: chunk(zip(sampleData)), 958 // 959 // expectedHeaders: http.Header{ 960 // "Content-Length": nil, // no content-length headers 961 // "Transfer-Encoding": nil, // Transfer-Encoding gets removed 962 // }, 963 // expectedBody: sampleData, 964 // }, 965 } 966 967 successfulResponse := "backend passed tests" 968 for k, item := range table { 969 // Start the downstream server 970 downstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 971 // Verify headers 972 for header, v := range item.expectedHeaders { 973 if !reflect.DeepEqual(v, req.Header[header]) { 974 t.Errorf("%s: Expected headers for %s to be %v, got %v", k, header, v, req.Header[header]) 975 } 976 } 977 978 // Read body 979 body, err := ioutil.ReadAll(req.Body) 980 if err != nil { 981 t.Errorf("%s: unexpected error %v", k, err) 982 } 983 req.Body.Close() 984 985 // Verify length 986 if req.ContentLength > 0 && req.ContentLength != int64(len(body)) { 987 t.Errorf("%s: ContentLength was %d, len(data) was %d", k, req.ContentLength, len(body)) 988 } 989 990 // Verify content 991 if !bytes.Equal(item.expectedBody, body) { 992 t.Errorf("%s: Expected %q, got %q", k, string(item.expectedBody), string(body)) 993 } 994 995 // Write successful response 996 w.Write([]byte(successfulResponse)) 997 })) 998 defer downstreamServer.Close() 999 1000 responder := &fakeResponder{t: t} 1001 backendURL, _ := url.Parse(downstreamServer.URL) 1002 proxyHandler := NewUpgradeAwareHandler(backendURL, nil, false, false, responder) 1003 proxyServer := httptest.NewServer(proxyHandler) 1004 defer proxyServer.Close() 1005 1006 // Dial the proxy server 1007 conn, err := net.Dial(proxyServer.Listener.Addr().Network(), proxyServer.Listener.Addr().String()) 1008 if err != nil { 1009 t.Errorf("unexpected error %v", err) 1010 continue 1011 } 1012 defer conn.Close() 1013 1014 // Add standard http 1.1 headers 1015 if item.reqHeaders == nil { 1016 item.reqHeaders = http.Header{} 1017 } 1018 item.reqHeaders.Add("Connection", "close") 1019 item.reqHeaders.Add("Host", proxyServer.Listener.Addr().String()) 1020 1021 // Write the request headers 1022 if _, err := fmt.Fprint(conn, "POST / HTTP/1.1\r\n"); err != nil { 1023 t.Fatalf("%s unexpected error %v", k, err) 1024 } 1025 for header, values := range item.reqHeaders { 1026 for _, value := range values { 1027 if _, err := fmt.Fprintf(conn, "%s: %s\r\n", header, value); err != nil { 1028 t.Fatalf("%s: unexpected error %v", k, err) 1029 } 1030 } 1031 } 1032 // Header separator 1033 if _, err := fmt.Fprint(conn, "\r\n"); err != nil { 1034 t.Fatalf("%s: unexpected error %v", k, err) 1035 } 1036 // Body 1037 if _, err := conn.Write(item.reqBody); err != nil { 1038 t.Fatalf("%s: unexpected error %v", k, err) 1039 } 1040 1041 // Read response 1042 response, err := ioutil.ReadAll(conn) 1043 if err != nil { 1044 t.Errorf("%s: unexpected error %v", k, err) 1045 continue 1046 } 1047 if !strings.HasSuffix(string(response), successfulResponse) { 1048 t.Errorf("%s: Did not get successful response: %s", k, string(response)) 1049 continue 1050 } 1051 } 1052 } 1053 1054 func TestFlushIntervalHeaders(t *testing.T) { 1055 const expected = "hi" 1056 stopCh := make(chan struct{}) 1057 backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1058 w.Header().Add("MyHeader", expected) 1059 w.WriteHeader(200) 1060 w.(http.Flusher).Flush() 1061 <-stopCh 1062 })) 1063 defer backend.Close() 1064 defer close(stopCh) 1065 1066 backendURL, err := url.Parse(backend.URL) 1067 if err != nil { 1068 t.Fatal(err) 1069 } 1070 1071 responder := &fakeResponder{t: t} 1072 proxyHandler := NewUpgradeAwareHandler(backendURL, nil, false, false, responder) 1073 1074 frontend := httptest.NewServer(proxyHandler) 1075 defer frontend.Close() 1076 1077 req, _ := http.NewRequest("GET", frontend.URL, nil) 1078 req.Close = true 1079 1080 ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second) 1081 defer cancel() 1082 req = req.WithContext(ctx) 1083 1084 res, err := frontend.Client().Do(req) 1085 if err != nil { 1086 t.Fatalf("Get: %v", err) 1087 } 1088 defer res.Body.Close() 1089 1090 if res.Header.Get("MyHeader") != expected { 1091 t.Errorf("got header %q; expected %q", res.Header.Get("MyHeader"), expected) 1092 } 1093 } 1094 1095 type fakeRT struct { 1096 err error 1097 } 1098 1099 func (frt *fakeRT) RoundTrip(*http.Request) (*http.Response, error) { 1100 return nil, frt.err 1101 } 1102 1103 // TestErrorPropagation checks if the default transport doesn't swallow the errors by providing a fakeResponder that intercepts and stores the error. 1104 func TestErrorPropagation(t *testing.T) { 1105 backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1106 panic("unreachable") 1107 })) 1108 defer backend.Close() 1109 1110 backendURL, err := url.Parse(backend.URL) 1111 if err != nil { 1112 t.Fatal(err) 1113 } 1114 1115 responder := &fakeResponder{t: t} 1116 expectedErr := errors.New("nasty error") 1117 proxyHandler := NewUpgradeAwareHandler(backendURL, &fakeRT{err: expectedErr}, true, false, responder) 1118 1119 frontend := httptest.NewServer(proxyHandler) 1120 defer frontend.Close() 1121 1122 req, _ := http.NewRequest("GET", frontend.URL, nil) 1123 req.Close = true 1124 1125 ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second) 1126 defer cancel() 1127 req = req.WithContext(ctx) 1128 1129 res, err := frontend.Client().Do(req) 1130 if err != nil { 1131 t.Fatalf("Get: %v", err) 1132 } 1133 defer res.Body.Close() 1134 if res.StatusCode != fakeStatusCode { 1135 t.Fatalf("unexpected HTTP status code returned: %v, expected: %v", res.StatusCode, fakeStatusCode) 1136 } 1137 if !strings.Contains(responder.err.Error(), expectedErr.Error()) { 1138 t.Fatalf("responder got unexpected error: %v, expected the error to contain %q", responder.err.Error(), expectedErr.Error()) 1139 } 1140 } 1141 1142 func TestProxyRedirectsforRootPath(t *testing.T) { 1143 1144 tests := []struct { 1145 name string 1146 method string 1147 requestPath string 1148 expectedHeader http.Header 1149 expectedStatusCode int 1150 redirect bool 1151 }{ 1152 { 1153 name: "root path, simple get", 1154 method: "GET", 1155 requestPath: "", 1156 redirect: true, 1157 expectedStatusCode: 301, 1158 expectedHeader: http.Header{ 1159 "Location": []string{"/"}, 1160 }, 1161 }, 1162 { 1163 name: "root path, simple put", 1164 method: "PUT", 1165 requestPath: "", 1166 redirect: false, 1167 expectedStatusCode: 200, 1168 }, 1169 { 1170 name: "root path, simple head", 1171 method: "HEAD", 1172 requestPath: "", 1173 redirect: true, 1174 expectedStatusCode: 301, 1175 expectedHeader: http.Header{ 1176 "Location": []string{"/"}, 1177 }, 1178 }, 1179 { 1180 name: "root path, simple delete with params", 1181 method: "DELETE", 1182 requestPath: "", 1183 redirect: false, 1184 expectedStatusCode: 200, 1185 }, 1186 } 1187 1188 for _, test := range tests { 1189 func() { 1190 w := httptest.NewRecorder() 1191 req, err := http.NewRequest(test.method, test.requestPath, nil) 1192 if err != nil { 1193 t.Fatal(err) 1194 } 1195 1196 redirect := proxyRedirectsforRootPath(test.requestPath, w, req) 1197 if got, want := redirect, test.redirect; got != want { 1198 t.Errorf("Expected redirect state %v; got %v", want, got) 1199 } 1200 1201 res := w.Result() 1202 if got, want := res.StatusCode, test.expectedStatusCode; got != want { 1203 t.Errorf("Expected status code %d; got %d", want, got) 1204 } 1205 1206 if res.StatusCode == 301 && !reflect.DeepEqual(res.Header, test.expectedHeader) { 1207 t.Errorf("Expected location header to be %v, got %v", test.expectedHeader, res.Header) 1208 } 1209 }() 1210 } 1211 } 1212 1213 // exampleCert was generated from crypto/tls/generate_cert.go with the following command: 1214 // 1215 // go run generate_cert.go --rsa-bits 1024 --host example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h 1216 var exampleCert = []byte(`-----BEGIN CERTIFICATE----- 1217 MIIDADCCAeigAwIBAgIQVHG3Fn9SdWayyLOZKCW1vzANBgkqhkiG9w0BAQsFADAS 1218 MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw 1219 MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A 1220 MIIBCgKCAQEArTCu9fiIclNgDdWHphewM+JW55dCb5yYGlJgCBvwbOx547M9p+tn 1221 zm9QOhsdZDHDZsG9tqnWxE2Nc1HpIJyOlfYsOoonpEoG/Ep6nnK91ngj0bn/JlNy 1222 +i/bwU4r97MOukvnOIQez9/D9jAJaOX2+b8/d4lRz9BsqiwJyg+ynZ5tVVYj7aMi 1223 vXnd6HOnJmtqutOtr3beucJnkd6XbwRkLUcAYATT+ZihOWRbTuKqhCg6zGkJOoUG 1224 f8sX61JjoilxiURA//ftGVbdTCU3DrmGmardp5NNOHbumMYU8Vhmqgx1Bqxb+9he 1225 7G42uW5YWYK/GqJzgVPjjlB2dOGj9KrEWQIDAQABo1AwTjAOBgNVHQ8BAf8EBAMC 1226 AqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAWBgNVHREE 1227 DzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAig4AIi9xWs1+pLES 1228 eeGGdSDoclplFpcbXANnsYYFyLf+8pcWgVi2bOmb2gXMbHFkB07MA82wRJAUTaA+ 1229 2iNXVQMhPCoA7J6ADUbww9doJX2S9HGyArhiV/MhHtE8txzMn2EKNLdhhk3N9rmV 1230 x/qRbWAY1U2z4BpdrAR87Fe81Nlj7h45csW9K+eS+NgXipiNTIfEShKgCFM8EdxL 1231 1WXg7r9AvYV3TNDPWTjLsm1rQzzZQ7Uvcf6deWiNodZd8MOT/BFLclDPTK6cF2Hr 1232 UU4dq6G4kCwMSxWE4cM3HlZ4u1dyIt47VbkP0rtvkBCXx36y+NXYA5lzntchNFZP 1233 uvEQdw== 1234 -----END CERTIFICATE-----`) 1235 1236 var exampleKey = []byte(`-----BEGIN RSA PRIVATE KEY----- 1237 MIIEpQIBAAKCAQEArTCu9fiIclNgDdWHphewM+JW55dCb5yYGlJgCBvwbOx547M9 1238 p+tnzm9QOhsdZDHDZsG9tqnWxE2Nc1HpIJyOlfYsOoonpEoG/Ep6nnK91ngj0bn/ 1239 JlNy+i/bwU4r97MOukvnOIQez9/D9jAJaOX2+b8/d4lRz9BsqiwJyg+ynZ5tVVYj 1240 7aMivXnd6HOnJmtqutOtr3beucJnkd6XbwRkLUcAYATT+ZihOWRbTuKqhCg6zGkJ 1241 OoUGf8sX61JjoilxiURA//ftGVbdTCU3DrmGmardp5NNOHbumMYU8Vhmqgx1Bqxb 1242 +9he7G42uW5YWYK/GqJzgVPjjlB2dOGj9KrEWQIDAQABAoIBAQClt4CiYaaF5ltx 1243 wVDjz6TNcJUBUs3CKE+uWAYFnF5Ii1nyU876Pxj8Aaz9fHZ6Kde0GkwiXY7gFOj1 1244 YHo2tzcELSKS/SEDZcYbYFTGCjq13g1AH74R+SV6WZLn+5m8kPvVrM1ZWap188H5 1245 bmuCkRDqVmIvShkbRW7EwhC35J9fiuW3majC/sjmsxtxyP6geWmu4f5/Ttqahcdb 1246 osPZIgIIPzqAkNtkLTi7+meHYI9wlrGhL7XZTwnJ1Oc/Y67zzmbthLYB5YFSLUew 1247 rXT58jtSjX4gbiQyheBSrWxW08QE4qYg6jJlAdffHhWv72hJW2MCXhuXp8gJs/Do 1248 XLRHGwSBAoGBAMdNtsbe4yae/QeHUPGxNW0ipa0yoTF6i+VYoxvqiRMzDM3+3L8k 1249 dgI1rr4330SivqDahMA/odWtM/9rVwJI2B2QhZLMHA0n9ytH007OO9TghgVB12nN 1250 xosRYBpKdHXyyvV/MUZl7Jux6zKIzRDWOkF95VVYPcAaxJqd1E5/jJ6JAoGBAN51 1251 QrebA1w/jfydeqQTz1sK01sbO4HYj4qGfo/JarVqGEkm1azeBBPPRnHz3jNKnCkM 1252 S4PpqRDased3NIcViXlAgoqPqivZ8mQa/Rb146l7WaTErASHsZ023OGrxsr/Ed6N 1253 P3GrmvxVJjebaFNaQ9sP80dLkpgeas0t2TY8iQNRAoGATOcnx8TpUVW3vNfx29DN 1254 FLdxxkrq9/SZVn3FMlhlXAsuva3B799ZybB9JNjaRdmmRNsMrkHfaFvU3JHGmRMS 1255 kRXa9LHdgRYSwZiNaLMbUyDvlce6HxFPswmZU4u3NGvi9KeHk+pwSgN1BaLTvdNr 1256 1ymE/FF4QlAR3LdZ3JBK6kECgYEA0wW4/CJ31ZIURoW8SNjh4iMqy0nR8SJVR7q9 1257 Y/hU2TKDRyEnoIwaohAFayNCrLUh3W5kVAXa8roB+OgDVAECH5sqOfZ+HorofD19 1258 x8II7ESujLZj1whBXDkm3ovsT7QWZ17lyBZZNvQvBKDPHgKKS8udowv1S4fPGENd 1259 wS07a4ECgYEAwLSbmMIVJme0jFjsp5d1wOGA2Qi2ZwGIAVlsbnJtygrU/hSBfnu8 1260 VfyJSCgg3fPe7kChWKlfcOebVKSb68LKRsz1Lz1KdbY0HOJFp/cT4lKmDAlRY9gq 1261 LB4rdf46lV0mUkvd2/oofIbTrzukjQSnyfLawb/2uJGV1IkTcZcn9CI= 1262 -----END RSA PRIVATE KEY-----`)