Hello,
This issue also applies to 6.x-1.x.
Here is my use case.
Let's say my website is www.example.com and has a French version www.example.fr. I need language negotiation to be set to "by domain name only" (Drupal core setting).
When set, Drupal outputs absolute URLs using the current language's domain name (which needs to contain a scheme, and is, in my case, "http://www.example.com" for English, as only a few pages need to be secured). It also means that url() function will outputs absolute URL using this domain as a base, and same goes for forms action attribute.
Let's take a specific page of my site, www.example.com/node/7, that displays a webform. This webform's form action attribute is "http://www.example.com/node/7".
Enters Secure Pages. Let's say I choose to "make secure only the listed pages", and add node/7 to the list.
When visiting http://www.example.com/node/7, secure pages does its job and redirects to the same page, but using HTTPS.
But, and that is the issue I want to raise here. The Webform's form action attribute didn't change and is still "http://www.example.com/node/7". Which means that my webform will be submitted in a unsecure way, and my browser will throw me a warning about that.
Looking at 6.x-2.x code, especially the hook_form_alter() implementation (line 71), this struck me:
/**
* Implements hook_form_alter().
*/
function securepages_form_alter(&$form, &$form_state, $form_id) {
$is_https = securepages_is_secure();
global $user;
if (!variable_get('securepages_enable', 0)) {
return;
}
if (isset($form['#action']) && securepages_can_alter_url($form['#action'])) {
// Remove the base_path, and extract the path component.
$url = substr($form['#action'], strlen(base_path()));
$url = @parse_url($url);
$path = drupal_get_normal_path($url['path']);
In my case, $form['#action'] is "http://www.example.com/node/7" and base_path() returns "/". Although securepages_can_alter_url() function considers the fact that the URL can be absolute, it looks like the code I pasted above makes the assumption that $form['#action'] is relative, which is not always true. This has the small consequence, in my case, to get $url['scheme'] equal to "ttp". For sites running on a subfolder (for example: www.example.com/drupal_root/), then the parse would fail worsely, either eating a few characters form the host, or failing completely to return a parsed URL.
My first suggestion, thus, is to change the code to:
if (isset($form['#action']) && securepages_can_alter_url($form['#action'])) {
// Remove the base_path, and extract the path component.
$url = @parse_url($form['#action']);
$path = substr($url['path'], strlen(base_path()));
$path = drupal_get_normal_path($path);
But this is not enough, as my form still submits to HTTP. Let's have a look at a few lines below:
if ($page_match && !$is_https) {
$form['#action'] = url($path, array('absolute' => TRUE, 'base_url' => securepages_baseurl(TRUE)));
}
elseif ($page_match === 0 && $is_https && variable_get('securepages_switch', FALSE)) {
$form['#action'] = url($path, array('absolute' => TRUE, 'base_url' => securepages_baseurl(FALSE)));
}
}
In words:
- if the current page is not secured, but the form action should be, then change the form action to be in HTTPS
- if the current page is secured, but the form action should not be, and the administrator wanted to "Switch back to http pages when there are no matches", then change the form action to be in HTTP
I understand that this code makes the assumption that if the current page is secured, then by default the form action as already been secured (either because it is a relative path, or because url() function outputted an absolute URL that matches current page, so is already in HTTPS). This statement becomes wrong as soon as language negotiation to be set to "by domain name only" (look back at my explanation on top).
I suggest then to alter the form's action all the time, and say:
- wether the current page is secured or not, if form action should be secured, then change the form action to be in HTTPS
- wether the current page is secured or not, if the form action should not be secured, and the administrator wanted to "Switch back to http pages when there are no matches", then change the form action to be in HTTP
This will alter the form action more often, in most case, won't change anything, but in the case I describe, it will change the form action, and will work.
Translated in code, we get something like this:
if ($page_match) {
$form['#action'] = url($path, array('absolute' => TRUE, 'base_url' => securepages_baseurl(TRUE)));
}
elseif ($page_match === 0 && variable_get('securepages_switch', FALSE)) {
$form['#action'] = url($path, array('absolute' => TRUE, 'base_url' => securepages_baseurl(FALSE)));
}
}
Thanks for your attention, any remark is welcome. I will also try to provide a patch soon.
Regards,
David
| Comment | File | Size | Author |
|---|---|---|---|
| #2 | 1932722-2-securepages-form-language-by-domain-6.x-1.x.patch | 1.04 KB | David Stosik |
| #1 | 1932722-1-securepages-form-language-by-domain.patch | 3.02 KB | David Stosik |
Comments
Comment #1
David Stosik commentedHello,
Here is a patch for 6.x-2.x-dev.
I realized that url() forces the base_url to be current language domain if negotiation "by domain name" and if no language is passed in options. So I tricked Drupal by passing a fake language object to url() function.
I don't like it because it feels a bit "hackish", but there is no other way to force base_url when calling url(), if language negotiation is by domain name...
Any test or remark are welcome.
David
Comment #2
David Stosik commentedAnd here is a backport to 6.x-1.x branch, which was easier to implement, because 6.x-1.x does not use
url()function.Regards,
David
Comment #3
astonvictor commentedI'm closing it because the issue was created a long time ago without any further steps.
if you still need it then raise a new one.
thanks