public_handers.go
package manager
import (
"net/http"
"regexp"
"strconv"
"io"
"strings"
"fmt"
"time"
)
var publicUrlRegex *regexp.Regexp
func init() {
var err error
publicUrlRegex, err = regexp.Compile("/([0-9]*)/([0-9]*)/(.*)")
if err != nil {
panic(err)
}
}
//公共资源处理器
func (vm *VolumeManager)publicEntry(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet, http.MethodHead:
if publicUrlRegex.MatchString(r.URL.Path) {
vm.publicReadFile(w, r)
} else {
http.NotFound(w, r)
}
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
//读取公共资源文件
func (vm *VolumeManager)publicReadFile(w http.ResponseWriter, r *http.Request) {
match := publicUrlRegex.FindStringSubmatch(r.URL.Path)
vid, _ := strconv.ParseUint(match[1], 10, 64)
volume := vm.Volumes[vid]
if volume == nil {
http.Error(w, "can't find volume", http.StatusNotFound)
return
}
fid, _ := strconv.ParseUint(match[2], 10, 64)
file, err := volume.Get(fid)
if err != nil || file.Info.FileName != match[3] {
http.NotFound(w, r)
return
}
w.Header().Set("Content-Type", get_content_type(file.Info.FileName))
w.Header().Set("Accept-Ranges", "bytes")
w.Header().Set("ETag", fmt.Sprintf("\"%d\"", fid))
//暂时不使用Last-Modified,用ETag即可
//w.Header().Set("Last-Modified", file.Info.Mtime.Format(http.TimeFormat))
w.Header().Set("Expires", time.Now().In(time.UTC).Add(DefaultExpires).Format(http.TimeFormat))
etagMatch := false
if r.Header.Get("If-None-Match") != "" {
s := r.Header.Get("If-None-Match")
if etag, err := strconv.ParseUint(s[1:len(s) - 1], 10, 64); err == nil && etag == fid {
etagMatch = true
}
}
if r.Header.Get("Range") != "" {
ranges := strings.Split(r.Header.Get("Range")[6:], "-")
start, err := strconv.ParseUint(ranges[0], 10, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
length := uint64(0)
if start > file.Info.Size {
start = file.Info.Size
} else if ranges[1] != "" {
end, err := strconv.ParseUint(ranges[1], 10, 64)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
end += 1
if end > file.Info.Size {
end = file.Info.Size
}
length = end - start
} else {
length = file.Info.Size - start
}
w.Header().Set("Content-Length", strconv.FormatUint(length, 10))
if length == 0 {
w.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
return
}
w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, start + length - 1, file.Info.Size))
if etagMatch {
w.WriteHeader(http.StatusNotModified)
return
}
w.WriteHeader(http.StatusPartialContent)
if r.Method != http.MethodHead {
file.Seek(int64(start), 0)
io.CopyN(w, file, int64(length))
}
} else {
w.Header().Set("Content-Length", strconv.FormatUint(file.Info.Size, 10))
if etagMatch {
w.WriteHeader(http.StatusNotModified)
} else if r.Method != http.MethodHead {
io.Copy(w, file)
}
}
}
public_handers.go的更多相关文章
随机推荐
- html5中的全局属性
在html5中,新增了一个"全局属性"的概念,所谓全局属性,是指可以对任何属性都使用的属性.下面列出常用的全局属性. 1.contentEditable属性,是微软开发的,该属性主 ...
- 智能合约最佳实践 之 Solidity 编码规范
每一门语言都有其相应的编码规范, Solidity 也一样, 下面官方推荐的规范及我的总结,供大家参考,希望可以帮助大家写出更好规范的智能合约. 命名规范 避免使用 小写的l,大写的I,大写的O 应该 ...
- 对DB2常见错误的列举以及破解方案
我们今天主要描述的是DB2常见错误还有正对这些错误的解决方案,以下就是文章对DB2常见错误还有正对这些错误的解决方案的主要内容的详细描述. 以下的文章主要是介绍DB2常见错误还有正对这些错误的解决方案 ...
- iframe实现局部刷新和回调(转)
今天做项目遇到一个问题.就是提交表单的时候,要在后台验证用户名是否存在和验证码是否正确. 当验证码或者用户名存在的时候.在后台弹窗提示.可页面原本file里面符合要求的值刷新没了.用户体验不好.因为用 ...
- 利用LinkedHashMap实现简单的缓存
update1:第二个实现,读操作不必要采用独占锁,缓存显然是读多于写,读的时候一开始用独占锁是考虑到要递增计数和更新时间戳要加锁,不过这两个变量都是采用原子变量,因此也不必采用独占锁,修改为读写锁. ...
- 学习Timer定时器
原文地址:http://www.cppblog.com/ivenher/articles/19969.html setTimer函数用于创建一个计时器,KillTimer函数用于销毁一个计时器.计时器 ...
- vue.js中的全局组件和局部组件
组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能. 组件的使用有三 ...
- 为什么在JDBC要使用Class.forName();这句话
为什么在调用JDBC的时候,我们总要写这句话:Class.forName("驱动类");解释:在JDBC编程中一般有以下几个步骤:1>加载驱动,也就是Class.forNam ...
- python 面向对象进阶之元类metaclass
一:知识储备 exec exec:三个参数 参数一:字符串形式的命令 参数二:全局作用域(字典形式),如果不指定,默认为globals() 参数三:局部作用域(字典形式),如果不指定,默认为local ...
- .NET之Dapper框架运用
Dapper框架 1.项目引用Dapper的Nuget程序包; 2.配置链接类 using System; using System.Collections.Generic; using System ...