...

Source file src/net/http/filetransport.go

Documentation: net/http

		 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.
		 4  
		 5  package http
		 6  
		 7  import (
		 8  	"fmt"
		 9  	"io"
		10  )
		11  
		12  // fileTransport implements RoundTripper for the 'file' protocol.
		13  type fileTransport struct {
		14  	fh fileHandler
		15  }
		16  
		17  // NewFileTransport returns a new RoundTripper, serving the provided
		18  // FileSystem. The returned RoundTripper ignores the URL host in its
		19  // incoming requests, as well as most other properties of the
		20  // request.
		21  //
		22  // The typical use case for NewFileTransport is to register the "file"
		23  // protocol with a Transport, as in:
		24  //
		25  //	 t := &http.Transport{}
		26  //	 t.RegisterProtocol("file", http.NewFileTransport(http.Dir("/")))
		27  //	 c := &http.Client{Transport: t}
		28  //	 res, err := c.Get("file:///etc/passwd")
		29  //	 ...
		30  func NewFileTransport(fs FileSystem) RoundTripper {
		31  	return fileTransport{fileHandler{fs}}
		32  }
		33  
		34  func (t fileTransport) RoundTrip(req *Request) (resp *Response, err error) {
		35  	// We start ServeHTTP in a goroutine, which may take a long
		36  	// time if the file is large. The newPopulateResponseWriter
		37  	// call returns a channel which either ServeHTTP or finish()
		38  	// sends our *Response on, once the *Response itself has been
		39  	// populated (even if the body itself is still being
		40  	// written to the res.Body, a pipe)
		41  	rw, resc := newPopulateResponseWriter()
		42  	go func() {
		43  		t.fh.ServeHTTP(rw, req)
		44  		rw.finish()
		45  	}()
		46  	return <-resc, nil
		47  }
		48  
		49  func newPopulateResponseWriter() (*populateResponse, <-chan *Response) {
		50  	pr, pw := io.Pipe()
		51  	rw := &populateResponse{
		52  		ch: make(chan *Response),
		53  		pw: pw,
		54  		res: &Response{
		55  			Proto:			"HTTP/1.0",
		56  			ProtoMajor: 1,
		57  			Header:		 make(Header),
		58  			Close:			true,
		59  			Body:			 pr,
		60  		},
		61  	}
		62  	return rw, rw.ch
		63  }
		64  
		65  // populateResponse is a ResponseWriter that populates the *Response
		66  // in res, and writes its body to a pipe connected to the response
		67  // body. Once writes begin or finish() is called, the response is sent
		68  // on ch.
		69  type populateResponse struct {
		70  	res					*Response
		71  	ch					 chan *Response
		72  	wroteHeader	bool
		73  	hasContent	 bool
		74  	sentResponse bool
		75  	pw					 *io.PipeWriter
		76  }
		77  
		78  func (pr *populateResponse) finish() {
		79  	if !pr.wroteHeader {
		80  		pr.WriteHeader(500)
		81  	}
		82  	if !pr.sentResponse {
		83  		pr.sendResponse()
		84  	}
		85  	pr.pw.Close()
		86  }
		87  
		88  func (pr *populateResponse) sendResponse() {
		89  	if pr.sentResponse {
		90  		return
		91  	}
		92  	pr.sentResponse = true
		93  
		94  	if pr.hasContent {
		95  		pr.res.ContentLength = -1
		96  	}
		97  	pr.ch <- pr.res
		98  }
		99  
	 100  func (pr *populateResponse) Header() Header {
	 101  	return pr.res.Header
	 102  }
	 103  
	 104  func (pr *populateResponse) WriteHeader(code int) {
	 105  	if pr.wroteHeader {
	 106  		return
	 107  	}
	 108  	pr.wroteHeader = true
	 109  
	 110  	pr.res.StatusCode = code
	 111  	pr.res.Status = fmt.Sprintf("%d %s", code, StatusText(code))
	 112  }
	 113  
	 114  func (pr *populateResponse) Write(p []byte) (n int, err error) {
	 115  	if !pr.wroteHeader {
	 116  		pr.WriteHeader(StatusOK)
	 117  	}
	 118  	pr.hasContent = true
	 119  	if !pr.sentResponse {
	 120  		pr.sendResponse()
	 121  	}
	 122  	return pr.pw.Write(p)
	 123  }
	 124  

View as plain text