Coder Social home page Coder Social logo

sabre-io / http Goto Github PK

View Code? Open in Web Editor NEW
187.0 187.0 62.0 798 KB

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

PHP 100.00%

http's People

Contributors

amrita-shrestha avatar c0pyr1ght avatar cedric-anne avatar christiaan avatar come-nc avatar danielruf avatar dartui avatar davidprevot avatar deepdiver1975 avatar dependabot[bot] avatar derkostka avatar dominikto avatar dpakach avatar dratini0 avatar evert avatar fredrik-eriksson avatar hywan avatar icewind1991 avatar jakobsack avatar jens1o avatar kesselb avatar lukasreschke avatar mrcnpdlk avatar petrkotek avatar phil-davis avatar remicollet avatar schoetju avatar staabm avatar vfreex avatar worksdev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

http's Issues

UTF-8 encoding detection fails on PHP 8.1

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;
}

Client can't handle headers that appear multiple times

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

Lost custom CURLOPT_HTTPHEADER headers in \Sabre\HTTP\Client

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;

Re-using the cURL handle breaks all but the first request

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.

HTTP Cookie

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?

Problem after PUT request with stream resource

DESCRIPTION

After PUT request with stream resource, the following problems occured.

  1. The following warning occured on next request.

Warning: curl_exec(): CURLOPT_INFILE resource has gone away, resetting to default in ...

  1. If next request is PROPFIND, it hangs.

HOW TO REPRODUCE

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

COMMENT

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.

Unknown scalar type

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.

* @param scalar $value

In the previous version (4.2) type was defined as string|string[]

CURLOPT_INFILESIZE curl header option

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

Download with short Content-Range sends too much data

Regression in 5.0.3

  1. Have a file where you want to download just a short Content-Range - e.g. file has "Ignore this. Send this. Ignore this too."
  2. Try to download just bytes 13-22 "Send this."

Expected: you get the string "Send this."

Actual: you get the string "Send this. Ignore this too."

issues with haproxy + nginx + fpm - need some help debugging this

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.

Move sendResponse and make it dynamic

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?

  • adding the 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:

  1. we can send the response to another output stream, like a file, a variable (with the appropriated stream wrapper)โ€ฆ
  2. ease mocking (it's not easy to mock static methods most of the time),
  3. ease testing.

Thoughts?

Question: Allowed memory size

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;

parseCurlResponse() cannot take NULL body

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

Basic auth: use UTF-8 by default

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.

do not download whole file from remote mounted cloud when user cancel it

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?

Error in getBodyAsString when content-length is set as a string.

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

lib/AuthAWS.php hmacsha1 does not get test coverage

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

CI fails for PHP 7.3 and 7.4

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.

https://travis-ci.org/github/sabre-io/http/jobs/732214026

Improve file size limits on 32 Bit systems

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 !

[Sabre\HTTP\ClientException (65)] necessary data rewind wasn't possible

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

Update `splitPath` performance?

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.

  1. Would you like to improve this method?
  2. If yes, is Unicode support important here (I am not sure since we just stop on /)?

4GB file size workaround for 32bit OS breaks video streaming in iOs clients

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.

Runtime HTTP class

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.

undefined function Sabre\\HTTP\\mb_detect_encoding()

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.

unit tests are finishing early in 5.1 branch

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()?

Make php-curl required

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.

HTTP Header Issues?

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.

cookie usage

May I know any future development or current usage of cookie in sabreio/http?

Proposal: tag PHP7+ version 5.0.0

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?

DAV\Client: Request body missing on PROPFIND after HEAD request

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.

sending json

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

Generic decorator

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;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.