aboutsummaryrefslogtreecommitdiff
path: root/httpd.go
diff options
context:
space:
mode:
authorShulhan <m.shulhan@gmail.com>2020-07-25 02:39:33 +0700
committerShulhan <m.shulhan@gmail.com>2020-07-26 03:48:51 +0700
commit954a8f071deff27d0434027e4787e72fbd7880d4 (patch)
tree9c77cef7ba8edcaaee18b5b629ffae29ce04015c /httpd.go
parent53918e8b3fc8a68f7f88e6ece0706e1ae049a8e5 (diff)
downloadrescached-954a8f071deff27d0434027e4787e72fbd7880d4.tar.xz
all: implement UI to create, update, delete hosts file in hosts.d
The UI will update (insert or remove) the records on cache on the fly.
Diffstat (limited to 'httpd.go')
-rw-r--r--httpd.go211
1 files changed, 210 insertions, 1 deletions
diff --git a/httpd.go b/httpd.go
index 29ecc5c..0b051ef 100644
--- a/httpd.go
+++ b/httpd.go
@@ -9,13 +9,15 @@ import (
"fmt"
"log"
stdhttp "net/http"
+ "os"
liberrors "github.com/shuLhan/share/lib/errors"
"github.com/shuLhan/share/lib/http"
)
const (
- defHTTPDRootDir = "_www/public/"
+ defHTTPDRootDir = "_public/"
+ paramNameName = "name"
)
func (srv *Server) httpdInit() (err error) {
@@ -90,6 +92,49 @@ func (srv *Server) httpdRegisterEndpoints() (err error) {
return err
}
+ err = srv.httpd.RegisterEndpoint(&http.Endpoint{
+ Method: http.RequestMethodPut,
+ Path: "/api/hosts.d/:name",
+ RequestType: http.RequestTypeNone,
+ ResponseType: http.ResponseTypeNone,
+ Call: srv.apiHostsFileCreate,
+ })
+ if err != nil {
+ return err
+ }
+
+ err = srv.httpd.RegisterEndpoint(&http.Endpoint{
+ Method: http.RequestMethodGet,
+ Path: "/api/hosts.d/:name",
+ RequestType: http.RequestTypeNone,
+ ResponseType: http.ResponseTypeJSON,
+ Call: srv.apiHostsFileGet,
+ })
+ if err != nil {
+ return err
+ }
+
+ err = srv.httpd.RegisterEndpoint(&http.Endpoint{
+ Method: http.RequestMethodPost,
+ Path: "/api/hosts.d/:name",
+ RequestType: http.RequestTypeJSON,
+ ResponseType: http.ResponseTypeJSON,
+ Call: srv.apiHostsFileUpdate,
+ })
+ if err != nil {
+ return err
+ }
+ err = srv.httpd.RegisterEndpoint(&http.Endpoint{
+ Method: http.RequestMethodDelete,
+ Path: "/api/hosts.d/:name",
+ RequestType: http.RequestTypeNone,
+ ResponseType: http.ResponseTypeJSON,
+ Call: srv.apiHostsFileDelete,
+ })
+ if err != nil {
+ return err
+ }
+
return nil
}
@@ -207,3 +252,167 @@ func (srv *Server) apiPostHostsBlock(
return json.Marshal(res)
}
+
+func (srv *Server) apiHostsFileCreate(
+ httpres stdhttp.ResponseWriter, httpreq *stdhttp.Request, _ []byte,
+) (
+ resbody []byte, err error,
+) {
+ name := httpreq.Form.Get(paramNameName)
+ if len(name) == 0 {
+ return nil, &liberrors.E{
+ Code: stdhttp.StatusBadRequest,
+ Message: "hosts file name is invalid or empty",
+ }
+ }
+
+ for _, hf := range srv.env.HostsFiles {
+ if hf.Name == name {
+ return nil, nil
+ }
+ }
+
+ hfile, err := newHostsFile(name, nil)
+ if err != nil {
+ return nil, &liberrors.E{
+ Code: stdhttp.StatusInternalServerError,
+ Message: err.Error(),
+ }
+ }
+
+ err = hfile.close()
+ if err != nil {
+ return nil, &liberrors.E{
+ Code: stdhttp.StatusInternalServerError,
+ Message: err.Error(),
+ }
+ }
+
+ srv.env.HostsFiles = append(srv.env.HostsFiles, hfile)
+
+ httpres.WriteHeader(stdhttp.StatusCreated)
+
+ return nil, nil
+}
+
+func (srv *Server) apiHostsFileGet(
+ _ stdhttp.ResponseWriter, httpreq *stdhttp.Request, _ []byte,
+) (
+ resbody []byte, err error,
+) {
+ hosts := make([]*host, 0)
+ name := httpreq.Form.Get(paramNameName)
+
+ for _, hfile := range srv.env.HostsFiles {
+ if hfile.Name == name {
+ hosts = hfile.hosts
+ break
+ }
+ }
+
+ return json.Marshal(&hosts)
+}
+
+func (srv *Server) apiHostsFileUpdate(
+ _ stdhttp.ResponseWriter, httpreq *stdhttp.Request, reqbody []byte,
+) (
+ resbody []byte, err error,
+) {
+ var (
+ hosts = make([]*host, 0)
+ name = httpreq.Form.Get(paramNameName)
+ found bool
+ hfile *hostsFile
+ )
+
+ err = json.Unmarshal(reqbody, &hosts)
+ if err != nil {
+ return nil, &liberrors.E{
+ Code: stdhttp.StatusInternalServerError,
+ Message: err.Error(),
+ }
+ }
+
+ for _, hfile = range srv.env.HostsFiles {
+ if hfile.Name == name {
+ found = true
+ break
+ }
+ }
+ if !found {
+ hfile, err = newHostsFile(name, hosts)
+ if err != nil {
+ return nil, &liberrors.E{
+ Code: stdhttp.StatusInternalServerError,
+ Message: err.Error(),
+ }
+ }
+ srv.env.HostsFiles = append(srv.env.HostsFiles, hfile)
+ }
+
+ oldHostnames := hfile.names()
+
+ msgs, err := hfile.update(hosts)
+ if err != nil {
+ return nil, &liberrors.E{
+ Code: stdhttp.StatusInternalServerError,
+ Message: err.Error(),
+ }
+ }
+
+ // Remove the records associated with hosts file.
+ srv.dns.RemoveCachesByNames(oldHostnames)
+
+ // Populate new hosts to cache.
+ srv.dns.PopulateCaches(msgs)
+
+ resbody, err = json.Marshal(&hfile.hosts)
+ if err != nil {
+ return nil, &liberrors.E{
+ Code: stdhttp.StatusInternalServerError,
+ Message: err.Error(),
+ }
+ }
+
+ return resbody, nil
+}
+
+func (srv *Server) apiHostsFileDelete(
+ _ stdhttp.ResponseWriter, httpreq *stdhttp.Request, reqbody []byte,
+) (
+ resbody []byte, err error,
+) {
+ res := &liberrors.E{
+ Code: stdhttp.StatusOK,
+ }
+
+ name := httpreq.Form.Get(paramNameName)
+ if len(name) == 0 {
+ res.Message = "empty or invalid host file name"
+ return nil, res
+ }
+
+ for x, hfile := range srv.env.HostsFiles {
+ if hfile.Name != name {
+ continue
+ }
+
+ // Remove the records associated with hosts file.
+ srv.dns.RemoveCachesByNames(hfile.names())
+
+ err = os.RemoveAll(hfile.Path)
+ if err != nil {
+ res.Message = err.Error()
+ return nil, res
+ }
+
+ copy(srv.env.HostsFiles[x:], srv.env.HostsFiles[x+1:])
+ srv.env.HostsFiles[len(srv.env.HostsFiles)-1] = nil
+ srv.env.HostsFiles = srv.env.HostsFiles[:len(srv.env.HostsFiles)-1]
+
+ res.Message = name + " has been deleted"
+ return json.Marshal(res)
+ }
+ res.Message = "apiDeleteHostsFile: " + name + " not found"
+ return nil, res
+}