github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/talks/2013/oscon-dl/server-compose.go (about) 1 // +build ignore,OMIT 2 3 package main 4 5 import ( 6 "io" 7 "log" 8 "net/http" 9 "sort" 10 "strings" 11 "time" 12 ) 13 14 var modTime = time.Unix(1374708739, 0) 15 16 // START OMIT 17 func part(s string) SizeReaderAt { 18 return io.NewSectionReader(strings.NewReader(s), 0, int64(len(s))) 19 } 20 21 func handler(w http.ResponseWriter, r *http.Request) { 22 sra := NewMultiReaderAt( 23 part("Hello, "), part(" world! "), 24 part("You requested "+r.URL.Path+"\n"), 25 ) 26 rs := io.NewSectionReader(sra, 0, sra.Size()) 27 http.ServeContent(w, r, "foo.txt", modTime, rs) 28 } 29 30 //END OMIT 31 32 func main() { 33 log.Printf("Running...") 34 http.HandleFunc("/", handler) 35 log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil)) 36 } 37 38 // START_1 OMIT 39 // A SizeReaderAt is a ReaderAt with a Size method. 40 // 41 // An io.SectionReader implements SizeReaderAt. 42 type SizeReaderAt interface { 43 Size() int64 44 io.ReaderAt 45 } 46 47 // NewMultiReaderAt is like io.MultiReader but produces a ReaderAt 48 // (and Size), instead of just a reader. 49 func NewMultiReaderAt(parts ...SizeReaderAt) SizeReaderAt { 50 m := &multi{ 51 parts: make([]offsetAndSource, 0, len(parts)), 52 } 53 var off int64 54 for _, p := range parts { 55 m.parts = append(m.parts, offsetAndSource{off, p}) 56 off += p.Size() 57 } 58 m.size = off 59 return m 60 } 61 62 // END_1 OMIT 63 64 type offsetAndSource struct { 65 off int64 66 SizeReaderAt 67 } 68 69 type multi struct { 70 parts []offsetAndSource 71 size int64 72 } 73 74 func (m *multi) Size() int64 { return m.size } 75 76 func (m *multi) ReadAt(p []byte, off int64) (n int, err error) { 77 wantN := len(p) 78 79 // Skip past the requested offset. 80 skipParts := sort.Search(len(m.parts), func(i int) bool { 81 // This function returns whether parts[i] will 82 // contribute any bytes to our output. 83 part := m.parts[i] 84 return part.off+part.Size() > off 85 }) 86 parts := m.parts[skipParts:] 87 88 // How far to skip in the first part. 89 needSkip := off 90 if len(parts) > 0 { 91 needSkip -= parts[0].off 92 } 93 94 for len(parts) > 0 && len(p) > 0 { 95 readP := p 96 partSize := parts[0].Size() 97 if int64(len(readP)) > partSize-needSkip { 98 readP = readP[:partSize-needSkip] 99 } 100 pn, err0 := parts[0].ReadAt(readP, needSkip) 101 if err0 != nil { 102 return n, err0 103 } 104 n += pn 105 p = p[pn:] 106 if int64(pn)+needSkip == partSize { 107 parts = parts[1:] 108 } 109 needSkip = 0 110 } 111 112 if n != wantN { 113 err = io.ErrUnexpectedEOF 114 } 115 return 116 }