soc.go 3.56 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// Copyright 2021 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package api

import (
	"encoding/hex"
	"errors"
	"io/ioutil"
	"net/http"

13
	"github.com/ethersphere/bee/pkg/cac"
14 15 16 17 18 19
	"github.com/ethersphere/bee/pkg/jsonhttp"
	"github.com/ethersphere/bee/pkg/soc"
	"github.com/ethersphere/bee/pkg/swarm"
	"github.com/gorilla/mux"
)

20
var errBadRequestParams = errors.New("owner, id or span is not well formed")
21 22 23 24 25 26 27 28

type socPostResponse struct {
	Reference swarm.Address `json:"reference"`
}

func (s *server) socUploadHandler(w http.ResponseWriter, r *http.Request) {
	owner, err := hex.DecodeString(mux.Vars(r)["owner"])
	if err != nil {
29 30
		s.logger.Debugf("soc upload: bad owner: %v", err)
		s.logger.Error("soc upload: %v", errBadRequestParams)
31 32 33 34 35
		jsonhttp.BadRequest(w, "bad owner")
		return
	}
	id, err := hex.DecodeString(mux.Vars(r)["id"])
	if err != nil {
36 37
		s.logger.Debugf("soc upload: bad id: %v", err)
		s.logger.Error("soc upload: %v", errBadRequestParams)
38 39 40 41 42 43
		jsonhttp.BadRequest(w, "bad id")
		return
	}

	sigStr := r.URL.Query().Get("sig")
	if sigStr == "" {
44 45
		s.logger.Debugf("soc upload: empty signature")
		s.logger.Error("soc upload: empty signature")
46 47 48 49 50 51
		jsonhttp.BadRequest(w, "empty signature")
		return
	}

	sig, err := hex.DecodeString(sigStr)
	if err != nil {
52 53
		s.logger.Debugf("soc upload: bad signature: %v", err)
		s.logger.Error("soc upload: bad signature")
54 55 56 57 58 59 60 61 62
		jsonhttp.BadRequest(w, "bad signature")
		return
	}

	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		if jsonhttp.HandleBodyReadError(err, w) {
			return
		}
63 64
		s.logger.Debugf("soc upload: read chunk data error: %v", err)
		s.logger.Error("soc upload: read chunk data error")
65 66 67 68 69
		jsonhttp.InternalServerError(w, "cannot read chunk data")
		return
	}

	if len(data) < swarm.SpanSize {
70 71
		s.logger.Debugf("soc upload: chunk data too short")
		s.logger.Error("soc upload: %v", errBadRequestParams)
72 73 74 75 76
		jsonhttp.BadRequest(w, "short chunk data")
		return
	}

	if len(data) > swarm.ChunkSize+swarm.SpanSize {
77 78
		s.logger.Debugf("soc upload: chunk data exceeds %d bytes", swarm.ChunkSize+swarm.SpanSize)
		s.logger.Error("soc upload: chunk data error")
79 80 81 82
		jsonhttp.RequestEntityTooLarge(w, "payload too large")
		return
	}

83
	ch, err := cac.NewWithDataSpan(data)
84
	if err != nil {
85 86
		s.logger.Debugf("soc upload: create content addressed chunk: %v", err)
		s.logger.Error("soc upload: chunk data error")
87 88 89 90 91 92
		jsonhttp.BadRequest(w, "chunk data error")
		return
	}

	chunk, err := soc.NewSignedChunk(id, ch, owner, sig)
	if err != nil {
93 94
		s.logger.Debugf("soc upload: read chunk data error: %v", err)
		s.logger.Error("soc upload: read chunk data error")
95 96 97 98 99
		jsonhttp.InternalServerError(w, "cannot read chunk data")
		return
	}

	if !soc.Valid(chunk) {
100 101
		s.logger.Debugf("soc upload: invalid chunk: %v", err)
		s.logger.Error("soc upload: invalid chunk")
102 103 104 105
		jsonhttp.Unauthorized(w, "invalid chunk")
		return

	}
106

107 108
	ctx := r.Context()

109 110 111 112 113 114 115 116 117 118 119 120 121
	has, err := s.storer.Has(ctx, chunk.Address())
	if err != nil {
		s.logger.Debugf("soc upload: store has: %v", err)
		s.logger.Error("soc upload: store has")
		jsonhttp.InternalServerError(w, "storage error")
		return
	}
	if has {
		s.logger.Error("soc upload: chunk already exists")
		jsonhttp.Conflict(w, "chunk already exists")
		return
	}

122
	_, err = s.storer.Put(ctx, requestModePut(r), chunk)
123
	if err != nil {
124 125
		s.logger.Debugf("soc upload: chunk write error: %v", err)
		s.logger.Error("soc upload: chunk write error")
126 127 128 129 130 131
		jsonhttp.BadRequest(w, "chunk write error")
		return
	}

	jsonhttp.Created(w, chunkAddressResponse{Reference: chunk.Address()})
}