"Fossies" - the Fresh Open Source Software Archive 
Member "gdrive-2.1.1/vendor/google.golang.org/api/gensupport/media.go" (28 May 2021, 6205 Bytes) of package /linux/misc/gdrive-2.1.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 // Copyright 2016 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 gensupport
6
7 import (
8 "fmt"
9 "io"
10 "io/ioutil"
11 "mime/multipart"
12 "net/http"
13 "net/textproto"
14
15 "google.golang.org/api/googleapi"
16 )
17
18 const sniffBuffSize = 512
19
20 func newContentSniffer(r io.Reader) *contentSniffer {
21 return &contentSniffer{r: r}
22 }
23
24 // contentSniffer wraps a Reader, and reports the content type determined by sniffing up to 512 bytes from the Reader.
25 type contentSniffer struct {
26 r io.Reader
27 start []byte // buffer for the sniffed bytes.
28 err error // set to any error encountered while reading bytes to be sniffed.
29
30 ctype string // set on first sniff.
31 sniffed bool // set to true on first sniff.
32 }
33
34 func (cs *contentSniffer) Read(p []byte) (n int, err error) {
35 // Ensure that the content type is sniffed before any data is consumed from Reader.
36 _, _ = cs.ContentType()
37
38 if len(cs.start) > 0 {
39 n := copy(p, cs.start)
40 cs.start = cs.start[n:]
41 return n, nil
42 }
43
44 // We may have read some bytes into start while sniffing, even if the read ended in an error.
45 // We should first return those bytes, then the error.
46 if cs.err != nil {
47 return 0, cs.err
48 }
49
50 // Now we have handled all bytes that were buffered while sniffing. Now just delegate to the underlying reader.
51 return cs.r.Read(p)
52 }
53
54 // ContentType returns the sniffed content type, and whether the content type was succesfully sniffed.
55 func (cs *contentSniffer) ContentType() (string, bool) {
56 if cs.sniffed {
57 return cs.ctype, cs.ctype != ""
58 }
59 cs.sniffed = true
60 // If ReadAll hits EOF, it returns err==nil.
61 cs.start, cs.err = ioutil.ReadAll(io.LimitReader(cs.r, sniffBuffSize))
62
63 // Don't try to detect the content type based on possibly incomplete data.
64 if cs.err != nil {
65 return "", false
66 }
67
68 cs.ctype = http.DetectContentType(cs.start)
69 return cs.ctype, true
70 }
71
72 // DetermineContentType determines the content type of the supplied reader.
73 // If the content type is already known, it can be specified via ctype.
74 // Otherwise, the content of media will be sniffed to determine the content type.
75 // If media implements googleapi.ContentTyper (deprecated), this will be used
76 // instead of sniffing the content.
77 // After calling DetectContentType the caller must not perform further reads on
78 // media, but rather read from the Reader that is returned.
79 func DetermineContentType(media io.Reader, ctype string) (io.Reader, string) {
80 // Note: callers could avoid calling DetectContentType if ctype != "",
81 // but doing the check inside this function reduces the amount of
82 // generated code.
83 if ctype != "" {
84 return media, ctype
85 }
86
87 // For backwards compatability, allow clients to set content
88 // type by providing a ContentTyper for media.
89 if typer, ok := media.(googleapi.ContentTyper); ok {
90 return media, typer.ContentType()
91 }
92
93 sniffer := newContentSniffer(media)
94 if ctype, ok := sniffer.ContentType(); ok {
95 return sniffer, ctype
96 }
97 // If content type could not be sniffed, reads from sniffer will eventually fail with an error.
98 return sniffer, ""
99 }
100
101 type typeReader struct {
102 io.Reader
103 typ string
104 }
105
106 // multipartReader combines the contents of multiple readers to creat a multipart/related HTTP body.
107 // Close must be called if reads from the multipartReader are abandoned before reaching EOF.
108 type multipartReader struct {
109 pr *io.PipeReader
110 pipeOpen bool
111 ctype string
112 }
113
114 func newMultipartReader(parts []typeReader) *multipartReader {
115 mp := &multipartReader{pipeOpen: true}
116 var pw *io.PipeWriter
117 mp.pr, pw = io.Pipe()
118 mpw := multipart.NewWriter(pw)
119 mp.ctype = "multipart/related; boundary=" + mpw.Boundary()
120 go func() {
121 for _, part := range parts {
122 w, err := mpw.CreatePart(typeHeader(part.typ))
123 if err != nil {
124 mpw.Close()
125 pw.CloseWithError(fmt.Errorf("googleapi: CreatePart failed: %v", err))
126 return
127 }
128 _, err = io.Copy(w, part.Reader)
129 if err != nil {
130 mpw.Close()
131 pw.CloseWithError(fmt.Errorf("googleapi: Copy failed: %v", err))
132 return
133 }
134 }
135
136 mpw.Close()
137 pw.Close()
138 }()
139 return mp
140 }
141
142 func (mp *multipartReader) Read(data []byte) (n int, err error) {
143 return mp.pr.Read(data)
144 }
145
146 func (mp *multipartReader) Close() error {
147 if !mp.pipeOpen {
148 return nil
149 }
150 mp.pipeOpen = false
151 return mp.pr.Close()
152 }
153
154 // CombineBodyMedia combines a json body with media content to create a multipart/related HTTP body.
155 // It returns a ReadCloser containing the combined body, and the overall "multipart/related" content type, with random boundary.
156 //
157 // The caller must call Close on the returned ReadCloser if reads are abandoned before reaching EOF.
158 func CombineBodyMedia(body io.Reader, bodyContentType string, media io.Reader, mediaContentType string) (io.ReadCloser, string) {
159 mp := newMultipartReader([]typeReader{
160 {body, bodyContentType},
161 {media, mediaContentType},
162 })
163 return mp, mp.ctype
164 }
165
166 func typeHeader(contentType string) textproto.MIMEHeader {
167 h := make(textproto.MIMEHeader)
168 if contentType != "" {
169 h.Set("Content-Type", contentType)
170 }
171 return h
172 }
173
174 // PrepareUpload determines whether the data in the supplied reader should be
175 // uploaded in a single request, or in sequential chunks.
176 // chunkSize is the size of the chunk that media should be split into.
177 // If chunkSize is non-zero and the contents of media do not fit in a single
178 // chunk (or there is an error reading media), then media will be returned as a
179 // ResumableBuffer. Otherwise, media will be returned as a Reader.
180 //
181 // After PrepareUpload has been called, media should no longer be used: the
182 // media content should be accessed via one of the return values.
183 func PrepareUpload(media io.Reader, chunkSize int) (io.Reader,
184 *ResumableBuffer) {
185 if chunkSize == 0 { // do not chunk
186 return media, nil
187 }
188
189 rb := NewResumableBuffer(media, chunkSize)
190 rdr, _, _, err := rb.Chunk()
191
192 if err == io.EOF { // we can upload this in a single request
193 return rdr, nil
194 }
195 // err might be a non-EOF error. If it is, the next call to rb.Chunk will
196 // return the same error. Returning a ResumableBuffer ensures that this error
197 // will be handled at some point.
198
199 return nil, rb
200 }