@@ -54,36 +54,38 @@ protected function serverConfigHelp(): string {
5454 * Get all possible URLs that need to be checked for a local request test.
5555 * This takes all `trusted_domains` and the CLI overwrite URL into account.
5656 *
57- * @param string $url The relative URL to test starting with a /
57+ * @param string $url The absolute path (absolute URL without host but with web-root) to test starting with a /
58+ * @param bool $isRootRequest Set to remove the web-root from URL and host (e.g. when requesting a path in the domain root like '/.well-known')
5859 * @return list<string> List of possible absolute URLs
5960 */
60- protected function getTestUrls (string $ url , bool $ removeWebroot ): array {
61+ protected function getTestUrls (string $ url , bool $ isRootRequest = false ): array {
6162 $ url = '/ ' . ltrim ($ url , '/ ' );
6263
6364 $ webroot = rtrim ($ this ->urlGenerator ->getWebroot (), '/ ' );
64- // Similar to `getAbsoluteURL` of URLGenerator:
65- // The Nextcloud web root could already be prepended.
66- if ( $ webroot !== '' && str_starts_with ( $ url , $ webroot )) {
65+ if ( $ isRootRequest === false && $ webroot !== '' && str_starts_with ( $ url , $ webroot )) {
66+ // The URL contains the web- root but also the base url does so,
67+ // so we need to remove the web-root from the URL.
6768 $ url = substr ($ url , strlen ($ webroot ));
6869 }
6970
70- $ hosts = [];
71+ // Base URLs to test
72+ $ baseUrls = [];
7173
72- /* Try overwrite.cli.url first, it’s supposed to be how the server contacts itself */
74+ // Try overwrite.cli.url first, it’s supposed to be how the server contacts itself
7375 $ cliUrl = $ this ->config ->getSystemValueString ('overwrite.cli.url ' , '' );
7476 if ($ cliUrl !== '' ) {
75- $ hosts [] = $ this ->normalizeUrl (
77+ // The CLI URL already contains the web-root, so we need to normalize it if requested
78+ $ baseUrls [] = $ this ->normalizeUrl (
7679 $ cliUrl ,
77- $ webroot ,
78- $ removeWebroot
80+ $ isRootRequest
7981 );
8082 }
8183
82- /* Try URL generator second */
83- $ hosts [] = $ this ->normalizeUrl (
84+ // Try URL generator second
85+ // The base URL also contains the webroot so also normalize it
86+ $ baseUrls [] = $ this ->normalizeUrl (
8487 $ this ->urlGenerator ->getBaseUrl (),
85- $ webroot ,
86- $ removeWebroot
88+ $ isRootRequest
8789 );
8890
8991 /* Last resort: trusted domains */
@@ -93,47 +95,52 @@ protected function getTestUrls(string $url, bool $removeWebroot): array {
9395 /* Ignore domains with a wildcard */
9496 continue ;
9597 }
96- $ hosts [] = $ this ->normalizeUrl ("https:// $ host$ webroot " , $ webroot , $ removeWebroot );
97- $ hosts [] = $ this ->normalizeUrl ("http:// $ host$ webroot " , $ webroot , $ removeWebroot );
98+ $ baseUrls [] = $ this ->normalizeUrl ("https:// $ host$ webroot " , $ isRootRequest );
99+ $ baseUrls [] = $ this ->normalizeUrl ("http:// $ host$ webroot " , $ isRootRequest );
98100 }
99101
100- return array_map (fn (string $ host ) => $ host . $ url , array_values (array_unique ($ hosts )));
102+ return array_map (fn (string $ host ) => $ host . $ url , array_values (array_unique ($ baseUrls )));
101103 }
102104
103105 /**
104106 * Strip a trailing slash and remove the webroot if requested.
107+ * @param string $url The URL to normalize. Should be an absolute URL containing scheme, host and optionally web-root.
108+ * @param bool $removeWebroot If set the web-root is removed from the URL and an absolute URL with only the scheme and host (optional port) is returned
105109 */
106- protected function normalizeUrl (string $ url , string $ webroot , bool $ removeWebroot ): string {
107- $ url = rtrim ($ url , '/ ' );
108- if ($ removeWebroot && $ webroot !== '' && str_ends_with ($ url , $ webroot )) {
109- $ url = substr ($ url , 0 , -strlen ($ webroot ));
110+ protected function normalizeUrl (string $ url , bool $ removeWebroot ): string {
111+ if ($ removeWebroot ) {
112+ $ segments = parse_url ($ url );
113+ $ port = isset ($ segments ['port ' ]) ? (': ' . $ segments ['port ' ]) : '' ;
114+ return $ segments ['scheme ' ] . ':// ' . $ segments ['host ' ] . $ port ;
110115 }
111116 return rtrim ($ url , '/ ' );
112117 }
113118
114119 /**
115120 * Run a HTTP request to check header
116121 * @param string $method The HTTP method to use
117- * @param string $url The relative URL to check (e.g. output of IURLGenerator)
118- * @param bool $removeWebroot Remove the webroot from the URL (handle URL as relative to domain root)
119- * @param array{ignoreSSL?: bool, httpErrors?: bool, options?: array} $options Additional options, like
120- * [
121- * // Ignore invalid SSL certificates (e.g. self signed)
122- * 'ignoreSSL' => true,
123- * // Ignore requests with HTTP errors (will not yield if request has a 4xx or 5xx response)
124- * 'httpErrors' => true,
125- * ]
122+ * @param string $url The absolute path (URL with webroot but without host) to check, can be the output of `IURLGenerator`
123+ * @param bool $isRootRequest If set the webroot is removed from URLs to make the request target the host's root. Example usage are the /.well-known URLs in the root path.
124+ * @param array{ignoreSSL?: bool, httpErrors?: bool, options?: array} $options HTTP client related options, like
125+ * [
126+ * // Ignore invalid SSL certificates (e.g. self signed)
127+ * 'ignoreSSL' => true,
128+ * // Ignore requests with HTTP errors (will not yield if request has a 4xx or 5xx response)
129+ * 'httpErrors' => true,
130+ * // Additional options for the HTTP client (see `IClient`)
131+ * 'options' => [],
132+ * ]
126133 *
127134 * @return Generator<int, IResponse>
128135 */
129- protected function runRequest (string $ method , string $ url , array $ options = [], bool $ removeWebroot = false ): Generator {
136+ protected function runRequest (string $ method , string $ url , array $ options = [], bool $ isRootRequest = false ): Generator {
130137 $ options = array_merge (['ignoreSSL ' => true , 'httpErrors ' => true ], $ options );
131138
132139 $ client = $ this ->clientService ->newClient ();
133140 $ requestOptions = $ this ->getRequestOptions ($ options ['ignoreSSL ' ], $ options ['httpErrors ' ]);
134141 $ requestOptions = array_merge ($ requestOptions , $ options ['options ' ] ?? []);
135142
136- foreach ($ this ->getTestUrls ($ url , $ removeWebroot ) as $ testURL ) {
143+ foreach ($ this ->getTestUrls ($ url , $ isRootRequest ) as $ testURL ) {
137144 try {
138145 yield $ client ->request ($ method , $ testURL , $ requestOptions );
139146 } catch (\Throwable $ e ) {
@@ -147,11 +154,10 @@ protected function runRequest(string $method, string $url, array $options = [],
147154 * @param string $url The relative URL to check (e.g. output of IURLGenerator)
148155 * @param bool $ignoreSSL Ignore SSL certificates
149156 * @param bool $httpErrors Ignore requests with HTTP errors (will not yield if request has a 4xx or 5xx response)
150- * @param bool $removeWebroot Remove the webroot from the URL (handle URL as relative to domain root)
151157 * @return Generator<int, IResponse>
152158 */
153- protected function runHEAD (string $ url , bool $ ignoreSSL = true , bool $ httpErrors = true , bool $ removeWebroot = false ): Generator {
154- return $ this ->runRequest ('HEAD ' , $ url , ['ignoreSSL ' => $ ignoreSSL , 'httpErrors ' => $ httpErrors ], $ removeWebroot );
159+ protected function runHEAD (string $ url , bool $ ignoreSSL = true , bool $ httpErrors = true ): Generator {
160+ return $ this ->runRequest ('HEAD ' , $ url , ['ignoreSSL ' => $ ignoreSSL , 'httpErrors ' => $ httpErrors ]);
155161 }
156162
157163 protected function getRequestOptions (bool $ ignoreSSL , bool $ httpErrors ): array {
0 commit comments