mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 05:06:43 +00:00
http access: fix regression and improve
- correct slash handling and path matching in manifest - fix subpath match and use deepest path instead of longest for matching - http POST: give key as http response instead of fmt.Printf - improved logging
This commit is contained in:
parent
38d1bdf688
commit
021182f822
3 changed files with 53 additions and 31 deletions
18
bzz/api.go
18
bzz/api.go
|
|
@ -300,35 +300,35 @@ func (self *Api) getPath(uri string) (reader SectionReader, mimeType string, sta
|
|||
var size int
|
||||
size, err = manifestReader.Read(manifestData)
|
||||
if int64(size) < manifestReader.Size() {
|
||||
dpaLogger.Debugf("Swarm: Manifest for '%s' not found.", uri)
|
||||
dpaLogger.Debugf("Swarm: Manifest for '%s' not found (uri: '%s')", path[:pos], uri)
|
||||
if err == nil {
|
||||
err = fmt.Errorf("Manifest retrieval cut short: %v < %v", size, manifestReader.Size())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
dpaLogger.Debugf("Swarm: Manifest for '%s' retrieved", uri)
|
||||
dpaLogger.Debugf("Swarm: Manifest for '%s' retrieved", path[:pos])
|
||||
man := manifest{}
|
||||
err = json.Unmarshal(manifestData, &man)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Manifest for '%s' is malformed: %v", uri, err)
|
||||
err = fmt.Errorf("Manifest for '%s' is malformed: %v", path[:pos], err)
|
||||
dpaLogger.Debugf("Swarm: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
dpaLogger.Debugf("Swarm: Manifest for '%s' has %d entries. Retrieving entry for '%s'", uri, len(man.Entries), path)
|
||||
dpaLogger.Debugf("Swarm: Manifest for '%s' has %d entries. Match path '%s'", path[:pos], len(man.Entries), path[pos:])
|
||||
|
||||
// retrieve entry that matches path from manifest entries
|
||||
var entry *manifestEntry
|
||||
entry, pos = man.getEntry(path)
|
||||
entry, hop := man.getEntry(path[pos:])
|
||||
|
||||
if entry == nil {
|
||||
err = fmt.Errorf("Content for '%s' not found.", uri)
|
||||
err = fmt.Errorf("Path '%s' not found on manifest '%s'", path[:pos], path[pos:])
|
||||
return
|
||||
}
|
||||
|
||||
// check hash of entry
|
||||
if !hashMatcher.MatchString(entry.Hash) {
|
||||
err = fmt.Errorf("Incorrect hash '%064x' for '%s'", entry.Hash, uri)
|
||||
err = fmt.Errorf("Incorrect hash '%064x' for path '%s' on manifest for '%s')", entry.Hash, path[pos:], path[:pos])
|
||||
return
|
||||
}
|
||||
key = common.Hex2Bytes(entry.Hash)
|
||||
|
|
@ -349,7 +349,7 @@ func (self *Api) getPath(uri string) (reader SectionReader, mimeType string, sta
|
|||
}
|
||||
|
||||
// otherwise continue along the path with manifest resolution
|
||||
path = path[pos:]
|
||||
pos += hop
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,22 +4,24 @@ A simple http server interface to Swarm
|
|||
package bzz
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
const (
|
||||
notFoundStatus = 404
|
||||
rawType = "application/octet-stream"
|
||||
rawType = "application/octet-stream"
|
||||
)
|
||||
|
||||
var (
|
||||
rawUrl = regexp.MustCompile("^/+raw/*")
|
||||
trailingSlashes = regexp.MustCompile("/+$")
|
||||
forever = time.Unix(0, 0)
|
||||
)
|
||||
|
||||
type sequentialReader struct {
|
||||
|
|
@ -40,8 +42,9 @@ func startHttpServer(api *Api, port string) {
|
|||
}
|
||||
|
||||
func handler(w http.ResponseWriter, r *http.Request, api *Api) {
|
||||
dpaLogger.Debugf("request URL: '%s' Host: '%s', Path: '%s'", r.RequestURI, r.URL.Host, r.URL.Path)
|
||||
uri := r.URL.Path
|
||||
requestURL := r.URL
|
||||
dpaLogger.Debugf("Swarm: HTTP request URL: '%s', Host: '%s', Path: '%s', Referer: '%s', Accept: '%s'", r.RequestURI, requestURL.Host, requestURL.Path, r.Referer(), r.Header.Get("Accept"))
|
||||
uri := requestURL.Path
|
||||
var raw bool
|
||||
path := rawUrl.ReplaceAllStringFunc(uri, func(string) string {
|
||||
raw = true
|
||||
|
|
@ -50,7 +53,6 @@ func handler(w http.ResponseWriter, r *http.Request, api *Api) {
|
|||
|
||||
switch {
|
||||
case r.Method == "POST":
|
||||
dpaLogger.Debugf("request URL Host: '%s', Path: '%s'", r.URL.Host, r.URL.Path)
|
||||
if raw {
|
||||
dpaLogger.Debugf("Swarm: POST request received.")
|
||||
key, err := api.dpa.Store(io.NewSectionReader(&sequentialReader{
|
||||
|
|
@ -58,7 +60,8 @@ func handler(w http.ResponseWriter, r *http.Request, api *Api) {
|
|||
ahead: make(map[int64]chan bool),
|
||||
}, 0, r.ContentLength), nil)
|
||||
if err == nil {
|
||||
fmt.Fprintf(w, "%064x", key)
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
http.ServeContent(w, r, "", time.Now(), bytes.NewReader([]byte(common.Bytes2Hex(key))))
|
||||
dpaLogger.Debugf("Swarm: Content for '%064x' stored", key)
|
||||
} else {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
|
|
@ -70,7 +73,6 @@ func handler(w http.ResponseWriter, r *http.Request, api *Api) {
|
|||
}
|
||||
|
||||
case r.Method == "GET" || r.Method == "HEAD":
|
||||
dpaLogger.Debugf("request URL Host: '%s', Path: '%s'", r.URL.Host, uri)
|
||||
path = trailingSlashes.ReplaceAllString(path, "")
|
||||
if raw {
|
||||
dpaLogger.Debugf("Swarm: Raw GET request '%s' received", uri)
|
||||
|
|
@ -88,14 +90,14 @@ func handler(w http.ResponseWriter, r *http.Request, api *Api) {
|
|||
dpaLogger.Debugf("Swarm: Reading %d bytes.", reader.Size())
|
||||
|
||||
// setting mime type
|
||||
qv := r.URL.Query()
|
||||
qv := requestURL.Query()
|
||||
mimeType := qv.Get("content_type")
|
||||
if mimeType == "" {
|
||||
mimeType = rawType
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", mimeType)
|
||||
http.ServeContent(w, r, uri, time.Unix(0, 0), reader)
|
||||
http.ServeContent(w, r, uri, forever, reader)
|
||||
dpaLogger.Debugf("Swarm: Serve raw content '%s' (%d bytes) as '%s'", uri, reader.Size(), mimeType)
|
||||
|
||||
// retrieve path via manifest
|
||||
|
|
@ -121,9 +123,12 @@ func handler(w http.ResponseWriter, r *http.Request, api *Api) {
|
|||
w.Header().Set("Content-Type", mimeType)
|
||||
if status > 0 {
|
||||
w.WriteHeader(status)
|
||||
} else {
|
||||
status = 200
|
||||
}
|
||||
dpaLogger.Debugf("Swarm: Served '%s' (%d bytes) as '%s' (status code: %v)", uri, reader.Size(), mimeType, w.Header())
|
||||
http.ServeContent(w, r, uri, time.Unix(0, 0), reader)
|
||||
dpaLogger.Debugf("Swarm: Served '%s' (%d bytes) as '%s' (status code: %v)", uri, reader.Size(), mimeType, status)
|
||||
|
||||
http.ServeContent(w, r, path, forever, reader)
|
||||
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -24,24 +24,41 @@ type manifestEntry struct {
|
|||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
func (self *manifest) getEntry(path string) (entry *manifestEntry, pos int) {
|
||||
// path must not have any leading slashes
|
||||
func (self *manifest) getEntry(path string) (matchingEntry *manifestEntry, matchlength int) {
|
||||
var pos, depth, maxdepth int
|
||||
var entry *manifestEntry
|
||||
// path := leadingSlashes.ReplaceAllString(fullpath, "")
|
||||
// iterate over entries matching paths to the target
|
||||
// due to redundant slashes, it is NOT the longest match but the match with
|
||||
// the highest depth is chosen
|
||||
// this gives thse matches in case of trailing slashes:
|
||||
// "a/" -> "a/" not "a" and "a" matches "a" not "a/" if both exist
|
||||
// "a" never matches "a/" but "a/" matches a
|
||||
for _, entry = range self.Entries {
|
||||
entryPath := leadingSlashes.ReplaceAllString(entry.Path, "")
|
||||
pos = len(entryPath)
|
||||
if len(path) >= pos && path[:pos] == entryPath {
|
||||
var n int
|
||||
depth = len(slashes.Split(entryPath, -1))
|
||||
if len(path) >= pos && path[:pos] == entryPath && (depth > maxdepth || depth == maxdepth && pos > matchlength) {
|
||||
var hop int
|
||||
// hop and chop leading hashes of the continuation
|
||||
if len(path) > pos {
|
||||
chopped := leadingSlashes.ReplaceAllString(path[pos:], "")
|
||||
n = len(path) - pos - len(chopped)
|
||||
hop = len(path) - pos - len(chopped)
|
||||
}
|
||||
if n > 0 || pos == 0 || path[pos-1] == '/' {
|
||||
pos += n
|
||||
dpaLogger.Debugf("Swarm: '%s' matches '%s'.", path, entry.Path)
|
||||
return
|
||||
// check if pos actually ends a subpath "ab" matches on "" not on "a"
|
||||
if hop > 0 || pos == len(path) || pos == 0 || path[pos-1] == '/' {
|
||||
matchlength = pos + hop
|
||||
maxdepth = depth
|
||||
matchingEntry = entry
|
||||
}
|
||||
}
|
||||
}
|
||||
entry = nil
|
||||
dpaLogger.Debugf("Path '%s' on manifest not found.", path)
|
||||
if matchingEntry != nil {
|
||||
dpaLogger.Debugf("Swarm: '%s' matches '%s'.", path, matchingEntry.Path)
|
||||
} else {
|
||||
dpaLogger.Debugf("Path '%s' not found on manifest ", path)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue