diff options
| author | Shulhan <m.shulhan@gmail.com> | 2020-07-25 02:39:33 +0700 |
|---|---|---|
| committer | Shulhan <m.shulhan@gmail.com> | 2020-07-26 03:48:51 +0700 |
| commit | 954a8f071deff27d0434027e4787e72fbd7880d4 (patch) | |
| tree | 9c77cef7ba8edcaaee18b5b629ffae29ce04015c /httpd.go | |
| parent | 53918e8b3fc8a68f7f88e6ece0706e1ae049a8e5 (diff) | |
| download | rescached-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.go | 211 |
1 files changed, 210 insertions, 1 deletions
@@ -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 +} |
