aboutsummaryrefslogtreecommitdiffstats
path: root/swarm/api
diff options
context:
space:
mode:
Diffstat (limited to 'swarm/api')
-rw-r--r--swarm/api/api.go26
-rw-r--r--swarm/api/client/client.go31
-rw-r--r--swarm/api/client/client_test.go2
-rw-r--r--swarm/api/http/middleware.go2
-rw-r--r--swarm/api/http/response.go5
-rw-r--r--swarm/api/http/server.go4
-rw-r--r--swarm/api/http/server_test.go6
-rw-r--r--swarm/api/http/templates.go15
-rw-r--r--swarm/api/manifest.go17
9 files changed, 76 insertions, 32 deletions
diff --git a/swarm/api/api.go b/swarm/api/api.go
index ad4bd7dcb..99d971b10 100644
--- a/swarm/api/api.go
+++ b/swarm/api/api.go
@@ -525,6 +525,10 @@ func (a *API) GetDirectoryTar(ctx context.Context, uri *URI) (io.ReadCloser, err
return nil
})
+ // close tar writer before closing pipew
+ // to flush remaining data to pipew
+ // regardless of error value
+ tw.Close()
if err != nil {
apiGetTarFail.Inc(1)
pipew.CloseWithError(err)
@@ -700,11 +704,12 @@ func (a *API) AddFile(ctx context.Context, mhash, path, fname string, content []
return fkey, newMkey.String(), nil
}
-func (a *API) UploadTar(ctx context.Context, bodyReader io.ReadCloser, manifestPath string, mw *ManifestWriter) (storage.Address, error) {
+func (a *API) UploadTar(ctx context.Context, bodyReader io.ReadCloser, manifestPath, defaultPath string, mw *ManifestWriter) (storage.Address, error) {
apiUploadTarCount.Inc(1)
var contentKey storage.Address
tr := tar.NewReader(bodyReader)
defer bodyReader.Close()
+ var defaultPathFound bool
for {
hdr, err := tr.Next()
if err == io.EOF {
@@ -733,6 +738,25 @@ func (a *API) UploadTar(ctx context.Context, bodyReader io.ReadCloser, manifestP
apiUploadTarFail.Inc(1)
return nil, fmt.Errorf("error adding manifest entry from tar stream: %s", err)
}
+ if hdr.Name == defaultPath {
+ entry := &ManifestEntry{
+ Hash: contentKey.Hex(),
+ Path: "", // default entry
+ ContentType: hdr.Xattrs["user.swarm.content-type"],
+ Mode: hdr.Mode,
+ Size: hdr.Size,
+ ModTime: hdr.ModTime,
+ }
+ contentKey, err = mw.AddEntry(ctx, nil, entry)
+ if err != nil {
+ apiUploadTarFail.Inc(1)
+ return nil, fmt.Errorf("error adding default manifest entry from tar stream: %s", err)
+ }
+ defaultPathFound = true
+ }
+ }
+ if defaultPath != "" && !defaultPathFound {
+ return contentKey, fmt.Errorf("default path %q not found", defaultPath)
}
return contentKey, nil
}
diff --git a/swarm/api/client/client.go b/swarm/api/client/client.go
index b3a5e929d..8a9efe360 100644
--- a/swarm/api/client/client.go
+++ b/swarm/api/client/client.go
@@ -138,7 +138,7 @@ func (c *Client) Upload(file *File, manifest string, toEncrypt bool) (string, er
if file.Size <= 0 {
return "", errors.New("file size must be greater than zero")
}
- return c.TarUpload(manifest, &FileUploader{file}, toEncrypt)
+ return c.TarUpload(manifest, &FileUploader{file}, "", toEncrypt)
}
// Download downloads a file with the given path from the swarm manifest with
@@ -175,7 +175,15 @@ func (c *Client) UploadDirectory(dir, defaultPath, manifest string, toEncrypt bo
} else if !stat.IsDir() {
return "", fmt.Errorf("not a directory: %s", dir)
}
- return c.TarUpload(manifest, &DirectoryUploader{dir, defaultPath}, toEncrypt)
+ if defaultPath != "" {
+ if _, err := os.Stat(filepath.Join(dir, defaultPath)); err != nil {
+ if os.IsNotExist(err) {
+ return "", fmt.Errorf("the default path %q was not found in the upload directory %q", defaultPath, dir)
+ }
+ return "", fmt.Errorf("default path: %v", err)
+ }
+ }
+ return c.TarUpload(manifest, &DirectoryUploader{dir}, defaultPath, toEncrypt)
}
// DownloadDirectory downloads the files contained in a swarm manifest under
@@ -389,21 +397,11 @@ func (u UploaderFunc) Upload(upload UploadFn) error {
// DirectoryUploader uploads all files in a directory, optionally uploading
// a file to the default path
type DirectoryUploader struct {
- Dir string
- DefaultPath string
+ Dir string
}
// Upload performs the upload of the directory and default path
func (d *DirectoryUploader) Upload(upload UploadFn) error {
- if d.DefaultPath != "" {
- file, err := Open(d.DefaultPath)
- if err != nil {
- return err
- }
- if err := upload(file); err != nil {
- return err
- }
- }
return filepath.Walk(d.Dir, func(path string, f os.FileInfo, err error) error {
if err != nil {
return err
@@ -441,7 +439,7 @@ type UploadFn func(file *File) error
// TarUpload uses the given Uploader to upload files to swarm as a tar stream,
// returning the resulting manifest hash
-func (c *Client) TarUpload(hash string, uploader Uploader, toEncrypt bool) (string, error) {
+func (c *Client) TarUpload(hash string, uploader Uploader, defaultPath string, toEncrypt bool) (string, error) {
reqR, reqW := io.Pipe()
defer reqR.Close()
addr := hash
@@ -458,6 +456,11 @@ func (c *Client) TarUpload(hash string, uploader Uploader, toEncrypt bool) (stri
return "", err
}
req.Header.Set("Content-Type", "application/x-tar")
+ if defaultPath != "" {
+ q := req.URL.Query()
+ q.Set("defaultpath", defaultPath)
+ req.URL.RawQuery = q.Encode()
+ }
// use 'Expect: 100-continue' so we don't send the request body if
// the server refuses the request
diff --git a/swarm/api/client/client_test.go b/swarm/api/client/client_test.go
index dc608e3f1..ae82a91d7 100644
--- a/swarm/api/client/client_test.go
+++ b/swarm/api/client/client_test.go
@@ -194,7 +194,7 @@ func TestClientUploadDownloadDirectory(t *testing.T) {
// upload the directory
client := NewClient(srv.URL)
- defaultPath := filepath.Join(dir, testDirFiles[0])
+ defaultPath := testDirFiles[0]
hash, err := client.UploadDirectory(dir, defaultPath, "", false)
if err != nil {
t.Fatalf("error uploading directory: %s", err)
diff --git a/swarm/api/http/middleware.go b/swarm/api/http/middleware.go
index d338a782c..c0d8d1a40 100644
--- a/swarm/api/http/middleware.go
+++ b/swarm/api/http/middleware.go
@@ -64,8 +64,8 @@ func ParseURI(h http.Handler) http.Handler {
func InitLoggingResponseWriter(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
writer := newLoggingResponseWriter(w)
-
h.ServeHTTP(writer, r)
+ log.Debug("request served", "ruid", GetRUID(r.Context()), "code", writer.statusCode)
})
}
diff --git a/swarm/api/http/response.go b/swarm/api/http/response.go
index 9f4788d35..f050e706a 100644
--- a/swarm/api/http/response.go
+++ b/swarm/api/http/response.go
@@ -84,15 +84,16 @@ func RespondError(w http.ResponseWriter, r *http.Request, msg string, code int)
}
func respond(w http.ResponseWriter, r *http.Request, params *ResponseParams) {
+
w.WriteHeader(params.Code)
if params.Code >= 400 {
- w.Header().Del("Cache-Control") //avoid sending cache headers for errors!
+ w.Header().Del("Cache-Control")
w.Header().Del("ETag")
}
acceptHeader := r.Header.Get("Accept")
- // this cannot be in a switch form since an Accept header can be in the form of "Accept: */*, text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8"
+ // this cannot be in a switch since an Accept header can have multiple values: "Accept: */*, text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8"
if strings.Contains(acceptHeader, "application/json") {
if err := respondJSON(w, r, params); err != nil {
RespondError(w, r, "Internal server error", http.StatusInternalServerError)
diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go
index bd6949de6..5a5c42adc 100644
--- a/swarm/api/http/server.go
+++ b/swarm/api/http/server.go
@@ -336,7 +336,9 @@ func (s *Server) HandlePostFiles(w http.ResponseWriter, r *http.Request) {
func (s *Server) handleTarUpload(r *http.Request, mw *api.ManifestWriter) (storage.Address, error) {
log.Debug("handle.tar.upload", "ruid", GetRUID(r.Context()))
- key, err := s.api.UploadTar(r.Context(), r.Body, GetURI(r.Context()).Path, mw)
+ defaultPath := r.URL.Query().Get("defaultpath")
+
+ key, err := s.api.UploadTar(r.Context(), r.Body, GetURI(r.Context()).Path, defaultPath, mw)
if err != nil {
return nil, err
}
diff --git a/swarm/api/http/server_test.go b/swarm/api/http/server_test.go
index 3ac60596b..7934e37eb 100644
--- a/swarm/api/http/server_test.go
+++ b/swarm/api/http/server_test.go
@@ -576,7 +576,7 @@ func testBzzGetPath(encrypted bool, t *testing.T) {
pageFragments: []string{
fmt.Sprintf("Swarm index of bzz:/%s/a/", ref),
`<a class="normal-link" href="b/">b/</a>`,
- `<a class="normal-link" href="a">a</a>`,
+ fmt.Sprintf(`<a class="normal-link" href="/bzz:/%s/a/a">a</a>`, ref),
},
},
{
@@ -584,8 +584,8 @@ func testBzzGetPath(encrypted bool, t *testing.T) {
json: `{"entries":[{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/b/b","mod_time":"0001-01-01T00:00:00Z"},{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/b/c","mod_time":"0001-01-01T00:00:00Z"}]}`,
pageFragments: []string{
fmt.Sprintf("Swarm index of bzz:/%s/a/b/", ref),
- `<a class="normal-link" href="b">b</a>`,
- `<a class="normal-link" href="c">c</a>`,
+ fmt.Sprintf(`<a class="normal-link" href="/bzz:/%s/a/b/b">b</a>`, ref),
+ fmt.Sprintf(`<a class="normal-link" href="/bzz:/%s/a/b/c">c</a>`, ref),
},
},
{
diff --git a/swarm/api/http/templates.go b/swarm/api/http/templates.go
index 1cd42ca37..986f5f887 100644
--- a/swarm/api/http/templates.go
+++ b/swarm/api/http/templates.go
@@ -18,6 +18,7 @@ package http
import (
"encoding/hex"
+ "fmt"
"html/template"
"path"
@@ -45,7 +46,10 @@ func init() {
{
templateName: "bzz-list",
partial: bzzList,
- funcs: template.FuncMap{"basename": path.Base},
+ funcs: template.FuncMap{
+ "basename": path.Base,
+ "leaflink": leafLink,
+ },
},
{
templateName: "landing-page",
@@ -62,6 +66,10 @@ func init() {
faviconBytes = bytes
}
+func leafLink(URI api.URI, manifestEntry api.ManifestEntry) string {
+ return fmt.Sprintf("/bzz:/%s/%s", URI.Addr, manifestEntry.Path)
+}
+
const bzzList = `{{ define "content" }}
<h3 class="top-space">Swarm index of {{ .URI }}</h3>
<hr>
@@ -83,10 +91,11 @@ const bzzList = `{{ define "content" }}
<td>DIR</td>
<td>-</td>
</tr>
- {{ end }} {{ range .List.Entries }}
+ {{ end }}
+ {{ range .List.Entries }}
<tr>
<td>
- <a class="normal-link" href="{{ basename .Path }}">{{ basename .Path }}</a>
+ <a class="normal-link" href="{{ leaflink $.URI . }}">{{ basename .Path }}</a>
</td>
<td>{{ .ContentType }}</td>
<td>{{ .Size }}</td>
diff --git a/swarm/api/manifest.go b/swarm/api/manifest.go
index fbd143f29..2a163dd39 100644
--- a/swarm/api/manifest.go
+++ b/swarm/api/manifest.go
@@ -106,13 +106,18 @@ func (a *API) NewManifestWriter(ctx context.Context, addr storage.Address, quitC
}
// AddEntry stores the given data and adds the resulting key to the manifest
-func (m *ManifestWriter) AddEntry(ctx context.Context, data io.Reader, e *ManifestEntry) (storage.Address, error) {
- key, _, err := m.api.Store(ctx, data, e.Size, m.trie.encrypted)
- if err != nil {
- return nil, err
- }
+func (m *ManifestWriter) AddEntry(ctx context.Context, data io.Reader, e *ManifestEntry) (key storage.Address, err error) {
entry := newManifestTrieEntry(e, nil)
- entry.Hash = key.Hex()
+ if data != nil {
+ key, _, err = m.api.Store(ctx, data, e.Size, m.trie.encrypted)
+ if err != nil {
+ return nil, err
+ }
+ entry.Hash = key.Hex()
+ }
+ if entry.Hash == "" {
+ return key, errors.New("missing entry hash")
+ }
m.trie.addEntry(entry, m.quitC)
return key, nil
}