| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 | 
							- /*
 
-  * Public Domain Software
 
-  *
 
-  * I (Matthias Ladkau) am the author of the source code in this file.
 
-  * I have placed the source code in this file in the public domain.
 
-  *
 
-  * For further information see: http://creativecommons.org/publicdomain/zero/1.0/
 
-  */
 
- package httputil
 
- import (
 
- 	"bytes"
 
- 	"crypto/tls"
 
- 	"crypto/x509"
 
- 	"flag"
 
- 	"fmt"
 
- 	"html"
 
- 	"io/ioutil"
 
- 	"net"
 
- 	"net/http"
 
- 	"os"
 
- 	"sync"
 
- 	"syscall"
 
- 	"testing"
 
- 	"time"
 
- 	"devt.de/krotik/common/cryptutil"
 
- 	"devt.de/krotik/common/fileutil"
 
- )
 
- const certdir = "certs"
 
- const testporthttp = ":9050"
 
- const testporthttps = ":9051"
 
- const invalidFileName = "**" + string(0x0)
 
- func TestMain(m *testing.M) {
 
- 	flag.Parse()
 
- 	// Setup
 
- 	if res, _ := fileutil.PathExists(certdir); res {
 
- 		os.RemoveAll(certdir)
 
- 	}
 
- 	err := os.Mkdir(certdir, 0770)
 
- 	if err != nil {
 
- 		fmt.Print("Could not create test directory:", err.Error())
 
- 		os.Exit(1)
 
- 	}
 
- 	// Run the tests
 
- 	res := m.Run()
 
- 	// Teardown
 
- 	err = os.RemoveAll(certdir)
 
- 	if err != nil {
 
- 		fmt.Print("Could not remove test directory:", err.Error())
 
- 	}
 
- 	os.Exit(res)
 
- }
 
- func TestHTTPSServer(t *testing.T) {
 
- 	// Generate a certificate and private key
 
- 	err := cryptutil.GenCert(certdir, "cert.pem", "key.pem", "localhost", "", 365*24*time.Hour, true, 2048, "")
 
- 	if err != nil {
 
- 		t.Error(err)
 
- 		return
 
- 	}
 
- 	// Add dummy handler
 
- 	http.HandleFunc("/httpsserver_test", func(w http.ResponseWriter, r *http.Request) {
 
- 		fmt.Fprintf(w, "Hello over HTTPS, %q", html.EscapeString(r.URL.Path))
 
- 	})
 
- 	hs := &HTTPServer{}
 
- 	var wg sync.WaitGroup
 
- 	wg.Add(1)
 
- 	go hs.RunHTTPSServer(certdir, "cert.pem", "key.pem", testporthttps, &wg)
 
- 	wg.Wait()
 
- 	// HTTPS Server has started
 
- 	if hs.LastError != nil {
 
- 		t.Error(hs.LastError)
 
- 		return
 
- 	}
 
- 	// Check we can't start two servers
 
- 	var wg2 sync.WaitGroup
 
- 	hs2 := &HTTPServer{}
 
- 	wg2.Add(1)
 
- 	err = hs2.RunHTTPSServer(certdir, "c.pem", "k.pem", testporthttps, &wg2)
 
- 	if hs2.LastError == nil ||
 
- 		(hs2.LastError.Error() != "open certs/c.pem: no such file or directory" &&
 
- 			hs2.LastError.Error() != "open certs/c.pem: The system cannot find the file specified.") ||
 
- 		err != hs2.LastError {
 
- 		t.Error("Unexpected error return:", hs2.LastError)
 
- 		return
 
- 	}
 
- 	// Add again to wait group so we can try again
 
- 	wg2.Add(1)
 
- 	err = hs2.RunHTTPSServer(certdir, "cert.pem", "key.pem", testporthttps, &wg2)
 
- 	if hs2.LastError == nil || (hs2.LastError.Error() != "listen tcp "+testporthttps+
 
- 		": bind: address already in use" && hs2.LastError.Error() != "listen tcp "+testporthttps+
 
- 		": bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.") ||
 
- 		err != hs2.LastError {
 
- 		t.Error("Unexpected error return:", hs2.LastError)
 
- 	}
 
- 	// Add to the wait group so we can wait for the shutdown
 
- 	wg.Add(1)
 
- 	// Send something to the server
 
- 	if res := sendTestHTTPSRequest(certdir + "/cert.pem"); res != `Hello over HTTPS, "/httpsserver_test"` {
 
- 		t.Error("Unexpected request response:", res)
 
- 		return
 
- 	}
 
- 	// Server is shut down
 
- 	hs.Shutdown()
 
- 	if hs.Running == true {
 
- 		wg.Wait()
 
- 	} else {
 
- 		t.Error("Server was not running as expected")
 
- 	}
 
- }
 
- func TestSignalling(t *testing.T) {
 
- 	// Add dummy handler
 
- 	http.HandleFunc("/httpserver_test", func(w http.ResponseWriter, r *http.Request) {
 
- 		fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
 
- 	})
 
- 	hs := &HTTPServer{}
 
- 	var wg sync.WaitGroup
 
- 	wg.Add(1)
 
- 	go hs.RunHTTPServer(testporthttp, &wg)
 
- 	wg.Wait()
 
- 	// Server is started
 
- 	if hs.LastError != nil {
 
- 		t.Error(hs.LastError)
 
- 		return
 
- 	}
 
- 	// Check we can't start two servers
 
- 	var wg2 sync.WaitGroup
 
- 	wg2.Add(1)
 
- 	hs2 := &HTTPServer{}
 
- 	err := hs2.RunHTTPServer(testporthttp, &wg2)
 
- 	if hs2.LastError == nil || (hs2.LastError.Error() != "listen tcp "+testporthttp+
 
- 		": bind: address already in use" && hs2.LastError.Error() != "listen tcp "+testporthttp+
 
- 		": bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.") ||
 
- 		err != hs2.LastError {
 
- 		t.Error("Unexpected error return:", hs2.LastError)
 
- 	}
 
- 	// Add to the wait group so we can wait for the shutdown
 
- 	wg.Add(1)
 
- 	// Send something to the server
 
- 	if res := sendTestRequest(); res != `Hello, "/httpserver_test"` {
 
- 		t.Error("Unexpected request response:", res)
 
- 		return
 
- 	}
 
- 	// Check we can send other signals
 
- 	hs.signalling <- syscall.SIGHUP
 
- 	time.Sleep(time.Duration(50) * time.Millisecond)
 
- 	if hs.Running != true {
 
- 		t.Error("Server should still be running after sending wrong shutdown signal")
 
- 		return
 
- 	}
 
- 	// Server is shut down
 
- 	hs.Shutdown()
 
- 	if hs.Running == true {
 
- 		wg.Wait()
 
- 	} else {
 
- 		t.Error("Server was not running as expected")
 
- 	}
 
- 	// Test listener panic
 
- 	originalListener, _ := net.Listen("tcp", testporthttp)
 
- 	sl := newSignalTCPListener(originalListener, originalListener.(*net.TCPListener), nil)
 
- 	go testUnknownSignalPanic(t, sl)
 
- 	sl.Signals <- -1
 
- }
 
- func testUnknownSignalPanic(t *testing.T, sl *signalTCPListener) {
 
- 	defer func() {
 
- 		if r := recover(); r == nil {
 
- 			t.Error("Sending an unknown signal did not cause a panic.")
 
- 		}
 
- 	}()
 
- 	sl.Accept()
 
- }
 
- func sendTestRequest() string {
 
- 	url := "http://localhost" + testporthttp + "/httpserver_test"
 
- 	var jsonStr = []byte(`{"msg":"Hello!"}`)
 
- 	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
 
- 	req.Header.Set("X-Custom-Header", "myvalue")
 
- 	req.Header.Set("Content-Type", "application/json")
 
- 	client := &http.Client{}
 
- 	resp, err := client.Do(req)
 
- 	if err != nil {
 
- 		panic(err)
 
- 	}
 
- 	defer resp.Body.Close()
 
- 	body, _ := ioutil.ReadAll(resp.Body)
 
- 	return string(body)
 
- }
 
- func sendTestHTTPSRequest(caCert string) string {
 
- 	// Build ca cert pool
 
- 	caPool := x509.NewCertPool()
 
- 	serverCert, err := ioutil.ReadFile(caCert)
 
- 	if err != nil {
 
- 		panic(err)
 
- 	}
 
- 	caPool.AppendCertsFromPEM(serverCert)
 
- 	tr := &http.Transport{
 
- 		TLSClientConfig:    &tls.Config{RootCAs: caPool},
 
- 		DisableCompression: true,
 
- 	}
 
- 	url := "https://localhost" + testporthttps + "/httpsserver_test"
 
- 	var jsonStr = []byte(`{"msg":"Hello!"}`)
 
- 	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
 
- 	req.Header.Set("X-Custom-Header", "myvalue")
 
- 	req.Header.Set("Content-Type", "application/json")
 
- 	client := &http.Client{Transport: tr}
 
- 	resp, err := client.Do(req)
 
- 	if err != nil {
 
- 		panic(err)
 
- 	}
 
- 	defer resp.Body.Close()
 
- 	body, _ := ioutil.ReadAll(resp.Body)
 
- 	return string(body)
 
- }
 
 
  |