Merge pull request #7947 from wallabag/migrate-from-guzzle-to-symfony-httpclient

Migrate from Guzzle to Symfony HttpClient
This commit is contained in:
Kevin Decherf 2025-02-17 11:06:02 +01:00 committed by GitHub
commit 8e0b9d4d94
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 661 additions and 1303 deletions

View file

@ -32,7 +32,6 @@ class AppKernel extends Kernel
new BabDev\PagerfantaBundle\BabDevPagerfantaBundle(), new BabDev\PagerfantaBundle\BabDevPagerfantaBundle(),
new FOS\JsRoutingBundle\FOSJsRoutingBundle(), new FOS\JsRoutingBundle\FOSJsRoutingBundle(),
new OldSound\RabbitMqBundle\OldSoundRabbitMqBundle(), new OldSound\RabbitMqBundle\OldSoundRabbitMqBundle(),
new Http\HttplugBundle\HttplugBundle(),
new Sentry\SentryBundle\SentryBundle(), new Sentry\SentryBundle\SentryBundle(),
new Twig\Extra\TwigExtraBundle\TwigExtraBundle(), new Twig\Extra\TwigExtraBundle\TwigExtraBundle(),
new Symfony\WebpackEncoreBundle\WebpackEncoreBundle(), new Symfony\WebpackEncoreBundle\WebpackEncoreBundle(),

View file

@ -48,6 +48,10 @@ framework:
X-Accept: 'application/json' X-Accept: 'application/json'
request_html_function.client: request_html_function.client:
scope: '.*' scope: '.*'
browser.client:
scope: '.*'
verify_host: false
verify_peer: false
# Twig Configuration # Twig Configuration
twig: twig:
@ -452,17 +456,6 @@ sensio_framework_extra:
router: router:
annotations: false annotations: false
httplug:
clients:
wallabag:
factory: Wallabag\Helper\HttpClientFactory
config:
defaults:
timeout: 10
plugins: ['httplug.plugin.logger']
discovery:
client: false
# define custom entity so we can override length attribute to fix utf8mb4 issue # define custom entity so we can override length attribute to fix utf8mb4 issue
craue_config: craue_config:
entity_name: Wallabag\Entity\InternalSetting entity_name: Wallabag\Entity\InternalSetting

View file

@ -191,11 +191,17 @@ services:
tags: tags:
- { name: doctrine.event_subscriber } - { name: doctrine.event_subscriber }
psr18.wallabag.client:
class: Symfony\Component\HttpClient\Psr18Client
arguments:
$client: '@Wallabag\HttpClient\WallabagClient'
Graby\Graby: Graby\Graby:
arguments: arguments:
$config: $config:
error_message: '%wallabag.fetching_error_message%' error_message: '%wallabag.fetching_error_message%'
error_message_title: '%wallabag.fetching_error_message_title%' error_message_title: '%wallabag.fetching_error_message_title%'
$client: '@psr18.wallabag.client'
calls: calls:
- [ setLogger, [ "@logger" ] ] - [ setLogger, [ "@logger" ] ]
tags: tags:
@ -205,9 +211,6 @@ services:
arguments: arguments:
$config: {} $config: {}
wallabag.http_client:
alias: 'httplug.client.wallabag'
Wallabag\SiteConfig\GrabySiteConfigBuilder: Wallabag\SiteConfig\GrabySiteConfigBuilder:
tags: tags:
- { name: monolog.logger, channel: graby } - { name: monolog.logger, channel: graby }
@ -216,11 +219,9 @@ services:
Wallabag\SiteConfig\SiteConfigBuilder: Wallabag\SiteConfig\SiteConfigBuilder:
alias: Wallabag\SiteConfig\GrabySiteConfigBuilder alias: Wallabag\SiteConfig\GrabySiteConfigBuilder
GuzzleHttp\Cookie\CookieJar: ~ Symfony\Component\BrowserKit\HttpBrowser:
arguments:
Wallabag\Helper\HttpClientFactory: $client: '@browser.client'
calls:
- ['addSubscriber', ['@Wallabag\Guzzle\AuthenticatorSubscriber']]
RulerZ\RulerZ: RulerZ\RulerZ:
alias: rulerz alias: rulerz

View file

@ -29,8 +29,6 @@ $config
'mnapoli/piwik-twig-extension', 'mnapoli/piwik-twig-extension',
'ocramius/proxy-manager', 'ocramius/proxy-manager',
'pagerfanta/twig', 'pagerfanta/twig',
'php-http/client-common',
'php-http/httplug',
'php-http/mock-client', 'php-http/mock-client',
'phpstan/extension-installer', 'phpstan/extension-installer',
'phpstan/phpstan', 'phpstan/phpstan',
@ -39,13 +37,11 @@ $config
'phpstan/phpstan-symfony', 'phpstan/phpstan-symfony',
'psr/http-client', 'psr/http-client',
'psr/http-factory', 'psr/http-factory',
'psr/http-message',
'rulerz-php/doctrine-orm', 'rulerz-php/doctrine-orm',
'scheb/2fa-qr-code', 'scheb/2fa-qr-code',
'scheb/2fa-trusted-device', 'scheb/2fa-trusted-device',
'shipmonk/composer-dependency-analyser', 'shipmonk/composer-dependency-analyser',
'symfony/asset', 'symfony/asset',
'symfony/browser-kit',
'symfony/css-selector', 'symfony/css-selector',
'symfony/doctrine-bridge', 'symfony/doctrine-bridge',
'symfony/google-mailer', 'symfony/google-mailer',
@ -57,10 +53,8 @@ $config
'twig/string-extra', 'twig/string-extra',
], [ErrorType::UNUSED_DEPENDENCY]) ], [ErrorType::UNUSED_DEPENDENCY])
->ignoreErrorsOnPackages([ ->ignoreErrorsOnPackages([
'guzzlehttp/streams',
'monolog/monolog', 'monolog/monolog',
'symfony/filesystem', 'symfony/filesystem',
'symfony/http-client',
], [ErrorType::PROD_DEPENDENCY_ONLY_IN_DEV]) ], [ErrorType::PROD_DEPENDENCY_ONLY_IN_DEV])
->ignoreErrorsOnPackages([ ->ignoreErrorsOnPackages([
'dama/doctrine-test-bundle', 'dama/doctrine-test-bundle',

View file

@ -75,9 +75,7 @@
"friendsofsymfony/oauth-server-bundle": "dev-master#dc8ff343363cf794d30eb1a123610d186a43f162", "friendsofsymfony/oauth-server-bundle": "dev-master#dc8ff343363cf794d30eb1a123610d186a43f162",
"friendsofsymfony/rest-bundle": "^3.6", "friendsofsymfony/rest-bundle": "^3.6",
"friendsofsymfony/user-bundle": "^3.2.1", "friendsofsymfony/user-bundle": "^3.2.1",
"guzzlehttp/guzzle": "^5.3.4",
"guzzlehttp/psr7": "^2.6.2", "guzzlehttp/psr7": "^2.6.2",
"guzzlehttp/streams": "^3.0",
"html2text/html2text": "^4.3.1", "html2text/html2text": "^4.3.1",
"incenteev/composer-parameter-handler": "^2.2", "incenteev/composer-parameter-handler": "^2.2",
"j0k3r/graby": "^2.4.5", "j0k3r/graby": "^2.4.5",
@ -99,10 +97,6 @@
"pagerfanta/twig": "^3.8", "pagerfanta/twig": "^3.8",
"php-amqplib/php-amqplib": "^3.6.1", "php-amqplib/php-amqplib": "^3.6.1",
"php-amqplib/rabbitmq-bundle": "^2.14.0", "php-amqplib/rabbitmq-bundle": "^2.14.0",
"php-http/client-common": "^2.7.1",
"php-http/guzzle5-adapter": "^2.0",
"php-http/httplug": "^2.4",
"php-http/httplug-bundle": "^1.32",
"pragmarx/recovery": "^0.2.1", "pragmarx/recovery": "^0.2.1",
"predis/predis": "^2.2.2", "predis/predis": "^2.2.2",
"psr/http-client": "^1.0.3", "psr/http-client": "^1.0.3",
@ -122,6 +116,7 @@
"spiriitlabs/form-filter-bundle": "^10.0", "spiriitlabs/form-filter-bundle": "^10.0",
"stof/doctrine-extensions-bundle": "^1.11.0", "stof/doctrine-extensions-bundle": "^1.11.0",
"symfony/asset": "^5.4.35", "symfony/asset": "^5.4.35",
"symfony/browser-kit": "^5.4.35",
"symfony/config": "^5.4.35", "symfony/config": "^5.4.35",
"symfony/console": "^5.4.35", "symfony/console": "^5.4.35",
"symfony/dependency-injection": "^5.4.35", "symfony/dependency-injection": "^5.4.35",
@ -182,7 +177,6 @@
"phpstan/phpstan-symfony": "^1.3.7", "phpstan/phpstan-symfony": "^1.3.7",
"phpunit/phpunit": "^9.6.17", "phpunit/phpunit": "^9.6.17",
"shipmonk/composer-dependency-analyser": "^1.7", "shipmonk/composer-dependency-analyser": "^1.7",
"symfony/browser-kit": "^5.4.35",
"symfony/css-selector": "^5.4.35", "symfony/css-selector": "^5.4.35",
"symfony/debug-bundle": "^5.4.35", "symfony/debug-bundle": "^5.4.35",
"symfony/maker-bundle": "^1.43", "symfony/maker-bundle": "^1.43",

751
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "1f0877b1f0f7fc3b074786b51d772cb6", "content-hash": "a85056bec7fa90b9be4aa16c34464c0e",
"packages": [ "packages": [
{ {
"name": "babdev/pagerfanta-bundle", "name": "babdev/pagerfanta-bundle",
@ -2980,63 +2980,6 @@
}, },
"time": "2015-05-14T08:18:23+00:00" "time": "2015-05-14T08:18:23+00:00"
}, },
{
"name": "guzzlehttp/guzzle",
"version": "5.3.4",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "b87eda7a7162f95574032da17e9323c9899cb6b2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b87eda7a7162f95574032da17e9323c9899cb6b2",
"reference": "b87eda7a7162f95574032da17e9323c9899cb6b2",
"shasum": ""
},
"require": {
"guzzlehttp/ringphp": "^1.1",
"php": ">=5.4.0",
"react/promise": "^2.2"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.0"
},
"type": "library",
"autoload": {
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/5.3"
},
"time": "2019-10-30T09:32:00+00:00"
},
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "2.7.0", "version": "2.7.0",
@ -3153,117 +3096,6 @@
], ],
"time": "2024-07-18T11:15:46+00:00" "time": "2024-07-18T11:15:46+00:00"
}, },
{
"name": "guzzlehttp/ringphp",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/RingPHP.git",
"reference": "5e2a174052995663dd68e6b5ad838afd47dd615b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/RingPHP/zipball/5e2a174052995663dd68e6b5ad838afd47dd615b",
"reference": "5e2a174052995663dd68e6b5ad838afd47dd615b",
"shasum": ""
},
"require": {
"guzzlehttp/streams": "~3.0",
"php": ">=5.4.0",
"react/promise": "~2.0"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "~4.0"
},
"suggest": {
"ext-curl": "Guzzle will use specific adapters if cURL is present"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Ring\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.",
"support": {
"issues": "https://github.com/guzzle/RingPHP/issues",
"source": "https://github.com/guzzle/RingPHP/tree/1.1.1"
},
"abandoned": true,
"time": "2018-07-31T13:22:33+00:00"
},
{
"name": "guzzlehttp/streams",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/streams.git",
"reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
"reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Stream\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Provides a simple abstraction over streams of data",
"homepage": "http://guzzlephp.org/",
"keywords": [
"Guzzle",
"stream"
],
"support": {
"issues": "https://github.com/guzzle/streams/issues",
"source": "https://github.com/guzzle/streams/tree/master"
},
"abandoned": true,
"time": "2014-10-12T19:18:40+00:00"
},
{ {
"name": "hoa/compiler", "name": "hoa/compiler",
"version": "3.17.08.08", "version": "3.17.08.08",
@ -6511,74 +6343,6 @@
}, },
"time": "2024-10-02T11:20:13+00:00" "time": "2024-10-02T11:20:13+00:00"
}, },
{
"name": "php-http/guzzle5-adapter",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-http/guzzle5-adapter.git",
"reference": "cce48360b1f8a3467bd94e853e6107aa4532008e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/guzzle5-adapter/zipball/cce48360b1f8a3467bd94e853e6107aa4532008e",
"reference": "cce48360b1f8a3467bd94e853e6107aa4532008e",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^5.1",
"php": "^7.0",
"php-http/discovery": "^1.0",
"php-http/httplug": "^2.0"
},
"provide": {
"php-http/client-implementation": "1.0",
"psr/http-client-implementation": "1.0"
},
"require-dev": {
"ext-curl": "*",
"guzzlehttp/ringphp": "^1.1",
"php-http/client-integration-tests": "^2.0",
"phpunit/phpunit": "^6.0 || ^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"Http\\Adapter\\Guzzle5\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Eric GELOEN",
"email": "geloen.eric@gmail.com"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com"
}
],
"description": "Guzzle 5 HTTP Adapter",
"homepage": "http://httplug.io",
"keywords": [
"Guzzle",
"http"
],
"support": {
"issues": "https://github.com/php-http/guzzle5-adapter/issues",
"source": "https://github.com/php-http/guzzle5-adapter/tree/2.0.0"
},
"abandoned": "php-http/guzzle7-adapter",
"time": "2019-02-05T12:28:45+00:00"
},
{ {
"name": "php-http/httplug", "name": "php-http/httplug",
"version": "2.4.1", "version": "2.4.1",
@ -6636,169 +6400,6 @@
}, },
"time": "2024-09-23T11:39:58+00:00" "time": "2024-09-23T11:39:58+00:00"
}, },
{
"name": "php-http/httplug-bundle",
"version": "1.34.3",
"source": {
"type": "git",
"url": "https://github.com/php-http/HttplugBundle.git",
"reference": "87c61d27c025dd9d699a2208a6d06be58061e433"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/HttplugBundle/zipball/87c61d27c025dd9d699a2208a6d06be58061e433",
"reference": "87c61d27c025dd9d699a2208a6d06be58061e433",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0",
"php-http/client-common": "^1.9 || ^2.0",
"php-http/client-implementation": "^1.0",
"php-http/discovery": "^1.14",
"php-http/httplug": "^2.0",
"php-http/logger-plugin": "^1.1",
"php-http/message": "^1.13",
"php-http/message-factory": "^1.0.2",
"php-http/stopwatch-plugin": "^1.2",
"psr/http-message": "^1.0 || ^2.0",
"symfony/config": "^4.4 || ^5.0 || ^6.0 || ^7.0",
"symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0 || ^7.0",
"symfony/event-dispatcher": "^4.4 || ^5.0 || ^6.0 || ^7.0",
"symfony/http-kernel": "^4.4 || ^5.0 || ^6.0 || ^7.0",
"symfony/options-resolver": "^4.4 || ^5.0 || ^6.0 || ^7.0"
},
"conflict": {
"php-http/cache-plugin": "<1.7.0",
"php-http/curl-client": "<2.0",
"php-http/guzzle6-adapter": "<1.1",
"php-http/socket-client": "<2.0",
"php-http/throttle-plugin": "<1.1"
},
"require-dev": {
"guzzlehttp/psr7": "^1.7 || ^2.0",
"matthiasnoback/symfony-config-test": "^4.3 || ^5.0",
"matthiasnoback/symfony-dependency-injection-test": "^4.3.1 || ^5.0",
"nyholm/nsa": "^1.1",
"nyholm/psr7": "^1.2.1",
"php-http/cache-plugin": "^1.7",
"php-http/mock-client": "^1.2",
"php-http/promise": "^1.0",
"phpunit/phpunit": "^9.6",
"symfony/browser-kit": "^4.4 || ^5.0 || ^6.0 || ^7.0",
"symfony/cache": "^4.4 || ^5.0 || ^6.0 || ^7.0",
"symfony/dom-crawler": "^4.4 || ^5.0 || ^6.0 || ^7.0",
"symfony/framework-bundle": "^4.4 || ^5.0 || ^6.0 || ^7.0",
"symfony/http-foundation": "^4.4.19 || ^5.0 || ^6.0 || ^7.0",
"symfony/stopwatch": "^4.4 || ^5.0 || ^6.0 || ^7.0",
"symfony/twig-bundle": "^4.4 || ^5.0 || ^6.0 || ^7.0",
"symfony/web-profiler-bundle": "^4.4.19 || ^5.0 || ^6.0 || ^7.0",
"twig/twig": "^1.41 || ^2.10 || ^3.0"
},
"suggest": {
"php-http/cache-plugin": "To configure clients that cache responses",
"php-http/mock-client": "Add this to your require-dev section to mock HTTP responses easily",
"twig/twig": "Add this to your require-dev section when using the WebProfilerBundle"
},
"type": "symfony-bundle",
"autoload": {
"psr-4": {
"Http\\HttplugBundle\\": "src/"
},
"exclude-from-classmap": [
"/Tests/Resources/MyPsr18TestClient.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "David Buchmann",
"email": "mail@davidbu.ch"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com"
}
],
"description": "Symfony integration for HTTPlug",
"homepage": "http://httplug.io",
"keywords": [
"adapter",
"bundle",
"discovery",
"factory",
"http",
"httplug",
"message",
"php-http"
],
"support": {
"issues": "https://github.com/php-http/HttplugBundle/issues",
"source": "https://github.com/php-http/HttplugBundle/tree/1.34.3"
},
"time": "2024-09-01T08:25:40+00:00"
},
{
"name": "php-http/logger-plugin",
"version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/php-http/logger-plugin.git",
"reference": "bf47eb5cb379962d276c94da14861669c2313563"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/logger-plugin/zipball/bf47eb5cb379962d276c94da14861669c2313563",
"reference": "bf47eb5cb379962d276c94da14861669c2313563",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
"php-http/client-common": "^1.9 || ^2.0",
"php-http/message": "^1.0",
"psr/log": "^1.0 || ^2 || ^3",
"symfony/polyfill-php73": "^1.17"
},
"require-dev": {
"phpspec/phpspec": "^5.1 || ^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
}
},
"autoload": {
"psr-4": {
"Http\\Client\\Common\\Plugin\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com"
}
],
"description": "PSR-3 Logger plugin for HTTPlug",
"homepage": "http://httplug.io",
"keywords": [
"http",
"httplug",
"logger",
"plugin"
],
"support": {
"issues": "https://github.com/php-http/logger-plugin/issues",
"source": "https://github.com/php-http/logger-plugin/tree/1.3.1"
},
"time": "2024-09-01T06:51:51+00:00"
},
{ {
"name": "php-http/message", "name": "php-http/message",
"version": "1.16.2", "version": "1.16.2",
@ -6975,64 +6576,6 @@
}, },
"time": "2024-03-15T13:55:21+00:00" "time": "2024-03-15T13:55:21+00:00"
}, },
{
"name": "php-http/stopwatch-plugin",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/php-http/stopwatch-plugin.git",
"reference": "11862cfbc719afade4ff407964ab3fbfe9ec2baa"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/stopwatch-plugin/zipball/11862cfbc719afade4ff407964ab3fbfe9ec2baa",
"reference": "11862cfbc719afade4ff407964ab3fbfe9ec2baa",
"shasum": ""
},
"require": {
"php": "^7.3 || ^8.0",
"php-http/client-common": "^1.9 || ^2.0",
"symfony/stopwatch": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"require-dev": {
"guzzlehttp/psr7": "^2.1",
"symfony/phpunit-bridge": "^6.4.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3-dev"
}
},
"autoload": {
"psr-4": {
"Http\\Client\\Common\\Plugin\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com"
}
],
"description": "Symfony Stopwatch plugin for HTTPlug",
"homepage": "http://httplug.io",
"keywords": [
"http",
"httplug",
"plugin",
"stopwatch"
],
"support": {
"issues": "https://github.com/php-http/stopwatch-plugin/issues",
"source": "https://github.com/php-http/stopwatch-plugin/tree/1.4.2"
},
"time": "2023-12-05T14:36:57+00:00"
},
{ {
"name": "phpdocumentor/reflection-common", "name": "phpdocumentor/reflection-common",
"version": "2.2.0", "version": "2.2.0",
@ -8126,78 +7669,6 @@
}, },
"time": "2019-03-08T08:55:37+00:00" "time": "2019-03-08T08:55:37+00:00"
}, },
{
"name": "react/promise",
"version": "v2.11.0",
"source": {
"type": "git",
"url": "https://github.com/reactphp/promise.git",
"reference": "1a8460931ea36dc5c76838fec5734d55c88c6831"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/promise/zipball/1a8460931ea36dc5c76838fec5734d55c88c6831",
"reference": "1a8460931ea36dc5c76838fec5734d55c88c6831",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
},
"type": "library",
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"React\\Promise\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jan Sorgalla",
"email": "jsorgalla@gmail.com",
"homepage": "https://sorgalla.com/"
},
{
"name": "Christian Lück",
"email": "christian@clue.engineering",
"homepage": "https://clue.engineering/"
},
{
"name": "Cees-Jan Kiewiet",
"email": "reactphp@ceesjankiewiet.nl",
"homepage": "https://wyrihaximus.net/"
},
{
"name": "Chris Boden",
"email": "cboden@gmail.com",
"homepage": "https://cboden.dev/"
}
],
"description": "A lightweight implementation of CommonJS Promises/A for PHP",
"keywords": [
"promise",
"promises"
],
"support": {
"issues": "https://github.com/reactphp/promise/issues",
"source": "https://github.com/reactphp/promise/tree/v2.11.0"
},
"funding": [
{
"url": "https://opencollective.com/reactphp",
"type": "open_collective"
}
],
"time": "2023-11-16T16:16:50+00:00"
},
{ {
"name": "rulerz-php/doctrine-orm", "name": "rulerz-php/doctrine-orm",
"version": "dev-master", "version": "dev-master",
@ -9325,6 +8796,78 @@
], ],
"time": "2024-10-22T13:05:35+00:00" "time": "2024-10-22T13:05:35+00:00"
}, },
{
"name": "symfony/browser-kit",
"version": "v5.4.45",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
"reference": "03cce39764429e07fbab9b989a1182a24578341d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/03cce39764429e07fbab9b989a1182a24578341d",
"reference": "03cce39764429e07fbab9b989a1182a24578341d",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/dom-crawler": "^4.4|^5.0|^6.0",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"symfony/css-selector": "^4.4|^5.0|^6.0",
"symfony/http-client": "^4.4|^5.0|^6.0",
"symfony/mime": "^4.4|^5.0|^6.0",
"symfony/process": "^4.4|^5.0|^6.0"
},
"suggest": {
"symfony/process": ""
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\BrowserKit\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/browser-kit/tree/v5.4.45"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-10-22T13:05:35+00:00"
},
{ {
"name": "symfony/cache", "name": "symfony/cache",
"version": "v5.4.46", "version": "v5.4.46",
@ -18533,6 +18076,78 @@
], ],
"time": "2023-11-13T13:48:05+00:00" "time": "2023-11-13T13:48:05+00:00"
}, },
{
"name": "react/promise",
"version": "v2.11.0",
"source": {
"type": "git",
"url": "https://github.com/reactphp/promise.git",
"reference": "1a8460931ea36dc5c76838fec5734d55c88c6831"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/promise/zipball/1a8460931ea36dc5c76838fec5734d55c88c6831",
"reference": "1a8460931ea36dc5c76838fec5734d55c88c6831",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
},
"type": "library",
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"React\\Promise\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jan Sorgalla",
"email": "jsorgalla@gmail.com",
"homepage": "https://sorgalla.com/"
},
{
"name": "Christian Lück",
"email": "christian@clue.engineering",
"homepage": "https://clue.engineering/"
},
{
"name": "Cees-Jan Kiewiet",
"email": "reactphp@ceesjankiewiet.nl",
"homepage": "https://wyrihaximus.net/"
},
{
"name": "Chris Boden",
"email": "cboden@gmail.com",
"homepage": "https://cboden.dev/"
}
],
"description": "A lightweight implementation of CommonJS Promises/A for PHP",
"keywords": [
"promise",
"promises"
],
"support": {
"issues": "https://github.com/reactphp/promise/issues",
"source": "https://github.com/reactphp/promise/tree/v2.11.0"
},
"funding": [
{
"url": "https://opencollective.com/reactphp",
"type": "open_collective"
}
],
"time": "2023-11-16T16:16:50+00:00"
},
{ {
"name": "react/socket", "name": "react/socket",
"version": "v1.16.0", "version": "v1.16.0",
@ -19720,78 +19335,6 @@
}, },
"time": "2024-12-30T12:31:04+00:00" "time": "2024-12-30T12:31:04+00:00"
}, },
{
"name": "symfony/browser-kit",
"version": "v5.4.45",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
"reference": "03cce39764429e07fbab9b989a1182a24578341d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/03cce39764429e07fbab9b989a1182a24578341d",
"reference": "03cce39764429e07fbab9b989a1182a24578341d",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/dom-crawler": "^4.4|^5.0|^6.0",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"symfony/css-selector": "^4.4|^5.0|^6.0",
"symfony/http-client": "^4.4|^5.0|^6.0",
"symfony/mime": "^4.4|^5.0|^6.0",
"symfony/process": "^4.4|^5.0|^6.0"
},
"suggest": {
"symfony/process": ""
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\BrowserKit\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/browser-kit/tree/v5.4.45"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-10-22T13:05:35+00:00"
},
{ {
"name": "symfony/css-selector", "name": "symfony/css-selector",
"version": "v5.4.45", "version": "v5.4.45",
@ -20407,9 +19950,9 @@
"ext-tokenizer": "*", "ext-tokenizer": "*",
"ext-xml": "*" "ext-xml": "*"
}, },
"platform-dev": [], "platform-dev": {},
"platform-overrides": { "platform-overrides": {
"php": "7.4.29" "php": "7.4.29"
}, },
"plugin-api-version": "2.3.0" "plugin-api-version": "2.6.0"
} }

View file

@ -1,121 +0,0 @@
<?php
namespace Wallabag\Guzzle;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Event\SubscriberInterface;
use GuzzleHttp\Message\RequestInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Wallabag\SiteConfig\LoginFormAuthenticator;
use Wallabag\SiteConfig\SiteConfig;
use Wallabag\SiteConfig\SiteConfigBuilder;
class AuthenticatorSubscriber implements SubscriberInterface, LoggerAwareInterface
{
// avoid loop when login failed which can just be a bad login/password
// after 2 attempts, we skip the login
public const MAX_RETRIES = 2;
private int $retries = 0;
/** @var SiteConfigBuilder */
private $configBuilder;
/** @var LoginFormAuthenticator */
private $authenticator;
/** @var LoggerInterface */
private $logger;
/**
* AuthenticatorSubscriber constructor.
*/
public function __construct(SiteConfigBuilder $configBuilder, LoginFormAuthenticator $authenticator)
{
$this->configBuilder = $configBuilder;
$this->authenticator = $authenticator;
$this->logger = new NullLogger();
}
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
public function getEvents(): array
{
return [
'before' => ['loginIfRequired'],
'complete' => ['loginIfRequested'],
];
}
public function loginIfRequired(BeforeEvent $event)
{
$config = $this->buildSiteConfig($event->getRequest());
if (false === $config || !$config->requiresLogin()) {
$this->logger->debug('loginIfRequired> will not require login');
return;
}
$client = $event->getClient();
if (!$this->authenticator->isLoggedIn($config, $client)) {
$this->logger->debug('loginIfRequired> user is not logged in, attach authenticator');
$emitter = $client->getEmitter();
$emitter->detach($this);
$this->authenticator->login($config, $client);
$emitter->attach($this);
}
}
public function loginIfRequested(CompleteEvent $event)
{
$config = $this->buildSiteConfig($event->getRequest());
if (false === $config || !$config->requiresLogin()) {
$this->logger->debug('loginIfRequested> will not require login');
return;
}
$body = $event->getResponse()->getBody();
if (
null === $body
|| '' === $body->getContents()
) {
$this->logger->debug('loginIfRequested> empty body, ignoring');
return;
}
$isLoginRequired = $this->authenticator->isLoginRequired($config, $body);
$this->logger->debug('loginIfRequested> retry #' . $this->retries . ' with login ' . ($isLoginRequired ? '' : 'not ') . 'required');
if ($isLoginRequired && $this->retries < self::MAX_RETRIES) {
$client = $event->getClient();
$emitter = $client->getEmitter();
$emitter->detach($this);
$this->authenticator->login($config, $client);
$emitter->attach($this);
$event->retry();
++$this->retries;
}
}
/**
* @return SiteConfig|false
*/
private function buildSiteConfig(RequestInterface $request)
{
return $this->configBuilder->buildForHost($request->getHost());
}
}

View file

@ -1,74 +0,0 @@
<?php
namespace Wallabag\Helper;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Event\SubscriberInterface;
use Http\Adapter\Guzzle5\Client as GuzzleAdapter;
use Http\Client\HttpClient;
use Http\HttplugBundle\ClientFactory\ClientFactory;
use Psr\Log\LoggerInterface;
/**
* Builds and configures the HTTP client.
*/
class HttpClientFactory implements ClientFactory
{
/** @var SubscriberInterface[] */
private $subscribers = [];
/** @var CookieJar */
private $cookieJar;
private $restrictedAccess;
private $logger;
/**
* HttpClientFactory constructor.
*
* @param string $restrictedAccess This param is a kind of boolean. Values: 0 or 1
*/
public function __construct(CookieJar $cookieJar, $restrictedAccess, LoggerInterface $logger)
{
$this->cookieJar = $cookieJar;
$this->restrictedAccess = $restrictedAccess;
$this->logger = $logger;
}
/**
* Adds a subscriber to the HTTP client.
*/
public function addSubscriber(SubscriberInterface $subscriber)
{
$this->subscribers[] = $subscriber;
}
/**
* Input an array of configuration to be able to create a HttpClient.
*
* @return HttpClient
*/
public function createClient(array $config = [])
{
$this->logger->log('debug', 'Restricted access config enabled?', ['enabled' => (int) $this->restrictedAccess]);
if (0 === (int) $this->restrictedAccess) {
return new GuzzleAdapter(new GuzzleClient($config));
}
// we clear the cookie to avoid websites who use cookies for analytics
$this->cookieJar->clear();
if (!isset($config['defaults']['cookies'])) {
// need to set the (shared) cookie jar
$config['defaults']['cookies'] = $this->cookieJar;
}
$guzzle = new GuzzleClient($config);
foreach ($this->subscribers as $subscriber) {
$guzzle->getEmitter()->attach($subscriber);
}
return new GuzzleAdapter($guzzle);
}
}

View file

@ -0,0 +1,95 @@
<?php
namespace Wallabag\HttpClient;
use GuzzleHttp\Psr7\Uri;
use Psr\Http\Message\UriInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Wallabag\SiteConfig\LoginFormAuthenticator;
use Wallabag\SiteConfig\SiteConfig;
use Wallabag\SiteConfig\SiteConfigBuilder;
class Authenticator implements LoggerAwareInterface
{
/** @var SiteConfigBuilder */
private $configBuilder;
/** @var LoginFormAuthenticator */
private $authenticator;
/** @var LoggerInterface */
private $logger;
public function __construct(SiteConfigBuilder $configBuilder, LoginFormAuthenticator $authenticator)
{
$this->configBuilder = $configBuilder;
$this->authenticator = $authenticator;
$this->logger = new NullLogger();
}
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
public function loginIfRequired(string $url): bool
{
$config = $this->buildSiteConfig(new Uri($url));
if (false === $config || !$config->requiresLogin()) {
$this->logger->debug('loginIfRequired> will not require login');
return false;
}
if ($this->authenticator->isLoggedIn($config)) {
return false;
}
$this->logger->debug('loginIfRequired> user is not logged in, attach authenticator');
$this->authenticator->login($config);
return true;
}
public function loginIfRequested(ResponseInterface $response): bool
{
$config = $this->buildSiteConfig(new Uri($response->getInfo('url')));
if (false === $config || !$config->requiresLogin()) {
$this->logger->debug('loginIfRequested> will not require login');
return false;
}
$body = $response->getContent();
if ('' === $body) {
$this->logger->debug('loginIfRequested> empty body, ignoring');
return false;
}
$isLoginRequired = $this->authenticator->isLoginRequired($config, $body);
$this->logger->debug('loginIfRequested> retry with login ' . ($isLoginRequired ? '' : 'not ') . 'required');
if (!$isLoginRequired) {
return false;
}
$this->authenticator->login($config);
return true;
}
/**
* @return SiteConfig|false
*/
private function buildSiteConfig(UriInterface $uri)
{
return $this->configBuilder->buildForHost($uri->getHost());
}
}

View file

@ -0,0 +1,84 @@
<?php
namespace Wallabag\HttpClient;
use Psr\Log\LoggerInterface;
use Symfony\Component\BrowserKit\HttpBrowser;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Symfony\Contracts\HttpClient\ResponseStreamInterface;
class WallabagClient implements HttpClientInterface
{
private $restrictedAccess;
private HttpClientInterface $httpClient;
private HttpBrowser $browser;
private Authenticator $authenticator;
private LoggerInterface $logger;
public function __construct($restrictedAccess, HttpBrowser $browser, Authenticator $authenticator, LoggerInterface $logger)
{
$this->restrictedAccess = $restrictedAccess;
$this->browser = $browser;
$this->authenticator = $authenticator;
$this->logger = $logger;
$this->httpClient = HttpClient::create([
'timeout' => 10,
]);
}
public function request(string $method, string $url, array $options = []): ResponseInterface
{
$this->logger->log('debug', 'Restricted access config enabled?', ['enabled' => (int) $this->restrictedAccess]);
if (0 === (int) $this->restrictedAccess) {
return $this->httpClient->request($method, $url, $options);
}
$login = $this->authenticator->loginIfRequired($url);
if (!$login) {
return $this->httpClient->request($method, $url, $options);
}
if (null !== $cookieHeader = $this->getCookieHeader($url)) {
$options['headers']['cookie'] = $cookieHeader;
}
$response = $this->httpClient->request($method, $url, $options);
$login = $this->authenticator->loginIfRequested($response);
if (!$login) {
return $response;
}
if (null !== $cookieHeader = $this->getCookieHeader($url)) {
$options['headers']['cookie'] = $cookieHeader;
}
return $this->httpClient->request($method, $url, $options);
}
public function stream($responses, ?float $timeout = null): ResponseStreamInterface
{
return $this->httpClient->stream($responses, $timeout);
}
private function getCookieHeader(string $url): ?string
{
$cookies = [];
foreach ($this->browser->getCookieJar()->allRawValues($url) as $name => $value) {
$cookies[] = $name . '=' . $value;
}
if ([] === $cookies) {
return null;
}
return implode('; ', $cookies);
}
}

View file

@ -2,18 +2,19 @@
namespace Wallabag\SiteConfig; namespace Wallabag\SiteConfig;
use GuzzleHttp\ClientInterface; use Symfony\Component\BrowserKit\HttpBrowser;
use GuzzleHttp\Cookie\CookieJar;
use Symfony\Component\DomCrawler\Crawler; use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Wallabag\ExpressionLanguage\AuthenticatorProvider; use Wallabag\ExpressionLanguage\AuthenticatorProvider;
class LoginFormAuthenticator class LoginFormAuthenticator
{ {
private HttpBrowser $browser;
private ExpressionLanguage $expressionLanguage; private ExpressionLanguage $expressionLanguage;
public function __construct(AuthenticatorProvider $authenticatorProvider) public function __construct(HttpBrowser $browser, AuthenticatorProvider $authenticatorProvider)
{ {
$this->browser = $browser;
$this->expressionLanguage = new ExpressionLanguage(null, [$authenticatorProvider]); $this->expressionLanguage = new ExpressionLanguage(null, [$authenticatorProvider]);
} }
@ -22,17 +23,14 @@ class LoginFormAuthenticator
* *
* @return self * @return self
*/ */
public function login(SiteConfig $siteConfig, ClientInterface $guzzle) public function login(SiteConfig $siteConfig)
{ {
$postFields = [ $postFields = [
$siteConfig->getUsernameField() => $siteConfig->getUsername(), $siteConfig->getUsernameField() => $siteConfig->getUsername(),
$siteConfig->getPasswordField() => $siteConfig->getPassword(), $siteConfig->getPasswordField() => $siteConfig->getPassword(),
] + $this->getExtraFields($siteConfig); ] + $this->getExtraFields($siteConfig);
$guzzle->post( $this->browser->request('POST', $siteConfig->getLoginUri(), $postFields);
$siteConfig->getLoginUri(),
['body' => $postFields, 'allow_redirects' => true, 'verify' => false]
);
return $this; return $this;
} }
@ -42,15 +40,12 @@ class LoginFormAuthenticator
* *
* @return bool * @return bool
*/ */
public function isLoggedIn(SiteConfig $siteConfig, ClientInterface $guzzle) public function isLoggedIn(SiteConfig $siteConfig)
{ {
if (($cookieJar = $guzzle->getDefaultOption('cookies')) instanceof CookieJar) { foreach ($this->browser->getCookieJar()->all() as $cookie) {
/** @var \GuzzleHttp\Cookie\SetCookie $cookie */ // check required cookies
foreach ($cookieJar as $cookie) { if ($cookie->getDomain() === $siteConfig->getHost()) {
// check required cookies return true;
if ($cookie->getDomain() === $siteConfig->getHost()) {
return true;
}
} }
} }

View file

@ -1,314 +0,0 @@
<?php
namespace Tests\Wallabag\Guzzle;
use GuzzleHttp\Client;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Subscriber\Mock;
use Monolog\Handler\TestHandler;
use Monolog\Logger;
use PHPUnit\Framework\TestCase;
use Wallabag\Guzzle\AuthenticatorSubscriber;
use Wallabag\SiteConfig\ArraySiteConfigBuilder;
use Wallabag\SiteConfig\LoginFormAuthenticator;
class AuthenticatorSubscriberTest extends TestCase
{
public function testGetEvents()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$subscriber = new AuthenticatorSubscriber(
new ArraySiteConfigBuilder(),
$authenticator
);
$events = $subscriber->getEvents();
$this->assertArrayHasKey('before', $events);
$this->assertArrayHasKey('complete', $events);
$this->assertSame('loginIfRequired', $events['before'][0]);
$this->assertSame('loginIfRequested', $events['complete'][0]);
}
public function testLoginIfRequiredNotRequired()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$builder = new ArraySiteConfigBuilder(['example.com' => []]);
$subscriber = new AuthenticatorSubscriber($builder, $authenticator);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$subscriber->setLogger($logger);
$request = new Request('GET', 'http://www.example.com');
$event = $this->getMockBuilder(BeforeEvent::class)
->disableOriginalConstructor()
->getMock();
$event->expects($this->once())
->method('getRequest')
->willReturn($request);
$subscriber->loginIfRequired($event);
$records = $handler->getRecords();
$this->assertCount(1, $records);
$this->assertSame('loginIfRequired> will not require login', $records[0]['message']);
}
public function testLoginIfRequiredWithNotLoggedInUser()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$authenticator->expects($this->once())
->method('isLoggedIn')
->willReturn(false);
$authenticator->expects($this->once())
->method('login');
$builder = new ArraySiteConfigBuilder(['example.com' => ['requiresLogin' => true]]);
$subscriber = new AuthenticatorSubscriber($builder, $authenticator);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$subscriber->setLogger($logger);
$response = new Response(
200,
['content-type' => 'text/html'],
Stream::factory('')
);
$guzzle = new Client();
$guzzle->getEmitter()->attach(new Mock([$response]));
$request = new Request('GET', 'http://www.example.com');
$event = $this->getMockBuilder(BeforeEvent::class)
->disableOriginalConstructor()
->getMock();
$event->expects($this->once())
->method('getRequest')
->willReturn($request);
$event->expects($this->once())
->method('getClient')
->willReturn($guzzle);
$subscriber->loginIfRequired($event);
$records = $handler->getRecords();
$this->assertCount(1, $records);
$this->assertSame('loginIfRequired> user is not logged in, attach authenticator', $records[0]['message']);
}
public function testLoginIfRequestedNotRequired()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$builder = new ArraySiteConfigBuilder(['example.com' => []]);
$subscriber = new AuthenticatorSubscriber($builder, $authenticator);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$subscriber->setLogger($logger);
$request = new Request('GET', 'http://www.example.com');
$event = $this->getMockBuilder(CompleteEvent::class)
->disableOriginalConstructor()
->getMock();
$event->expects($this->once())
->method('getRequest')
->willReturn($request);
$subscriber->loginIfRequested($event);
$records = $handler->getRecords();
$this->assertCount(1, $records);
$this->assertSame('loginIfRequested> will not require login', $records[0]['message']);
}
public function testLoginIfRequestedNotRequested()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$authenticator->expects($this->once())
->method('isLoginRequired')
->willReturn(false);
$builder = new ArraySiteConfigBuilder(['example.com' => [
'requiresLogin' => true,
'notLoggedInXpath' => '//html',
]]);
$subscriber = new AuthenticatorSubscriber($builder, $authenticator);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$subscriber->setLogger($logger);
$response = new Response(
200,
['content-type' => 'text/html'],
Stream::factory('<html><body/></html>')
);
$request = new Request('GET', 'http://www.example.com');
$event = $this->getMockBuilder(CompleteEvent::class)
->disableOriginalConstructor()
->getMock();
$event->expects($this->once())
->method('getResponse')
->willReturn($response);
$event->expects($this->once())
->method('getRequest')
->willReturn($request);
$subscriber->loginIfRequested($event);
$records = $handler->getRecords();
$this->assertCount(1, $records);
$this->assertSame('loginIfRequested> retry #0 with login not required', $records[0]['message']);
}
public function testLoginIfRequestedRequested()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$authenticator->expects($this->once())
->method('isLoginRequired')
->willReturn(true);
$authenticator->expects($this->once())
->method('login');
$builder = new ArraySiteConfigBuilder(['example.com' => [
'requiresLogin' => true,
'notLoggedInXpath' => '//html',
]]);
$subscriber = new AuthenticatorSubscriber($builder, $authenticator);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$subscriber->setLogger($logger);
$response = new Response(
200,
['content-type' => 'text/html'],
Stream::factory('<html><body/></html>')
);
$guzzle = new Client();
$guzzle->getEmitter()->attach(new Mock([$response]));
$request = new Request('GET', 'http://www.example.com');
$event = $this->getMockBuilder(CompleteEvent::class)
->disableOriginalConstructor()
->getMock();
$event->expects($this->once())
->method('getResponse')
->willReturn($response);
$event->expects($this->once())
->method('getRequest')
->willReturn($request);
$event->expects($this->any())
->method('getClient')
->willReturn($guzzle);
$subscriber->loginIfRequested($event);
$records = $handler->getRecords();
$this->assertCount(1, $records);
$this->assertSame('loginIfRequested> retry #0 with login required', $records[0]['message']);
}
public function testLoginIfRequestedRedirect()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$builder = new ArraySiteConfigBuilder(['example.com' => [
'requiresLogin' => true,
'notLoggedInXpath' => '//html',
]]);
$subscriber = new AuthenticatorSubscriber($builder, $authenticator);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$subscriber->setLogger($logger);
$response = new Response(
301,
[],
Stream::factory('')
);
$guzzle = new Client();
$guzzle->getEmitter()->attach(new Mock([$response]));
$request = new Request('GET', 'http://www.example.com');
$event = $this->getMockBuilder(CompleteEvent::class)
->disableOriginalConstructor()
->getMock();
$event->expects($this->once())
->method('getResponse')
->willReturn($response);
$event->expects($this->once())
->method('getRequest')
->willReturn($request);
$event->expects($this->any())
->method('getClient')
->willReturn($guzzle);
$subscriber->loginIfRequested($event);
$records = $handler->getRecords();
$this->assertCount(1, $records);
$this->assertSame('loginIfRequested> empty body, ignoring', $records[0]['message']);
}
}

View file

@ -2,13 +2,12 @@
namespace Tests\Wallabag\SiteConfig; namespace Tests\Wallabag\SiteConfig;
use GuzzleHttp\Client;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Subscriber\Mock;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\BrowserKit\HttpBrowser;
use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse; use Symfony\Component\HttpClient\Response\MockResponse;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Wallabag\ExpressionLanguage\AuthenticatorProvider; use Wallabag\ExpressionLanguage\AuthenticatorProvider;
use Wallabag\SiteConfig\LoginFormAuthenticator; use Wallabag\SiteConfig\LoginFormAuthenticator;
use Wallabag\SiteConfig\SiteConfig; use Wallabag\SiteConfig\SiteConfig;
@ -17,16 +16,6 @@ class LoginFormAuthenticatorTest extends TestCase
{ {
public function testLoginPost() public function testLoginPost()
{ {
$response = new Response(
200,
['content-type' => 'text/html'],
Stream::factory('')
);
$guzzle = new Client();
$guzzle->getEmitter()->attach(new Mock([$response]));
$mockHttpClient = new MockHttpClient([new MockResponse('', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']])]);
$siteConfig = new SiteConfig([ $siteConfig = new SiteConfig([
'host' => 'example.com', 'host' => 'example.com',
'loginUri' => 'http://example.com/login', 'loginUri' => 'http://example.com/login',
@ -40,25 +29,23 @@ class LoginFormAuthenticatorTest extends TestCase
'password' => 'unkn0wn', 'password' => 'unkn0wn',
]); ]);
$authenticatorProvider = new AuthenticatorProvider($mockHttpClient); $browserResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
$auth = new LoginFormAuthenticator($authenticatorProvider); $browserClient = new MockHttpClient([$browserResponse]);
$res = $auth->login($siteConfig, $guzzle); $browser = new HttpBrowser($browserClient);
$requestHtmlFunctionResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
$requestHtmlFunctionClient = new MockHttpClient([$requestHtmlFunctionResponse]);
$authenticatorProvider = new AuthenticatorProvider($requestHtmlFunctionClient);
$auth = new LoginFormAuthenticator($browser, $authenticatorProvider);
$res = $auth->login($siteConfig);
$this->assertInstanceOf(LoginFormAuthenticator::class, $res); $this->assertInstanceOf(LoginFormAuthenticator::class, $res);
} }
public function testLoginPostWithExtraFieldsButEmptyHtml() public function testLoginPostWithExtraFieldsButEmptyHtml()
{ {
$response = new Response(
200,
['content-type' => 'text/html'],
Stream::factory('<html></html>')
);
$guzzle = new Client();
$guzzle->getEmitter()->attach(new Mock([$response, $response]));
$mockHttpClient = new MockHttpClient([new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']])]);
$siteConfig = new SiteConfig([ $siteConfig = new SiteConfig([
'host' => 'example.com', 'host' => 'example.com',
'loginUri' => 'http://example.com/login', 'loginUri' => 'http://example.com/login',
@ -73,9 +60,17 @@ class LoginFormAuthenticatorTest extends TestCase
'password' => 'unkn0wn', 'password' => 'unkn0wn',
]); ]);
$authenticatorProvider = new AuthenticatorProvider($mockHttpClient); $browserResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
$auth = new LoginFormAuthenticator($authenticatorProvider); $browserClient = new MockHttpClient([$browserResponse]);
$res = $auth->login($siteConfig, $guzzle); $browser = new HttpBrowser($browserClient);
$requestHtmlFunctionResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
$requestHtmlFunctionClient = new MockHttpClient([$requestHtmlFunctionResponse]);
$authenticatorProvider = new AuthenticatorProvider($requestHtmlFunctionClient);
$auth = new LoginFormAuthenticator($browser, $authenticatorProvider);
$res = $auth->login($siteConfig);
$this->assertInstanceOf(LoginFormAuthenticator::class, $res); $this->assertInstanceOf(LoginFormAuthenticator::class, $res);
} }
@ -83,49 +78,6 @@ class LoginFormAuthenticatorTest extends TestCase
// testing preg_match // testing preg_match
public function testLoginPostWithExtraFieldsWithRegex() public function testLoginPostWithExtraFieldsWithRegex()
{ {
$response = $this->getMockBuilder(Response::class)
->disableOriginalConstructor()
->getMock();
$response->expects($this->any())
->method('getBody')
->willReturn(file_get_contents(__DIR__ . '/../fixtures/aoc.media.html'));
$response->expects($this->any())
->method('getStatusCode')
->willReturn(200);
$mockHttpClient = new MockHttpClient([new MockResponse(file_get_contents(__DIR__ . '/../fixtures/aoc.media.html'), ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']])]);
$client = $this->getMockBuilder(Client::class)
->disableOriginalConstructor()
->getMock();
$client->expects($this->any())
->method('post')
->with(
$this->equalTo('https://aoc.media/wp-admin/admin-ajax.php'),
$this->equalTo([
'body' => [
'nom' => 'johndoe',
'password' => 'unkn0wn',
'security' => 'c506c1b8bc',
'action' => 'login_user',
],
'allow_redirects' => true,
'verify' => false,
])
)
->willReturn($response);
$client->expects($this->any())
->method('get')
->with(
$this->equalTo('https://aoc.media/'),
$this->equalTo([])
)
->willReturn($response);
$siteConfig = new SiteConfig([ $siteConfig = new SiteConfig([
'host' => 'aoc.media', 'host' => 'aoc.media',
'loginUri' => 'https://aoc.media/wp-admin/admin-ajax.php', 'loginUri' => 'https://aoc.media/wp-admin/admin-ajax.php',
@ -139,78 +91,44 @@ class LoginFormAuthenticatorTest extends TestCase
'password' => 'unkn0wn', 'password' => 'unkn0wn',
]); ]);
$authenticatorProvider = new AuthenticatorProvider($mockHttpClient); $browserResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
$auth = new LoginFormAuthenticator($authenticatorProvider); $browserClient = new MockHttpClient([$browserResponse]);
$res = $auth->login($siteConfig, $client); $browser = $this->getMockBuilder(HttpBrowser::class)
->setConstructorArgs([$browserClient])
$this->assertInstanceOf(LoginFormAuthenticator::class, $res);
}
public function testLoginPostWithExtraFieldsWithData()
{
$response = $this->getMockBuilder(Response::class)
->disableOriginalConstructor()
->getMock(); ->getMock();
$browser->expects($this->any())
$response->expects($this->any()) ->method('request')
->method('getBody')
->willReturn(file_get_contents(__DIR__ . '/../fixtures/nextinpact-login.html'));
$response->expects($this->any())
->method('getStatusCode')
->willReturn(200);
$mockHttpClient = new MockHttpClient([new MockResponse(file_get_contents(__DIR__ . '/../fixtures/nextinpact-login.html'), ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']])]);
$client = $this->getMockBuilder(Client::class)
->disableOriginalConstructor()
->getMock();
$client->expects($this->any())
->method('post')
->with( ->with(
$this->equalTo('https://compte.nextinpact.com/Account/Login'), $this->equalTo('POST'),
$this->equalTo('https://aoc.media/wp-admin/admin-ajax.php'),
$this->equalTo([ $this->equalTo([
'body' => [ 'nom' => 'johndoe',
'UserName' => 'johndoe', 'password' => 'unkn0wn',
'Password' => 'unkn0wn', 'security' => 'c506c1b8bc',
'__RequestVerificationToken' => 's6x2QcnQDUL92mkKSi_JuUBXcgUYx_Plf-KyQ2eJypKAjQZIeTvaFHOsfEdTrcSXt3dt2CW39V7r9V16LUtvjszodAU1', 'action' => 'login_user',
'returnUrl' => 'https://www.nextinpact.com/news/102835-pour-cour-comptes-fonctionnement-actuel-vote-par-internet-nest-pas-satisfaisant.htm',
],
'allow_redirects' => true,
'verify' => false,
]) ])
) )
->willReturn($response); ;
$client->expects($this->any()) $requestHtmlFunctionResponse = $this->getMockBuilder(ResponseInterface::class)->getMock();
->method('get') $requestHtmlFunctionResponse->expects($this->any())
->method('getContent')
->willReturn(file_get_contents(__DIR__ . '/../fixtures/aoc.media.html'))
;
$requestHtmlFunctionClient = $this->getMockBuilder(HttpClientInterface::class)->getMock();
$requestHtmlFunctionClient->expects($this->any())
->method('request')
->with( ->with(
$this->equalTo('https://compte.nextinpact.com/Account/Login?http://www.nextinpact.com/'), $this->equalTo('GET'),
$this->equalTo([ $this->equalTo('https://aoc.media/'),
'headers' => [
'X-Requested-With' => 'XMLHttpRequest',
],
])
) )
->willReturn($response); ->willReturn($requestHtmlFunctionResponse)
;
$authenticatorProvider = new AuthenticatorProvider($requestHtmlFunctionClient);
$siteConfig = new SiteConfig([ $auth = new LoginFormAuthenticator($browser, $authenticatorProvider);
'host' => 'nextinpact.com',
'loginUri' => 'https://compte.nextinpact.com/Account/Login',
'usernameField' => 'UserName',
'passwordField' => 'Password',
'extraFields' => [
'__RequestVerificationToken' => '@=xpath(\'//form[@action="/Account/Login"]/input[@name="__RequestVerificationToken"]\', request_html(\'https://compte.nextinpact.com/Account/Login?http://www.nextinpact.com/\', {\'headers\': {\'X-Requested-With\':\'XMLHttpRequest\'}}))',
'returnUrl' => 'https://www.nextinpact.com/news/102835-pour-cour-comptes-fonctionnement-actuel-vote-par-internet-nest-pas-satisfaisant.htm',
],
'username' => 'johndoe',
'password' => 'unkn0wn',
]);
$authenticatorProvider = new AuthenticatorProvider($mockHttpClient); $res = $auth->login($siteConfig);
$auth = new LoginFormAuthenticator($authenticatorProvider);
$res = $auth->login($siteConfig, $client);
$this->assertInstanceOf(LoginFormAuthenticator::class, $res); $this->assertInstanceOf(LoginFormAuthenticator::class, $res);
} }
@ -225,10 +143,16 @@ class LoginFormAuthenticatorTest extends TestCase
'password' => 'unkn0wn', 'password' => 'unkn0wn',
]); ]);
$mockHttpClient = new MockHttpClient(); $browserResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
$browserClient = new MockHttpClient([$browserResponse]);
$browser = new HttpBrowser($browserClient);
$requestHtmlFunctionResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
$requestHtmlFunctionClient = new MockHttpClient([$requestHtmlFunctionResponse]);
$authenticatorProvider = new AuthenticatorProvider($requestHtmlFunctionClient);
$auth = new LoginFormAuthenticator($browser, $authenticatorProvider);
$authenticatorProvider = new AuthenticatorProvider($mockHttpClient);
$auth = new LoginFormAuthenticator($authenticatorProvider);
$loginRequired = $auth->isLoginRequired($siteConfig, file_get_contents(__DIR__ . '/../fixtures/nextinpact-login.html')); $loginRequired = $auth->isLoginRequired($siteConfig, file_get_contents(__DIR__ . '/../fixtures/nextinpact-login.html'));
$this->assertFalse($loginRequired); $this->assertFalse($loginRequired);
@ -245,10 +169,16 @@ class LoginFormAuthenticatorTest extends TestCase
'notLoggedInXpath' => '//h2[@class="title_reserve_article"]', 'notLoggedInXpath' => '//h2[@class="title_reserve_article"]',
]); ]);
$mockHttpClient = new MockHttpClient(); $browserResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
$browserClient = new MockHttpClient([$browserResponse]);
$browser = new HttpBrowser($browserClient);
$requestHtmlFunctionResponse = new MockResponse('<html></html>', ['http_code' => 200, 'response_headers' => ['content-type' => 'text/html']]);
$requestHtmlFunctionClient = new MockHttpClient([$requestHtmlFunctionResponse]);
$authenticatorProvider = new AuthenticatorProvider($requestHtmlFunctionClient);
$auth = new LoginFormAuthenticator($browser, $authenticatorProvider);
$authenticatorProvider = new AuthenticatorProvider($mockHttpClient);
$auth = new LoginFormAuthenticator($authenticatorProvider);
$loginRequired = $auth->isLoginRequired($siteConfig, file_get_contents(__DIR__ . '/../fixtures/nextinpact-article.html')); $loginRequired = $auth->isLoginRequired($siteConfig, file_get_contents(__DIR__ . '/../fixtures/nextinpact-article.html'));
$this->assertTrue($loginRequired); $this->assertTrue($loginRequired);

View file

@ -0,0 +1,239 @@
<?php
namespace Tests\Wallabag\HttpClient;
use Monolog\Handler\TestHandler;
use Monolog\Logger;
use PHPUnit\Framework\TestCase;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Wallabag\HttpClient\Authenticator;
use Wallabag\SiteConfig\ArraySiteConfigBuilder;
use Wallabag\SiteConfig\LoginFormAuthenticator;
class AuthenticatorTest extends TestCase
{
public function testLoginIfRequiredNotRequired()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$builder = new ArraySiteConfigBuilder(['example.com' => []]);
$subscriber = new Authenticator($builder, $authenticator);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$subscriber->setLogger($logger);
$login = $subscriber->loginIfRequired('http://www.example.com');
$this->assertFalse($login);
$records = $handler->getRecords();
$this->assertCount(1, $records);
$this->assertSame('loginIfRequired> will not require login', $records[0]['message']);
}
public function testLoginIfRequiredWithNotLoggedInUser()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$authenticator->expects($this->once())
->method('isLoggedIn')
->willReturn(false);
$authenticator->expects($this->once())
->method('login');
$builder = new ArraySiteConfigBuilder(['example.com' => ['requiresLogin' => true]]);
$subscriber = new Authenticator($builder, $authenticator);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$subscriber->setLogger($logger);
$login = $subscriber->loginIfRequired('http://www.example.com');
$this->assertTrue($login);
$records = $handler->getRecords();
$this->assertCount(1, $records);
$this->assertSame('loginIfRequired> user is not logged in, attach authenticator', $records[0]['message']);
}
public function testLoginIfRequestedNotRequired()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$builder = new ArraySiteConfigBuilder(['example.com' => []]);
$subscriber = new Authenticator($builder, $authenticator);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$subscriber->setLogger($logger);
$response = $this->getMockBuilder(ResponseInterface::class)
->disableOriginalConstructor()
->getMock();
$response->expects($this->once())
->method('getInfo')
->with($this->equalTo('url'))
->willReturn('http://www.example.com');
$login = $subscriber->loginIfRequested($response);
$this->assertFalse($login);
$records = $handler->getRecords();
$this->assertCount(1, $records);
$this->assertSame('loginIfRequested> will not require login', $records[0]['message']);
}
public function testLoginIfRequestedNotRequested()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$authenticator->expects($this->once())
->method('isLoginRequired')
->willReturn(false);
$builder = new ArraySiteConfigBuilder(['example.com' => [
'requiresLogin' => true,
'notLoggedInXpath' => '//html',
]]);
$subscriber = new Authenticator($builder, $authenticator);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$subscriber->setLogger($logger);
$response = $this->getMockBuilder(ResponseInterface::class)
->disableOriginalConstructor()
->getMock();
$response->expects($this->once())
->method('getInfo')
->with($this->equalTo('url'))
->willReturn('http://www.example.com');
$response->expects($this->once())
->method('getContent')
->willReturn('<html><body/></html>');
$login = $subscriber->loginIfRequested($response);
$this->assertFalse($login);
$records = $handler->getRecords();
$this->assertCount(1, $records);
$this->assertSame('loginIfRequested> retry with login not required', $records[0]['message']);
}
public function testLoginIfRequestedRequested()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$authenticator->expects($this->once())
->method('isLoginRequired')
->willReturn(true);
$authenticator->expects($this->once())
->method('login');
$builder = new ArraySiteConfigBuilder(['example.com' => [
'requiresLogin' => true,
'notLoggedInXpath' => '//html',
]]);
$subscriber = new Authenticator($builder, $authenticator);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$subscriber->setLogger($logger);
$response = $this->getMockBuilder(ResponseInterface::class)
->disableOriginalConstructor()
->getMock();
$response->expects($this->once())
->method('getInfo')
->with($this->equalTo('url'))
->willReturn('http://www.example.com');
$response->expects($this->once())
->method('getContent')
->willReturn('<html><body/></html>');
$login = $subscriber->loginIfRequested($response);
$this->assertTrue($login);
$records = $handler->getRecords();
$this->assertCount(1, $records);
$this->assertSame('loginIfRequested> retry with login required', $records[0]['message']);
}
public function testLoginIfRequestedRedirect()
{
$authenticator = $this->getMockBuilder(LoginFormAuthenticator::class)
->disableOriginalConstructor()
->getMock();
$builder = new ArraySiteConfigBuilder(['example.com' => [
'requiresLogin' => true,
'notLoggedInXpath' => '//html',
]]);
$subscriber = new Authenticator($builder, $authenticator);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$subscriber->setLogger($logger);
$response = $this->getMockBuilder(ResponseInterface::class)
->disableOriginalConstructor()
->getMock();
$response->expects($this->once())
->method('getInfo')
->with($this->equalTo('url'))
->willReturn('http://www.example.com');
$response->expects($this->once())
->method('getContent')
->willReturn('');
$login = $subscriber->loginIfRequested($response);
$this->assertFalse($login);
$records = $handler->getRecords();
$this->assertCount(1, $records);
$this->assertSame('loginIfRequested> empty body, ignoring', $records[0]['message']);
}
}