+2021-04-19 Chris Gambrell <cgambrell@apple.com>
+
+ [LayoutTests] Convert http/tests/blink convert PHP to Python
+ https://bugs.webkit.org/show_bug.cgi?id=224702
+ <rdar://problem/76783504>
+
+ Reviewed by Darin Adler.
+
+ * http/tests/blink/sendbeacon/beacon-cookie-expected.txt:
+ * http/tests/blink/sendbeacon/beacon-cookie.html:
+ * http/tests/blink/sendbeacon/beacon-cross-origin-expected.txt:
+ * http/tests/blink/sendbeacon/beacon-cross-origin.html:
+ * http/tests/blink/sendbeacon/beacon-cross-origin.https-expected.txt:
+ * http/tests/blink/sendbeacon/beacon-cross-origin.https.html:
+ * http/tests/blink/sendbeacon/beacon-same-origin-expected.txt:
+ * http/tests/blink/sendbeacon/beacon-same-origin.html:
+ * http/tests/blink/sendbeacon/resources/check-beacon.php: Removed.
+ * http/tests/blink/sendbeacon/resources/check-beacon.py: Added.
+ (extensive_strip):
+ * http/tests/blink/sendbeacon/resources/save-beacon.php: Removed.
+ * http/tests/blink/sendbeacon/resources/save-beacon.py: Added.
+ (prettify):
+ (decode_multipart):
+ * http/tests/resources/portabilityLayer.py:
+ (get_post_data):
+ (get_request):
+ * platform/ios/http/tests/blink/sendbeacon/beacon-same-origin-expected.txt:
+ * platform/mac/http/tests/blink/sendbeacon/beacon-same-origin-expected.txt:
+
2021-04-19 Philippe Normand <pnormand@igalia.com>
Unreviewed, GLIB gardening
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-PASS navigator.sendBeacon("resources/save-beacon.php?name=cookie", "Blip"); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=cookie", "Blip"); is true
PASS Beacon sent successfully
PASS Content-Type: text/plain;charset=UTF-8
PASS Cookie: hello=world
finishJSTest();
}
- shouldBeTrue('navigator.sendBeacon("resources/save-beacon.php?name=cookie", "Blip");');
+ shouldBeTrue('navigator.sendBeacon("resources/save-beacon.py?name=cookie", "Blip");');
var xhr = new XMLHttpRequest();
- xhr.open("GET", "resources/check-beacon.php?name=cookie");
+ xhr.open("GET", "resources/check-beacon.py?name=cookie");
xhr.onload = function () {
var lines = xhr.responseText.split("\n");
for (var i in lines)
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-PASS navigator.sendBeacon("http://localhost:8000/blink/sendbeacon/resources/save-beacon.php?name=cross-origin", "CrossOrigin"); is true
+PASS navigator.sendBeacon("http://localhost:8000/blink/sendbeacon/resources/save-beacon.py?name=cross-origin", "CrossOrigin"); is true
PASS Beacon sent successfully
PASS Content-Type: text/plain;charset=UTF-8
PASS Origin: http://127.0.0.1:8000
//testRunner.dumpPingLoaderCallbacks();
}
- shouldBeTrue('navigator.sendBeacon("http://localhost:8000/blink/sendbeacon/resources/save-beacon.php?name=cross-origin", "CrossOrigin");');
+ shouldBeTrue('navigator.sendBeacon("http://localhost:8000/blink/sendbeacon/resources/save-beacon.py?name=cross-origin", "CrossOrigin");');
var xhr = new XMLHttpRequest();
- xhr.open("GET", "resources/check-beacon.php?name=cross-origin");
+ xhr.open("GET", "resources/check-beacon.py?name=cross-origin");
xhr.onload = function () {
var lines = xhr.responseText.split("\n");
for (var i in lines)
-Blocked access to external URL http://example.test:8000/blink/sendbeacon/resources/save-beacon.php?name=cross-origin
-CONSOLE MESSAGE: Beacon API cannot load http://example.test:8000/blink/sendbeacon/resources/save-beacon.php?name=cross-origin due to access control checks.
+Blocked access to external URL http://example.test:8000/blink/sendbeacon/resources/save-beacon.py?name=cross-origin
+CONSOLE MESSAGE: Beacon API cannot load http://example.test:8000/blink/sendbeacon/resources/save-beacon.py?name=cross-origin due to access control checks.
Verify navigator.sendBeacon() mixed content checking.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-PASS navigator.sendBeacon("http://example.test:8000/blink/sendbeacon/resources/save-beacon.php?name=cross-origin", "CrossOrigin"); is false
+PASS navigator.sendBeacon("http://example.test:8000/blink/sendbeacon/resources/save-beacon.py?name=cross-origin", "CrossOrigin"); is false
PASS successfullyParsed is true
TEST COMPLETE
testRunner.waitUntilDone();
}
- shouldBeFalse('navigator.sendBeacon("http://example.test:8000/blink/sendbeacon/resources/save-beacon.php?name=cross-origin", "CrossOrigin");');
+ shouldBeFalse('navigator.sendBeacon("http://example.test:8000/blink/sendbeacon/resources/save-beacon.py?name=cross-origin", "CrossOrigin");');
finishJSTest();
}
</script>
Sending beacon with type: [object String]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: text/plain;charset=UTF-8
PASS Origin: http://127.0.0.1:8000
PASS Body: SameOrigin
PASS
Sending beacon with type: [object Uint32Array]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: application/x-www-form-urlencoded
PASS Origin: http://127.0.0.1:8000
PASS Body: QAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAA==
PASS
Sending beacon with type: [object Blob]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: text/plain;from-beacon=true
PASS Origin: http://127.0.0.1:8000
PASS Body: hello world
PASS
Sending beacon with type: [object FormData]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: multipart/form-data;
PASS Origin: http://127.0.0.1:8000
PASS Body: key=value
PASS
Sending beacon with type: [object URLSearchParams]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: application/x-www-form-urlencoded;charset=UTF-8
PASS Origin: http://127.0.0.1:8000
return;
}
debug("Sending beacon with type: " + Object.prototype.toString.call(payload));
- shouldBeTrue('navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload);');
+ shouldBeTrue('navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload);');
var xhr = new XMLHttpRequest();
- xhr.open("GET", "resources/check-beacon.php?name=same-origin");
+ xhr.open("GET", "resources/check-beacon.py?name=same-origin");
xhr.onload = function () {
var lines = xhr.responseText.split("\n");
for (var i in lines)
+++ /dev/null
-<?php
-require_once '../../../resources/portabilityLayer.php';
-
-$beaconFilename = sys_get_temp_dir() . "/beacon" . (isset($_REQUEST['name']) ? $_REQUEST['name'] : "") . ".txt";
-
-$max_attempts = 700;
-$retries = isset($_REQUEST['retries']) ? (int)$_REQUEST['retries'] : $max_attempts;
-while (!file_exists($beaconFilename) && $retries != 0) {
- usleep(10000);
- # file_exists() caches results, we want to invalidate the cache.
- clearstatcache();
- $retries--;
-}
-
-header('Content-Type: text/plain');
-header('Access-Control-Allow-Origin: *');
-if (file_exists($beaconFilename)) {
- $beaconFile = false;
- if (is_readable($beaconFilename)) {
- $beaconFile = fopen($beaconFilename, 'r');
- }
- if ($beaconFile) {
- echo "Beacon sent successfully\n";
- while ($line = fgets($beaconFile)) {
- $trimmed = trim($line);
- if ($trimmed != "")
- echo "$trimmed\n";
- }
- fclose($beaconFile);
- unlink($beaconFilename);
- } else {
- echo "Beacon status not readable\n";
- }
-} else {
- echo "Beacon not sent\n";
-}
-?>
--- /dev/null
+#!/usr/bin/env python3
+
+import os
+import sys
+import tempfile
+import time
+
+file = __file__.split(':/cygwin')[-1]
+http_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(os.path.dirname(file)))))
+sys.path.insert(0, http_root)
+
+from resources.portabilityLayer import get_request
+
+
+def extensive_strip(text):
+ # Sometimes the string ends with \x00
+ # and .strip() does not remove it
+ text = text.strip()
+ while text[-1].encode() == b'\x00':
+ text = text[:-1]
+
+ return text
+
+
+request = get_request()
+beacon_filename = os.path.join(tempfile.gettempdir(), 'beacon{}.txt'.format(request.get('name', '')))
+
+max_attempts = 700
+retries = int(request.get('retries', max_attempts))
+while not os.path.isfile(beacon_filename) and retries != 0:
+ time.sleep(0.01)
+ retries -= 1
+
+sys.stdout.write(
+ 'Content-Type: text/plain\r\n'
+ 'Access-Control-Allow-Origin: *\r\n\r\n'
+)
+
+if os.path.isfile(beacon_filename):
+ with open(beacon_filename, 'r') as beacon_file:
+ sys.stdout.write('Beacon sent successfully\n')
+ for line in beacon_file.readlines():
+ trimmed = extensive_strip(line)
+ if trimmed != '':
+ sys.stdout.write('{}\n'.format(trimmed))
+
+ os.remove(beacon_filename)
+else:
+ sys.stdout.write('Beacon not sent\n')
+++ /dev/null
-<?php
-require_once '../../../resources/portabilityLayer.php';
-
-function prettify($name) {
- return str_replace(' ', '-', ucwords(str_replace('_', ' ', str_replace('http_', '', strtolower($name)))));
-}
-
-$beaconFilename = sys_get_temp_dir() . "/beacon" . (isset($_REQUEST['name']) ? $_REQUEST['name'] : "") . ".txt";
-$beaconFile = fopen($beaconFilename . ".tmp", 'w');
-$httpHeaders = $_SERVER;
-ksort($httpHeaders, SORT_STRING);
-$contentType = "";
-foreach ($httpHeaders as $name => $value) {
- if ($name === "CONTENT_TYPE" || $name === "HTTP_REFERER" || $name === "REQUEST_METHOD" || $name === "HTTP_COOKIE" || $name === "HTTP_ORIGIN") {
- if ($name === "CONTENT_TYPE") {
- $contentType = $value;
- $value = preg_replace('/boundary=.*$/', '', $value);
- }
- $headerName = prettify($name);
- fwrite($beaconFile, "$headerName: $value\n");
- }
-}
-$postdata = file_get_contents("php://input");
-if (strlen($postdata) == 0)
- $postdata = http_build_query($_POST);
-
-fwrite($beaconFile, "Length: " . strlen($postdata) . "\n");
-if (strpos($contentType, "application/") !== false) {
- $postdata = base64_encode($postdata);
-}
-
-fwrite($beaconFile, "Body: $postdata\n");
-fclose($beaconFile);
-rename($beaconFilename . ".tmp", $beaconFilename);
-
-if (!array_key_exists('dontclearcookies', $_GET)) {
- foreach ($_COOKIE as $name => $value)
- setcookie($name, "deleted", time() - 60, "/");
-}
-?>
--- /dev/null
+#!/usr/bin/env python3
+
+import os
+import re
+import sys
+import tempfile
+from base64 import b64encode
+from datetime import datetime, timedelta
+from urllib.parse import urlencode, parse_qs
+
+file = __file__.split(':/cygwin')[-1]
+http_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(os.path.dirname(file)))))
+sys.path.insert(0, http_root)
+
+from resources.portabilityLayer import get_cookies, get_post_data, get_request
+
+query = parse_qs(os.environ.get('QUERY_STRING', ''), keep_blank_values=True)
+
+
+def prettify(name):
+ return name.strip().lower().replace('http_', '').replace('_', ' ').title().replace(' ', '-')
+
+
+def decode_multipart(data, boundary):
+ data = [line for line in data.split('\r\n')[:-2] if line and boundary not in line]
+
+ key = None
+ data_obj = {}
+ for line in data:
+ if key is None:
+ key = re.search(r'\"(.*?)\"', line).group()[1:-1]
+ else:
+ data_obj[key] = line.strip()
+ key = None
+ return urlencode(data_obj)
+
+
+beacon_filename = os.path.join(tempfile.gettempdir(), 'beacon{}.txt'.format(get_request().get('name', '')))
+beacon_file = open('{}.tmp'.format(beacon_filename), 'w')
+
+content_type = ''
+boundary = None
+for name in sorted(os.environ.keys()):
+ if name in ['CONTENT_TYPE', 'HTTP_REFERER', 'REQUEST_METHOD', 'HTTP_COOKIE', 'HTTP_ORIGIN']:
+ value = os.environ.get(name)
+ if name == 'CONTENT_TYPE':
+ content_type = value
+
+ boundary = re.search(r'boundary=.*$', value)
+ if boundary is not None:
+ boundary = boundary.group().split('=')[-1]
+
+ value = re.sub(r'boundary=.*$', r'', value)
+
+ header_name = prettify(name)
+ beacon_file.write('{}: {}\n'.format(header_name, value))
+
+post_data = ''.join(sys.stdin.readlines())
+if len(post_data) == 0:
+ post_data = urlencode(get_post_data())
+
+if boundary is not None:
+ post_data = decode_multipart(post_data, boundary)
+
+beacon_file.write('Length: {}\n'.format(len(post_data)))
+
+if 'application/' in content_type:
+ post_data = b64encode(post_data.encode()).decode()
+
+beacon_file.write('Body: {}\n'.format(post_data.strip()))
+beacon_file.close()
+os.rename(beacon_filename + '.tmp', beacon_filename)
+
+if 'dontclearcookies' not in query.keys():
+ expires = datetime.utcnow() - timedelta(seconds=60)
+ for name in get_cookies().keys():
+ sys.stdout.write('Set-Cookie: {}=deleted; expires={} GMT; Max-Age=0; path=/\r\n'.format(name, expires.strftime('%a, %d-%b-%Y %H:%M:%S')))
+
+sys.stdout.write('Content-Type: text/html\r\n\r\n')
import os
from urllib.parse import parse_qs
+query = parse_qs(os.environ.get('QUERY_STRING', ''), keep_blank_values=True)
+post_data = {}
+
def get_cookies():
cookies = {}
return cookies
-def get_request():
- request = {}
+def get_post_data():
request_method = os.environ.get('REQUEST_METHOD', '')
if request_method == 'POST':
form = cgi.FieldStorage()
for key in form.keys():
- request.update({key: form.getvalue(key)})
- else:
- query = parse_qs(os.environ.get('QUERY_STRING', ''), keep_blank_values=True)
- for key in query.keys():
- request.update({key: query[key][0]})
+ if key not in query.keys():
+ post_data.update({key: form.getvalue(key)})
+
+ return post_data
- request.update(get_cookies())
+def get_request():
+ request = {}
+ for key in query.keys():
+ request.update({key: query[key][0]})
+
+ # request.update(get_post_data())
+ request.update(get_cookies())
return request
Sending beacon with type: [object String]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: text/plain;charset=UTF-8
PASS Origin: http://127.0.0.1:8000
PASS Body: SameOrigin
PASS
Sending beacon with type: [object Uint32Array]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Origin: http://127.0.0.1:8000
PASS Referer: http://127.0.0.1:8000/blink/sendbeacon/beacon-same-origin.html
PASS Body: @\0\0\0A\0\0\0B\0\0\0C\0\0\0D\0\0\0E\0\0\0F\0\0\0G\0\0\0H\0\0\0I
PASS
Sending beacon with type: [object Blob]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: text/plain;from-beacon=true
PASS Origin: http://127.0.0.1:8000
PASS Body: hello world
PASS
Sending beacon with type: [object FormData]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: multipart/form-data;
PASS Origin: http://127.0.0.1:8000
PASS Body: key=value
PASS
Sending beacon with type: [object URLSearchParams]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: application/x-www-form-urlencoded;charset=UTF-8
PASS Origin: http://127.0.0.1:8000
Sending beacon with type: [object String]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: text/plain;charset=UTF-8
PASS Origin: http://127.0.0.1:8000
PASS Body: SameOrigin
PASS
Sending beacon with type: [object Uint32Array]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Origin: http://127.0.0.1:8000
PASS Referer: http://127.0.0.1:8000/blink/sendbeacon/beacon-same-origin.html
PASS Body: @\0\0\0A\0\0\0B\0\0\0C\0\0\0D\0\0\0E\0\0\0F\0\0\0G\0\0\0H\0\0\0I
PASS
Sending beacon with type: [object Blob]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: text/plain;from-beacon=true
PASS Origin: http://127.0.0.1:8000
PASS Body: hello world
PASS
Sending beacon with type: [object FormData]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: multipart/form-data;
PASS Origin: http://127.0.0.1:8000
PASS Body: key=value
PASS
Sending beacon with type: [object URLSearchParams]
-PASS navigator.sendBeacon("resources/save-beacon.php?name=same-origin", payload); is true
+PASS navigator.sendBeacon("resources/save-beacon.py?name=same-origin", payload); is true
PASS Beacon sent successfully
PASS Content-Type: application/x-www-form-urlencoded;charset=UTF-8
PASS Origin: http://127.0.0.1:8000