github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/index/sniff.go (about) 1 /* 2 Copyright 2011 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package index 18 19 import ( 20 "bytes" 21 "errors" 22 23 "camlistore.org/pkg/blob" 24 "camlistore.org/pkg/magic" 25 "camlistore.org/pkg/schema" 26 ) 27 28 type BlobSniffer struct { 29 br blob.Ref 30 31 header []byte 32 written int64 33 meta *schema.Blob // or nil 34 mimeType string 35 camliType string 36 } 37 38 func NewBlobSniffer(ref blob.Ref) *BlobSniffer { 39 if !ref.Valid() { 40 panic("invalid ref") 41 } 42 return &BlobSniffer{br: ref} 43 } 44 45 func (sn *BlobSniffer) SchemaBlob() (meta *schema.Blob, ok bool) { 46 return sn.meta, sn.meta != nil 47 } 48 49 func (sn *BlobSniffer) Write(d []byte) (int, error) { 50 if !sn.br.Valid() { 51 panic("write on sniffer with invalid blobref") 52 } 53 sn.written += int64(len(d)) 54 if len(sn.header) < schema.MaxSchemaBlobSize { 55 n := schema.MaxSchemaBlobSize - len(sn.header) 56 if len(d) < n { 57 n = len(d) 58 } 59 sn.header = append(sn.header, d[:n]...) 60 } 61 return len(d), nil 62 } 63 64 func (sn *BlobSniffer) Size() int64 { 65 return sn.written 66 } 67 68 func (sn *BlobSniffer) IsTruncated() bool { 69 return sn.written > schema.MaxSchemaBlobSize 70 } 71 72 func (sn *BlobSniffer) Body() ([]byte, error) { 73 if sn.IsTruncated() { 74 return nil, errors.New("index.Body: was truncated") 75 } 76 return sn.header, nil 77 } 78 79 // MIMEType returns the sniffed blob's content-type or the empty string if unknown. 80 // If the blob is a Camlistore schema metadata blob, the MIME type will be of 81 // the form "application/json; camliType=foo". 82 func (sn *BlobSniffer) MIMEType() string { return sn.mimeType } 83 84 func (sn *BlobSniffer) CamliType() string { return sn.camliType } 85 86 func (sn *BlobSniffer) Parse() { 87 if sn.bufferIsCamliJSON() { 88 sn.camliType = sn.meta.Type() 89 sn.mimeType = "application/json; camliType=" + sn.camliType 90 } else { 91 sn.mimeType = magic.MIMEType(sn.header) 92 } 93 } 94 95 func (sn *BlobSniffer) bufferIsCamliJSON() bool { 96 buf := sn.header 97 if !schema.LikelySchemaBlob(buf) { 98 return false 99 } 100 blob, err := schema.BlobFromReader(sn.br, bytes.NewReader(buf)) 101 if err != nil { 102 return false 103 } 104 sn.meta = blob 105 return true 106 }