Skip to content

Instantly share code, notes, and snippets.

@mrkurt
Last active January 14, 2019 19:51
Show Gist options
  • Save mrkurt/e133f213f6885965ae5f2a72534a5a78 to your computer and use it in GitHub Desktop.
Save mrkurt/e133f213f6885965ae5f2a72534a5a78 to your computer and use it in GitHub Desktop.
package backend
import (
"encoding/json"
"fmt"
"mime"
"net/http"
"path"
"time"
"github.com/pkg/errors"
"github.com/superfly/go-proxy/log"
proxy "github.com/superfly/go-proxy/proxy/context"
)
// DropboxBackend is a Backend implementation for Dropbox
type DropboxBackend struct {
*GenericBackend
}
const (
dropboxEndpoint = "https://content.dropboxapi.com/2/files/"
)
// ProxyRequest proxies the Request to the DropboxBackend and returns a Response
func (b *DropboxBackend) ProxyRequest(ctx *proxy.Context, rw http.ResponseWriter, req *http.Request) (res *http.Response, err error) {
directory, err := b.GetSettingString("directory")
if err != nil {
return nil, errors.Wrap(err, "failed to get directory")
}
accessToken, err := b.GetSettingString("access_token")
if err != nil {
return nil, errors.Wrap(err, "failed to get access_token")
}
//curl -X POST https://content.dropboxapi.com/2/files/download \
//--header "Authorization: Bearer <token>" \
//--header "Dropbox-API-Arg: {\"path\": \"/Homework/math/Prime_Numbers.txt\"}"
if req.Method != "HEAD" && req.Method != "GET" {
h := make(http.Header)
h.Set("Allow", "GET, HEAD")
return &http.Response{
StatusCode: http.StatusMethodNotAllowed,
Body: http.NoBody,
Header: h,
}, nil
}
url := dropboxEndpoint + "download"
dpath := path.Join(directory, req.URL.Path)
log.Debugf("requesting %s from Dropbox endpoint %s", dpath, url)
// this seems heavy for one string
payload := map[string]interface{}{
"path": dpath,
}
jsonPayload, err := json.Marshal(payload)
if err != nil {
return nil, err
}
client := &http.Client{
Timeout: time.Second * 10,
}
dreq, err := http.NewRequest("POST", url, nil)
dreq.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
dreq.Header.Set("Dropbox-API-Arg", string(jsonPayload))
dresp, err := client.Do(dreq)
if err != nil {
return nil, err
}
resp := &http.Response{
StatusCode: dresp.StatusCode,
Header: make(http.Header),
}
if req.Method == "GET" {
resp.Body = dresp.Body
} else {
dresp.Body.Close()
resp.Body = http.NoBody
}
if dresp.StatusCode == http.StatusOK {
setDropboxResponseHeaders(dresp, resp, dpath)
} else if dresp.StatusCode == http.StatusConflict { // should be a 404
resp.StatusCode = http.StatusNotFound
}
return resp, nil
}
func setDropboxResponseHeaders(dres *http.Response, resp *http.Response, dpath string) {
// HTTP/1.1 200 OK
// Server: nginx
//Date: Sat, 02 Sep 2017 00:17:08 GMT
//Content-Type: application/octet-stream
//Content-Length: 181778
//Connection: keep-alive
//accept-ranges: bytes
//etag: W/"25bcdd45a"
//pragma: no-cache
//cache-control: no-cache
//original-content-length: 181778
//dropbox-api-result: {"name": "hero.png", "path_lower": "/hero.png", "path_display": "/hero.png", "id": "id:xkk7UhkHpRAAAAAAAAAABw", "client_modified": "2017-08-28T20:47:08Z", "server_modified": "2017-08-28T20:47:08Z", "rev": "25bcdd45a", "size": 181778, "content_hash": "b98e5dce5349af9b3a882956997dd7322ba47cc544593b239f49f05559f29120"}
//X-Server-Response-Time: 431
//X-Dropbox-Request-Id: e9f9bc1ebf173060842175b2130c0a77
//X-Robots-Tag: noindex, nofollow, noimageindex
resp.Header.Set("Content-Length", dres.Header.Get("Content-Length"))
resp.Header.Set("etag", dres.Header.Get("etag"))
resp.Header.Set("Transfer-Encoding", dres.Header.Get("Transfer-Encoding"))
ext := path.Ext(dpath)
ctype := dres.Header.Get("Content-Type")
if ext != "" {
detected := mime.TypeByExtension(ext)
if detected != "" {
ctype = detected
}
}
resp.Header.Set("Content-Type", ctype)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment