Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] 使用webdav put方法chunked形式上传文件时,因Content-Length值的问题导致返回405 #5161

Closed
4 tasks done
fregie opened this issue Sep 4, 2023 · 3 comments · Fixed by #5162
Closed
4 tasks done
Labels
bug Something isn't working

Comments

@fregie
Copy link
Contributor

fregie commented Sep 4, 2023

Please make sure of the following things

  • I have read the documentation.
    我已经阅读了文档

  • I'm sure there are no duplicate issues or discussions.
    我确定没有重复的issue或讨论。

  • I'm sure it's due to AList and not something else(such as Network ,Dependencies or Operational).
    我确定是AList的问题,而不是其他原因(例如网络依赖操作)。

  • I'm sure this issue is not fixed in the latest version.
    我确定这个问题在最新版本中没有被修复。

AList Version / AList 版本

v3.27.0

Driver used / 使用的存储驱动

any

Describe the bug / 问题描述

使用webdav上传文件时,当content的内容长度未知时,会使用chunked模式来上传,这种情况下header中不会填写Content-Length,但在alist的http处理中(不确定是Gin还是net.http的行为)会把http.Request.ContentLength置为-1.

于是在这段代码中pkg/utils/file.go:
size的最终实际取值是http.Request.ContentLength,即-1,导致返回了错误.
我建议将size != 0修改为size > 0,以支持chunked模式

// CreateTempFile create temp file from io.ReadCloser, and seek to 0
func CreateTempFile(r io.Reader, size int64) (*os.File, error) {
        ....
	if size != 0 && readBytes != size {
		_ = os.Remove(f.Name())
		return nil, errs.NewErr(err, "CreateTempFile failed, incoming stream actual size= %d, expect = %d ", readBytes, size)
	}
	....
	return f, nil
}

同时建议internal/stream/stream.go中的FileStreamGetSize()方法,如果已经存了临时文件就先取临时文件的长度,以减少以上场景取到无效的Size.像这样:

type FileStream struct {
	Ctx context.Context
	model.Obj
	io.Reader
	Mimetype     string
	WebPutAsTask bool
	Exist        model.Obj //the file existed in the destination, we can reuse some info since we wil overwrite it
	utils.Closers
	tmpFile  *os.File //if present, tmpFile has full content, it will be deleted at last
	peekBuff *bytes.Reader
}

func (f *FileStream) GetSize() int64 {
	if f.tmpFile != nil {
		info, err := f.tmpFile.Stat()
		if err == nil {
			return info.Size()
		}
	}
	return f.Obj.GetSize()
}

我愿意提一个PR来修改这个问题

Reproduction / 复现链接

Config / 配置

Logs / 日志

ERRO[2023-09-04 08:52:19] PUT /dav/quark/photos/2023/09/02/20230902012905_20230902_132905.JPG %!w(<nil>); CreateTempFile failed, incoming stream actual size= 2786239, expec
t = -1                                                                                github.com/alist-org/alist/v3/internal/op.Put                                         
        /app/internal/op/fs.go:566                                                    
@fregie fregie added the bug Something isn't working label Sep 4, 2023
@SeanHeuc
Copy link
Contributor

SeanHeuc commented Sep 4, 2023

FileStream getSize 不应该从临时文件的大小来拿,你这个场景我觉得应该在CreateTempFile特殊处理size=-1的场景,tmpfile本地存完了之后可以把size赋值给Obj。

另:不知道你什么使用场景,目前几乎全部的软件都支持上传时给出content-length, 如果不给的话很容易网络不稳造成文件不完整,不推荐这种方式上传

@fregie
Copy link
Contributor Author

fregie commented Sep 4, 2023

@SeanHeuc
场景: 类似文件转存的场景,数据流转发,实际上也能得到文件的长度,但是我认为alist仍然应该支持chunked形势的http请求

关于Content-Length: chunked并不是真的不发内容长度,而是放在了body里,所以也没有你说的完整性的问题

在哪里获取文件长度:我认为两种方式都可行。但是你说的方法要向结构体加一个字段来存这个值,因为GetSize方法是从Obj这个接口获取到的

xhofe pushed a commit that referenced this issue Sep 5, 2023
But we do not recommend not adding the content-length header when putting files
@9-2-1
Copy link

9-2-1 commented Sep 19, 2023

FileStream getSize 不应该从临时文件的大小来拿,你这个场景我觉得应该在CreateTempFile特殊处理size=-1的场景,tmpfile本地存完了之后可以把size赋值给Obj。

另:不知道你什么使用场景,目前几乎全部的软件都支持上传时给出content-length, 如果不给的话很容易网络不稳造成文件不完整,不推荐这种方式上传

kopia 是个例外。kopia 必须套一层 rclone 才能正常上传

另外 chunked 模式最后需要发送一个终止信号(0长度的chunk)代表传输完成,正常情况下不会出现“传一半断开被判为完成”的情况,不知道 alist 有没有处理

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants