duandanai6470 2019-07-24 12:57
浏览 71
已采纳

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

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条回答

  • dongmu2517 2019-07-24 14:55
    关注

    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
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料