Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AppProvider: report errors from WOPI and return base64-encoded fileids #2103

Merged
merged 2 commits into from
Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog/unreleased/app-errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Bugfix: AppProvider: propagate back errors reported by WOPI
on /app/open and return base64-encoded fileids on /app/new

https://github.com/cs3org/reva/pull/2103
5 changes: 2 additions & 3 deletions internal/grpc/services/appprovider/appprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package appprovider

import (
"context"
"errors"
"os"
"time"

Expand All @@ -35,7 +36,6 @@ import (
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/sharedconf"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"google.golang.org/grpc"
)

Expand Down Expand Up @@ -145,9 +145,8 @@ func getProvider(c *config) (app.Provider, error) {
func (s *service) OpenInApp(ctx context.Context, req *providerpb.OpenInAppRequest) (*providerpb.OpenInAppResponse, error) {
appURL, err := s.provider.GetAppURL(ctx, req.ResourceInfo, req.ViewMode, req.AccessToken)
if err != nil {
err := errors.Wrap(err, "appprovider: error calling GetAppURL")
res := &providerpb.OpenInAppResponse{
Status: status.NewInternal(ctx, err, "error getting app URL"),
Status: status.NewInternal(ctx, errors.New("appprovider: error calling GetAppURL"), err.Error()),
}
return res, nil
}
Expand Down
20 changes: 14 additions & 6 deletions internal/http/services/appprovider/appprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ import (
"github.com/rs/zerolog/log"
)

const (
idDelimiter string = ":"
glpatcern marked this conversation as resolved.
Show resolved Hide resolved
)

func init() {
global.Register("appprovider", New)
}
Expand Down Expand Up @@ -199,14 +203,17 @@ func (s *svc) handleNew(w http.ResponseWriter, r *http.Request) {
return
}

// Stat created file and return its file id
// Stat the newly created file
statRes, ocmderr, err := statRef(ctx, provider.Reference{Path: target}, client)
if err != nil {
log.Error().Err(err).Msg("error statting created file")
ocmd.WriteError(w, r, ocmderr, "Created file not found", errtypes.NotFound("Created file not found"))
return
}
js, err := json.Marshal(map[string]interface{}{"file_id": statRes.Id})

// Base64-encode the fileid for the web to consume it
b64id := base64.StdEncoding.EncodeToString([]byte(statRes.Id.StorageId + idDelimiter + statRes.Id.OpaqueId))
js, err := json.Marshal(map[string]interface{}{"file_id": b64id})
if err != nil {
ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error marshalling JSON response", err)
return
Expand Down Expand Up @@ -274,12 +281,13 @@ func (s *svc) handleOpen(w http.ResponseWriter, r *http.Request) {
}
openRes, err := client.OpenInApp(ctx, &openReq)
if err != nil {
ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error opening resource", err)
log.Error().Err(err).Msg("error calling OpenInApp")
ocmd.WriteError(w, r, ocmd.APIErrorServerError, err.Error(), err)
return
}
if openRes.Status.Code != rpc.Code_CODE_OK {
ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error opening resource information",
status.NewErrorFromCode(openRes.Status.Code, "appprovider"))
ocmd.WriteError(w, r, ocmd.APIErrorServerError, openRes.Status.Message,
status.NewErrorFromCode(openRes.Status.Code, "error calling OpenInApp"))
return
}

Expand Down Expand Up @@ -327,7 +335,7 @@ func (s *svc) getStatInfo(ctx context.Context, fileID string, client gateway.Gat
return nil, ocmd.APIErrorInvalidParameter, errors.Wrap(err, "fileID doesn't follow the required format")
}

parts := strings.Split(string(decodedID), ":")
parts := strings.Split(string(decodedID), idDelimiter)
if !utf8.ValidString(parts[0]) || !utf8.ValidString(parts[1]) {
return nil, ocmd.APIErrorInvalidParameter, errors.New("fileID contains illegal characters")
}
Expand Down
16 changes: 11 additions & 5 deletions pkg/app/provider/wopi/wopi.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func (p *wopiProvider) GetAppURL(ctx context.Context, resource *provider.Resourc
q.Add("endpoint", resource.GetId().StorageId)
q.Add("viewmode", viewMode.String())
u, ok := ctxpkg.ContextGetUser(ctx)
if ok { // else defaults to "Anonymous Guest"
if ok { // else defaults to "Guest xyz"
q.Add("username", u.Username)
}

Expand All @@ -161,20 +161,26 @@ func (p *wopiProvider) GetAppURL(ctx context.Context, resource *provider.Resourc
httpReq.Header.Set("Authorization", "Bearer "+p.conf.IOPSecret)
httpReq.Header.Set("TokenHeader", token)

// Call the WOPI server and parse the response (body will always contain a payload)
openRes, err := p.wopiClient.Do(httpReq)
if err != nil {
return nil, errors.Wrap(err, "wopi: error performing open request to WOPI server")
}
defer openRes.Body.Close()

if openRes.StatusCode != http.StatusOK {
return nil, errtypes.InternalError("wopi: unexpected status from WOPI server: " + openRes.Status)
}

body, err := ioutil.ReadAll(openRes.Body)
if err != nil {
return nil, err
}
if openRes.StatusCode != http.StatusOK {
glpatcern marked this conversation as resolved.
Show resolved Hide resolved
// WOPI returned failure: body contains a user-friendly error message (yet perform a sanity check)
sbody := ""
if body != nil {
sbody = string(body)
}
log.Warn().Msg(fmt.Sprintf("wopi: WOPI server returned HTTP %s, error was: %s", openRes.Status, sbody))
return nil, errors.New(sbody)
}

var result map[string]interface{}
err = json.Unmarshal(body, &result)
Expand Down