sabre-io / http Goto Github PK
View Code? Open in Web Editor NEWThe sabre/http library provides utilities for dealing with http requests and responses.
Home Page: http://sabre.io/http/
License: BSD 3-Clause "New" or "Revised" License
The sabre/http library provides utilities for dealing with http requests and responses.
Home Page: http://sabre.io/http/
License: BSD 3-Clause "New" or "Revised" License
MD5 is cryptographically broken and unsuitable for further use. Please do not use it as default built-in hashing for validation of passwords.
See also: https://www.php.net/manual/en/faq.passwords.php#faq.passwords.fasthash
Hello
Someone openned an issue at Nextcloud signaling that creating a folder with special character broke when using PHP 8.1.
It appears that this comes from mb_detect_encoding changes in PHP 8.1 that end up detecting ISO-8859-1 instead of UTF-8
The code handling this is the same as the one in you decodePathSegment at https://github.com/sabre-io/http/blob/master/lib/functions.php#L404
You can see the behavior here: https://3v4l.org/IT9dJ
It feels we should not be trying to detect encoding here but maybe assume UTF-8, or only check with mb_check_encoding (which does return true for UTF-8).
What is the reason for this test, are some dav client sending ISO-8859-1? Is that allowed by webdav protocol?
Would this be ok instead:
/**
* Decodes a url-encoded path segment.
*/
function decodePathSegment(string $path): string
{
$path = rawurldecode($path);
if (!mb_check_encoding($path, 'UTF-8') && mb_check_encoding($path, 'ISO-8859-1')) {
$path = utf8_encode($path);
}
return $path;
}
I have run into an issue with your handy HTTP client. If a header appears more than once, only the last value will be taken into account. Seems that RFC2616 allows multiple headers with the same name if they contain comma-separated values.
Consider the following DAV header(s):
DAV: 1, 2, 3, access-control, calendar-access, calendar-schedule
DAV: extended-mkcol, bind, addressbook, calendar-auto-schedule, calendar-proxy
When retrieved by the client, a getHeader('Dav')
will only return the last set of values:
array(5) {
[0]=>
string(14) "extended-mkcol"
[1]=>
string(4) "bind"
[2]=>
string(11) "addressbook"
[3]=>
string(22) "calendar-auto-schedule"
[4]=>
string(14) "calendar-proxy"
}
This happens on sabre/http 2.0.4
If i set custom CURLOPT_HTTPHEADER in \Sabre\HTTP\Client:426 them purged.
if(isset($settings[CURLOPT_HTTPHEADER]))
$settings[CURLOPT_HTTPHEADER] = array_merge((array)$settings[CURLOPT_HTTPHEADER], $nHeaders);
else
$settings[CURLOPT_HTTPHEADER] = $nHeaders;
As for 4.0.0 some functions from these classes got moved to better locations, but a few stayed behind. Lets move those as well before we release 4.0.0 as stable.
I am using SabreDAV 2.0.5 with Sabre HTTP 2.0.4 on PHP 5.6 (Win x64). This is my test code, which should just check if a file exists (expected to 404) and then create it:
require 'vendor/autoload.php';
$client = new Sabre\DAV\Client(array(
'baseUri' => 'http://my.webdav.host/',
'proxy' => 'http://127.0.0.1:8888/' // for debugging with Fiddler
));
$client->request('HEAD', '/foo.txt'); // throws NotFound exception, as expected
$client->request('PUT', '/foo.txt', 'my content');
We are -- for testing -- tunneling WebDAV through nginx. Unexpectedly, we get an HTTP 500 for the PUT request, because it looks like this in Fiddler
PUT http://my.webdav.host/foo.txt HTTP/1.1
Host: my.webdav.host
Accept: */*
Connection: Keep-Alive
There is no content and no Content-Length
header, making the nginx barf.
I traced the problem down to the Sabre\HTTP\Client
class and its recycling of the cURL handle.
protected function doRequest(RequestInterface $request) {
$settings = $this->createCurlSettingsArray($request);
if (!$this->curlHandle) {
$this->curlHandle = curl_init();
}
// ...snip...
}
If I disable the if
and always recreate a new cURL handle, everything works as expected.
Since the curlHandle
is private, I have very little chance to work around this except creating a new SabreDAV client for every single request.
I am trying to use sabreio/http to develop my own php framework, I not see any convenient method to send and receive cookie from Response API. May I know any easy way to implement it?
After PUT request with stream resource, the following problems occured.
Warning: curl_exec(): CURLOPT_INFILE resource has gone away, resetting to default in ...
My test program is as follows:
<?php
require_once 'vendor/autoload.php';
use Sabre\HTTP;
$url = 'http://example.net/webdav/foo';
$client = new HTTP\Client();
$client->on('beforeRequest', function ($request) {
$request->setHeader('Authorization', 'Basic '.base64_encode('username:password'));
});
// request 1
$stream = tmpfile();
$request1 = new HTTP\Request('PUT', $url, null, $stream);
$response1 = $client->send($request1);
fclose($stream);
printf("response1: %d\n", $response1->getStatus());
// request 2
$header = [
'Depth' => 0,
'Content-Type' => 'application/xml'
];
$body = <<<BODY
<?xml version="1.0" encoding="UTF-8"?>
<d:propfind xmlns:d="DAV:">
<d:prop>
<d:displayname/>
<d:getcontentlength/>
<d:getcontenttype/>
<d:getlastmodified/>
</d:prop>
</d:propfind>
BODY;
$request2 = new HTTP\Request('PROPFIND', $url, $header, $body);
$response2 = $client->send($request2);
printf("response2: %d\n", $response2->getStatus());
% php test.php
response1: 201
PHP Warning: curl_exec(): CURLOPT_INFILE resource has gone away, resetting to default in /home/matsui/src/sabre-http-test/vendor/sabre/http/lib/Client.php on line 578
^C
I tried it on ubuntu and mac, but both were the same result.
Mac:
PHP 7.1.10
cURL 7.54.0
sabre/http 4.2.3
Ubuntu:
PHP 7.0.22-0ubuntu0.16.04.1
cURL 7.47.0
sabre/http 4.2.3
I think the root cause is the problem of initialization when curl handle is reused, which was discussed in #35, #47. The last problem was fixed with 6b06c03, but this time it is covered by CURLOPT_INFILE which is not included in the previous fix.
In my environment, this problem seems to be solved by modifying doRequest function of \Sabre\HTTP\Client class to do curl_reset() when re-using curl handle.
However, curl_reset was added since PHP 5.5 and is not available in PHP 5.4.
When PHP's open_basedir setting is on, using curls FOLLOW_LOCATION
will fail with an error.
This has caused issues for a number of people, and has been mentioned in the following issues:
Lets fix this.
Moved from here:
After upgrade to 5.0 my IDE (PHP Storm) shows me a warning:
Expected \Sabre\HTTP\scalar, got string Inspection info: Invocation parameter types are not compatible with declared.
Line 223 in 3577f01
In the previous version (4.2) type was defined as string|string[]
Hi there. We've recently encountered a problem in connecting the sabre dav client with an owncloud server, it seems that when we pass the body of Request as a php stream resource, the CURLOPT_INFILE is being set in this file
https://github.com/sabre-io/http/blob/master/lib/Client.php
$settings[CURLOPT_PUT] = true;
$settings[CURLOPT_INFILE] = $request->getBody();
but the CURLOPT_INFILESIZE is not added to it, the result being that the uploaded file has 0 bytes in size.
If i add the missing code as:
$file_stats = fstat($settings[CURLOPT_INFILE]);
if( isset($file_stats['size']) ) {
$settings[CURLOPT_INFILESIZE] = $file_stats['size'];
}
then the upload works ok. It works however if we set the target webdav server to yandex for instance, i am guessing they do not process the CURLOPT_INFILESIZE header.
Would you consider implementing this option or accepting a pull request? Thank you
Regression in 5.0.3
Content-Range
- e.g. file has "Ignore this. Send this. Ignore this too."Expected: you get the string "Send this."
Actual: you get the string "Send this. Ignore this too."
hi,
i have a nextcloud instance running behind a pfsense haproxy:
[client] -- https --> [haproxy] -- http --> [nginx] -- fpm --> [nextcloud]
and i am seeing stalled uploads and this:
Error | no app in context |
Sabre\DAV\Exception\BadRequest: Expected filesize of 1724803 bytes but read (from Nextcloud client) and wrote (to Nextcloud storage) 40960 bytes. Could either be a network problem on the sending side or a problem writing to the storage on the server side.
/var/www/html/apps/dav/lib/Connector/Sabre/Directory.php - line 156:
OCA\DAV\Connector\Sabre\File->put(null)
/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php - line 1098:
OCA\DAV\Connector\Sabre\Directory->createFile(" --- filename --- ", null)
/var/www/html/3rdparty/sabre/dav/lib/DAV/CorePlugin.php - line 504:
Sabre\DAV\Server->createFile(" --- filename --- ", null, null)
/var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php - line 89:
Sabre\DAV\CorePlugin->httpPut(Sabre\HTTP\Request {}, Sabre\HTTP\Response {})
/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php - line 472:
Sabre\DAV\Server->emit("method:PUT", [ Sabre\HTTP ... }])
/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php - line 253:
Sabre\DAV\Server->invokeMethod(Sabre\HTTP\Request {}, Sabre\HTTP\Response {})
/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php - line 321: Sabre\DAV\Server->start()
/var/www/html/apps/dav/appinfo/v1/webdav.php - line 84:
Sabre\DAV\Server->exec()/var/www/html/remote.php - line 167: require_once("/var/www/ht ... p")
-- | -- | --
the only combination of settings that i have found to work thus far is smaller chunks (<32k) and "option forceclose" in haproxy. i am pretty sure something is going wrong in between haproxy and nginx, and i am assuming something along the lines of a mismatch between size in header size in body - but i am not entirely sure how to approach debugging this.
See:
http://evertpot.com/fpassthru-broken/
Reported here:
Needs to be backported to sabre/dav as well.
Hello :-),
Sapi::sendResponse
disturbs me. I understand why it is static hereโฆ but it might not be the right place for this method.
What about reversing it?
Response::send(OutputStream)
method,Sapi
becomes an OutputStream
.To not break the BC, the OutputStream
interface can define the sendResponse
method.
Why this change?
Because:
Thoughts?
TypeError: Argument 2 passed to Sabre\HTTP\Client::parseCurlResponse() must be of the type string, null given
I am using sabre\dav and sabre\client to send large files to another host, but the response I have got the following error
Allowed memory size of 134217728 bytes exhausted (tried to allocate 31860068 bytes)
I have investigated and have found that the error comes from Sabre\HTTP\Client:499
$headerBlob = substr($response, 0, $curlInfo['header_size']);
$responseBody = substr($response, $curlInfo['header_size']) ?: null;
https://drone.owncloud.com/owncloud/core/20613/25/10
PHPUnit 6.5.14 by Sebastian Bergmann and contributors.
Runtime: PHPDBG 7.1.30-1+ubuntu16.04.1+deb.sury.org+1
Configuration: /drone/src/tests/phpunit-autotest-external.xml
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE 65 / 85 ( 76%)
EEEEEEEEEEEEEEEEEEEE 85 / 85 (100%)
Time: 8.17 seconds, Memory: 34.00MB
There were 85 errors:
1) OCA\Files_External\Tests\Storage\WebdavTest::testRoot
TypeError: Argument 2 passed to Sabre\HTTP\Client::parseCurlResponse() must be of the type string, null given, called in /drone/src/lib/composer/sabre/http/lib/Client.php on line 547
/drone/src/lib/composer/sabre/http/lib/Client.php:457
/drone/src/lib/composer/sabre/http/lib/Client.php:547
/drone/src/lib/composer/sabre/http/lib/Client.php:432
/drone/src/lib/composer/sabre/http/lib/Client.php:325
/drone/src/lib/composer/sabre/http/lib/Client.php:114
/drone/src/lib/composer/sabre/dav/lib/DAV/Client.php:372
/drone/src/lib/private/Files/Storage/DAV.php:678
/drone/src/lib/private/Files/Storage/DAV.php:188
/drone/src/apps/files_external/tests/Storage/WebdavTest.php:57
It looks like https://github.com/sabre-io/http/blob/5.0.1/lib/Client.php#L532
$responseBody = substr($response, $curlInfo['header_size']) ?: null;
can cause $responseBody
to be NULL
and that gets passed to
return $this->parseCurlResponse($headerBlob, $responseBody, $curlHandle);
but parseCurlResponse
has:
protected function parseCurlResponse(array $headerLines, string $body, $curlHandle): array
and in this case $body
is null
, not a string.
This "null body" edge case seems to have been missed in the refactoring done in PR #115
In the past (since RFC 2617), there have been difficulties with non-US-ASCII characters in Basic auth credentials. Some clients use ISO-8859-1, some use UTF-8, and so on the server side. In reality, only US-ASCII characters are usable expect for proprietary solutions where clients and servers are tailored together.
Since RFC 7617, it's clear that UTF-8 is the future.
requireLogin()
: Please send Basic realm="โฆ",charset="UTF-8"
(see RFC 7617) on the server side in the 401 response, so that clients know that the server expects UTF-8 credentials.getCredentials()
: Make sure that UTF-8 credentials are understood correctly.This is based on
nextcloud/server#5279
if i have locally mounted remote drive,
for example rclone is mounting as fuse fs google drive to /local_folder
and when in nextcloud i start to download some big file,
and when i cancel it
php script still works, still is reading from google drive.
I think its probably because of sabre http sapi wants to immediately load whole big post data into input and read from it
as seen here:
https://github.com/fruux/sabre-http/blob/master/lib/Sapi.php
lines 50 - 53
$r = self::createFromServerArray($serverArr);
$r->setBody(fopen('php://input', 'r'));
$r->setPostData($_POST);
return $r;
How to do it that when user cancels downloads, it will stop, not still read?
From @memmaker on December 25, 2016 22:2
The current release version of SabreDAV bundles a faulty version of sabre-http (4.2.1).
If PHP is set to print out warnings, this release of sabre-http produces warnings in the output if a content-length header has been set, thus rendering the XML output invalid:
stream_get_contents() expects parameter 2 to be integer, string given in /code/vendor/sabre/http/lib/Message.php on line 81
Current versions of sabre-http have fixed this bug by casting the content-length to int.
If we could have the current composer file of SabreDAV pointing to a fixed release, this would not be an issue anymore.
Copied from original issue: fruux/sabre-dav#926
The method is:
/**
* Generates an HMAC-SHA1 signature.
*/
private function hmacsha1(string $key, string $message): string
{
if (function_exists('hash_hmac')) {
return hash_hmac('sha1', $message, $key, true);
}
$blocksize = 64;
if (strlen($key) > $blocksize) {
$key = pack('H*', sha1($key));
}
$key = str_pad($key, $blocksize, chr(0x00));
$ipad = str_repeat(chr(0x36), $blocksize);
$opad = str_repeat(chr(0x5C), $blocksize);
$hmac = pack('H*', sha1(($key ^ $opad).pack('H*', sha1(($key ^ $ipad).$message))));
return $hmac;
}
IMO https://www.php.net/manual/en/function.hash-hmac.php exists in CI, and so it is used, and the subsequent code that has a "manual" implementation of hash_hmac
never gets run during the unit tests.
https://www.php.net/manual/en/hash.installation.php
"As of PHP 7.4.0, the Hash extension is a core PHP extension, so it is always enabled."
So, IMO, we can remove the function_exists
check, and the "manual" implementation, and just directly call hash_hmac
See demo PR #156
And Travis logs:
https://travis-ci.org/github/sabre-io/http/jobs/732214024
$ if [ $RUN_PHPSTAN == "FALSE" ]; then php vendor/bin/phpunit --configuration tests/phpunit.xml $WITH_COVERAGE; fi
PHPUnit 9.4.0 by Sebastian Bergmann and contributors.
Warning: Your XML configuration validates against a deprecated schema.
Suggestion: Migrate your XML configuration using "--migrate-configuration"!
.............................F................................. 63 / 158 ( 39%)
............................................................... 126 / 158 ( 79%)
................................ 158 / 158 (100%)
Time: 00:13.094, Memory: 56.00 MB
There was 1 failure:
1) Sabre\HTTP\ClientTest::testSendToGetLargeContent
Failed asserting that 41943040 is greater than 49558920.
/home/travis/build/sabre-io/http/tests/HTTP/ClientTest.php:215
FAILURES!
Tests: 158, Assertions: 288, Failures: 1.
When I play large video files, moving seekbar of those files or loading a number of thumbnails of photos php-fpm processes stay and don't disappear. It caused php error saying "server reached php-max_children" and timeout.
This will be solved by changing a configuration if ($copied <= 0) {
to if ($copied <= 0 || connection_aborted()) {
in a file named Sapi.php.
In Owncloud and Nextcloud, which are using sabre-http, one drawback is, that downloading big files failes on 32 Bit machines. Many machines with 32 Bit architecture are SBCs, such as Raspberry Pi and Odroid devices.
With the related patch, the function stream_copy_to_stream is replaced by a chunked process, to overcome that issue.
Please take over this patch to improve greatly for 32 Bit systems, for the time beeing ...
Patch:
#74
Details:
nextcloud/server#1707
owncloud/core#23788
Thanks !
Hi,
First of all thanks your work.
I use this package for a longtime along with backup-manager/backup-manager but it stop working since 7 october.
I have try to find a reason to this date (new release of any package that i use) but this is not related because i have go back in my git history and make clean install, and the same error happen.
here is the stack trace :
In Client.php line 327:
[Sabre\HTTP\ClientException (65)]
necessary data rewind wasn't possible
Exception trace:
at /var/www/vendor/sabre/http/lib/Client.php:327
Sabre\HTTP\Client->doRequest() at /var/www/vendor/sabre/http/lib/Client.php:114
Sabre\HTTP\Client->send() at /var/www/vendor/sabre/dav/lib/DAV/Client.php:367
Sabre\DAV\Client->request() at /var/www/vendor/league/flysystem-webdav/src/WebDAVAdapter.php:151
League\Flysystem\WebDAV\WebDAVAdapter->write() at /var/www/vendor/league/flysystem-webdav/src/WebDAVAdapter.php:171
League\Flysystem\WebDAV\WebDAVAdapter->writeStream() at /var/www/vendor/league/flysystem/src/Filesystem.php:88
League\Flysystem\Filesystem->writeStream() at /var/www/vendor/backup-manager/backup-manager/src/Tasks/Storage/TransferFile.php:45
BackupManager\Tasks\Storage\TransferFile->execute() at /var/www/vendor/backup-manager/backup-manager/src/Procedures/Sequence.php:29
BackupManager\Procedures\Sequence->execute() at /var/www/vendor/backup-manager/backup-manager/src/Procedures/BackupProcedure.php:66
Have you any idea on how to solve this problem ?
Thanks
Hello :-),
I have noticed (while reading the code) that the URLUtil::spliPath
method is used a lot. Thus, I was wondering if preg_match
was performant enough in this very simple case. Here is my 5mn benchmarkยฎ:
<?php
require '/usr/local/lib/Hoa/Core/Core.php';
use Hoa\Bench;
$bench = new Bench();
const N = 1000000;
const STR = '/foo/bar/baz/qux';
$bench->pregu->start();
for($n = N - 1; $n >= 0; --$n)
preg_match('/^(?:(.*)\/+)?([^\/]+)\/?$/u', STR, $matches);
$bench->pregu->stop();
$bench->preg->start();
for($n = N - 1; $n >= 0; --$n)
preg_match('/^(?:(.*)\/+)?([^\/]+)\/?$/', STR, $matches);
$bench->preg->stop();
$bench->mbsubstring->start();
for($n = N - 1; $n >= 0; --$n) {
$string = rtrim(STR, '/');
if(false !== $pos = mb_strrpos($string, '/'))
$matches = [
mb_substr($string, 0, $pos),
mb_substr($string, $pos + 1)
];
else
$matches = [
null,
$string
];
}
$bench->mbsubstring->stop();
$bench->substring->start();
for($n = N - 1; $n >= 0; --$n) {
$string = rtrim(STR, '/');
if(false !== $pos = strrpos($string, '/'))
$matches = [
substr($string, 0, $pos),
substr($string, $pos + 1)
];
else
$matches = [
null,
$string
];
}
$bench->substring->stop();
echo $bench;
Here is the result:
__global__ ||||||||||||||||||||||||||||||||||||||||||||||||||| 4995ms, 100.0%
pregu |||||||||||||| 1409ms, 28.2%
preg ||||||||||||| 1289ms, 25.8%
mbsubstring |||||||||||||| 1358ms, 27.2%
substring |||||||||| 939ms, 18.8%
Using the substring
algorithm is 1.5 faster than the existing algorithm, namely pregu
.
/
)?Using Sabredav embeded with Nextcloud 13 (v4.2.3), on a RPI3 Raspbian stretch server (32bit OS). Webserver is Nginx 1.14.0, fastcgi php-fpm 7.0.30.
Video playback in iOs requires partial content requests (range) support.
When starting a Video playback , from the Nextcloud iOs app (>v2.22) or from the Nextcloud Web UI within iOS Safari browser, both clients start with a partial content GET request of the first 2 bytes.
The #74 change ignores the Content-Length header info, resulting in a response body with the entire video file, but with response headers saying "range: bytes 0-1/filesize" and "content-length: 2".
This mismatch in response information headers and body content is not supported by the iOs client. The client breaks the connection and won't play any image.
Hello :-),
Is it interesting to have a runtime HTTP class like Hoa\Http\Runtime
? It allows to have the getMethod
, getUri
, getData
(useful), getHeaders
methods and so on. This is a read-only object.
Note: such class could return a Sabre\Http\Request
object.
Hello,
I don't know if this is the right place to post that, but I'm currently trying to set up a CalDAV server using sabre/dav/calendarserver.php with apache2. When I enter the URL in a browser, it does nothing but "displaying" a blank page. So if i go to the apache error log file, I get this:
PHP Fatal error: Uncaught Error: Call to undefined function Sabre\\HTTP\\mb_detect_encoding() in /var/www/sabredav/vendor/sabre/http/lib/functions.php:434\nStack trace:\n#0 /var/www/sabredav/vendor/sabre/http/lib/functions.php(421): Sabre\\HTTP\\decodePathSegment('/calendarserver...')\n#1 /var/www/sabredav/vendor/sabre/http/lib/URLUtil.php(59): Sabre\\HTTP\\decodePath('/calendarserver...')\n#2 /var/www/sabredav/vendor/sabre/dav/lib/DAV/Server.php(379): Sabre\\HTTP\\URLUtil::decodePath('/calendarserver...')\n#3 /var/www/sabredav/vendor/sabre/dav/lib/DAV/Server.php(349): Sabre\\DAV\\Server->guessBaseUri()\n#4 /var/www/sabredav/vendor/sabre/dav/lib/DAV/Server.php(253): Sabre\\DAV\\Server->getBaseUri()\n#5 /var/www/sabredav/calendarserver.php(80): Sabre\\DAV\\Server->exec()\n#6 {main}\n thrown in /var/www/sabredav/vendor/sabre/http/lib/functions.php on line 434
I'm using:
- PHP 7.3.19-1~deb10u1
- the latest sabre/* versions
- Apache/2.4.38 (Raspbian)
Any idea on the problem? Let me know if you need more intel.
It falls back to 1.1.
https://github.com/fruux/sabre-http/blob/master/lib/Sapi.php#L134-L136
Happy to provide a pr when you want it to be fixed.
https://github.com/sabre-io/http/actions/runs/5891207873/job/15977804886
PHPUnit 9.6.10 by Sebastian Bergmann and contributors.
Warning: Your XML configuration validates against a deprecated schema.
Suggestion: Migrate your XML configuration using "--migrate-configuration"!
............................................................... 63 / 167 ( 37%)
...array(1) {
[0]=>
string(17) "invalid_mime_type"
}
This comes from the unit test:
public function testParseMimeTypeOnInvalidMimeType()
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Not a valid mime-type: invalid_mime_type');
parseMimeType('invalid_mime_type');
}
and that exercises the code in lib/functions.php
parseMimeType()
$mimeType = explode('/', $mimeType);
if (2 !== count($mimeType)) {
// Illegal value
var_dump($mimeType);
exit();
// throw new InvalidArgumentException('Not a valid mime-type: '.$str);
}
The output is caused by the var_dump
and the unit test run seems to stop there because of the exit()
Why does that code do an exit()
?
If using release 5.0.0 with sabre/uri 2.1.0 and sabre/event 5.0.3 i get the following error " Uncaught Error: Class 'Sabre\HTTP\URLUtil' not found".
I think composer should alert you, when you're installing this package and don't have php-curl extension installed, cause if you don't, that causes weird behaviour while creating Sabre\HTTP\Client.
After spending a few days fighting to get Sabredav running with Caddy (and a few other webservers) via php-fpm, I noticed that I was struggling to get the server to work. I messed around with a bunch of stuff and I kept getting 5xx errors whenever I should have received 4xx or 207 statuses. I'm not sure if Caddy and other servers are just discarding the status responses that Sabredav is sending, or if the statuses are being composed incorrectly.
I spent the whole night digging around and hacked some edits to the Sabre\HTTP\Sapi class and figured out that either the headers are incorrectly formed or they're just incompatible with Caddy. I tweaked some of the code and ended up replacing all of the single quotes with double quotes and changed line 66 to:
header("Status: ".$response->getStatus()." ".$response->getStatusText());
I'm not a very proficient coder but this was enough to get Caddy + php 8.1.3 + php-fpm to appear to work correctly. I'm assuming that this probably breaks other headers that Sabredav (and everything using the sabre/http library) sets, but it gets the HTTP Status headers to work correctly.
Here's an example log entry I was getting before:
Mar 04 10:36:17 mail.server.tld caddy[1142361]: {"level":"error","ts":1646390177.6592603,"logger":"http.log.error","msg":"malformed MIME header: missing colon: \"HTTP/2.0 404 Not Found\"","request":{"remote_addr":"216.25.210.230:60265","proto":"HTTP/2.0","method":"GET","host":"calendar.server.tld","uri":"/pepsi","headers":{"Upgrade-Insecure-Requests":["1"],"Authorization":["Basic auth"],"Sec-Ch-Ua":["\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"99\", \"Google Chrome\";v=\"99\""],"Sec-Ch-Ua-Mobile":["?0"],"Sec-Ch-Ua-Platform":["\"Windows\""],"Sec-Fetch-Site":["none"],"User-Agent":["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Sec-Fetch-Dest":["document"],"Accept-Language":["en-US,en;q=0.9"],"Cache-Control":["max-age=0"],"Sec-Fetch-Mode":["navigate"],"Sec-Fetch-User":["?1"],"Accept-Encoding":["gzip, deflate, br"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","proto_mutual":true,"server_name":"calendar.server.tld"}},"duration":2.797615189,"status":502," err_id":"zbp0a19qv","err_trace":"reverseproxy.statusError (reverseproxy.go:886)"}
Caddy complains about a missing colon (and I guess never recognizes it as a status header) and just assumes that php-fpm is broken and returns a 502 error/status to the client. It ends up doing this for any error that isn't 200.
Hi there,
first of all, I love using this library, but I have one question:
Why don't you cache the result? String operations are really slow in php... That is something that bothers and worries me... If you mind changing it, I'll create a simple pr.
Regards and thanks
May I know any future development or current usage of cookie in sabreio/http?
Recent commits have switched to PHPUnit 6.x, which is only for PHP >=7.0. Can you tag a 5.0.0 release that officially drops PHP 5 support?
Moved from https://github.com/fruux/sabre-dav/issues/649
When using the Sabre\DAV\Client
to do a HEAD
request, followed by a PROPFIND
request, the latter fails because of a missing response body.
Reason for this problem is that the curl settings (including the CURLOPT_NOBODY
option) are not cleared/reset between requests.
Test case:
<?php
require 'vendor/autoload.php';
use Sabre\DAV;
$client = new Sabre\DAV\Client(
array(
'userName' => 'admin',
'password' => 'admin',
'baseUri' => 'http://wolke.bogo/remote.php/webdav/'
)
);
//check if file exists
$client->request('HEAD', 'Notes');
//then fetch properties
$res = $client->propFind('Notes', array('{DAV:}resourcetype'), 1);
var_dump($res);
?>
Result:
PHP Fatal error: Uncaught exception 'InvalidArgumentException' with message
'The body passed to parseMultiStatus could not be parsed. Is it really xml?'
This happens with sabre/dav 2.1.3
.
im building a podio client, which accepts json in post requests
so i put a json string in request body and expected it to work
then i wasted some time thinking podio is stupid, until i pasted the json in postman and sent it as raw json
to my surprise it worked
and as i look at your code, sabre doesn't allow this, because it automatically sets boy as postfields which is useless
Hello :-),
Is there a need for a generic decorator? I see that all decorators in sabre/http
are combined with interfaces, which is clever. A generic decorator (or we can also call it a dynamic decorator) would redirect all calls, static calls, sets, gets, issets and unsets to a subject (what you call inner
). Please, see the Decorator
trait below my message. Such a generic decorator works pretty well, except that, because of interfaces, we need to implement methods by hands, which is contradictory to the generic/dynamic approach ;-). However, for other methods that are not specified by an interface, this can be very useful and time saver.
Here is my proposal. Integrating this decorator either in sabre/http
or as a new library (it does not really matter, except if we can re-use it in other libraries).
Thoughts?
trait Decorator {
protected $decoratorSubject = null;
protected static $decoratorStaticSubject = null;
protected function setDecoratorSubject ( $subject ) {
$this->decoratorSubject = $subject;
static::setDecoratorStaticSubject(get_class($subject));
}
protected static function setDecoratorStaticSubject ( $subject ) {
static::$decoratorStaticSubject = $subject;
}
protected function getDecoratorSubject ( ) {
return $this->decoratorSubject;
}
protected static function getDecoratorStaticSubject ( ) {
return static::$decoratorStaticSubject;
}
public function __call ( $name, Array $arguments ) {
$_name = $name;
$subject = $this->getDecoratorSubject();
if(null === $subject)
throw new \RuntimeException(
'Decorator failed because subject class has not been yet defined.');
if(false === method_exists($subject, $_name)) {
$_name = '__call';
if(false === method_exists($subject, $_name))
throw new \RuntimeException(
'Method ' . $name . ' does not exist; cannot call it.');
}
return call_user_func_array(array($subject, $_name), $arguments);
}
public static function __callStatic ( $name, Array $arguments ) {
$_name = $name;
$subject = static::getDecoratorStaticSubject();
if(null === $subject)
throw new \RuntimeException(
'Decorator failed because subject class has not been yet defined.');
if(false === method_exists($subject, $_name)) {
$_name = '__callStatic';
if(false === method_exists($subject, $_name))
throw new \RuntimeException(
'Method ' . $name . ' does not exist; cannot call it.');
}
return call_user_func_array($subject . '::' . $_name, $arguments);
}
public function __set ( $name, $value ) {
$subject = $this->getDecoratorSubject();
if(null === $subject)
throw new \RuntimeException(
'Decorator failed because subject class has not been yet defined.');
if(false === property_exists($subject, $name)) {
if(true === method_exists($subject, '__set'))
return $subject->__set($name, $value);
throw new \RuntimeException(
'Attribute ' . $name . ' does not exist; cannot set it.');
}
return $subject->$name = $value;
}
public function __get ( $name ) {
$subject = $this->getDecoratorSubject();
if(null === $subject)
throw new \RuntimeException(
'Decorator failed because subject class has not been yet defined.');
if(false === property_exists($subject, $name)) {
if(true === method_exists($subject, '__get'))
return $subject->__get($name, $value);
throw new \RuntimeException(
'Attribute ' . $name . ' does not exist; cannot get it.');
}
return $subject->$name;
}
public function __isset ( $name ) {
$subject = $this->getDecoratorSubject();
if(null === $subject)
throw new \RuntimeException(
'Decorator failed because subject class has not been yet defined.');
if(false === property_exists($subject, $name)) {
if(true === method_exists($subject, '__isset'))
return $subject->__isset($name);
}
return isset($subject->$name);
}
public function __unset ( $name ) {
$subject = $this->getDecoratorSubject();
if(null === $subject)
throw new \RuntimeException(
'Decorator failed because subject class has not been yet defined.');
if(false === property_exists($subject, $name)) {
if(true === method_exists($subject, '__unset'))
return $subject->__unset($name);
throw new \RuntimeException(
'Attribute ' . $name . ' does not exist; cannot unset it.');
}
unset($subject->$name);
return;
}
public function __toString ( ) {
return $this->__call('__toString', array());
}
}
Usage example:
class C {
public $x = 42;
public function f ( ) {
return $this->ff();
}
protected function ff ( ) {
return __METHOD__;
}
public function g ( $x, $y ) {
return $this->f() . '(' . $x . ',' . $y . ')';
}
public static function s ( $x, $y ) {
return __METHOD__ . '(' . $x . ',' . $y . ')';
}
public function __toString ( ) {
return 'foobar';
}
}
class Cbis {
use Decorator;
public function __construct ( ) {
$this->setDecoratorSubject(new C());
}
}
$cb = new Cbis();
var_dump($cb->f());
var_dump($cb->g(1, 2));
var_dump($cb::s(1, 2));
var_dump($cb->x);
$cb->x = 43;
var_dump($cb->x);
var_dump(isset($cb->x));
unset($cb->x);
var_dump(isset($cb->x));
$cb->x = 7;
var_dump(isset($cb->x));
var_dump($cb->x);
echo $cb;
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.