Exemple #1
0
func TestFakeSecureService(t *testing.T) {
	var resp, token []byte

	wg := new(sync.WaitGroup)

	server := NewFakeSecureService(wg, func(path string, status int, resp []byte) {
	})
	defer server.Close()

	wg.Add(3)

	client := NewHTTPClient(server.URL, &HTTPClientConfig{Debug: true})
	resp, _ = client.Get("/token")
	token = proto.Body(resp)

	// Right token
	resp, _ = client.Get("/secure?token=" + string(token))
	if !bytes.Equal(proto.Status(resp), []byte("202")) {
		t.Error("Valid token should return status 202:", string(proto.Status(resp)))
	}

	// Wrong tokens forbidden
	resp, _ = client.Get("/secure?token=wrong")
	if !bytes.Equal(proto.Status(resp), []byte("403")) {
		t.Error("Wrong token should returns status 403:", string(proto.Status(resp)))
	}

	wg.Wait()
}
Exemple #2
0
func (p *ESPlugin) ResponseAnalyze(req, resp []byte, start, stop time.Time) {
	if len(resp) == 0 {
		// nil http response - skipped elasticsearch export for this request
		return
	}
	t := time.Now()
	rtt := p.RttDurationToMs(stop.Sub(start))
	req = payloadBody(req)

	esResp := ESRequestResponse{
		ReqURL:               string(proto.Path(req)),
		ReqMethod:            string(proto.Method(req)),
		ReqUserAgent:         string(proto.Header(req, []byte("User-Agent"))),
		ReqAcceptLanguage:    string(proto.Header(req, []byte("Accept-Language"))),
		ReqAccept:            string(proto.Header(req, []byte("Accept"))),
		ReqAcceptEncoding:    string(proto.Header(req, []byte("Accept-Encoding"))),
		ReqIfModifiedSince:   string(proto.Header(req, []byte("If-Modified-Since"))),
		ReqConnection:        string(proto.Header(req, []byte("Connection"))),
		ReqCookies:           string(proto.Header(req, []byte("Cookie"))),
		RespStatus:           string(proto.Status(resp)),
		RespStatusCode:       string(proto.Status(resp)),
		RespProto:            string(proto.Method(resp)),
		RespContentLength:    string(proto.Header(resp, []byte("Content-Length"))),
		RespContentType:      string(proto.Header(resp, []byte("Content-Type"))),
		RespTransferEncoding: string(proto.Header(resp, []byte("Transfer-Encoding"))),
		RespContentEncoding:  string(proto.Header(resp, []byte("Content-Encoding"))),
		RespExpires:          string(proto.Header(resp, []byte("Expires"))),
		RespCacheControl:     string(proto.Header(resp, []byte("Cache-Control"))),
		RespVary:             string(proto.Header(resp, []byte("Vary"))),
		RespSetCookie:        string(proto.Header(resp, []byte("Set-Cookie"))),
		Rtt:                  rtt,
		Timestamp:            t,
	}
	j, err := json.Marshal(&esResp)
	if err != nil {
		log.Println(err)
	} else {
		p.indexor.Index(p.Index, "RequestResponse", "", "", "", &t, j)
	}
	return
}
Exemple #3
0
func TestHTTPClientBasicAuth(t *testing.T) {
	wg := new(sync.WaitGroup)
	wg.Add(2)

	GETPayload := []byte("GET / HTTP/1.1\r\n\r\n")

	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		user, pass, _ := r.BasicAuth()

		if user != "user" || pass != "pass" {
			http.Error(w, "Unauthorized.", 401)
			wg.Done()
			return
		}

		wg.Done()
	}))
	defer server.Close()

	client := NewHTTPClient(server.URL, &HTTPClientConfig{Debug: false})
	resp, _ := client.Send(GETPayload)
	client.Disconnect()

	if !bytes.Equal(proto.Status(resp), []byte("401")) {
		t.Error("Should return unauthorized error", string(resp))
	}

	authUrl := strings.Replace(server.URL, "http://", "http://*****:*****@", -1)
	client = NewHTTPClient(authUrl, &HTTPClientConfig{Debug: false})
	resp, _ = client.Send(GETPayload)
	client.Disconnect()

	if !bytes.Equal(proto.Status(resp), []byte("200")) {
		t.Error("Should return proper response", string(resp))
	}

	wg.Wait()
}
Exemple #4
0
func (c *HTTPClient) Send(data []byte) (response []byte, err error) {
	// Don't exit on panic
	defer func() {
		if r := recover(); r != nil {
			Debug("[HTTPClient]", r, string(data))

			if _, ok := r.(error); !ok {
				log.Println("[HTTPClient] Failed to send request: ", string(data))
				log.Println("PANIC: pkg:", r, debug.Stack())
			}
		}
	}()

	if c.conn == nil || !c.isAlive() {
		Debug("[HTTPClient] Connecting:", c.baseURL)
		if err = c.Connect(); err != nil {
			log.Println("[HTTPClient] Connection error:", err)
			response = errorPayload(HTTP_CONNECTION_ERROR)
			return
		}
	}

	timeout := time.Now().Add(c.config.Timeout)

	c.conn.SetWriteDeadline(timeout)

	if !c.config.OriginalHost {
		data = proto.SetHost(data, []byte(c.baseURL), []byte(c.host))
	}

	if c.auth != "" {
		data = proto.SetHeader(data, []byte("Authorization"), []byte(c.auth))
	}

	if c.config.Debug {
		Debug("[HTTPClient] Sending:", string(data))
	}

	if _, err = c.conn.Write(data); err != nil {
		Debug("[HTTPClient] Write error:", err, c.baseURL)
		response = errorPayload(HTTP_TIMEOUT)
		return
	}

	var readBytes, n int
	var currentChunk []byte
	timeout = time.Now().Add(c.config.Timeout)
	chunked := false
	contentLength := -1
	currentContentLength := 0
	chunks := 0

	for {
		c.conn.SetReadDeadline(timeout)

		if readBytes < len(c.respBuf) {
			n, err = c.conn.Read(c.respBuf[readBytes:])
			readBytes += n
			chunks++

			if err != nil {
				if err == io.EOF {
					err = nil
				}
				break
			}

			// First chunk
			if chunked || contentLength != -1 {
				currentContentLength += n
			} else {
				// If headers are finished
				if bytes.Contains(c.respBuf[:readBytes], proto.EmptyLine) {
					if bytes.Equal(proto.Header(c.respBuf, []byte("Transfer-Encoding")), []byte("chunked")) {
						chunked = true
					} else {
						status, _ := strconv.Atoi(string(proto.Status(c.respBuf)))
						if (status >= 100 && status < 200) || status == 204 || status == 304 {
							contentLength = 0
						} else {
							l := proto.Header(c.respBuf, []byte("Content-Length"))
							if len(l) > 0 {
								contentLength, _ = strconv.Atoi(string(l))
							}
						}
					}

					currentContentLength += len(proto.Body(c.respBuf[:readBytes]))
				}
			}

			if chunked {
				// Check if chunked message finished
				if bytes.HasSuffix(c.respBuf[:readBytes], chunkedSuffix) {
					break
				}
			} else if contentLength != -1 {
				if currentContentLength > contentLength {
					Debug("[HTTPClient] disconnected, wrong length", currentContentLength, contentLength)
					c.Disconnect()
					break
				} else if currentContentLength == contentLength {
					break
				}
			}
		} else {
			if currentChunk == nil {
				currentChunk = make([]byte, readChunkSize)
			}

			n, err = c.conn.Read(currentChunk)

			if err == io.EOF {
				break
			} else if err != nil {
				Debug("[HTTPClient] Read the whole body error:", err, c.baseURL)
				break
			}

			readBytes += int(n)
			chunks++
			currentContentLength += n

			if chunked {
				// Check if chunked message finished
				if bytes.HasSuffix(currentChunk[:n], chunkedSuffix) {
					break
				}
			} else if contentLength != -1 {
				if currentContentLength > contentLength {
					Debug("[HTTPClient] disconnected, wrong length", currentContentLength, contentLength)
					c.Disconnect()
					break
				} else if currentContentLength == contentLength {
					break
				}
			} else {
				Debug("[HTTPClient] disconnected, can't find Content-Length or Chunked")
				c.Disconnect()
				break
			}
		}

		if readBytes >= maxResponseSize {
			Debug("[HTTPClient] Body is more than the max size", maxResponseSize,
				c.baseURL)
			break
		}

		// For following chunks expect less timeout
		timeout = time.Now().Add(c.config.Timeout / 5)
	}

	if err != nil {
		Debug("[HTTPClient] Response read error", err, c.conn, readBytes)
		response = errorPayload(HTTP_TIMEOUT)
		return
	}

	if readBytes > len(c.respBuf) {
		readBytes = len(c.respBuf)
	}
	payload := make([]byte, readBytes)
	copy(payload, c.respBuf[:readBytes])

	if c.config.Debug {
		Debug("[HTTPClient] Received:", string(payload))
	}

	if c.config.FollowRedirects > 0 && c.redirectsCount < c.config.FollowRedirects {
		status := payload[9:12]

		// 3xx requests
		if status[0] == '3' {
			c.redirectsCount++

			location := proto.Header(payload, []byte("Location"))
			redirectPayload := []byte("GET " + string(location) + " HTTP/1.1\r\n\r\n")

			if c.config.Debug {
				Debug("[HTTPClient] Redirecting to: " + string(location))
			}

			return c.Send(redirectPayload)
		}
	}

	if bytes.Equal(proto.Status(payload), []byte("400")) {
		c.Disconnect()
		Debug("[HTTPClient] Closed connection on 400 response")
	}

	c.redirectsCount = 0

	return payload, err
}
Exemple #5
0
func TestHTTPClientErrors(t *testing.T) {
	req := []byte("GET http://foobar.com/path HTTP/1.0\r\n\r\n")

	// Port not exists
	client := NewHTTPClient("http://127.0.0.1:1", &HTTPClientConfig{Debug: true})
	if resp, err := client.Send(req); err != nil {
		if s := proto.Status(resp); !bytes.Equal(s, []byte("521")) {
			t.Error("Should return status 521 for connection refused, instead:", string(s))
		}
	} else {
		t.Error("Should throw error")
	}

	client = NewHTTPClient("http://not.existing", &HTTPClientConfig{Debug: true})
	if resp, err := client.Send(req); err != nil {
		if s := proto.Status(resp); !bytes.Equal(s, []byte("521")) {
			t.Error("Should return status 521 for no such host, instead:", string(s))
		}
	} else {
		t.Error("Should throw error")
	}

	// Non routable IP address to simulate connection timeout
	client = NewHTTPClient("http://10.255.255.1", &HTTPClientConfig{Debug: true, ConnectionTimeout: 100 * time.Millisecond})

	if resp, err := client.Send(req); err != nil {
		if s := proto.Status(resp); !bytes.Equal(s, []byte("521")) {
			t.Error("Should return status 521 for io/timeout:", string(s))
		}
	} else {
		t.Error("Should throw error")
	}

	// Connecting but io timeout on read
	ln, _ := net.Listen("tcp", "127.0.0.1:0")
	client = NewHTTPClient("http://"+ln.Addr().String(), &HTTPClientConfig{Debug: true, Timeout: 10 * time.Millisecond})
	defer ln.Close()

	if resp, err := client.Send(req); err != nil {
		if s := proto.Status(resp); !bytes.Equal(s, []byte("524")) {
			t.Error("Should return status 524 for io read, instead:", string(s))
		}
	} else {
		t.Error("Should throw error")
	}

	// Response read error read tcp [::1]:51128: connection reset by peer &{{0xc20802a000}}
	ln1, _ := net.Listen("tcp", "127.0.0.1:0")
	go func() {
		ln1.Accept()
	}()
	defer ln1.Close()

	client = NewHTTPClient("http://"+ln1.Addr().String(), &HTTPClientConfig{Debug: true, Timeout: 10 * time.Millisecond})

	if resp, err := client.Send(req); err != nil {
		if s := proto.Status(resp); !bytes.Equal(s, []byte("524")) {
			t.Error("Should return status 524 for connection reset by peer, instead:", string(s))
		}
	} else {
		t.Error("Should throw error")
	}
}
Exemple #6
0
func TestTokenMiddleware(t *testing.T) {
	var resp, token []byte

	wg := new(sync.WaitGroup)

	from := NewFakeSecureService(wg, func(path string, status int, tok []byte) {
		time.Sleep(10 * time.Millisecond)
	})
	defer from.Close()

	to := NewFakeSecureService(wg, func(path string, status int, tok []byte) {
		switch path {
		case "/secure":
			if status != 202 {
				t.Error("Server should receive valid rewritten token")
			}
		}

		time.Sleep(10 * time.Millisecond)
	})
	defer to.Close()

	quit := make(chan int)

	Settings.middleware = "go run ./examples/middleware/token_modifier.go"

	fromAddr := strings.Replace(from.Listener.Addr().String(), "[::]", "127.0.0.1", -1)
	// Catch traffic from one service
	input := NewRAWInput(fromAddr, testRawExpire)
	defer input.Close()

	// And redirect to another
	output := NewHTTPOutput(to.URL, &HTTPOutputConfig{Debug: true})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{output}

	// Start Gor
	go Start(quit)

	// Wait for middleware to initialize
	// Give go compiller time to build programm
	time.Sleep(500 * time.Millisecond)

	// Should receive 2 requests from original + 2 from replayed
	wg.Add(4)

	client := NewHTTPClient(from.URL, &HTTPClientConfig{Debug: false})

	// Sending traffic to original service
	resp, _ = client.Get("/token")
	token = proto.Body(resp)

	// When delay is too smal, middleware does not always rewrite requests in time
	// Hopefuly client will have delay more then 10ms :)
	time.Sleep(10 * time.Millisecond)

	resp, _ = client.Get("/secure?token=" + string(token))
	if !bytes.Equal(proto.Status(resp), []byte("202")) {
		t.Error("Valid token should return 202:", proto.Status(resp))
	}

	wg.Wait()
	close(quit)
	time.Sleep(100 * time.Millisecond)
	Settings.middleware = ""
}