lh

package module
v0.0.0-...-de17b8e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 25, 2018 License: MIT Imports: 21 Imported by: 0

README

lh

A package to serve http.Handlers in the Amazon Lambda Go runtime. GoDoc

This is a replacement for the lambda package as published in the aws/aws-lambda-go repository. This package allows serving (many or most) http.Handlers.

Usage

Call lh.ServeHTTP(handler) from a main package. If handler is nil, http.DefaultServeMux will be served.

Deployment

The lago commandline tool is designed to make deploying Go handlers to Lambda about as easy as it can possibly be.

Notes

This package only works with API Gateway requests. Undefined behavior may occur if the Lambda function is called with other request types. API Gateway must be configured to treat all content types as binary (*/* is in "Binary Media Types" under the Settings tab). No notion of streaming or connections exists in the API Gateway/Lambda environment, therefore the ResponseWriter may not be asserted to http.Flusher nor http.Hijacker, the CONNECT method cannot be used in a useful way, and other behavior (like Expect headers) are handled upstream. Request and response size is limited by the Lambda environment; it's unlikely more than 10k of request headers, 6 megabytes of request body, or 10 megabytes of response will succeed. Finally, it's unreasonable to expect goroutines created from ServeHTTP methods to continue running indefinately after ServeHTTP exits; if something makes assumptions about long-running processes it's probably not a candidate for the Lambda environment.

That said, many packages that implement http.Handler should work fine. For example Gorilla's RPC works, and gin works OK when used as an http.Handler. Revel won't but you can't do most of the stuff it does in the Lambda environment anyway.

Documentation

Overview

Package lh enables http.Handlers to be served in the AWS Lambda Go runtime.

ServeHTTP(h) should be called from a main package. If h is nil, http.DefaultServeMux will be used.

Note this package is intended for Lambda functions as API Gateway endpoints; other payloads will have undefined behavior. Also note API Gateway must be configured so all media types are treated as binary. That is, "Binary Media Types" under "Settings" includes:

*/*

API Gateway can remap hostnames and paths. For example using an API Gateway domain (not a custom domain), the stage component of the request URL is elided from the path provided to Lambda handlers. This package inspects for Location headers that would be otherwise incorrect and attempts to correct them if FixRelativeRedirect is left at its default of true.

The Lambda environment can be inspected by asserting http.Responsewriter to the Lambda interface. The ResponseWriter may not be asserted to an http.Hijacker nor Flusher, as the Lambda environment does not support any form of streaming (including but not limited to websockets and EventSources).

Example
package main

import (
	"fmt"
	"net/http"

	"github.com/cloudinterfaces/lh"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		_, ok := w.(lh.Lambda)
		switch ok {
		case true:
			fmt.Fprintf(w, "Hello from the Lambda environment! via %s\n", r.Host)
		default:
			fmt.Fprintln(w, "Not running in Lambda environment")
		}
	})
	lh.ServeHTTP(nil)
}
Output:

Example (Complicated)
package main

import (
	"fmt"
	"math"
	"net/http"

	"github.com/cloudinterfaces/lh"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/rpc"
	"github.com/gorilla/rpc/json"
)

type Math struct{}

func (m *Math) Add(_ *http.Request, args *[]float64, sum *float64) error {
	for _, a := range *args {
		*sum += a
	}
	return nil
}

func (m *Math) Multiply(_ *http.Request, args *[]float64, product *float64) error {
	for i, a := range *args {
		if a == 0 {
			*product = 0
			return nil
		}
		if i == 0 {
			*product = a
			continue
		}
		*product *= a
	}
	return nil
}

func (m *Math) Divide(_ *http.Request, args *[]float64, div *float64) error {
	if len(*args) < 2 {
		return fmt.Errorf("At least 2 arguments required")
	}
	for _, f := range (*args)[1:] {
		if math.Abs(f) == 0 {
			return fmt.Errorf("Args includes a division by zero")
		}
	}
	*div = (*args)[0] / (*args)[1]
	for _, f := range (*args)[2:] {
		*div /= f
	}
	return nil
}

func main() {
	server := rpc.NewServer() // github.com/gorilla/rpc
	server.RegisterCodec(json.NewCodec(), "application/json")
	server.RegisterService(&Math{}, "Math")
	http.Handle("/rpc", server)
	g := gin.Default()
	g.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	http.Handle("/", g)
	http.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "../error", 307)
	})
	http.HandleFunc("/error", func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "This is an error", 500)
	})
	lh.ServeHTTP(nil)
}
Output:

Index

Examples

Constants

This section is empty.

Variables

View Source
var Demangle = map[string]struct{}{
	"X-Amzn-Remapped-Accept":             {},
	"X-Amzn-Remapped-Accept-Charset":     {},
	"X-Amzn-Remapped-Accept-Encoding":    {},
	"X-Amzn-Remapped-Age":                {},
	"X-Amzn-Remapped-Authorization":      {},
	"X-Amzn-Remapped-Connection":         {},
	"X-Amzn-Remapped-Content-Encoding":   {},
	"X-Amzn-Remapped-Content-Length":     {},
	"X-Amzn-Remapped-Content-MD5":        {},
	"X-Amzn-Remapped-Content-Type":       {},
	"X-Amzn-Remapped-Date":               {},
	"X-Amzn-Remapped-Expect":             {},
	"X-Amzn-Remapped-Host":               {},
	"X-Amzn-Remapped-Max-Forwards":       {},
	"X-Amzn-Remapped-Pragma":             {},
	"X-Amzn-Remapped-Proxy-Authenticate": {},
	"X-Amzn-Remapped-Range":              {},
	"X-Amzn-Remapped-Referer":            {},
	"X-Amzn-Remapped-Server":             {},
	"X-Amzn-Remapped-TE":                 {},
	"X-Amzn-Remapped-Trailer":            {},
	"X-Amzn-Remapped-Transfer-Encoding":  {},
	"X-Amzn-Remapped-Upgrade":            {},
	"X-Amzn-Remapped-User-Agent":         {},
	"X-Amzn-Remapped-Via":                {},
	"X-Amzn-Remapped-WWW-Authenticate":   {},
	"X-Amzn-Remapped-Warn":               {},
}

Demangle is the set of possible X-Amzn-Remapped headers. It is a good practice to reduce this to a set of concern prior to calling ServeHTTP if DemangleInputHeaders is true.

View Source
var DemangleInputHeaders = false

DemangleInputHeaders controls the attempt to replace X-Amzn-Remapped-* headers with non-remapped equivalents. If true, the X-Amzn-Remapped header is deleted if it can be unremapped. If the non-remapped header exists and is not empty, the X-Amzn-Remapped header will not be deleted. For example, the Via header will generally be supplied by API Gateway, therefore X-Amzn-Remapped-Via may still be present if the client sent a Via header. This should be set (if needed) prior to calling ServeHTTP.

View Source
var FixRelativeRedirect = true

FixRelativeRedirect attemtps to "fix" relative redirects when API gateway is not configured with a custom domain. Setting this to false prevents modification of Location headers.

View Source
var Mangle = map[string]struct{}{
	"Accept":             {},
	"Accept-Charset":     {},
	"Accept-Encoding":    {},
	"Age":                {},
	"Authorization":      {},
	"Connection":         {},
	"Content-Encoding":   {},
	"Content-Length":     {},
	"Content-MD5":        {},
	"Content-Type":       {},
	"Date":               {},
	"Expect":             {},
	"Host":               {},
	"Max-Forwards":       {},
	"Pragma":             {},
	"Proxy-Authenticate": {},
	"Range":              {},
	"Referer":            {},
	"Server":             {},
	"TE":                 {},
	"Trailer":            {},
	"Transfer-Encoding":  {},
	"Upgrade":            {},
	"User-Agent":         {},
	"Via":                {},
	"WWW-Authenticate":   {},
	"Warn":               {},
}

Mangle is the set of headers API Gateway may prefer as X-Amzn-Remapped headers. It's a good practice to reduce this to a set of concern prior to calling ServeHTTP if MangleOutputHeaders is true.

View Source
var MangleOutputHeaders = false

MangleOutputHeaders controls replacing output headers with X-Amzn-Remapped headers. If set, headers that need to be remapped have an additional X-Amzn-Remapped header created with the same value. This should be set (if needed) prior to calling ServeHTTP.

View Source
var PanicMessage = "Function panic"

PanicMessage is returned as the body of the 500 HTTP response when unrecovered panics occur.

Functions

func ServeHTTP

func ServeHTTP(h http.Handler)

ServeHTTP serves h for the AWS Lambda Go runtime. If h is nil, serves http.DefaultServeMux. If called outside the Lambda environment, starts a normal http.Server on localhost on a random port.

Types

type Lambda

type Lambda interface {
	InvokeRequest() messages.InvokeRequest
	ClientContext() lambdacontext.ClientContext
	GatewayRequest() events.APIGatewayProxyRequest
}

Lambda is an interface to retrieve Lambda-specific types. A Lambda http.ResponseWriter supports this type assertion.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL