http

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Mar 1, 2019 License: BSD-3-Clause Imports: 13 Imported by: 6

Documentation

Overview

Package http implement custom HTTP server with memory file system and simplified routing handler.

Problems

There are two problems that this library try to handle. First, optimizing serving local file system; second, complexity of routing regarding to their method, request type, and response type.

Assuming that we want to serve file system and API using ServeMux, the simplest registered handler are,

mux.HandleFunc("/", handleFileSystem)
mux.HandleFunc("/api", handleAPI)

The first problem is regarding to "http.ServeFile". Everytime the request hit "handleFileSystem" the "http.ServeFile" try to locate the file regarding to request path in system, read the content of file, parse its content type, and finally write the content-type, content-length, and body as response. This is time consuming. Of course, on modern OS, they may caching readed file descriptor in memory to minimize disk lookup, so the next call to the same file path may not touch the hard storage back again.

The second problem is regarding to handling API. We must check the request method, checking content-type, parsing query parameter or POST form in every sub-handler of API. Assume that we have an API with method POST and query parameter, the method to handle it would be like these,

handleAPILogin(res, req) {
	// (1) Check if method is POST
	// (2) Parse query parameter
	// (3) Process request
	// (4) Write response
}

The step number 1, 2, 4 needs to be written for every handler of our API.

Solutions

The solution to the first problem is by mapping all content of files to be served into memory. This cause more memory to be consumed on server side but we minimize path lookup, and cache-miss on OS level.

Serving file system is handled by memory file system using map of path to file node.

map[/index.html] = Node{Type: ..., Size: ..., ContentType: ...}

There is a limit on size of file to be mapped on memory. See the package "lib/memfs" for more information.

The solution to the second problem is by mapping the registered request per method and by path. User just need to focus on step 3, handling on how to process request, all of process on step 1, 2, and 4 will be handled by our library.

epAPILogin := &libhttp.Endpoint{
	Path: "/api/login",
	RequestType: libhttp.RequestTypeQuery,
	ResponseType: libhttp.ResponseTypeJSON,
	Call: handleLogin,
}
server.RequestPost(epAPILogin)

Upon receiving request to "/api/login", the library will call "req.ParseForm()", read the content of body and pass them to "handleLogin",

func handleLogin(req *http.Request, reqBody []byte) (resBody []byte, err error) {
	// Process login input from req.Form, req.PostForm, and/or
	// reqBody.
	// Return response body and error.
}

Known Bugs

* The server does not handle CONNECT method

* Missing test for request with content-type multipart-form

Index

Constants

View Source
const (
	ContentLength     = "Content-Length"
	ContentType       = "Content-Type"
	ContentTypeBinary = "application/octet-stream"
	ContentTypeForm   = "application/x-www-form-urlencoded"
	ContentTypeJSON   = "application/json"
	ContentTypePlain  = "text/plain; charset=utf-8"
	HeaderLocation    = "Location"
)
View Source
const (
	RequestTypeNone  RequestType = 0
	RequestTypeQuery             = 1 << iota
	RequestTypeForm
	RequestTypeMultipartForm
	RequestTypeJSON
)

List of valid request type.

View Source
const (
	ResponseTypeNone   ResponseType = 0
	ResponseTypeBinary              = 1 << iota
	ResponseTypePlain
	ResponseTypeJSON
)

List of valid response type.

Variables

This section is empty.

Functions

This section is empty.

Types

type Callback

type Callback func(res http.ResponseWriter, req *http.Request, reqBody []byte) (resBody []byte, err error)

Callback define a type of function for handling registered handler.

The function will have the query URL, request multipart form data, and request body ready to be used in req parameter.

The ResponseWriter can be used to write custom header or to write cookies but should not be used to write response body.

The error return type should be instance of StatusError. If error is not nil and not *StatusError, server will response with internal-server-error status code.

type Endpoint

type Endpoint struct {
	// Method contains HTTP method, default to GET.
	Method RequestMethod
	// Path contains route to be served, default to "/" if its empty.
	Path string
	// RequestType contains type of request, default to RequestTypeNone.
	RequestType RequestType
	// ResponseType contains type of request, default to ResponseTypeNone.
	ResponseType ResponseType
	// Eval define evaluator for route that will be called after global
	// evaluators and before callback.
	Eval Evaluator
	// Call is the main process of route.
	Call Callback
}

Endpoint represent route that will be handled by server. Each route have their own evaluator that will be evaluated after global evaluators from server.

type Evaluator

type Evaluator func(req *http.Request, reqBody []byte) error

Evaluator evaluate the request. If request is invalid, the error will tell the response code and the error message to be written back to client.

type RequestMethod

type RequestMethod int

RequestMethod define type of HTTP method.

const (
	RequestMethodGet     RequestMethod = 0
	RequestMethodConnect RequestMethod = 1 << iota
	RequestMethodDelete
	RequestMethodHead
	RequestMethodOptions
	RequestMethodPatch
	RequestMethodPost
	RequestMethodPut
	RequestMethodTrace
)

type RequestType

type RequestType int

RequestType define type of HTTP request.

type ResponseType

type ResponseType int

ResponseType define type for HTTP response

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server define HTTP server.

func NewServer

func NewServer(root string, conn *http.Server) (srv *Server, e error)

NewServer create and initialize new HTTP server that serve root directory with custom connection.

func (*Server) RedirectTemp

func (srv *Server) RedirectTemp(res http.ResponseWriter, redirectURL string)

RedirectTemp make the request to temporary redirect (307) to new URL.

func (*Server) RegisterDelete

func (srv *Server) RegisterDelete(ep *Endpoint)

RegisterDelete register HTTP method DELETE with callback to handle it.

func (*Server) RegisterEvaluator

func (srv *Server) RegisterEvaluator(eval Evaluator)

RegisterEvaluator register HTTP middleware that will be called before Endpoint evalutor and callback is called.

func (*Server) RegisterGet

func (srv *Server) RegisterGet(ep *Endpoint)

RegisterGet register HTTP method GET with callback to handle it.

func (*Server) RegisterPatch

func (srv *Server) RegisterPatch(ep *Endpoint)

RegisterPatch register HTTP method PATCH with callback to handle it.

func (*Server) RegisterPost

func (srv *Server) RegisterPost(ep *Endpoint)

RegisterPost register HTTP method POST with callback to handle it.

func (*Server) RegisterPut

func (srv *Server) RegisterPut(ep *Endpoint)

RegisterPut register HTTP method PUT with callback to handle it.

func (*Server) ServeHTTP

func (srv *Server) ServeHTTP(res http.ResponseWriter, req *http.Request)

ServeHTTP handle mapping of client request to registered endpoints.

func (*Server) Start

func (srv *Server) Start() (err error)

Start the HTTP server.

Jump to

Keyboard shortcuts

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