Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
1ae0411d
Commit
1ae0411d
authored
Oct 06, 2017
by
holisticode
Committed by
Felix Lange
Oct 06, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
swarm/api: fixed 404 handling on missing default entry (#15139)
parent
d54e3539
Changes
6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
311 additions
and
39 deletions
+311
-39
api.go
swarm/api/api.go
+7
-3
error.go
swarm/api/http/error.go
+42
-4
error_templates.go
swarm/api/http/error_templates.go
+179
-2
server.go
swarm/api/http/server.go
+43
-23
manifest.go
swarm/api/manifest.go
+28
-4
manifest_test.go
swarm/api/manifest_test.go
+12
-3
No files found.
swarm/api/api.go
View file @
1ae0411d
...
...
@@ -144,9 +144,13 @@ func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionRe
if
entry
!=
nil
{
key
=
common
.
Hex2Bytes
(
entry
.
Hash
)
status
=
entry
.
Status
mimeType
=
entry
.
ContentType
log
.
Trace
(
fmt
.
Sprintf
(
"content lookup key: '%v' (%v)"
,
key
,
mimeType
))
reader
=
self
.
dpa
.
Retrieve
(
key
)
if
status
==
http
.
StatusMultipleChoices
{
return
}
else
{
mimeType
=
entry
.
ContentType
log
.
Trace
(
fmt
.
Sprintf
(
"content lookup key: '%v' (%v)"
,
key
,
mimeType
))
reader
=
self
.
dpa
.
Retrieve
(
key
)
}
}
else
{
status
=
http
.
StatusNotFound
err
=
fmt
.
Errorf
(
"manifest entry for '%s' not found"
,
path
)
...
...
swarm/api/http/error.go
View file @
1ae0411d
...
...
@@ -25,9 +25,11 @@ import (
"fmt"
"html/template"
"net/http"
"strings"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/swarm/api"
)
//templateMap holds a mapping of an HTTP error code to a template
...
...
@@ -51,12 +53,14 @@ func initErrHandling() {
//pages are saved as strings - get these strings
genErrPage
:=
GetGenericErrorPage
()
notFoundPage
:=
GetNotFoundErrorPage
()
multipleChoicesPage
:=
GetMultipleChoicesErrorPage
()
//map the codes to the available pages
tnames
:=
map
[
int
]
string
{
0
:
genErrPage
,
//default
400
:
genErrPage
,
404
:
notFoundPage
,
500
:
genErrPage
,
0
:
genErrPage
,
//default
http
.
StatusBadRequest
:
genErrPage
,
http
.
StatusNotFound
:
notFoundPage
,
http
.
StatusMultipleChoices
:
multipleChoicesPage
,
http
.
StatusInternalServerError
:
genErrPage
,
}
templateMap
=
make
(
map
[
int
]
*
template
.
Template
)
for
code
,
tname
:=
range
tnames
{
...
...
@@ -65,6 +69,40 @@ func initErrHandling() {
}
}
//ShowMultipeChoices is used when a user requests a resource in a manifest which results
//in ambiguous results. It returns a HTML page with clickable links of each of the entry
//in the manifest which fits the request URI ambiguity.
//For example, if the user requests bzz:/<hash>/read and that manifest containes entries
//"readme.md" and "readinglist.txt", a HTML page is returned with this two links.
//This only applies if the manifest has no default entry
func
ShowMultipleChoices
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
,
list
api
.
ManifestList
)
{
msg
:=
""
if
list
.
Entries
==
nil
{
ShowError
(
w
,
r
,
"Internal Server Error"
,
http
.
StatusInternalServerError
)
return
}
//make links relative
//requestURI comes with the prefix of the ambiguous path, e.g. "read" for "readme.md" and "readinglist.txt"
//to get clickable links, need to remove the ambiguous path, i.e. "read"
idx
:=
strings
.
LastIndex
(
r
.
RequestURI
,
"/"
)
if
idx
==
-
1
{
ShowError
(
w
,
r
,
"Internal Server Error"
,
http
.
StatusInternalServerError
)
return
}
//remove ambiguous part
base
:=
r
.
RequestURI
[
:
idx
+
1
]
for
_
,
e
:=
range
list
.
Entries
{
//create clickable link for each entry
msg
+=
"<a href='"
+
base
+
e
.
Path
+
"'>"
+
e
.
Path
+
"</a><br/>"
}
respond
(
w
,
r
,
&
ErrorParams
{
Code
:
http
.
StatusMultipleChoices
,
Details
:
template
.
HTML
(
msg
),
Timestamp
:
time
.
Now
()
.
Format
(
time
.
RFC1123
),
template
:
getTemplate
(
http
.
StatusMultipleChoices
),
})
}
//ShowError is used to show an HTML error 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.
...
...
swarm/api/http/error_templates.go
View file @
1ae0411d
This diff is collapsed.
Click to expand it.
swarm/api/http/server.go
View file @
1ae0411d
...
...
@@ -441,14 +441,37 @@ func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) {
return
}
walker
,
err
:=
s
.
api
.
NewManifestWalker
(
key
,
nil
)
list
,
err
:=
s
.
getManifestList
(
key
,
r
.
uri
.
Path
)
if
err
!=
nil
{
s
.
Error
(
w
,
r
,
err
)
return
}
var
list
api
.
ManifestList
prefix
:=
r
.
uri
.
Path
// if the client wants HTML (e.g. a browser) then render the list as a
// HTML index with relative URLs
if
strings
.
Contains
(
r
.
Header
.
Get
(
"Accept"
),
"text/html"
)
{
w
.
Header
()
.
Set
(
"Content-Type"
,
"text/html"
)
err
:=
htmlListTemplate
.
Execute
(
w
,
&
htmlListData
{
URI
:
r
.
uri
,
List
:
&
list
,
})
if
err
!=
nil
{
s
.
logError
(
"error rendering list HTML: %s"
,
err
)
}
return
}
w
.
Header
()
.
Set
(
"Content-Type"
,
"application/json"
)
json
.
NewEncoder
(
w
)
.
Encode
(
&
list
)
}
func
(
s
*
Server
)
getManifestList
(
key
storage
.
Key
,
prefix
string
)
(
list
api
.
ManifestList
,
err
error
)
{
walker
,
err
:=
s
.
api
.
NewManifestWalker
(
key
,
nil
)
if
err
!=
nil
{
return
}
err
=
walker
.
Walk
(
func
(
entry
*
api
.
ManifestEntry
)
error
{
// handle non-manifest files
if
entry
.
ContentType
!=
api
.
ManifestType
{
...
...
@@ -495,27 +518,8 @@ func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) {
// so just skip it
return
api
.
SkipManifest
})
if
err
!=
nil
{
s
.
Error
(
w
,
r
,
err
)
return
}
// if the client wants HTML (e.g. a browser) then render the list as a
// HTML index with relative URLs
if
strings
.
Contains
(
r
.
Header
.
Get
(
"Accept"
),
"text/html"
)
{
w
.
Header
()
.
Set
(
"Content-Type"
,
"text/html"
)
err
:=
htmlListTemplate
.
Execute
(
w
,
&
htmlListData
{
URI
:
r
.
uri
,
List
:
&
list
,
})
if
err
!=
nil
{
s
.
logError
(
"error rendering list HTML: %s"
,
err
)
}
return
}
w
.
Header
()
.
Set
(
"Content-Type"
,
"application/json"
)
json
.
NewEncoder
(
w
)
.
Encode
(
&
list
)
return
list
,
nil
}
// HandleGetFile handles a GET request to bzz://<manifest>/<path> and responds
...
...
@@ -544,6 +548,22 @@ func (s *Server) HandleGetFile(w http.ResponseWriter, r *Request) {
return
}
//the request results in ambiguous files
//e.g. /read with readme.md and readinglist.txt available in manifest
if
status
==
http
.
StatusMultipleChoices
{
list
,
err
:=
s
.
getManifestList
(
key
,
r
.
uri
.
Path
)
if
err
!=
nil
{
s
.
Error
(
w
,
r
,
err
)
return
}
s
.
logDebug
(
fmt
.
Sprintf
(
"Multiple choices! --> %v"
,
list
))
//show a nice page links to available entries
ShowMultipleChoices
(
w
,
&
r
.
Request
,
list
)
return
}
// check the root chunk exists by retrieving the file's size
if
_
,
err
:=
reader
.
Size
(
nil
);
err
!=
nil
{
s
.
NotFound
(
w
,
r
,
fmt
.
Errorf
(
"File not found %s: %s"
,
r
.
uri
,
err
))
...
...
swarm/api/manifest.go
View file @
1ae0411d
...
...
@@ -22,6 +22,8 @@ import (
"errors"
"fmt"
"io"
"net/http"
"strings"
"sync"
"time"
...
...
@@ -422,25 +424,47 @@ func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *man
return
self
.
entries
[
256
],
0
}
//see if first char is in manifest entries
b
:=
byte
(
path
[
0
])
entry
=
self
.
entries
[
b
]
if
entry
==
nil
{
return
self
.
entries
[
256
],
0
}
epl
:=
len
(
entry
.
Path
)
log
.
Trace
(
fmt
.
Sprintf
(
"path = %v entry.Path = %v epl = %v"
,
path
,
entry
.
Path
,
epl
))
if
(
len
(
path
)
>=
epl
)
&&
(
path
[
:
epl
]
==
entry
.
Path
)
{
if
len
(
path
)
<=
epl
{
if
entry
.
Path
[
:
len
(
path
)]
==
path
{
if
entry
.
ContentType
==
ManifestType
{
entry
.
Status
=
http
.
StatusMultipleChoices
}
pos
=
len
(
path
)
return
}
return
nil
,
0
}
if
path
[
:
epl
]
==
entry
.
Path
{
log
.
Trace
(
fmt
.
Sprintf
(
"entry.ContentType = %v"
,
entry
.
ContentType
))
if
entry
.
ContentType
==
ManifestType
{
//the subentry is a manifest, load subtrie
if
entry
.
ContentType
==
ManifestType
&&
(
strings
.
Contains
(
entry
.
Path
,
path
)
||
strings
.
Contains
(
path
,
entry
.
Path
))
{
err
:=
self
.
loadSubTrie
(
entry
,
quitC
)
if
err
!=
nil
{
return
nil
,
0
}
entry
,
pos
=
entry
.
subtrie
.
findPrefixOf
(
path
[
epl
:
],
quitC
)
if
entry
!=
nil
{
sub
,
pos
:=
entry
.
subtrie
.
findPrefixOf
(
path
[
epl
:
],
quitC
)
if
sub
!=
nil
{
entry
=
sub
pos
+=
epl
return
sub
,
pos
}
else
if
path
==
entry
.
Path
{
entry
.
Status
=
http
.
StatusMultipleChoices
}
}
else
{
//entry is not a manifest, return it
if
path
!=
entry
.
Path
{
return
nil
,
0
}
pos
=
epl
}
}
...
...
swarm/api/manifest_test.go
View file @
1ae0411d
...
...
@@ -17,7 +17,6 @@
package
api
import
(
// "encoding/json"
"bytes"
"encoding/json"
"fmt"
...
...
@@ -72,11 +71,21 @@ func TestGetEntry(t *testing.T) {
testGetEntry
(
t
,
"/a"
,
""
,
""
)
testGetEntry
(
t
,
"/a/b"
,
"a/b"
,
"a/b"
)
// longest/deepest math
testGetEntry
(
t
,
"a/b"
,
"-"
,
"a"
,
"a/ba"
,
"a/b/c"
)
testGetEntry
(
t
,
"read"
,
"read"
,
"readme.md"
,
"readit.md"
)
testGetEntry
(
t
,
"rf"
,
"-"
,
"readme.md"
,
"readit.md"
)
testGetEntry
(
t
,
"readme"
,
"readme"
,
"readme.md"
)
testGetEntry
(
t
,
"readme"
,
"-"
,
"readit.md"
)
testGetEntry
(
t
,
"readme.md"
,
"readme.md"
,
"readme.md"
)
testGetEntry
(
t
,
"readme.md"
,
"-"
,
"readit.md"
)
testGetEntry
(
t
,
"readmeAmd"
,
"-"
,
"readit.md"
)
testGetEntry
(
t
,
"readme.mdffff"
,
"-"
,
"readme.md"
)
testGetEntry
(
t
,
"ab"
,
"ab"
,
"ab/cefg"
,
"ab/cedh"
,
"ab/kkkkkk"
)
testGetEntry
(
t
,
"ab/ce"
,
"ab/ce"
,
"ab/cefg"
,
"ab/cedh"
,
"ab/ceuuuuuuuuuu"
)
testGetEntry
(
t
,
"abc"
,
"abc"
,
"abcd"
,
"abczzzzef"
,
"abc/def"
,
"abc/e/g"
)
testGetEntry
(
t
,
"a/b"
,
"a/b"
,
"a"
,
"a/bc"
,
"a/ba"
,
"a/b/c"
)
testGetEntry
(
t
,
"a/b"
,
"a/b"
,
"a"
,
"a/b"
,
"a/bb"
,
"a/b/c"
)
testGetEntry
(
t
,
"//a//b//"
,
"a/b"
,
"a"
,
"a/b"
,
"a/bb"
,
"a/b/c"
)
}
func
TestDeleteEntry
(
t
*
testing
.
T
)
{
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment