@ -1,18 +1,37 @@
package main
package main
import (
import (
"bytes"
"html/template"
"io"
"io"
"net"
"net"
"net/http"
"net/http"
"strings"
"github.com/pkg/errors"
)
)
// Server that handles http responses
// Server that handles http responses
type Server struct {
type Server struct {
headerNames [ ] string
headerNames [ ] string
logger LoggerHandler
logger LoggerHandler
tmpl * template . Template
}
}
func ( s * Server ) ServeHTTP ( w http . ResponseWriter , req * http . Request ) {
type responseFormat int
const (
unknownResponse responseFormat = iota
jsonResponse
textResponse
htmlResponse
)
func ( s * Server ) ServeHTTP ( resp http . ResponseWriter , req * http . Request ) {
s . handleHTTP ( resp , req , s . getResponseType ( req ) )
}
func ( s * Server ) handleHTTP ( resp http . ResponseWriter , req * http . Request , responseType responseFormat ) {
for _ , headerName := range s . headerNames {
for _ , headerName := range s . headerNames {
possibleIP := req . Header . Get ( headerName )
possibleIP := req . Header . Get ( headerName )
if possibleIP == "" {
if possibleIP == "" {
@ -24,28 +43,89 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
continue
continue
}
}
s . sendResponse ( w, ip )
s . sendResponse ( resp, ip , responseType )
return
return
}
}
addr , _ , err := net . SplitHostPort ( req . RemoteAddr )
addr , _ , err := net . SplitHostPort ( req . RemoteAddr )
if err != nil {
if err != nil {
s . handleError ( w , http . StatusBadRequest , err , "Could not get IP address from request" )
s . handleError ( resp , http . StatusBadRequest , err , "Could not get IP address from request" )
return
return
}
}
ip , err := NewIP ( addr )
ip , err := NewIP ( addr )
if err != nil {
if err != nil {
s . handleError ( w , http . StatusBadRequest , err , "Could not parse IP address" + addr )
s . handleError ( resp , http . StatusBadRequest , err , "Could not parse IP address" + addr )
return
return
}
}
s . sendResponse ( w , ip )
s . sendResponse ( resp , ip , responseType )
}
func hasType ( accepts , valid [ ] string ) bool {
for _ , accept := range accepts {
value := strings . Trim ( strings . Split ( accept , ";" ) [ 0 ] , " " )
for _ , check := range valid {
if check == value {
return true
}
}
}
return false
}
func ( s * Server ) getResponseType ( req * http . Request ) responseFormat {
accepts := strings . Split ( req . Header . Get ( "Accept" ) , "," )
if hasType ( accepts , [ ] string { "text/html" , "application/xhtml+xml" } ) {
return htmlResponse
}
if hasType ( accepts , [ ] string { "application/json" , "text/json" , "text/javascript" } ) {
return jsonResponse
}
if hasType ( accepts , [ ] string { "text/plain" } ) {
return textResponse
}
return unknownResponse
}
}
func ( s * Server ) sendResponse ( resp http . ResponseWriter , ip * IP ) {
func ( s * Server ) sendResponse ( resp http . ResponseWriter , ip * IP , responseType responseFormat ) {
io . WriteString ( resp , ip . String ( ) + "\n" )
s . logger . Printf ( "Request from %s %s\n" , ip . version , ip )
s . logger . Printf ( "Request from %s %s\n" , ip . version , ip )
var body [ ] byte
var contentType = "text/plain"
var err error
switch responseType {
case jsonResponse :
jsonBody , marshalErr := ip . MarshalJSON ( )
if marshalErr != nil {
err = errors . Wrap ( marshalErr , "could not marshal json" )
}
contentType = "application/json"
body = jsonBody
case htmlResponse :
buffer := bytes . NewBuffer ( [ ] byte { } )
exeErr := s . tmpl . Execute ( buffer , map [ string ] string { "IP" : ip . String ( ) } )
if exeErr != nil {
err = errors . Wrap ( exeErr , "could not get html" )
}
contentType = "text/html"
body = buffer . Bytes ( )
default :
body = [ ] byte ( ip . String ( ) )
}
if err != nil {
const errorMessage = "could not send response"
s . handleError ( resp , http . StatusInternalServerError , errors . Wrap ( err , errorMessage ) , errorMessage )
return
}
resp . Header ( ) . Set ( "Content-Type" , contentType )
resp . Write ( body )
}
}
func ( s * Server ) handleError ( resp http . ResponseWriter , status int , err error , message string ) {
func ( s * Server ) handleError ( resp http . ResponseWriter , status int , err error , message string ) {