parent
53f569e88e
commit
bf3a40ffb7
@ -0,0 +1,18 @@
|
||||
# dumb-http
|
||||
## Simple HTTP Server
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
dumb-http [-path path-to-serve] [port]
|
||||
```
|
||||
### Example
|
||||
```
|
||||
$ dumb-http -path ./docs
|
||||
Serving at http://0.0.0.0:8000/ from ./docs
|
||||
127.0.0.1 - - [05/Jul/2018 18:08:16] "GET / HTTP/1.1" 200 38 0.0000 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:61.0) Gecko/20100101 Firefox/61.0"
|
||||
```
|
||||
|
||||
>Inspired by Python module http.server
|
||||
|
||||
> Reference: https://gist.github.com/cespare/3985516
|
@ -0,0 +1,61 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LoggingHandler is to be used as wrapper of mux.
|
||||
type LoggingHandler struct {
|
||||
handler http.Handler
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
// NewLoggingHandler for creating a new Logging Handler
|
||||
func NewLoggingHandler(handler http.Handler, out io.Writer) http.Handler {
|
||||
return &LoggingHandler{
|
||||
handler: handler,
|
||||
out: out,
|
||||
}
|
||||
}
|
||||
|
||||
func (h LoggingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
ipPort := strings.Split(r.RemoteAddr, ":")
|
||||
|
||||
logRecord := &LogRecord{
|
||||
ResponseWriter: w,
|
||||
time: time.Time{},
|
||||
method: r.Method,
|
||||
statusCode: http.StatusOK,
|
||||
protocol: r.Proto,
|
||||
path: r.RequestURI,
|
||||
clientIP: strings.Join(ipPort[:len(ipPort)-1], ":"),
|
||||
referer: "-",
|
||||
userAgent: "-",
|
||||
totalTime: time.Duration(0),
|
||||
}
|
||||
|
||||
// For logging Real IP Address
|
||||
if realIP := r.Header.Get("X-Real-IP"); realIP != "" {
|
||||
logRecord.clientIP = realIP
|
||||
}
|
||||
|
||||
// For logging Referer URL
|
||||
if referer := r.Header.Get("Referer"); referer != "" {
|
||||
logRecord.referer = referer
|
||||
}
|
||||
|
||||
// For logging User Agent
|
||||
if userAgent := r.Header.Get("User-Agent"); userAgent != "" {
|
||||
logRecord.userAgent = userAgent
|
||||
}
|
||||
startTime := time.Now()
|
||||
h.handler.ServeHTTP(logRecord, r)
|
||||
endTime := time.Now()
|
||||
logRecord.time = endTime.UTC()
|
||||
logRecord.totalTime = endTime.Sub(startTime) / 1000.0
|
||||
logRecord.Log(h.out)
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// LogPattern is format for writing the logRecord
|
||||
LogPattern = "%s - - [%s] \"%s\" %d %d %.4f \"%s\" \"%s\"\n"
|
||||
// DateTimeFormat is for logging Date and Time of request
|
||||
DateTimeFormat = "02/Jan/2006 15:04:05" // Minimal
|
||||
// DateTimeFormat = "Mon, 02 Jan 2006 15:04:05 MST" // Full
|
||||
)
|
||||
|
||||
// LogRecord struct extends http.ResponseWriter interface which has different methods included in it.
|
||||
type LogRecord struct {
|
||||
http.ResponseWriter
|
||||
method string
|
||||
path string
|
||||
clientIP string
|
||||
time time.Time
|
||||
contentLength int64
|
||||
protocol string
|
||||
statusCode int
|
||||
referer string
|
||||
userAgent string
|
||||
totalTime time.Duration
|
||||
}
|
||||
|
||||
// Log method to be called for logging to "out"
|
||||
func (l *LogRecord) Log(out io.Writer) {
|
||||
timeFormatted := l.time.Format(DateTimeFormat)
|
||||
requestLine := l.method + " " + l.path + " " + l.protocol
|
||||
fmt.Fprintf(out, LogPattern, l.clientIP, timeFormatted, requestLine,
|
||||
l.statusCode, l.contentLength, l.totalTime.Seconds(), l.referer, l.userAgent)
|
||||
}
|
||||
|
||||
// WriteHeader method has been extended to record status code from previous handler.
|
||||
func (l *LogRecord) WriteHeader(statusCode int) {
|
||||
l.statusCode = statusCode
|
||||
l.ResponseWriter.WriteHeader(statusCode)
|
||||
}
|
||||
|
||||
// Write method has been extended to record the bytes written or the content length
|
||||
func (l *LogRecord) Write(p []byte) (int, error) {
|
||||
written, err := l.ResponseWriter.Write(p)
|
||||
l.contentLength += int64(written)
|
||||
return written, err
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
localDir = "."
|
||||
host = "0.0.0.0"
|
||||
port = "8000"
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&localDir, "path", ".", "Path to serve from")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
// Check for port in commandline
|
||||
if commandPort := flag.Arg(0); commandPort != "" {
|
||||
port = commandPort
|
||||
}
|
||||
// Start serving...
|
||||
serve(host + ":" + port)
|
||||
}
|
||||
|
||||
func serve(addr string) {
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir(localDir))))
|
||||
server := http.Server{
|
||||
Addr: addr,
|
||||
Handler: NewLoggingHandler(mux, os.Stdout),
|
||||
}
|
||||
fmt.Printf("Serving at http://%s/ from %s\n", addr, localDir)
|
||||
err := server.ListenAndServe()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in new issue