mirror of
https://github.com/golang/go
synced 2024-11-21 19:24:45 -07:00
mime: implement TypeByExtension for windows
Fixes #2071. R=golang-dev, hcwfrichter, pascal, rsc CC=golang-dev https://golang.org/cl/5369056
This commit is contained in:
parent
9859af879b
commit
ac17fd4cd2
@ -10,4 +10,24 @@ GOFILES=\
|
||||
mediatype.go\
|
||||
type.go\
|
||||
|
||||
GOFILES_freebsd=\
|
||||
type_unix.go
|
||||
|
||||
GOFILES_darwin=\
|
||||
type_unix.go
|
||||
|
||||
GOFILES_linux=\
|
||||
type_unix.go
|
||||
|
||||
GOFILES_openbsd=\
|
||||
type_unix.go
|
||||
|
||||
GOFILES_plan9=\
|
||||
type_unix.go
|
||||
|
||||
GOFILES_windows=\
|
||||
type_windows.go
|
||||
|
||||
GOFILES+=$(GOFILES_$(GOOS))
|
||||
|
||||
include ../../Make.pkg
|
||||
|
@ -6,19 +6,11 @@
|
||||
package mime
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var typeFiles = []string{
|
||||
"/etc/mime.types",
|
||||
"/etc/apache2/mime.types",
|
||||
"/etc/apache/mime.types",
|
||||
}
|
||||
|
||||
var mimeTypes = map[string]string{
|
||||
".css": "text/css; charset=utf-8",
|
||||
".gif": "image/gif",
|
||||
@ -33,46 +25,13 @@ var mimeTypes = map[string]string{
|
||||
|
||||
var mimeLock sync.RWMutex
|
||||
|
||||
func loadMimeFile(filename string) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(f)
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) <= 1 || fields[0][0] == '#' {
|
||||
continue
|
||||
}
|
||||
mimeType := fields[0]
|
||||
for _, ext := range fields[1:] {
|
||||
if ext[0] == '#' {
|
||||
break
|
||||
}
|
||||
setExtensionType("."+ext, mimeType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initMime() {
|
||||
for _, filename := range typeFiles {
|
||||
loadMimeFile(filename)
|
||||
}
|
||||
}
|
||||
|
||||
var once sync.Once
|
||||
|
||||
// TypeByExtension returns the MIME type associated with the file extension ext.
|
||||
// The extension ext should begin with a leading dot, as in ".html".
|
||||
// When ext has no associated type, TypeByExtension returns "".
|
||||
//
|
||||
// The built-in table is small but is is augmented by the local
|
||||
// The built-in table is small but on unix it is augmented by the local
|
||||
// system's mime.types file(s) if available under one or more of these
|
||||
// names:
|
||||
//
|
||||
@ -80,6 +39,8 @@ var once sync.Once
|
||||
// /etc/apache2/mime.types
|
||||
// /etc/apache/mime.types
|
||||
//
|
||||
// Windows system mime types are extracted from registry.
|
||||
//
|
||||
// Text types have the charset parameter set to "utf-8" by default.
|
||||
func TypeByExtension(ext string) string {
|
||||
once.Do(initMime)
|
||||
|
@ -6,15 +6,9 @@ package mime
|
||||
|
||||
import "testing"
|
||||
|
||||
var typeTests = map[string]string{
|
||||
".t1": "application/test",
|
||||
".t2": "text/test; charset=utf-8",
|
||||
".png": "image/png",
|
||||
}
|
||||
var typeTests = initMimeForTests()
|
||||
|
||||
func TestTypeByExtension(t *testing.T) {
|
||||
typeFiles = []string{"test.types"}
|
||||
|
||||
for ext, want := range typeTests {
|
||||
val := TypeByExtension(ext)
|
||||
if val != want {
|
||||
|
59
src/pkg/mime/type_unix.go
Normal file
59
src/pkg/mime/type_unix.go
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package mime
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var typeFiles = []string{
|
||||
"/etc/mime.types",
|
||||
"/etc/apache2/mime.types",
|
||||
"/etc/apache/mime.types",
|
||||
}
|
||||
|
||||
func loadMimeFile(filename string) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(f)
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) <= 1 || fields[0][0] == '#' {
|
||||
continue
|
||||
}
|
||||
mimeType := fields[0]
|
||||
for _, ext := range fields[1:] {
|
||||
if ext[0] == '#' {
|
||||
break
|
||||
}
|
||||
setExtensionType("."+ext, mimeType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initMime() {
|
||||
for _, filename := range typeFiles {
|
||||
loadMimeFile(filename)
|
||||
}
|
||||
}
|
||||
|
||||
func initMimeForTests() map[string]string {
|
||||
typeFiles = []string{"test.types"}
|
||||
return map[string]string{
|
||||
".t1": "application/test",
|
||||
".t2": "text/test; charset=utf-8",
|
||||
".png": "image/png",
|
||||
}
|
||||
}
|
62
src/pkg/mime/type_windows.go
Normal file
62
src/pkg/mime/type_windows.go
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package mime
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func initMime() {
|
||||
var root syscall.Handle
|
||||
if syscall.RegOpenKeyEx(syscall.HKEY_CLASSES_ROOT, syscall.StringToUTF16Ptr(`\`),
|
||||
0, syscall.KEY_READ, &root) != 0 {
|
||||
return
|
||||
}
|
||||
defer syscall.RegCloseKey(root)
|
||||
var count uint32
|
||||
if syscall.RegQueryInfoKey(root, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil) != 0 {
|
||||
return
|
||||
}
|
||||
var buf [1 << 10]uint16
|
||||
for i := uint32(0); i < count; i++ {
|
||||
n := uint32(len(buf))
|
||||
if syscall.RegEnumKeyEx(root, i, &buf[0], &n, nil, nil, nil, nil) != 0 {
|
||||
continue
|
||||
}
|
||||
ext := syscall.UTF16ToString(buf[:])
|
||||
if len(ext) < 2 || ext[0] != '.' { // looking for extensions only
|
||||
continue
|
||||
}
|
||||
var h syscall.Handle
|
||||
if syscall.RegOpenKeyEx(
|
||||
syscall.HKEY_CLASSES_ROOT, syscall.StringToUTF16Ptr(`\`+ext),
|
||||
0, syscall.KEY_READ, &h) != 0 {
|
||||
continue
|
||||
}
|
||||
var typ uint32
|
||||
n = uint32(len(buf) * 2) // api expects array of bytes, not uint16
|
||||
if syscall.RegQueryValueEx(
|
||||
h, syscall.StringToUTF16Ptr("Content Type"),
|
||||
nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n) != 0 {
|
||||
syscall.RegCloseKey(h)
|
||||
continue
|
||||
}
|
||||
syscall.RegCloseKey(h)
|
||||
if typ != syscall.REG_SZ { // null terminated strings only
|
||||
continue
|
||||
}
|
||||
mimeType := syscall.UTF16ToString(buf[:])
|
||||
setExtensionType(ext, mimeType)
|
||||
}
|
||||
}
|
||||
|
||||
func initMimeForTests() map[string]string {
|
||||
return map[string]string{
|
||||
".bmp": "image/bmp",
|
||||
".png": "image/png",
|
||||
".wav": "audio/wav",
|
||||
}
|
||||
}
|
@ -154,6 +154,11 @@ func NewCallback(fn interface{}) uintptr
|
||||
//sys CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) = crypt32.CertOpenSystemStoreW
|
||||
//sys CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext) = crypt32.CertEnumCertificatesInStore
|
||||
//sys CertCloseStore(store Handle, flags uint32) (err error) = crypt32.CertCloseStore
|
||||
//sys RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno uintptr) = advapi32.RegOpenKeyExW
|
||||
//sys RegCloseKey(key Handle) (regerrno uintptr) = advapi32.RegCloseKey
|
||||
//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno uintptr) = advapi32.RegQueryInfoKeyW
|
||||
//sys RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno uintptr) = advapi32.RegEnumKeyExW
|
||||
//sys RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno uintptr) = advapi32.RegQueryValueExW
|
||||
|
||||
// syscall interface implementation for other packages
|
||||
|
||||
|
@ -85,6 +85,11 @@ var (
|
||||
procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW")
|
||||
procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore")
|
||||
procCertCloseStore = modcrypt32.NewProc("CertCloseStore")
|
||||
procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW")
|
||||
procRegCloseKey = modadvapi32.NewProc("RegCloseKey")
|
||||
procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW")
|
||||
procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW")
|
||||
procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW")
|
||||
procWSAStartup = modws2_32.NewProc("WSAStartup")
|
||||
procWSACleanup = modws2_32.NewProc("WSACleanup")
|
||||
procWSAIoctl = modws2_32.NewProc("WSAIoctl")
|
||||
@ -982,6 +987,36 @@ func CertCloseStore(store Handle, flags uint32) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno uintptr) {
|
||||
r0, _, _ := Syscall6(procRegOpenKeyExW.Addr(), 5, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result)), 0)
|
||||
regerrno = uintptr(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func RegCloseKey(key Handle) (regerrno uintptr) {
|
||||
r0, _, _ := Syscall(procRegCloseKey.Addr(), 1, uintptr(key), 0, 0)
|
||||
regerrno = uintptr(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno uintptr) {
|
||||
r0, _, _ := Syscall12(procRegQueryInfoKeyW.Addr(), 12, uintptr(key), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(subkeysLen)), uintptr(unsafe.Pointer(maxSubkeyLen)), uintptr(unsafe.Pointer(maxClassLen)), uintptr(unsafe.Pointer(valuesLen)), uintptr(unsafe.Pointer(maxValueNameLen)), uintptr(unsafe.Pointer(maxValueLen)), uintptr(unsafe.Pointer(saLen)), uintptr(unsafe.Pointer(lastWriteTime)))
|
||||
regerrno = uintptr(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno uintptr) {
|
||||
r0, _, _ := Syscall9(procRegEnumKeyExW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime)), 0)
|
||||
regerrno = uintptr(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno uintptr) {
|
||||
r0, _, _ := Syscall6(procRegQueryValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)))
|
||||
regerrno = uintptr(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func WSAStartup(verreq uint32, data *WSAData) (sockerr uintptr) {
|
||||
r0, _, _ := Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
|
||||
sockerr = uintptr(r0)
|
||||
|
@ -85,6 +85,11 @@ var (
|
||||
procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW")
|
||||
procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore")
|
||||
procCertCloseStore = modcrypt32.NewProc("CertCloseStore")
|
||||
procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW")
|
||||
procRegCloseKey = modadvapi32.NewProc("RegCloseKey")
|
||||
procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW")
|
||||
procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW")
|
||||
procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW")
|
||||
procWSAStartup = modws2_32.NewProc("WSAStartup")
|
||||
procWSACleanup = modws2_32.NewProc("WSACleanup")
|
||||
procWSAIoctl = modws2_32.NewProc("WSAIoctl")
|
||||
@ -982,6 +987,36 @@ func CertCloseStore(store Handle, flags uint32) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno uintptr) {
|
||||
r0, _, _ := Syscall6(procRegOpenKeyExW.Addr(), 5, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result)), 0)
|
||||
regerrno = uintptr(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func RegCloseKey(key Handle) (regerrno uintptr) {
|
||||
r0, _, _ := Syscall(procRegCloseKey.Addr(), 1, uintptr(key), 0, 0)
|
||||
regerrno = uintptr(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno uintptr) {
|
||||
r0, _, _ := Syscall12(procRegQueryInfoKeyW.Addr(), 12, uintptr(key), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(subkeysLen)), uintptr(unsafe.Pointer(maxSubkeyLen)), uintptr(unsafe.Pointer(maxClassLen)), uintptr(unsafe.Pointer(valuesLen)), uintptr(unsafe.Pointer(maxValueNameLen)), uintptr(unsafe.Pointer(maxValueLen)), uintptr(unsafe.Pointer(saLen)), uintptr(unsafe.Pointer(lastWriteTime)))
|
||||
regerrno = uintptr(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno uintptr) {
|
||||
r0, _, _ := Syscall9(procRegEnumKeyExW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime)), 0)
|
||||
regerrno = uintptr(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno uintptr) {
|
||||
r0, _, _ := Syscall6(procRegQueryValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)))
|
||||
regerrno = uintptr(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func WSAStartup(verreq uint32, data *WSAData) (sockerr uintptr) {
|
||||
r0, _, _ := Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
|
||||
sockerr = uintptr(r0)
|
||||
|
@ -664,3 +664,43 @@ type CertContext struct {
|
||||
CertInfo uintptr
|
||||
Store Handle
|
||||
}
|
||||
|
||||
const (
|
||||
HKEY_CLASSES_ROOT = 0x80000000 + iota
|
||||
HKEY_CURRENT_USER
|
||||
HKEY_LOCAL_MACHINE
|
||||
HKEY_USERS
|
||||
HKEY_PERFORMANCE_DATA
|
||||
HKEY_CURRENT_CONFIG
|
||||
HKEY_DYN_DATA
|
||||
|
||||
KEY_QUERY_VALUE = 1
|
||||
KEY_SET_VALUE = 2
|
||||
KEY_CREATE_SUB_KEY = 4
|
||||
KEY_ENUMERATE_SUB_KEYS = 8
|
||||
KEY_NOTIFY = 16
|
||||
KEY_CREATE_LINK = 32
|
||||
KEY_WRITE = 0x20006
|
||||
KEY_EXECUTE = 0x20019
|
||||
KEY_READ = 0x20019
|
||||
KEY_WOW64_64KEY = 0x0100
|
||||
KEY_WOW64_32KEY = 0x0200
|
||||
KEY_ALL_ACCESS = 0xf003f
|
||||
)
|
||||
|
||||
const (
|
||||
REG_NONE = iota
|
||||
REG_SZ
|
||||
REG_EXPAND_SZ
|
||||
REG_BINARY
|
||||
REG_DWORD_LITTLE_ENDIAN
|
||||
REG_DWORD_BIG_ENDIAN
|
||||
REG_LINK
|
||||
REG_MULTI_SZ
|
||||
REG_RESOURCE_LIST
|
||||
REG_FULL_RESOURCE_DESCRIPTOR
|
||||
REG_RESOURCE_REQUIREMENTS_LIST
|
||||
REG_QWORD_LITTLE_ENDIAN
|
||||
REG_DWORD = REG_DWORD_LITTLE_ENDIAN
|
||||
REG_QWORD = REG_QWORD_LITTLE_ENDIAN
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user