解密后的反向代理服务文件

I need to put an *os.File into the request.Body but I don't know how to handle the closure of the file descriptor (and the elimination of the temporary file). I cannot use http.ServeFile to serve the file.

I have 3 softwares: A) User interface ( that I cannot edit ) B) Backend which serves files C) An http reverse proxy whose role is to sign the requests coming from A going to B, to encrypt files going from A to B, and decrypto files going from B to A.

The software A is expected to receive the body of the decrypted file content. I know it would be easier just to decrypt the file in a directory using B and then have A open it, but unfortunately I cannot edit A which expects the file in the request body.

the work flow of the softwares is the following: software A sends a request to C which signs the request and forwards it to B, then C proceeds to decrypt the file and has to serve the decrypted content to A in a the request body.

type transportPageServeFile struct {
    http.RoundTripper
    // vault handles encryption and decryption of files
    vault *vault.Container
}

func (t *transportPageServeFile) RoundTrip(req *http.Request) (resp *http.Response, err error) {
    resp, err = t.RoundTripper.RoundTrip(req)
    if err != nil {
        return nil, errors.Wrap(err, "transportPageServeFile")
    }
    // create temporary destination dir for the decrypted file
    dstDir, err := utils.MkTmpDir()
    if err != nil {
        return nil, errors.Wrap(err, "transportPageServeFile")
    }
    defer os.RemoveAll(dstDir) // i'm deleting the directory where the temporary file is stored, deleting it before it even gets transmitted to software A
    fileName := req.Header.Get(api.FileNameHeader)
    decryptedFileDst := fmt.Sprintf("%s/%s", dstDir, fileName)
    // DecryptFileFromReader takes a reader and decrypts the file, saving it in the decided destination
    err = t.vault.DecryptFileFromReader(resp.Body, decryptedFileDst)
    if err != nil {
        return nil, errors.Wrap(err, "transportPageServeFile")
    }
    defer resp.Body.Close()
    // now open the saved decrypted file
    decryptedFile, err := os.Open(decryptedFileDst)
    if err != nil {
        return nil, errors.Wrap(err,"transportPageServeFile")
    }
    defer decryptedFile.Close() // close file before serving the content?
    resp.Body = decryptedFile
    return resp, nil
}
// pageServeFile is the handler of /serveFile
func (rpc *RPC) pageServeFile(c *gin.Context) {
    transport := &transportPageServeFile{RoundTripper:http.DefaultTransport, vault:rpc.vault}
    target, err := url.Parse(rpc.apiEndpoint)
    if err != nil {
        rpc.onError(c, errors.Wrapf(err, "pageServeFile"))
        return
    }
    proxy := httputil.NewSingleHostReverseProxy(target)
    proxy.Transport = transport
    proxy.ServeHTTP(c.Writer, c.Request)
}

How do I copy the file in the request body (using a reader) and when/how do I close the file descriptor once the response is forwarded?

1个回答



响应主体是io.ReadCloser,因此可以合理地假设反向代理调用Close。 确实可以做到,正如您通过运行以下程序所看到的:</ p>

  package main 

import(
“ fmt “
” io“
” net / http“
” net / http / httptest“
” net / http / httputil“
” net / url“
”运行时/调试“

type dbg struct {io.ReadCloser}

func(d dbg)Close()error {
fmt.Println(“ Close()call ::”)
debug.PrintStack()

返回d。 ReadCloser.Close()
}

func main(){
// srv模拟“软件B”
srv:= httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter,r * http。 请求){
w.Write([] byte(“ Hello,world”))
}))

目标,_:= url.Parse(srv.URL)
p:= httputil.NewSingleHostReverseProxy( target)

//要修改响应,请使用适当命名的ModifyResponse字段; 否
//需要实现RoundTipper。
p.ModifyResponse = func(res * http.Response)错误{
res.Body = dbg {res.Body}
return nil
}

req:= httptest.NewRequest(“ GET”,“ http://example.com/hello”,nil)
rec:= httptest.NewRecorder()

p.ServeHTTP(rec,req)
}

//输出:
// Close()称为:
// goroutine 1 [运行中]:
// runtime / debug.Stack(0x10,0x0,0x0)
// / usr / local / go / src / runtime / debug / stack.go:24 + 0x9d
// runtime / debug.PrintStack()
// /usr/local/go/src/runtime/debug/stack.go:16 + 0x22
// main.dbg.Close(0x75b780,0xc00013e140,0xc000152000,0x7f61fc523088)
// /tmp/tmp.H9O7cizbkv/main.go:17 + 0x7f
// net / http / httputil。(* ReverseProxy).ServeHTTP(0xc0000ac0f0、0x75e460、0xc000032440、0xc00010a000)
// /usr/local/go/src/net/http/httputil/reverseproxy.go:311 + 0x8a6
// main.main()
// /tmp/tmp.H9O7cizbkv/main.go:41 + 0x152
</ code> </ pre>
</ div>

展开原文

原文

The response body is an io.ReadCloser, so it is reasonable to assume that the reverse proxy calls Close. And indeed it does, as you can see by running the following program:

package main

import (
    "fmt"
    "io"
    "net/http"
    "net/http/httptest"
    "net/http/httputil"
    "net/url"
    "runtime/debug"
)

type dbg struct{ io.ReadCloser }

func (d dbg) Close() error {
    fmt.Println("Close() called:")
    debug.PrintStack()

    return d.ReadCloser.Close()
}

func main() {
    // srv simulates "software B"
    srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, world"))
    }))

    target, _ := url.Parse(srv.URL)
    p := httputil.NewSingleHostReverseProxy(target)

    // To modify the response, use the aptly named ModifyResponse field; no
    // need to implement a RoundTripper.
    p.ModifyResponse = func(res *http.Response) error {
        res.Body = dbg{res.Body}
        return nil
    }

    req := httptest.NewRequest("GET", "http://example.com/hello", nil)
    rec := httptest.NewRecorder()

    p.ServeHTTP(rec, req)
}

// Output:
// Close() called:
// goroutine 1 [running]:
// runtime/debug.Stack(0x10, 0x0, 0x0)
//         /usr/local/go/src/runtime/debug/stack.go:24 +0x9d
// runtime/debug.PrintStack()
//         /usr/local/go/src/runtime/debug/stack.go:16 +0x22
// main.dbg.Close(0x75b780, 0xc00013e140, 0xc000152000, 0x7f61fc523088)
//         /tmp/tmp.H9O7cizbkv/main.go:17 +0x7f
// net/http/httputil.(*ReverseProxy).ServeHTTP(0xc0000ac0f0, 0x75e460, 0xc000032440, 0xc00010a000)
//         /usr/local/go/src/net/http/httputil/reverseproxy.go:311 +0x8a6
// main.main()
//         /tmp/tmp.H9O7cizbkv/main.go:41 +0x152

doushou8730
doushou8730 你确实是对的。
大约一年之前 回复
duanduo7400
duanduo7400 我建议将DecryptFileFromReader更改为io.Writer而不是文件名,那么您根本不需要临时文件。 但是,这是一个不同的问题。 如果您决定提出问题,请确保在问题中包括DecryptFileFromReader的要旨。
大约一年之前 回复
dongshuzhuo5659
dongshuzhuo5659 哦好的。 至于删除临时文件的问题,我正在考虑将文件包装到readcloser接口中,该接口在关闭后会删除文件。
大约一年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问