1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
13 // fileTransport implements RoundTripper for the 'file' protocol.
14 type fileTransport struct {
18 // NewFileTransport returns a new RoundTripper, serving the provided
19 // FileSystem. The returned RoundTripper ignores the URL host in its
20 // incoming requests, as well as most other properties of the
23 // The typical use case for NewFileTransport is to register the "file"
24 // protocol with a Transport, as in:
26 // t := &http.Transport{}
27 // t.RegisterProtocol("file", http.NewFileTransport(http.Dir("/")))
28 // c := &http.Client{Transport: t}
29 // res, err := c.Get("file:///etc/passwd")
31 func NewFileTransport(fs FileSystem) RoundTripper {
32 return fileTransport{fileHandler{fs}}
35 // NewFileTransportFS returns a new RoundTripper, serving the provided
36 // file system fsys. The returned RoundTripper ignores the URL host in its
37 // incoming requests, as well as most other properties of the
40 // The typical use case for NewFileTransportFS is to register the "file"
41 // protocol with a Transport, as in:
43 // fsys := os.DirFS("/")
44 // t := &http.Transport{}
45 // t.RegisterProtocol("file", http.NewFileTransportFS(fsys))
46 // c := &http.Client{Transport: t}
47 // res, err := c.Get("file:///etc/passwd")
49 func NewFileTransportFS(fsys fs.FS) RoundTripper {
50 return NewFileTransport(FS(fsys))
53 func (t fileTransport) RoundTrip(req *Request) (resp *Response, err error) {
54 // We start ServeHTTP in a goroutine, which may take a long
55 // time if the file is large. The newPopulateResponseWriter
56 // call returns a channel which either ServeHTTP or finish()
57 // sends our *Response on, once the *Response itself has been
58 // populated (even if the body itself is still being
59 // written to the res.Body, a pipe)
60 rw, resc := newPopulateResponseWriter()
62 t.fh.ServeHTTP(rw, req)
68 func newPopulateResponseWriter() (*populateResponse, <-chan *Response) {
70 rw := &populateResponse{
71 ch: make(chan *Response),
84 // populateResponse is a ResponseWriter that populates the *Response
85 // in res, and writes its body to a pipe connected to the response
86 // body. Once writes begin or finish() is called, the response is sent
88 type populateResponse struct {
97 func (pr *populateResponse) finish() {
101 if !pr.sentResponse {
107 func (pr *populateResponse) sendResponse() {
111 pr.sentResponse = true
114 pr.res.ContentLength = -1
119 func (pr *populateResponse) Header() Header {
123 func (pr *populateResponse) WriteHeader(code int) {
127 pr.wroteHeader = true
129 pr.res.StatusCode = code
130 pr.res.Status = fmt.Sprintf("%d %s", code, StatusText(code))
133 func (pr *populateResponse) Write(p []byte) (n int, err error) {
135 pr.WriteHeader(StatusOK)
138 if !pr.sentResponse {
141 return pr.pw.Write(p)