This commit is contained in:
2022-12-30 20:52:41 +08:00
parent f933400535
commit d3a950b54d
47 changed files with 10444 additions and 2 deletions

46
doc/APPLE-Finder-hints.md Normal file
View File

@@ -0,0 +1,46 @@
# APPLE-FINDER-HINTS
The Apple Finder (and other subsystems) seem to probe for a few
files at the root of the filesystems to get a hint about the
behaviour they should show processing this filesystem.
It also looks for files with extra localization information in
every directory, and for resource fork data (the `._` files).
## FILES
- `.metadata_never_index`
prevents the system from indexing all of the data
- `.ql_disablethumbnails`
prevent the system from downloading all files that look like an
image or a video to create a thumbnail
- `.ql_disablecache`
not really sure but it sounds useful
The `.ql_` files are configuration for the "QuickLook" functionality
of the Finder.
The `.metadata_never_index` file appears to be a hint for the
Spotlight indexing system.
Additionally, the Finder probes for a `.localized` file in every
directory it encounters, and it does a PROPSTAT for every file
in the directory prefixed with `._`.
## OPTIMIZATIONS
For a macOS client we return the metadata for a zero-sized file if it
does a PROPSTAT of `/.metadata_never_index` or `/.ql_disablethumbnails`.
We always return a 404 Not Found for a PROPSTAT of any `.localized` file.
Furthermore, we disallow moving, removing etc of those files. The files
do not show up in a PROPSTAT of the rootdirectory.
If a PROPFIND with `Depth: 1` is done on a directory, we add the
directory pathname to an LRU cache, and the pathname of each file of
which the name starts with `._`. Since we then know which `._` files
exist, it is easy to return a fast 404 for PROPSTAT request for `._`
files that do not exist. The cache is kept consistent by checking
the timestamp on the parent directory, and a timeout.

57
doc/APPLE-doubleinfo.md Normal file
View File

@@ -0,0 +1,57 @@
# APPLEDOUBLEINFO
Normally, after asking for a directory listing (using PROPFIND with Depth: 1)
the macOS Finder will send a PROPFIND request for every file in the
directory, prefixed with ".\_". Even though it just got a complete directory
listing which doesn't list those files.
An optimization the Apple iDisk service makes, is that it sometimes
synthesizes those info files ahead of time. It then lists those synthesized
files in the PROPFIND response together with the <appledoubleheader> propery,
which is the contents of the ".\_file" (if it would be present) in base64.
It appears to only do this when the appledoubleinfo data is completely
basic and is 82 bytes of size.
This prevents the webdav clients from launching an additional PROPFIND
request for every file prefixed with ".\_".
Note that you cannot add an <appledoubleheader> propery to a PROPSTAT
element of a "file" itself, that's ignored, alas. macOS only accepts
it on ".\_" files.
There is not much information about this, but an Apple engineer mentioned it in
https://lists.apple.com/archives/filesystem-dev/2009/Feb/msg00013.html
There is a default "empty"-like response for a file that I found at
https://github.com/DanRohde/webdavcgi/blob/master/lib/perl/WebDAV/Properties.pm
So, what we _could_ do (but don't, yet) to optimize the macOS webdav client,
when we reply to PROPFIND:
- for each file that does NOT have a ".\_file" present
- we synthesize a virtual response
- for a virtual file with name ".\_file
- with size: 82 bytes
- that contains:
<DAV:prop xmlns:S="http://www.apple.com/webdav\_fs/props/">
<S:appledoubleheader>
AAUWBwACAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAACAAAAJgAAACwAAAAJAAAAMgAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
</S:appledoubleheader>
The contents of this base64 string are explained at
https://github.com/DanRohde/webdavcgi/blob/master/lib/perl/WebDAV/Properties.pm
... and they are:
```
appledoubleheader: Magic(4) Version(4) Filler(16) EntryCout(2)
EntryDescriptor(id:4(2:resource fork),offset:4,length:4)
EntryDescriptor(id:9 finder)... Finder Info(16+16)
namespace: http://www.apple.com/webdav\_fs/props/
content: MIME::Base64(pack('H\*', '00051607'. '00020000' . ( '00' x 16 ) .
'0002'. '00000002'. '00000026' . '0000002C'.'00000009'. '00000032' . '00000020' .
('00' x 32) ))
```

View File

@@ -0,0 +1,85 @@
# HTTP PUT-with-Content-Range support.
The [mod_dav](https://httpd.apache.org/docs/2.4/mod/mod_dav.html) module of
the [Apache web server](https://httpd.apache.org/) was one of the first
implementations of [Webdav](https://tools.ietf.org/html/rfc4918). Ever since
the first released version, it has had support for partial uploads using
the Content-Range header with PUT requests.
## A sample request
```text
PUT /file.txt
Content-Length: 4
Content-Range: bytes 3-6/*
ABCD
```
This request updates 'file.txt', specifically the bytes 3-6 (inclusive) to
`ABCD`.
There is no explicit support for appending to a file, that is simply done
by writing just past the end of a file. For example, if a file has size
1000, and you want to append 4 bytes:
```text
PUT /file.txt
Content-Length: 4
Content-Range: bytes 1000-1003/*
1234
```
## Apache `mod_dav` behaviour:
- The `Content-Range` header is required, and the syntax is `bytes START-END/LENGTH`.
- END must be bigger than or equal to START.
- LENGTH is parsed by Apache mod_dav, and it must either be a valid number
or a `*` (star), but mod_dav otherwise ignores it. Since it is not clearly
defined what LENGTH should be, always use `*`.
- Neither the start, nor the end-byte have to be within the file's current size.
- If the start-byte is beyond the file's current length, the space in between
will be filled with NULL bytes (`0x00`).
## Notes
- `bytes<space>`, _not_ `bytes=`.
- The `Content-Length` header is not required by the original Apache mod_dav
implementation. The body must either have a valid Content-Length, or it must
use the `Chunked` transfer encoding. It is *strongly encouraged* though to
include Content-Length, so that it can be validated against the range before
accepting the PUT request.
- If the `Content-Length` header is present, its value must be equal
to `END - START + 1`.
## Status codes
### The following status codes are used:
Status code | Reason
----------- | ------
200 or 204 | When the operation was successful
400 | Invalid `Content-Range` header
416 | If there was something wrong with the bytes, such as a `Content-Length` not matching with what was sent as the start and end bytes, or an end byte being lower than the start byte.
501 | Content-Range header present, but not supported.
## RECKOGNIZING PUT-with-Content-Range support (client).
There is no official way to know if PUT-with-content-range is supported by
a webserver. For a client it's probably best to do an OPTIONS request,
and then check two things:
- the `Server` header must contain the word `Apache`
- the `DAV` header must contain `<http://apache.org/dav/propset/fs/1>`.
In that case, your are sure to talk to an Apache webserver with mod_dav enabled.
## IMPLEMENTING PUT-with-Content-Range support (server).
Don't. Implement [sabredav-partialupdate](SABREDAV-partialupdate.md).
## MORE INFORMATION.
https://blog.sphere.chronosempire.org.uk/2012/11/21/webdav-and-the-http-patch-nightmare

View File

@@ -0,0 +1,108 @@
# HTTP PATCH support
This is a markdown translation of the document at
[http://sabre.io/dav/http-patch/](http://sabre.io/dav/http-patch/)
[© 2018 fruux GmbH](https://fruux.com/)
The `Sabre\\DAV\\PartialUpdate\\Plugin` from the Sabre DAV library provides
support for the HTTP PATCH method [RFC5789](http://tools.ietf.org/html/rfc5789).
This allows you to update just a portion of a file, or append to a file.
This document can be used as a spec for other implementors. There is some
DAV-specific stuff in this document, but only in relation to the OPTIONS
request.
## A sample request
```
PATCH /file.txt
Content-Length: 4
Content-Type: application/x-sabredav-partialupdate
X-Update-Range: bytes=3-6
ABCD
```
This request updates 'file.txt', specifically the bytes 3-6 (inclusive) to
`ABCD`.
If you just want to append to an existing file, use the following syntax:
```
PATCH /file.txt
Content-Length: 4
Content-Type: application/x-sabredav-partialupdate
X-Update-Range: append
1234
```
The last request adds 4 bytes to the bottom of the file.
## The rules
- The `Content-Length` header is required.
- `X-Update-Range` is also required.
- The `bytes` value is the exact same as the HTTP Range header. The two numbers
are inclusive (so `3-6` means that bytes 3,4,5 and 6 will be updated).
- Just like the HTTP Range header, the specified bytes is a 0-based index.
- The `application/x-sabredav-partialupdate` must also be specified.
- The end-byte is optional.
- The start-byte cannot be omitted.
- If the start byte is negative, it's calculated from the end of the file. So
`-1` will update the last byte in the file.
- Use `X-Update-Range: append` to add to the end of the file.
- Neither the start, nor the end-byte have to be within the file's current size.
- If the start-byte is beyond the file's current length, the space in between
will be filled with NULL bytes (`0x00`).
- The specification currently does not support multiple ranges.
- If both start and end offsets are given, than both must be non-negative, and
the end offset must be greater or equal to the start offset.
## More examples
The following table illustrates most types of requests and what the end-result
of them will be.
It is assumed that the input file contains `1234567890`, and the request body
always contains 4 dashes (`----`).
X-Update-Range header | Result
--------------------- | -------
`bytes=0-3` | `----567890`
`bytes=1-4` | `1----67890`
`bytes=0-` | `----567890`
`bytes=-4` | `123456----`
`bytes=-2` | `12345678----`
`bytes=2-` | `12----7890`
`bytes=12-` | `1234567890..----`
`append` | `1234567890----`
Please note that in the `bytes=12-` example, we used dots (`.`) to represent
what are actually `NULL` bytes (so `0x00`). The null byte is not printable.
## Status codes
### The following status codes should be used:
Status code | Reason
----------- | ------
200 or 204 | When the operation was successful
400 | Invalid `X-Update-Range` header
411 | `Content-Length` header was not provided
415 | Unrecognized content-type, should be `application/x-sabredav-partialupdate`
416 | If there was something wrong with the bytes, such as a `Content-Length` not matching with what was sent as the start and end bytes, or an end byte being lower than the start byte.
## OPTIONS
If you want to be compliant with SabreDAV's implementation of PATCH, you must
also return 'sabredav-partialupdate' in the 'DAV:' header:
```
HTTP/1.1 204 No Content
DAV: 1, 2, 3, sabredav-partialupdate, extended-mkcol
```
This is only required if you are adding this feature to a DAV server. For
non-webdav implementations such as REST services this is optional.