wip w/ @mistra

This commit is contained in:
justelad 2018-06-28 13:25:31 +02:00
parent ca31f22a6a
commit 26490d8950
8 changed files with 246 additions and 182 deletions

View file

@ -22,41 +22,41 @@ import (
"strings" "strings"
"github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/api"
"github.com/ethereum/go-ethereum/swarm/api/http" "github.com/ethereum/go-ethereum/swarm/api/http/messages"
"github.com/ethereum/go-ethereum/swarm/api/http/views"
"github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/log"
"github.com/ethereum/go-ethereum/swarm/storage"
) )
type BzzListController struct { type BzzListController struct {
*Controller *Controller
} }
//var BzzListController BzzListController // Get handles a GET request to bzz-list:/<manifest>/<path> and returns
// HandleGetList handles a GET request to bzz-list:/<manifest>/<path> and returns
// a list of all files contained in <manifest> under <path> grouped into // a list of all files contained in <manifest> under <path> grouped into
// common prefixes using "/" as a delimiter // common prefixes using "/" as a delimiter
func (controller *BzzListController) Get(w http.ResponseWriter, r *Request) { func (controller *BzzListController) Get(w http.ResponseWriter, r *messages.Request) {
log.Debug("handle.get.list", "ruid", r.ruid, "uri", r.uri) log.Debug("handle.get.list", "ruid", r.Ruid, "uri", r.Uri)
getListCount.Inc(1) //getListCount.Inc(1)
// ensure the root path has a trailing slash so that relative URLs work // ensure the root path has a trailing slash so that relative URLs work
if r.uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") { if r.Uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") {
http.Redirect(w, &r.Request, r.URL.Path+"/", http.StatusMovedPermanently) http.Redirect(w, &r.Request, r.URL.Path+"/", http.StatusMovedPermanently)
return return
} }
addr, err := s.api.Resolve(r.uri) addr, err := controller.api.Resolve(r.Uri)
if err != nil { if err != nil {
getListFail.Inc(1) //getListFail.Inc(1)
Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.uri.Addr, err), http.StatusNotFound) controller.Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.Uri.Addr, err), http.StatusNotFound)
return return
} }
log.Debug("handle.get.list: resolved", "ruid", r.ruid, "key", addr) log.Debug("handle.get.list: resolved", "ruid", r.Ruid, "key", addr)
list, err := s.getManifestList(addr, r.uri.Path) list, err := controller.getManifestList(addr, r.Uri.Path)
if err != nil { if err != nil {
getListFail.Inc(1) // getListFail.Inc(1)
Respond(w, r, err.Error(), http.StatusInternalServerError) controller.Respond(w, r, err.Error(), http.StatusInternalServerError)
return return
} }
@ -64,16 +64,16 @@ func (controller *BzzListController) Get(w http.ResponseWriter, r *Request) {
// HTML index with relative URLs // HTML index with relative URLs
if strings.Contains(r.Header.Get("Accept"), "text/html") { if strings.Contains(r.Header.Get("Accept"), "text/html") {
w.Header().Set("Content-Type", "text/html") w.Header().Set("Content-Type", "text/html")
err := htmlListTemplate.Execute(w, &htmlListData{ err := views.HtmlListTemplate.Execute(w, &views.HtmlListData{
URI: &api.URI{ URI: &api.Uri{
Scheme: "bzz", Scheme: "bzz",
Addr: r.uri.Addr, Addr: r.Uri.Addr,
Path: r.uri.Path, Path: r.Uri.Path,
}, },
List: &list, List: &list,
}) })
if err != nil { if err != nil {
getListFail.Inc(1) // getListFail.Inc(1)
log.Error(fmt.Sprintf("error rendering list HTML: %s", err)) log.Error(fmt.Sprintf("error rendering list HTML: %s", err))
} }
return return
@ -82,3 +82,59 @@ func (controller *BzzListController) Get(w http.ResponseWriter, r *Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(&list) json.NewEncoder(w).Encode(&list)
} }
func (controller *BzzListController) getManifestList(addr storage.Address, prefix string) (list api.ManifestList, err error) {
walker, err := controller.api.NewManifestWalker(addr, nil)
if err != nil {
return
}
err = walker.Walk(func(entry *api.ManifestEntry) error {
// handle non-manifest files
if entry.ContentType != api.ManifestType {
// ignore the file if it doesn't have the specified prefix
if !strings.HasPrefix(entry.Path, prefix) {
return nil
}
// if the path after the prefix contains a slash, add a
// common prefix to the list, otherwise add the entry
suffix := strings.TrimPrefix(entry.Path, prefix)
if index := strings.Index(suffix, "/"); index > -1 {
list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1])
return nil
}
if entry.Path == "" {
entry.Path = "/"
}
list.Entries = append(list.Entries, entry)
return nil
}
// if the manifest's path is a prefix of the specified prefix
// then just recurse into the manifest by returning nil and
// continuing the walk
if strings.HasPrefix(prefix, entry.Path) {
return nil
}
// if the manifest's path has the specified prefix, then if the
// path after the prefix contains a slash, add a common prefix
// to the list and skip the manifest, otherwise recurse into
// the manifest by returning nil and continuing the walk
if strings.HasPrefix(entry.Path, prefix) {
suffix := strings.TrimPrefix(entry.Path, prefix)
if index := strings.Index(suffix, "/"); index > -1 {
list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1])
return api.ErrSkipManifest
}
return nil
}
// the manifest neither has the prefix or needs recursing in to
// so just skip it
return api.ErrSkipManifest
})
return list, nil
}

View file

@ -1,15 +1,64 @@
package controllers package controllers
import ( import (
"html/template"
"net/http" "net/http"
"time"
"github.com/ethereum/go-ethereum/swarm/api/http/request" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/api"
"github.com/ethereum/go-ethereum/swarm/api/http/messages"
"github.com/ethereum/go-ethereum/swarm/api/http/views"
l "github.com/ethereum/go-ethereum/swarm/log"
) )
type Controller struct { type Controller struct {
api *api.API
ControllerHandler ControllerHandler
} }
type ControllerHandler interface { type ControllerHandler interface {
Get(w http.ResponseWriter, r *request.Request) Get(w http.ResponseWriter, r *messages.Request)
Respond(w http.ResponseWriter, req *messages.Request, msg string, code int)
}
//Respond is used to show an HTML page to a client.
//If there is an `Accept` header of `application/json`, JSON will be returned instead
//The function just takes a string message which will be displayed in the error page.
//The code is used to evaluate which template will be displayed
//(and return the correct HTTP status code)
func (controller *Controller) Respond(w http.ResponseWriter, req *messages.Request, msg string, code int) {
//additionalMessage := ValidateCaseErrors(req)
//additionalMessage := ValidateCaseErrors(req)
additionalMessage := ""
switch code {
case http.StatusInternalServerError:
log.Output(msg, log.LvlError, l.CallDepth, "ruid", req.Ruid, "code", code)
default:
log.Output(msg, log.LvlDebug, l.CallDepth, "ruid", req.Ruid, "code", code)
}
if code >= 400 {
w.Header().Del("Cache-Control") //avoid sending cache headers for errors!
w.Header().Del("ETag")
}
respond(w, &req.Request, &messages.ResponseParams{
Code: code,
Msg: msg,
Details: template.HTML(additionalMessage),
Timestamp: time.Now().Format(time.RFC1123),
template: views.GetTemplate(code),
})
}
//evaluate if client accepts html or json response
func respond(w http.ResponseWriter, r *http.Request, params *messages.ResponseParams) {
w.WriteHeader(params.Code)
if r.Header.Get("Accept") == "application/json" {
// respondJSON(w, params)
} else {
// respondHTML(w, params)
}
} }

View file

@ -25,6 +25,6 @@ import (
type Request struct { type Request struct {
http.Request http.Request
uri *api.URI Uri *api.URI
ruid string // request unique id Ruid string // request unique id
} }

View file

@ -14,3 +14,14 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package messages package messages
import "html/template"
//parameters needed for formatting the correct HTML page
type ResponseParams struct {
Msg string
Code int
Timestamp string
template *template.Template
Details template.HTML
}

View file

@ -42,7 +42,8 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/api"
"github.com/ethereum/go-ethereum/swarm/api/http/request" "github.com/ethereum/go-ethereum/swarm/api/http/controllers"
"github.com/ethereum/go-ethereum/swarm/api/http/messages"
"github.com/ethereum/go-ethereum/swarm/log" "github.com/ethereum/go-ethereum/swarm/log"
"github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage"
"github.com/ethereum/go-ethereum/swarm/storage/mru" "github.com/ethereum/go-ethereum/swarm/storage/mru"
@ -113,23 +114,23 @@ type Server struct {
// HandlePostRaw handles a POST request to a raw bzz-raw:/ URI, stores the request // HandlePostRaw handles a POST request to a raw bzz-raw:/ URI, stores the request
// body in swarm and returns the resulting storage address as a text/plain response // body in swarm and returns the resulting storage address as a text/plain response
func (s *Server) HandlePostRaw(w http.ResponseWriter, r *request.Request) { func (s *Server) HandlePostRaw(w http.ResponseWriter, r *messages.Request) {
log.Debug("handle.post.raw", "ruid", r.ruid) log.Debug("handle.post.raw", "ruid", r.Ruid)
postRawCount.Inc(1) postRawCount.Inc(1)
toEncrypt := false toEncrypt := false
if r.uri.Addr == "encrypt" { if r.Uri.Addr == "encrypt" {
toEncrypt = true toEncrypt = true
} }
if r.uri.Path != "" { if r.Uri.Path != "" {
postRawFail.Inc(1) postRawFail.Inc(1)
Respond(w, r, "raw POST request cannot contain a path", http.StatusBadRequest) Respond(w, r, "raw POST request cannot contain a path", http.StatusBadRequest)
return return
} }
if r.uri.Addr != "" && r.uri.Addr != "encrypt" { if r.Uri.Addr != "" && r.Uri.Addr != "encrypt" {
postRawFail.Inc(1) postRawFail.Inc(1)
Respond(w, r, "raw POST request addr can only be empty or \"encrypt\"", http.StatusBadRequest) Respond(w, r, "raw POST request addr can only be empty or \"encrypt\"", http.StatusBadRequest)
return return
@ -147,7 +148,7 @@ func (s *Server) HandlePostRaw(w http.ResponseWriter, r *request.Request) {
return return
} }
log.Debug("stored content", "ruid", r.ruid, "key", addr) log.Debug("stored content", "ruid", r.Ruid, "key", addr)
w.Header().Set("Content-Type", "text/plain") w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
@ -159,8 +160,8 @@ func (s *Server) HandlePostRaw(w http.ResponseWriter, r *request.Request) {
// (either a tar archive or multipart form), adds those files either to an // (either a tar archive or multipart form), adds those files either to an
// existing manifest or to a new manifest under <path> and returns the // existing manifest or to a new manifest under <path> and returns the
// resulting manifest hash as a text/plain response // resulting manifest hash as a text/plain response
func (s *Server) HandlePostFiles(w http.ResponseWriter, r *request.Request) { func (s *Server) HandlePostFiles(w http.ResponseWriter, r *messages.Request) {
log.Debug("handle.post.files", "ruid", r.ruid) log.Debug("handle.post.files", "ruid", r.Ruid)
postFilesCount.Inc(1) postFilesCount.Inc(1)
contentType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type")) contentType, params, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
@ -171,19 +172,19 @@ func (s *Server) HandlePostFiles(w http.ResponseWriter, r *request.Request) {
} }
toEncrypt := false toEncrypt := false
if r.uri.Addr == "encrypt" { if r.Uri.Addr == "encrypt" {
toEncrypt = true toEncrypt = true
} }
var addr storage.Address var addr storage.Address
if r.uri.Addr != "" && r.uri.Addr != "encrypt" { if r.Uri.Addr != "" && r.Uri.Addr != "encrypt" {
addr, err = s.api.Resolve(r.uri) addr, err = s.api.Resolve(r.uri)
if err != nil { if err != nil {
postFilesFail.Inc(1) postFilesFail.Inc(1)
Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.uri.Addr, err), http.StatusInternalServerError) Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.Uri.Addr, err), http.StatusInternalServerError)
return return
} }
log.Debug("resolved key", "ruid", r.ruid, "key", addr) log.Debug("resolved key", "ruid", r.Ruid, "key", addr)
} else { } else {
addr, err = s.api.NewManifest(toEncrypt) addr, err = s.api.NewManifest(toEncrypt)
if err != nil { if err != nil {
@ -191,7 +192,7 @@ func (s *Server) HandlePostFiles(w http.ResponseWriter, r *request.Request) {
Respond(w, r, err.Error(), http.StatusInternalServerError) Respond(w, r, err.Error(), http.StatusInternalServerError)
return return
} }
log.Debug("new manifest", "ruid", r.ruid, "key", addr) log.Debug("new manifest", "ruid", r.Ruid, "key", addr)
} }
newAddr, err := s.updateManifest(addr, func(mw *api.ManifestWriter) error { newAddr, err := s.updateManifest(addr, func(mw *api.ManifestWriter) error {
@ -213,15 +214,15 @@ func (s *Server) HandlePostFiles(w http.ResponseWriter, r *request.Request) {
return return
} }
log.Debug("stored content", "ruid", r.ruid, "key", newAddr) log.Debug("stored content", "ruid", r.Ruid, "key", newAddr)
w.Header().Set("Content-Type", "text/plain") w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
fmt.Fprint(w, newAddr) fmt.Fprint(w, newAddr)
} }
func (s *Server) handleTarUpload(req *request.Request, mw *api.ManifestWriter) error { func (s *Server) handleTarUpload(req *messages.Request, mw *api.ManifestWriter) error {
log.Debug("handle.tar.upload", "ruid", req.ruid) log.Debug("handle.tar.upload", "ruid", req.Ruid)
tr := tar.NewReader(req.Body) tr := tar.NewReader(req.Body)
for { for {
hdr, err := tr.Next() hdr, err := tr.Next()
@ -237,7 +238,7 @@ func (s *Server) handleTarUpload(req *request.Request, mw *api.ManifestWriter) e
} }
// add the entry under the path from the request // add the entry under the path from the request
path := path.Join(req.uri.Path, hdr.Name) path := path.Join(req.Uri.Path, hdr.Name)
entry := &api.ManifestEntry{ entry := &api.ManifestEntry{
Path: path, Path: path,
ContentType: hdr.Xattrs["user.swarm.content-type"], ContentType: hdr.Xattrs["user.swarm.content-type"],
@ -245,17 +246,17 @@ func (s *Server) handleTarUpload(req *request.Request, mw *api.ManifestWriter) e
Size: hdr.Size, Size: hdr.Size,
ModTime: hdr.ModTime, ModTime: hdr.ModTime,
} }
log.Debug("adding path to new manifest", "ruid", req.ruid, "bytes", entry.Size, "path", entry.Path) log.Debug("adding path to new manifest", "ruid", req.Ruid, "bytes", entry.Size, "path", entry.Path)
contentKey, err := mw.AddEntry(tr, entry) contentKey, err := mw.AddEntry(tr, entry)
if err != nil { if err != nil {
return fmt.Errorf("error adding manifest entry from tar stream: %s", err) return fmt.Errorf("error adding manifest entry from tar stream: %s", err)
} }
log.Debug("stored content", "ruid", req.ruid, "key", contentKey) log.Debug("stored content", "ruid", req.Ruid, "key", contentKey)
} }
} }
func (s *Server) handleMultipartUpload(req *request.Request, boundary string, mw *api.ManifestWriter) error { func (s *Server) handleMultipartUpload(req *messages.Request, boundary string, mw *api.ManifestWriter) error {
log.Debug("handle.multipart.upload", "ruid", req.ruid) log.Debug("handle.multipart.upload", "ruid", req.Ruid)
mr := multipart.NewReader(req.Body, boundary) mr := multipart.NewReader(req.Body, boundary)
for { for {
part, err := mr.NextPart() part, err := mr.NextPart()
@ -296,26 +297,26 @@ func (s *Server) handleMultipartUpload(req *request.Request, boundary string, mw
if name == "" { if name == "" {
name = part.FormName() name = part.FormName()
} }
path := path.Join(req.uri.Path, name) path := path.Join(req.Uri.Path, name)
entry := &api.ManifestEntry{ entry := &api.ManifestEntry{
Path: path, Path: path,
ContentType: part.Header.Get("Content-Type"), ContentType: part.Header.Get("Content-Type"),
Size: size, Size: size,
ModTime: time.Now(), ModTime: time.Now(),
} }
log.Debug("adding path to new manifest", "ruid", req.ruid, "bytes", entry.Size, "path", entry.Path) log.Debug("adding path to new manifest", "ruid", req.Ruid, "bytes", entry.Size, "path", entry.Path)
contentKey, err := mw.AddEntry(reader, entry) contentKey, err := mw.AddEntry(reader, entry)
if err != nil { if err != nil {
return fmt.Errorf("error adding manifest entry from multipart form: %s", err) return fmt.Errorf("error adding manifest entry from multipart form: %s", err)
} }
log.Debug("stored content", "ruid", req.ruid, "key", contentKey) log.Debug("stored content", "ruid", req.Ruid, "key", contentKey)
} }
} }
func (s *Server) handleDirectUpload(req *request.Request, mw *api.ManifestWriter) error { func (s *Server) handleDirectUpload(req *messages.Request, mw *api.ManifestWriter) error {
log.Debug("handle.direct.upload", "ruid", req.ruid) log.Debug("handle.direct.upload", "ruid", req.Ruid)
key, err := mw.AddEntry(req.Body, &api.ManifestEntry{ key, err := mw.AddEntry(req.Body, &api.ManifestEntry{
Path: req.uri.Path, Path: req.Uri.Path,
ContentType: req.Header.Get("Content-Type"), ContentType: req.Header.Get("Content-Type"),
Mode: 0644, Mode: 0644,
Size: req.ContentLength, Size: req.ContentLength,
@ -324,27 +325,27 @@ func (s *Server) handleDirectUpload(req *request.Request, mw *api.ManifestWriter
if err != nil { if err != nil {
return err return err
} }
log.Debug("stored content", "ruid", req.ruid, "key", key) log.Debug("stored content", "ruid", req.Ruid, "key", key)
return nil return nil
} }
// HandleDelete handles a DELETE request to bzz:/<manifest>/<path>, removes // HandleDelete handles a DELETE request to bzz:/<manifest>/<path>, removes
// <path> from <manifest> and returns the resulting manifest hash as a // <path> from <manifest> and returns the resulting manifest hash as a
// text/plain response // text/plain response
func (s *Server) HandleDelete(w http.ResponseWriter, r *request.Request) { func (s *Server) HandleDelete(w http.ResponseWriter, r *messages.Request) {
log.Debug("handle.delete", "ruid", r.ruid) log.Debug("handle.delete", "ruid", r.Ruid)
deleteCount.Inc(1) deleteCount.Inc(1)
key, err := s.api.Resolve(r.uri) key, err := s.api.Resolve(r.uri)
if err != nil { if err != nil {
deleteFail.Inc(1) deleteFail.Inc(1)
Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.uri.Addr, err), http.StatusInternalServerError) Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.Uri.Addr, err), http.StatusInternalServerError)
return return
} }
newKey, err := s.updateManifest(key, func(mw *api.ManifestWriter) error { newKey, err := s.updateManifest(key, func(mw *api.ManifestWriter) error {
log.Debug(fmt.Sprintf("removing %s from manifest %s", r.uri.Path, key.Log()), "ruid", r.ruid) log.Debug(fmt.Sprintf("removing %s from manifest %s", r.Uri.Path, key.Log()), "ruid", r.Ruid)
return mw.RemoveEntry(r.uri.Path) return mw.RemoveEntry(r.Uri.Path)
}) })
if err != nil { if err != nil {
deleteFail.Inc(1) deleteFail.Inc(1)
@ -392,13 +393,13 @@ func resourcePostMode(path string) (isRaw bool, frequency uint64, err error) {
// The resource name will be verbatim what is passed as the address part of the url. // The resource name will be verbatim what is passed as the address part of the url.
// For example, if a POST is made to /bzz-resource:/foo.eth/raw/13 a new resource with frequency 13 // For example, if a POST is made to /bzz-resource:/foo.eth/raw/13 a new resource with frequency 13
// and name "foo.eth" will be created // and name "foo.eth" will be created
func (s *Server) HandlePostResource(w http.ResponseWriter, r *request.Request) { func (s *Server) HandlePostResource(w http.ResponseWriter, r *messages.Request) {
log.Debug("handle.post.resource", "ruid", r.ruid) log.Debug("handle.post.resource", "ruid", r.Ruid)
var err error var err error
var addr storage.Address var addr storage.Address
var name string var name string
var outdata []byte var outdata []byte
isRaw, frequency, err := resourcePostMode(r.uri.Path) isRaw, frequency, err := resourcePostMode(r.Uri.Path)
if err != nil { if err != nil {
Respond(w, r, err.Error(), http.StatusBadRequest) Respond(w, r, err.Error(), http.StatusBadRequest)
return return
@ -407,7 +408,7 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *request.Request) {
// new mutable resource creation will always have a frequency field larger than 0 // new mutable resource creation will always have a frequency field larger than 0
if frequency > 0 { if frequency > 0 {
name = r.uri.Addr name = r.Uri.Addr
// the key is the content addressed root chunk holding mutable resource metadata information // the key is the content addressed root chunk holding mutable resource metadata information
addr, err = s.api.ResourceCreate(r.Context(), name, frequency) addr, err = s.api.ResourceCreate(r.Context(), name, frequency)
@ -439,12 +440,12 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *request.Request) {
} else { } else {
// to update the resource through http we need to retrieve the key for the mutable resource root chunk // to update the resource through http we need to retrieve the key for the mutable resource root chunk
// that means that we retrieve the manifest and inspect its Hash member. // that means that we retrieve the manifest and inspect its Hash member.
manifestAddr := r.uri.Address() manifestAddr := r.Uri.Address()
if manifestAddr == nil { if manifestAddr == nil {
manifestAddr, err = s.api.Resolve(r.uri) manifestAddr, err = s.api.Resolve(r.uri)
if err != nil { if err != nil {
getFail.Inc(1) getFail.Inc(1)
Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.uri.Addr, err), http.StatusNotFound) Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.Uri.Addr, err), http.StatusNotFound)
return return
} }
} else { } else {
@ -455,11 +456,11 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *request.Request) {
addr, err = s.api.ResolveResourceManifest(manifestAddr) addr, err = s.api.ResolveResourceManifest(manifestAddr)
if err != nil { if err != nil {
getFail.Inc(1) getFail.Inc(1)
Respond(w, r, fmt.Sprintf("error resolving resource root chunk for %s: %s", r.uri.Addr, err), http.StatusNotFound) Respond(w, r, fmt.Sprintf("error resolving resource root chunk for %s: %s", r.Uri.Addr, err), http.StatusNotFound)
return return
} }
log.Debug("handle.post.resource: resolved", "ruid", r.ruid, "manifestkey", manifestAddr, "rootchunkkey", addr) log.Debug("handle.post.resource: resolved", "ruid", r.Ruid, "manifestkey", manifestAddr, "rootchunkkey", addr)
name, _, err = s.api.ResourceLookup(r.Context(), addr, 0, 0, &mru.LookupParams{}) name, _, err = s.api.ResourceLookup(r.Context(), addr, 0, 0, &mru.LookupParams{})
if err != nil { if err != nil {
@ -511,22 +512,22 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *request.Request) {
// bzz-resource://<id>/<n> - get latest update on period n // bzz-resource://<id>/<n> - get latest update on period n
// bzz-resource://<id>/<n>/<m> - get update version m of period n // bzz-resource://<id>/<n>/<m> - get update version m of period n
// <id> = ens name or hash // <id> = ens name or hash
func (s *Server) HandleGetResource(w http.ResponseWriter, r *request.Request) { func (s *Server) HandleGetResource(w http.ResponseWriter, r *messages.Request) {
s.handleGetResource(w, r) s.handleGetResource(w, r)
} }
// TODO: Enable pass maxPeriod parameter // TODO: Enable pass maxPeriod parameter
func (s *Server) handleGetResource(w http.ResponseWriter, r *request.Request) { func (s *Server) handleGetResource(w http.ResponseWriter, r *messages.Request) {
log.Debug("handle.get.resource", "ruid", r.ruid) log.Debug("handle.get.resource", "ruid", r.Ruid)
var err error var err error
// resolve the content key. // resolve the content key.
manifestAddr := r.uri.Address() manifestAddr := r.Uri.Address()
if manifestAddr == nil { if manifestAddr == nil {
manifestAddr, err = s.api.Resolve(r.uri) manifestAddr, err = s.api.Resolve(r.uri)
if err != nil { if err != nil {
getFail.Inc(1) getFail.Inc(1)
Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.uri.Addr, err), http.StatusNotFound) Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.Uri.Addr, err), http.StatusNotFound)
return return
} }
} else { } else {
@ -537,16 +538,16 @@ func (s *Server) handleGetResource(w http.ResponseWriter, r *request.Request) {
key, err := s.api.ResolveResourceManifest(manifestAddr) key, err := s.api.ResolveResourceManifest(manifestAddr)
if err != nil { if err != nil {
getFail.Inc(1) getFail.Inc(1)
Respond(w, r, fmt.Sprintf("error resolving resource root chunk for %s: %s", r.uri.Addr, err), http.StatusNotFound) Respond(w, r, fmt.Sprintf("error resolving resource root chunk for %s: %s", r.Uri.Addr, err), http.StatusNotFound)
return return
} }
log.Debug("handle.get.resource: resolved", "ruid", r.ruid, "manifestkey", manifestAddr, "rootchunk key", key) log.Debug("handle.get.resource: resolved", "ruid", r.Ruid, "manifestkey", manifestAddr, "rootchunk key", key)
// determine if the query specifies period and version // determine if the query specifies period and version
var params []string var params []string
if len(r.uri.Path) > 0 { if len(r.Uri.Path) > 0 {
params = strings.Split(r.uri.Path, "/") params = strings.Split(r.Uri.Path, "/")
} }
var name string var name string
var period uint64 var period uint64
@ -585,12 +586,12 @@ func (s *Server) handleGetResource(w http.ResponseWriter, r *request.Request) {
} }
// All ok, serve the retrieved update // All ok, serve the retrieved update
log.Debug("Found update", "name", name, "ruid", r.ruid) log.Debug("Found update", "name", name, "ruid", r.Ruid)
w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Type", "application/octet-stream")
http.ServeContent(w, &r.Request, "", now, bytes.NewReader(data)) http.ServeContent(w, &r.Request, "", now, bytes.NewReader(data))
} }
func (s *Server) translateResourceError(w http.ResponseWriter, r *request.Request, supErr string, err error) (int, error) { func (s *Server) translateResourceError(w http.ResponseWriter, r *messages.Request, supErr string, err error) (int, error) {
code := 0 code := 0
defaultErr := fmt.Errorf("%s: %v", supErr, err) defaultErr := fmt.Errorf("%s: %v", supErr, err)
rsrcErr, ok := err.(*mru.Error) rsrcErr, ok := err.(*mru.Error)
@ -616,27 +617,27 @@ func (s *Server) translateResourceError(w http.ResponseWriter, r *request.Reques
// given storage key // given storage key
// - bzz-hash://<key> and responds with the hash of the content stored // - bzz-hash://<key> and responds with the hash of the content stored
// at the given storage key as a text/plain response // at the given storage key as a text/plain response
func (s *Server) HandleGet(w http.ResponseWriter, r *request.Request) { func (s *Server) HandleGet(w http.ResponseWriter, r *messages.Request) {
log.Debug("handle.get", "ruid", r.ruid, "uri", r.uri) log.Debug("handle.get", "ruid", r.Ruid, "uri", r.uri)
getCount.Inc(1) getCount.Inc(1)
var err error var err error
addr := r.uri.Address() addr := r.Uri.Address()
if addr == nil { if addr == nil {
addr, err = s.api.Resolve(r.uri) addr, err = s.api.Resolve(r.uri)
if err != nil { if err != nil {
getFail.Inc(1) getFail.Inc(1)
Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.uri.Addr, err), http.StatusNotFound) Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.Uri.Addr, err), http.StatusNotFound)
return return
} }
} else { } else {
w.Header().Set("Cache-Control", "max-age=2147483648, immutable") // url was of type bzz://<hex key>/path, so we are sure it is immutable. w.Header().Set("Cache-Control", "max-age=2147483648, immutable") // url was of type bzz://<hex key>/path, so we are sure it is immutable.
} }
log.Debug("handle.get: resolved", "ruid", r.ruid, "key", addr) log.Debug("handle.get: resolved", "ruid", r.Ruid, "key", addr)
// if path is set, interpret <key> as a manifest and return the // if path is set, interpret <key> as a manifest and return the
// raw entry at the given path // raw entry at the given path
if r.uri.Path != "" { if r.Uri.Path != "" {
walker, err := s.api.NewManifestWalker(addr, nil) walker, err := s.api.NewManifestWalker(addr, nil)
if err != nil { if err != nil {
getFail.Inc(1) getFail.Inc(1)
@ -647,7 +648,7 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *request.Request) {
walker.Walk(func(e *api.ManifestEntry) error { walker.Walk(func(e *api.ManifestEntry) error {
// if the entry matches the path, set entry and stop // if the entry matches the path, set entry and stop
// the walk // the walk
if e.Path == r.uri.Path { if e.Path == r.Uri.Path {
entry = e entry = e
// return an error to cancel the walk // return an error to cancel the walk
return errors.New("found") return errors.New("found")
@ -661,7 +662,7 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *request.Request) {
// if the manifest's path is a prefix of the // if the manifest's path is a prefix of the
// requested path, recurse into it by returning // requested path, recurse into it by returning
// nil and continuing the walk // nil and continuing the walk
if strings.HasPrefix(r.uri.Path, e.Path) { if strings.HasPrefix(r.Uri.Path, e.Path) {
return nil return nil
} }
@ -695,7 +696,7 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *request.Request) {
w.Header().Set("X-Decrypted", fmt.Sprintf("%v", isEncrypted)) w.Header().Set("X-Decrypted", fmt.Sprintf("%v", isEncrypted))
switch { switch {
case r.uri.Raw(): case r.Uri.Raw():
// allow the request to overwrite the content type using a query // allow the request to overwrite the content type using a query
// parameter // parameter
contentType := "application/octet-stream" contentType := "application/octet-stream"
@ -704,7 +705,7 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *request.Request) {
} }
w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Type", contentType)
http.ServeContent(w, &r.Request, "", time.Now(), reader) http.ServeContent(w, &r.Request, "", time.Now(), reader)
case r.uri.Hash(): case r.Uri.Hash():
w.Header().Set("Content-Type", "text/plain") w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
fmt.Fprint(w, addr) fmt.Fprint(w, addr)
@ -714,10 +715,10 @@ func (s *Server) HandleGet(w http.ResponseWriter, r *request.Request) {
// HandleGetFiles handles a GET request to bzz:/<manifest> with an Accept // HandleGetFiles handles a GET request to bzz:/<manifest> with an Accept
// header of "application/x-tar" and returns a tar stream of all files // header of "application/x-tar" and returns a tar stream of all files
// contained in the manifest // contained in the manifest
func (s *Server) HandleGetFiles(w http.ResponseWriter, r *request.Request) { func (s *Server) HandleGetFiles(w http.ResponseWriter, r *messages.Request) {
log.Debug("handle.get.files", "ruid", r.ruid, "uri", r.uri) log.Debug("handle.get.files", "ruid", r.Ruid, "uri", r.uri)
getFilesCount.Inc(1) getFilesCount.Inc(1)
if r.uri.Path != "" { if r.Uri.Path != "" {
getFilesFail.Inc(1) getFilesFail.Inc(1)
Respond(w, r, "files request cannot contain a path", http.StatusBadRequest) Respond(w, r, "files request cannot contain a path", http.StatusBadRequest)
return return
@ -726,10 +727,10 @@ func (s *Server) HandleGetFiles(w http.ResponseWriter, r *request.Request) {
addr, err := s.api.Resolve(r.uri) addr, err := s.api.Resolve(r.uri)
if err != nil { if err != nil {
getFilesFail.Inc(1) getFilesFail.Inc(1)
Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.uri.Addr, err), http.StatusNotFound) Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.Uri.Addr, err), http.StatusNotFound)
return return
} }
log.Debug("handle.get.files: resolved", "ruid", r.ruid, "key", addr) log.Debug("handle.get.files: resolved", "ruid", r.Ruid, "key", addr)
walker, err := s.api.NewManifestWalker(addr, nil) walker, err := s.api.NewManifestWalker(addr, nil)
if err != nil { if err != nil {
@ -787,89 +788,33 @@ func (s *Server) HandleGetFiles(w http.ResponseWriter, r *request.Request) {
} }
} }
func (s *Server) getManifestList(addr storage.Address, prefix string) (list api.ManifestList, err error) {
walker, err := s.api.NewManifestWalker(addr, nil)
if err != nil {
return
}
err = walker.Walk(func(entry *api.ManifestEntry) error {
// handle non-manifest files
if entry.ContentType != api.ManifestType {
// ignore the file if it doesn't have the specified prefix
if !strings.HasPrefix(entry.Path, prefix) {
return nil
}
// if the path after the prefix contains a slash, add a
// common prefix to the list, otherwise add the entry
suffix := strings.TrimPrefix(entry.Path, prefix)
if index := strings.Index(suffix, "/"); index > -1 {
list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1])
return nil
}
if entry.Path == "" {
entry.Path = "/"
}
list.Entries = append(list.Entries, entry)
return nil
}
// if the manifest's path is a prefix of the specified prefix
// then just recurse into the manifest by returning nil and
// continuing the walk
if strings.HasPrefix(prefix, entry.Path) {
return nil
}
// if the manifest's path has the specified prefix, then if the
// path after the prefix contains a slash, add a common prefix
// to the list and skip the manifest, otherwise recurse into
// the manifest by returning nil and continuing the walk
if strings.HasPrefix(entry.Path, prefix) {
suffix := strings.TrimPrefix(entry.Path, prefix)
if index := strings.Index(suffix, "/"); index > -1 {
list.CommonPrefixes = append(list.CommonPrefixes, prefix+suffix[:index+1])
return api.ErrSkipManifest
}
return nil
}
// the manifest neither has the prefix or needs recursing in to
// so just skip it
return api.ErrSkipManifest
})
return list, nil
}
// HandleGetFile handles a GET request to bzz://<manifest>/<path> and responds // HandleGetFile handles a GET request to bzz://<manifest>/<path> and responds
// with the content of the file at <path> from the given <manifest> // with the content of the file at <path> from the given <manifest>
func (s *Server) HandleGetFile(w http.ResponseWriter, r *request.Request) { func (s *Server) HandleGetFile(w http.ResponseWriter, r *messages.Request) {
log.Debug("handle.get.file", "ruid", r.ruid) log.Debug("handle.get.file", "ruid", r.Ruid)
getFileCount.Inc(1) getFileCount.Inc(1)
// ensure the root path has a trailing slash so that relative URLs work // ensure the root path has a trailing slash so that relative URLs work
if r.uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") { if r.Uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") {
http.Redirect(w, &r.Request, r.URL.Path+"/", http.StatusMovedPermanently) http.Redirect(w, &r.Request, r.URL.Path+"/", http.StatusMovedPermanently)
return return
} }
var err error var err error
manifestAddr := r.uri.Address() manifestAddr := r.Uri.Address()
if manifestAddr == nil { if manifestAddr == nil {
manifestAddr, err = s.api.Resolve(r.uri) manifestAddr, err = s.api.Resolve(r.uri)
if err != nil { if err != nil {
getFileFail.Inc(1) getFileFail.Inc(1)
Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.uri.Addr, err), http.StatusNotFound) Respond(w, r, fmt.Sprintf("cannot resolve %s: %s", r.Uri.Addr, err), http.StatusNotFound)
return return
} }
} else { } else {
w.Header().Set("Cache-Control", "max-age=2147483648, immutable") // url was of type bzz://<hex key>/path, so we are sure it is immutable. w.Header().Set("Cache-Control", "max-age=2147483648, immutable") // url was of type bzz://<hex key>/path, so we are sure it is immutable.
} }
log.Debug("handle.get.file: resolved", "ruid", r.ruid, "key", manifestAddr) log.Debug("handle.get.file: resolved", "ruid", r.Ruid, "key", manifestAddr)
reader, contentType, status, contentKey, err := s.api.Get(manifestAddr, r.uri.Path) reader, contentType, status, contentKey, err := s.api.Get(manifestAddr, r.Uri.Path)
etag := common.Bytes2Hex(contentKey) etag := common.Bytes2Hex(contentKey)
noneMatchEtag := r.Header.Get("If-None-Match") noneMatchEtag := r.Header.Get("If-None-Match")
@ -896,7 +841,7 @@ func (s *Server) HandleGetFile(w http.ResponseWriter, r *request.Request) {
//the request results in ambiguous files //the request results in ambiguous files
//e.g. /read with readme.md and readinglist.txt available in manifest //e.g. /read with readme.md and readinglist.txt available in manifest
if status == http.StatusMultipleChoices { if status == http.StatusMultipleChoices {
list, err := s.getManifestList(manifestAddr, r.uri.Path) list, err := s.getManifestList(manifestAddr, r.Uri.Path)
if err != nil { if err != nil {
getFileFail.Inc(1) getFileFail.Inc(1)
@ -904,7 +849,7 @@ func (s *Server) HandleGetFile(w http.ResponseWriter, r *request.Request) {
return return
} }
log.Debug(fmt.Sprintf("Multiple choices! --> %v", list), "ruid", r.ruid) log.Debug(fmt.Sprintf("Multiple choices! --> %v", list), "ruid", r.Ruid)
//show a nice page links to available entries //show a nice page links to available entries
ShowMultipleChoices(w, r, list) ShowMultipleChoices(w, r, list)
return return
@ -954,16 +899,16 @@ func (b bufferedReadSeeker) Seek(offset int64, whence int) (int64, error) {
func (s *Server) ServeHTTP(rw http.ResponseWriter, r *http.Request) { func (s *Server) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
defer metrics.GetOrRegisterResettingTimer(fmt.Sprintf("http.request.%s.time", r.Method), nil).UpdateSince(time.Now()) defer metrics.GetOrRegisterResettingTimer(fmt.Sprintf("http.request.%s.time", r.Method), nil).UpdateSince(time.Now())
req := &Request{Request: *r, ruid: uuid.New()[:8]} req := &messages.Request{Request: *r, Ruid: uuid.New()[:8]}
metrics.GetOrRegisterCounter(fmt.Sprintf("http.request.%s", r.Method), nil).Inc(1) metrics.GetOrRegisterCounter(fmt.Sprintf("http.request.%s", r.Method), nil).Inc(1)
log.Info("serving request", "ruid", req.ruid, "method", r.Method, "url", r.RequestURI) log.Info("serving request", "ruid", req.Ruid, "method", r.Method, "url", r.RequestURI)
// wrapping the ResponseWriter, so that we get the response code set by http.ServeContent // wrapping the ResponseWriter, so that we get the response code set by http.ServeContent
w := newLoggingResponseWriter(rw) w := newLoggingResponseWriter(rw)
if r.RequestURI == "/" && strings.Contains(r.Header.Get("Accept"), "text/html") { if r.RequestURI == "/" && strings.Contains(r.Header.Get("Accept"), "text/html") {
err := landingPageTemplate.Execute(w, nil) err := views.LandingPageTemplate.Execute(w, nil)
if err != nil { if err != nil {
log.Error(fmt.Sprintf("error rendering landing page: %s", err)) log.Error(fmt.Sprintf("error rendering landing page: %s", err))
} }
@ -991,7 +936,7 @@ func (s *Server) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
req.uri = uri req.uri = uri
log.Debug("parsed request path", "ruid", req.ruid, "method", req.Method, "uri.Addr", req.uri.Addr, "uri.Path", req.uri.Path, "uri.Scheme", req.uri.Scheme) log.Debug("parsed request path", "ruid", req.Ruid, "method", req.Method, "uri.Addr", req.Uri.Addr, "uri.Path", req.Uri.Path, "uri.Scheme", req.Uri.Scheme)
switch r.Method { switch r.Method {
case "POST": case "POST":
@ -1033,8 +978,8 @@ func (s *Server) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
} }
if uri.List() { if uri.List() {
list := &controllers.BzzListController{api: s.api}
//ctrl.(w, req) list.Get(w, req)
return return
} }
@ -1049,7 +994,7 @@ func (s *Server) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
Respond(w, req, fmt.Sprintf("%s method is not supported", r.Method), http.StatusMethodNotAllowed) Respond(w, req, fmt.Sprintf("%s method is not supported", r.Method), http.StatusMethodNotAllowed)
} }
log.Info("served response", "ruid", req.ruid, "code", w.statusCode) log.Info("served response", "ruid", req.Ruid, "code", w.statusCode)
} }
func (s *Server) updateManifest(addr storage.Address, update func(mw *api.ManifestWriter) error) (storage.Address, error) { func (s *Server) updateManifest(addr storage.Address, update func(mw *api.ManifestWriter) error) (storage.Address, error) {

View file

@ -18,7 +18,7 @@
Show nicely (but simple) formatted HTML error pages (or respond with JSON Show nicely (but simple) formatted HTML error pages (or respond with JSON
if the appropriate `Accept` header is set)) for the http package. if the appropriate `Accept` header is set)) for the http package.
*/ */
package http package views
import ( import (
"encoding/json" "encoding/json"
@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/api"
"github.com/ethereum/go-ethereum/swarm/api/http/messages"
l "github.com/ethereum/go-ethereum/swarm/log" l "github.com/ethereum/go-ethereum/swarm/log"
) )
@ -56,8 +57,8 @@ type ResponseParams struct {
//a custom error case struct that would be used to store validators and //a custom error case struct that would be used to store validators and
//additional error info to display with client responses. //additional error info to display with client responses.
type CaseError struct { type CaseError struct {
Validator func(*Request) bool Validator func(*messages.Request) bool
Msg func(*Request) string Msg func(*messages.Request) string
} }
//we init the error handling right on boot time, so lookup and http response is fast //we init the error handling right on boot time, so lookup and http response is fast
@ -86,9 +87,11 @@ func initErrHandling() {
caseErrors = []CaseError{ caseErrors = []CaseError{
{ {
Validator: func(r *Request) bool { return r.uri != nil && r.uri.Addr != "" && strings.HasPrefix(r.uri.Addr, "0x") }, Validator: func(r *messages.Request) bool {
Msg: func(r *Request) string { return r.Uri != nil && r.Uri.Addr != "" && strings.HasPrefix(r.Uri.Addr, "0x")
uriCopy := r.uri },
Msg: func(r *messages.Request) string {
uriCopy := r.Uri
uriCopy.Addr = strings.TrimPrefix(uriCopy.Addr, "0x") uriCopy.Addr = strings.TrimPrefix(uriCopy.Addr, "0x")
return fmt.Sprintf(`The requested hash seems to be prefixed with '0x'. You will be redirected to the correct URL within 5 seconds.<br/> return fmt.Sprintf(`The requested hash seems to be prefixed with '0x'. You will be redirected to the correct URL within 5 seconds.<br/>
Please click <a href='%[1]s'>here</a> if your browser does not redirect you.<script>setTimeout("location.href='%[1]s';",5000);</script>`, "/"+uriCopy.String()) Please click <a href='%[1]s'>here</a> if your browser does not redirect you.<script>setTimeout("location.href='%[1]s';",5000);</script>`, "/"+uriCopy.String())
@ -98,7 +101,7 @@ func initErrHandling() {
//ValidateCaseErrors is a method that process the request object through certain validators //ValidateCaseErrors is a method that process the request object through certain validators
//that assert if certain conditions are met for further information to log as an error //that assert if certain conditions are met for further information to log as an error
func ValidateCaseErrors(r *Request) string { func ValidateCaseErrors(r *messages.Request) string {
for _, err := range caseErrors { for _, err := range caseErrors {
if err.Validator(r) { if err.Validator(r) {
return err.Msg(r) return err.Msg(r)
@ -114,7 +117,7 @@ func ValidateCaseErrors(r *Request) string {
//For example, if the user requests bzz:/<hash>/read and that manifest contains entries //For example, if the user requests bzz:/<hash>/read and that manifest contains entries
//"readme.md" and "readinglist.txt", a HTML page is returned with this two links. //"readme.md" and "readinglist.txt", a HTML page is returned with this two links.
//This only applies if the manifest has no default entry //This only applies if the manifest has no default entry
func ShowMultipleChoices(w http.ResponseWriter, req *Request, list api.ManifestList) { func ShowMultipleChoices(w http.ResponseWriter, req *messages.Request, list api.ManifestList) {
msg := "" msg := ""
if list.Entries == nil { if list.Entries == nil {
Respond(w, req, "Could not resolve", http.StatusInternalServerError) Respond(w, req, "Could not resolve", http.StatusInternalServerError)
@ -142,13 +145,13 @@ func ShowMultipleChoices(w http.ResponseWriter, req *Request, list api.ManifestL
//The function just takes a string message which will be displayed in the error page. //The function just takes a string message which will be displayed in the error page.
//The code is used to evaluate which template will be displayed //The code is used to evaluate which template will be displayed
//(and return the correct HTTP status code) //(and return the correct HTTP status code)
func Respond(w http.ResponseWriter, req *Request, msg string, code int) { func Respond(w http.ResponseWriter, req *messages.Request, msg string, code int) {
additionalMessage := ValidateCaseErrors(req) additionalMessage := ValidateCaseErrors(req)
switch code { switch code {
case http.StatusInternalServerError: case http.StatusInternalServerError:
log.Output(msg, log.LvlError, l.CallDepth, "ruid", req.ruid, "code", code) log.Output(msg, log.LvlError, l.CallDepth, "ruid", req.Ruid, "code", code)
default: default:
log.Output(msg, log.LvlDebug, l.CallDepth, "ruid", req.ruid, "code", code) log.Output(msg, log.LvlDebug, l.CallDepth, "ruid", req.Ruid, "code", code)
} }
if code >= 400 { if code >= 400 {
@ -161,7 +164,7 @@ func Respond(w http.ResponseWriter, req *Request, msg string, code int) {
Msg: msg, Msg: msg,
Details: template.HTML(additionalMessage), Details: template.HTML(additionalMessage),
Timestamp: time.Now().Format(time.RFC1123), Timestamp: time.Now().Format(time.RFC1123),
template: getTemplate(code), template: GetTemplate(code),
}) })
} }
@ -192,7 +195,7 @@ func respondJSON(w http.ResponseWriter, params *ResponseParams) {
} }
//get the HTML template for a given code //get the HTML template for a given code
func getTemplate(code int) *template.Template { func GetTemplate(code int) *template.Template {
if val, tmpl := templateMap[code]; tmpl { if val, tmpl := templateMap[code]; tmpl {
return val return val
} }

View file

@ -24,7 +24,7 @@ they won't be found.
For this reason we resort to save the HTML error pages as strings, which then can be For this reason we resort to save the HTML error pages as strings, which then can be
parsed by Go's html/template package parsed by Go's html/template package
*/ */
package http package views
//This returns the HTML for generic errors //This returns the HTML for generic errors
func GetGenericErrorPage() string { func GetGenericErrorPage() string {

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package http package views
import ( import (
"html/template" "html/template"
@ -23,12 +23,12 @@ import (
"github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/swarm/api"
) )
type htmlListData struct { type HtmlListData struct {
URI *api.URI URI *api.URI
List *api.ManifestList List *api.ManifestList
} }
var htmlListTemplate = template.Must(template.New("html-list").Funcs(template.FuncMap{"basename": path.Base}).Parse(` var HtmlListTemplate = template.Must(template.New("html-list").Funcs(template.FuncMap{"basename": path.Base}).Parse(`
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
@ -71,7 +71,7 @@ var htmlListTemplate = template.Must(template.New("html-list").Funcs(template.Fu
</body> </body>
`[1:])) `[1:]))
var landingPageTemplate = template.Must(template.New("landingPage").Parse(` var LandingPageTemplate = template.Must(template.New("landingPage").Parse(`
<html> <html>
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">