mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-16 00:08:59 +00:00
improve XMLHTTPRequest. Legacy xhr.html pass
This commit is contained in:
@@ -201,7 +201,11 @@ fn promiseRejectCallback(v8_msg: v8.C_PromiseRejectMessage) callconv(.c) void {
|
||||
else
|
||||
"no value";
|
||||
|
||||
log.debug(.js, "unhandled rejection", .{ .value = value, .stack = context.stackTrace() catch |err| @errorName(err) orelse "???" });
|
||||
log.debug(.js, "unhandled rejection", .{
|
||||
.value = value,
|
||||
.stack = context.stackTrace() catch |err| @errorName(err) orelse "???",
|
||||
.note = "This should be updated to call window.unhandledrejection",
|
||||
});
|
||||
}
|
||||
|
||||
// Give it a Zig struct, get back a v8.FunctionTemplate.
|
||||
|
||||
@@ -11,13 +11,12 @@
|
||||
testing.expectEqual(cbk, req.onload);
|
||||
req.onload = cbk;
|
||||
|
||||
req.open('GET', 'http://127.0.0.1:9582/xhr');
|
||||
req.open('GET', 'http://127.0.0.1:9589/xhr');
|
||||
testing.expectEqual(0, req.status);
|
||||
testing.expectEqual('', req.statusText);
|
||||
testing.expectEqual('', req.getAllResponseHeaders());
|
||||
testing.expectEqual(null, req.getResponseHeader('Content-Type'));
|
||||
testing.expectEqual('', req.responseText);
|
||||
|
||||
req.send();
|
||||
});
|
||||
|
||||
@@ -31,7 +30,6 @@
|
||||
testing.expectEqual('content-length: 100\r\nContent-Type: text/html; charset=utf-8\r\n', req.getAllResponseHeaders());
|
||||
testing.expectEqual(100, req.responseText.length);
|
||||
testing.expectEqual(req.responseText.length, req.response.length);
|
||||
testing.expectEqual(true, req.responseXML instanceof Document);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -39,7 +37,7 @@
|
||||
const req2 = new XMLHttpRequest()
|
||||
const promise2 = new Promise((resolve) => {
|
||||
req2.onload = resolve;
|
||||
req2.open('GET', 'http://127.0.0.1:9582/xhr')
|
||||
req2.open('GET', 'http://127.0.0.1:9589/xhr')
|
||||
req2.responseType = 'document';
|
||||
req2.send()
|
||||
});
|
||||
@@ -56,7 +54,7 @@
|
||||
const req3 = new XMLHttpRequest()
|
||||
const promise3 = new Promise((resolve) => {
|
||||
req3.onload = resolve;
|
||||
req3.open('GET', 'http://127.0.0.1:9582/xhr/json')
|
||||
req3.open('GET', 'http://127.0.0.1:9589/xhr/json')
|
||||
req3.responseType = 'json';
|
||||
req3.send()
|
||||
});
|
||||
@@ -72,7 +70,7 @@
|
||||
const req4 = new XMLHttpRequest()
|
||||
const promise4 = new Promise((resolve) => {
|
||||
req4.onload = resolve;
|
||||
req4.open('POST', 'http://127.0.0.1:9582/xhr')
|
||||
req4.open('POST', 'http://127.0.0.1:9589/xhr')
|
||||
req4.send('foo')
|
||||
});
|
||||
|
||||
@@ -94,7 +92,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
req5.open('GET', 'http://127.0.0.1:9582/xhr');
|
||||
req5.open('GET', 'http://127.0.0.1:9589/xhr');
|
||||
req5.send();
|
||||
});
|
||||
|
||||
|
||||
@@ -7,4 +7,195 @@
|
||||
testing.expectEqual(2, XMLHttpRequest.HEADERS_RECEIVED);
|
||||
testing.expectEqual(3, XMLHttpRequest.LOADING);
|
||||
testing.expectEqual(4, XMLHttpRequest.DONE);
|
||||
|
||||
testing.async(async (restore) => {
|
||||
const req = new XMLHttpRequest();
|
||||
const event = await new Promise((resolve) => {
|
||||
function cbk(event) {
|
||||
resolve(event)
|
||||
}
|
||||
|
||||
req.onload = cbk;
|
||||
testing.expectEqual(cbk, req.onload);
|
||||
req.onload = cbk;
|
||||
|
||||
req.open('GET', 'http://127.0.0.1:9582/xhr');
|
||||
testing.expectEqual(0, req.status);
|
||||
testing.expectEqual('', req.statusText);
|
||||
testing.expectEqual('', req.getAllResponseHeaders());
|
||||
testing.expectEqual(null, req.getResponseHeader('Content-Type'));
|
||||
testing.expectEqual('', req.responseText);
|
||||
testing.expectEqual('', req.responseURL);
|
||||
req.send();
|
||||
});
|
||||
|
||||
restore();
|
||||
testing.expectEqual('load', event.type);
|
||||
testing.expectEqual(true, event.loaded > 0);
|
||||
testing.expectEqual(true, event instanceof ProgressEvent);
|
||||
testing.expectEqual(200, req.status);
|
||||
testing.expectEqual('OK', req.statusText);
|
||||
testing.expectEqual('text/html; charset=utf-8', req.getResponseHeader('Content-Type'));
|
||||
testing.expectEqual('content-length: 100\r\nContent-Type: text/html; charset=utf-8\r\n', req.getAllResponseHeaders());
|
||||
testing.expectEqual(100, req.responseText.length);
|
||||
testing.expectEqual(req.responseText.length, req.response.length);
|
||||
testing.expectEqual('http://127.0.0.1:9582/xhr', req.responseURL);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script id=xhr2>
|
||||
const req2 = new XMLHttpRequest()
|
||||
testing.async(async (restore) => {
|
||||
await new Promise((resolve) => {
|
||||
req2.onload = resolve;
|
||||
req2.open('GET', 'http://127.0.0.1:9582/xhr')
|
||||
req2.responseType = 'document';
|
||||
req2.send()
|
||||
});
|
||||
|
||||
restore();
|
||||
testing.expectEqual(200, req2.status);
|
||||
testing.expectEqual('OK', req2.statusText);
|
||||
testing.expectEqual(true, req2.response instanceof Document);
|
||||
testing.expectEqual(true, req2.responseXML instanceof Document);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script id=xhr3>
|
||||
const req3 = new XMLHttpRequest()
|
||||
testing.async(async (restore) => {
|
||||
await new Promise((resolve) => {
|
||||
req3.onload = resolve;
|
||||
req3.open('GET', 'http://127.0.0.1:9582/xhr/json')
|
||||
req3.responseType = 'json';
|
||||
req3.send()
|
||||
});
|
||||
|
||||
restore();
|
||||
testing.expectEqual(200, req3.status);
|
||||
testing.expectEqual('OK', req3.statusText);
|
||||
testing.expectEqual('9000!!!', req3.response.over);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script id=xhr4>
|
||||
const req4 = new XMLHttpRequest()
|
||||
testing.async(async (restore) => {
|
||||
await new Promise((resolve) => {
|
||||
req4.onload = resolve;
|
||||
req4.open('POST', 'http://127.0.0.1:9582/xhr')
|
||||
req4.send('foo')
|
||||
});
|
||||
|
||||
restore();
|
||||
testing.expectEqual(200, req4.status);
|
||||
testing.expectEqual('OK', req4.statusText);
|
||||
testing.expectEqual(true, req4.responseText.length > 64);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script id=xhr5>
|
||||
testing.async(async (restore) => {
|
||||
let state = [];
|
||||
const req5 = new XMLHttpRequest();
|
||||
|
||||
const result = await new Promise((resolve) => {
|
||||
req5.onreadystatechange = (e) => {
|
||||
state.push(req5.readyState);
|
||||
if (req5.readyState === XMLHttpRequest.DONE) {
|
||||
resolve({states: state, target: e.currentTarget});
|
||||
}
|
||||
}
|
||||
|
||||
req5.open('GET', 'http://127.0.0.1:9582/xhr');
|
||||
req5.send();
|
||||
});
|
||||
|
||||
restore();
|
||||
const {states: states, target: target} = result;
|
||||
testing.expectEqual(4, states.length)
|
||||
testing.expectEqual(XMLHttpRequest.OPENED, states[0]);
|
||||
testing.expectEqual(XMLHttpRequest.HEADERS_RECEIVED, states[1]);
|
||||
testing.expectEqual(XMLHttpRequest.LOADING, states[2]);
|
||||
testing.expectEqual(XMLHttpRequest.DONE, states[3]);
|
||||
testing.expectEqual(req5, target);
|
||||
})
|
||||
</script>
|
||||
|
||||
<script id=xhr_redirect>
|
||||
testing.async(async (restore) => {
|
||||
const req = new XMLHttpRequest();
|
||||
await new Promise((resolve) => {
|
||||
req.onload = resolve;
|
||||
req.open('GET', 'http://127.0.0.1:9582/xhr/redirect');
|
||||
req.send();
|
||||
});
|
||||
|
||||
restore();
|
||||
testing.expectEqual(200, req.status);
|
||||
testing.expectEqual('OK', req.statusText);
|
||||
testing.expectEqual('http://127.0.0.1:9582/xhr', req.responseURL);
|
||||
testing.expectEqual(100, req.responseText.length);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script id=xhr_404>
|
||||
testing.async(async (restore) => {
|
||||
|
||||
const req = new XMLHttpRequest();
|
||||
await new Promise((resolve) => {
|
||||
req.onload = resolve;
|
||||
req.open('GET', 'http://127.0.0.1:9582/xhr/404');
|
||||
req.send();
|
||||
});
|
||||
|
||||
restore();
|
||||
testing.expectEqual(404, req.status);
|
||||
testing.expectEqual('Not Found', req.statusText);
|
||||
testing.expectEqual('Not Found', req.responseText);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script id=xhr_500>
|
||||
testing.async(async (restore) => {
|
||||
const req = new XMLHttpRequest();
|
||||
await new Promise((resolve) => {
|
||||
req.onload = resolve;
|
||||
req.open('GET', 'http://127.0.0.1:9582/xhr/500');
|
||||
req.send();
|
||||
});
|
||||
|
||||
restore();
|
||||
testing.expectEqual(500, req.status);
|
||||
testing.expectEqual('Internal Server Error', req.statusText);
|
||||
testing.expectEqual('Internal Server Error', req.responseText);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script id=xhr_abort>
|
||||
testing.async(async (restore) => {
|
||||
const req = new XMLHttpRequest();
|
||||
let abortFired = false;
|
||||
let errorFired = false;
|
||||
let loadEndFired = false;
|
||||
|
||||
await new Promise((resolve) => {
|
||||
req.onabort = () => { abortFired = true; };
|
||||
req.onerror = () => { errorFired = true; };
|
||||
req.onloadend = () => {
|
||||
loadEndFired = true;
|
||||
resolve();
|
||||
};
|
||||
|
||||
req.open('GET', 'http://127.0.0.1:9582/xhr');
|
||||
req.send();
|
||||
req.abort();
|
||||
});
|
||||
|
||||
restore();
|
||||
testing.expectEqual(true, abortFired);
|
||||
testing.expectEqual(true, errorFired);
|
||||
testing.expectEqual(true, loadEndFired);
|
||||
testing.expectEqual(XMLHttpRequest.UNSENT, req.readyState);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -64,10 +64,8 @@
|
||||
}
|
||||
|
||||
async function async(cb) {
|
||||
const script_id = document.currentScript.id;
|
||||
const stack = new Error().stack;
|
||||
async_capture = {script_id: script_id, stack: stack};
|
||||
await cb();
|
||||
let capture = {script_id: document.currentScript.id, stack: new Error().stack};
|
||||
await cb(() => { async_capture = capture; });
|
||||
async_capture = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ const Http = @import("../../../http/Http.zig");
|
||||
const URL = @import("../../URL.zig");
|
||||
const Mime = @import("../../Mime.zig");
|
||||
const Page = @import("../../Page.zig");
|
||||
const Node = @import("../Node.zig");
|
||||
const Event = @import("../Event.zig");
|
||||
const Headers = @import("Headers.zig");
|
||||
const EventTarget = @import("../EventTarget.zig");
|
||||
@@ -44,17 +45,19 @@ _method: Http.Method = .GET,
|
||||
_request_headers: *Headers,
|
||||
_request_body: ?[]const u8 = null,
|
||||
|
||||
_response: std.ArrayList(u8) = .empty,
|
||||
_response: ?Response = null,
|
||||
_response_data: std.ArrayList(u8) = .empty,
|
||||
_response_status: u16 = 0,
|
||||
_response_len: ?usize = 0,
|
||||
_response_url: [:0]const u8 = "",
|
||||
_response_mime: ?Mime = null,
|
||||
_response_headers: std.ArrayList([]const u8) = .empty,
|
||||
_response_type: ResponseType = .text,
|
||||
|
||||
_state: State = .unsent,
|
||||
_ready_state: ReadyState = .unsent,
|
||||
_on_ready_state_change: ?js.Function = null,
|
||||
|
||||
const State = enum(u8) {
|
||||
const ReadyState = enum(u8) {
|
||||
unsent = 0,
|
||||
opened = 1,
|
||||
headers_received = 2,
|
||||
@@ -62,9 +65,16 @@ const State = enum(u8) {
|
||||
done = 4,
|
||||
};
|
||||
|
||||
const Response = union(ResponseType) {
|
||||
text: []const u8,
|
||||
json: std.json.Value,
|
||||
document: *Node.Document,
|
||||
};
|
||||
|
||||
const ResponseType = enum {
|
||||
text,
|
||||
json,
|
||||
document,
|
||||
// TODO: other types to support
|
||||
};
|
||||
|
||||
@@ -100,30 +110,6 @@ pub fn setOnReadyStateChange(self: *XMLHttpRequest, cb_: ?js.Function) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getResponseType(self: *const XMLHttpRequest) []const u8 {
|
||||
return @tagName(self._response_type);
|
||||
}
|
||||
|
||||
pub fn setResponseType(self: *XMLHttpRequest, value: []const u8) void {
|
||||
if (std.meta.stringToEnum(ResponseType, value)) |rt| {
|
||||
self._response_type = rt;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getStatus(self: *const XMLHttpRequest) u16 {
|
||||
return self._response_status;
|
||||
}
|
||||
|
||||
pub fn getResponse(self: *const XMLHttpRequest, page: *Page) !Response {
|
||||
switch (self._response_type) {
|
||||
.text => return .{ .text = self._response.items },
|
||||
.json => {
|
||||
const parsed = try std.json.parseFromSliceLeaky(std.json.Value, page.call_arena, self._response.items, .{});
|
||||
return .{ .json = parsed };
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this takes an opitonal 3 more parameters
|
||||
// TODO: url should be a union, as it can be multiple things
|
||||
pub fn open(self: *XMLHttpRequest, method_: []const u8, url: [:0]const u8) !void {
|
||||
@@ -168,6 +154,105 @@ pub fn send(self: *XMLHttpRequest, body_: ?[]const u8) !void {
|
||||
.error_callback = httpErrorCallback,
|
||||
});
|
||||
}
|
||||
pub fn getReadyState(self: *const XMLHttpRequest) u32 {
|
||||
return @intFromEnum(self._ready_state);
|
||||
}
|
||||
|
||||
pub fn getResponseHeader(self: *const XMLHttpRequest, name: []const u8) ?[]const u8 {
|
||||
for (self._response_headers.items) |entry| {
|
||||
if (entry.len <= name.len) {
|
||||
continue;
|
||||
}
|
||||
if (std.ascii.eqlIgnoreCase(name, entry[0..name.len]) == false) {
|
||||
continue;
|
||||
}
|
||||
if (entry[name.len] != ':') {
|
||||
continue;
|
||||
}
|
||||
return std.mem.trimLeft(u8, entry[name.len + 1 ..], " ");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn getAllResponseHeaders(self: *const XMLHttpRequest, page: *Page) ![]const u8 {
|
||||
if (self._ready_state != .done) {
|
||||
// MDN says this should return null, but it seems to return an empty string
|
||||
// in every browser. Specs are too hard for a dumbo like me to understand.
|
||||
return "";
|
||||
}
|
||||
|
||||
var buf = std.Io.Writer.Allocating.init(page.call_arena);
|
||||
for (self._response_headers.items) |entry| {
|
||||
try buf.writer.writeAll(entry);
|
||||
try buf.writer.writeAll("\r\n");
|
||||
}
|
||||
return buf.written();
|
||||
}
|
||||
|
||||
pub fn getResponseType(self: *const XMLHttpRequest) []const u8 {
|
||||
if (self._ready_state != .done) {
|
||||
return "";
|
||||
}
|
||||
return @tagName(self._response_type);
|
||||
}
|
||||
|
||||
pub fn setResponseType(self: *XMLHttpRequest, value: []const u8) void {
|
||||
if (std.meta.stringToEnum(ResponseType, value)) |rt| {
|
||||
self._response_type = rt;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getResponseText(self: *const XMLHttpRequest) []const u8 {
|
||||
return self._response_data.items;
|
||||
}
|
||||
|
||||
pub fn getStatus(self: *const XMLHttpRequest) u16 {
|
||||
return self._response_status;
|
||||
}
|
||||
|
||||
pub fn getStatusText(self: *const XMLHttpRequest) []const u8 {
|
||||
return std.http.Status.phrase(@enumFromInt(self._response_status)) orelse "";
|
||||
}
|
||||
|
||||
pub fn getResponseURL(self: *XMLHttpRequest) []const u8 {
|
||||
return self._response_url;
|
||||
}
|
||||
|
||||
pub fn getResponse(self: *XMLHttpRequest, page: *Page) !?Response {
|
||||
if (self._ready_state != .done) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (self._response) |res| {
|
||||
// was already loaded
|
||||
return res;
|
||||
}
|
||||
|
||||
const data = self._response_data.items;
|
||||
const res: Response = switch (self._response_type) {
|
||||
.text => .{ .text = data },
|
||||
.json => blk: {
|
||||
const parsed = try std.json.parseFromSliceLeaky(std.json.Value, page.call_arena, data, .{});
|
||||
break :blk .{ .json = parsed };
|
||||
},
|
||||
.document => blk: {
|
||||
const document = try page._factory.node(Node.Document{ ._proto = undefined, ._type = .generic });
|
||||
try page.parseHtmlAsChildren(document.asNode(), data);
|
||||
break :blk .{ .document = document };
|
||||
},
|
||||
};
|
||||
|
||||
self._response = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
pub fn getResponseXML(self: *XMLHttpRequest, page: *Page) !?*Node.Document {
|
||||
const res = (try self.getResponse(page)) orelse return null;
|
||||
return switch (res) {
|
||||
.document => |doc| doc,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
fn httpStartCallback(transfer: *Http.Transfer) !void {
|
||||
const self: *XMLHttpRequest = @ptrCast(@alignCast(transfer.ctx));
|
||||
@@ -211,8 +296,9 @@ fn httpHeaderDoneCallback(transfer: *Http.Transfer) !void {
|
||||
self._response_status = header.status;
|
||||
if (transfer.getContentLength()) |cl| {
|
||||
self._response_len = cl;
|
||||
try self._response.ensureTotalCapacity(self._arena, cl);
|
||||
try self._response_data.ensureTotalCapacity(self._arena, cl);
|
||||
}
|
||||
self._response_url = try self._arena.dupeZ(u8, std.mem.span(header.url));
|
||||
|
||||
try self.stateChanged(.headers_received, self._page);
|
||||
try self._proto.dispatch(.load_start, .{ .loaded = 0, .total = self._response_len orelse 0 }, self._page);
|
||||
@@ -221,11 +307,11 @@ fn httpHeaderDoneCallback(transfer: *Http.Transfer) !void {
|
||||
|
||||
fn httpDataCallback(transfer: *Http.Transfer, data: []const u8) !void {
|
||||
const self: *XMLHttpRequest = @ptrCast(@alignCast(transfer.ctx));
|
||||
try self._response.appendSlice(self._arena, data);
|
||||
try self._response_data.appendSlice(self._arena, data);
|
||||
|
||||
try self._proto.dispatch(.progress, .{
|
||||
.total = self._response_len orelse 0,
|
||||
.loaded = self._response.items.len,
|
||||
.loaded = self._response_data.items.len,
|
||||
}, self._page);
|
||||
}
|
||||
|
||||
@@ -236,7 +322,7 @@ fn httpDoneCallback(ctx: *anyopaque) !void {
|
||||
.source = "xhr",
|
||||
.url = self._url,
|
||||
.status = self._response_status,
|
||||
.len = self._response.items.len,
|
||||
.len = self._response_data.items.len,
|
||||
});
|
||||
|
||||
// Not that the request is done, the http/client will free the transfer
|
||||
@@ -244,7 +330,7 @@ fn httpDoneCallback(ctx: *anyopaque) !void {
|
||||
self._transfer = null;
|
||||
try self.stateChanged(.done, self._page);
|
||||
|
||||
const loaded = self._response.items.len;
|
||||
const loaded = self._response_data.items.len;
|
||||
try self._proto.dispatch(.load, .{
|
||||
.total = loaded,
|
||||
.loaded = loaded,
|
||||
@@ -262,7 +348,7 @@ fn httpErrorCallback(ctx: *anyopaque, err: anyerror) void {
|
||||
self.handleError(err);
|
||||
}
|
||||
|
||||
pub fn _abort(self: *XMLHttpRequest) void {
|
||||
pub fn abort(self: *XMLHttpRequest) void {
|
||||
self.handleError(error.Abort);
|
||||
if (self._transfer) |transfer| {
|
||||
transfer.abort();
|
||||
@@ -281,13 +367,14 @@ fn handleError(self: *XMLHttpRequest, err: anyerror) void {
|
||||
fn _handleError(self: *XMLHttpRequest, err: anyerror) !void {
|
||||
const is_abort = err == error.Abort;
|
||||
|
||||
const new_state: State = if (is_abort) .unsent else .done;
|
||||
if (new_state != self._state) {
|
||||
const new_state: ReadyState = if (is_abort) .unsent else .done;
|
||||
if (new_state != self._ready_state) {
|
||||
const page = self._page;
|
||||
try self.stateChanged(new_state, page);
|
||||
if (is_abort) {
|
||||
try self._proto.dispatch(.abort, null, page);
|
||||
}
|
||||
try self._proto.dispatch(.err, null, page);
|
||||
try self._proto.dispatch(.load_end, null, page);
|
||||
}
|
||||
|
||||
@@ -299,9 +386,10 @@ fn _handleError(self: *XMLHttpRequest, err: anyerror) !void {
|
||||
});
|
||||
}
|
||||
|
||||
fn stateChanged(self: *XMLHttpRequest, state: State, page: *Page) !void {
|
||||
fn stateChanged(self: *XMLHttpRequest, state: ReadyState, page: *Page) !void {
|
||||
// there are more rules than this, but it's a start
|
||||
std.debug.assert(state != self._state);
|
||||
std.debug.assert(state != self._ready_state);
|
||||
self._ready_state = state;
|
||||
|
||||
const event = try Event.init("readystatechange", .{}, page);
|
||||
try page._event_manager.dispatchWithFunction(
|
||||
@@ -328,11 +416,6 @@ fn parseMethod(method: []const u8) !Http.Method {
|
||||
return error.InvalidMethod;
|
||||
}
|
||||
|
||||
const Response = union(enum) {
|
||||
text: []const u8,
|
||||
json: std.json.Value,
|
||||
};
|
||||
|
||||
pub const JsApi = struct {
|
||||
pub const bridge = js.Bridge(XMLHttpRequest);
|
||||
|
||||
@@ -343,19 +426,27 @@ pub const JsApi = struct {
|
||||
};
|
||||
|
||||
pub const constructor = bridge.constructor(XMLHttpRequest.init, .{});
|
||||
pub const UNSENT = bridge.property(@intFromEnum(XMLHttpRequest.State.unsent));
|
||||
pub const OPENED = bridge.property(@intFromEnum(XMLHttpRequest.State.opened));
|
||||
pub const HEADERS_RECEIVED = bridge.property(@intFromEnum(XMLHttpRequest.State.headers_received));
|
||||
pub const LOADING = bridge.property(@intFromEnum(XMLHttpRequest.State.loading));
|
||||
pub const DONE = bridge.property(@intFromEnum(XMLHttpRequest.State.done));
|
||||
pub const UNSENT = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.unsent));
|
||||
pub const OPENED = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.opened));
|
||||
pub const HEADERS_RECEIVED = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.headers_received));
|
||||
pub const LOADING = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.loading));
|
||||
pub const DONE = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.done));
|
||||
|
||||
pub const onreadystatechange = bridge.accessor(XMLHttpRequest.getOnReadyStateChange, XMLHttpRequest.setOnReadyStateChange, .{});
|
||||
pub const open = bridge.function(XMLHttpRequest.open, .{});
|
||||
pub const send = bridge.function(XMLHttpRequest.send, .{});
|
||||
pub const responseType = bridge.accessor(XMLHttpRequest.getResponseType, XMLHttpRequest.setResponseType, .{});
|
||||
pub const status = bridge.accessor(XMLHttpRequest.getStatus, null, .{});
|
||||
pub const statusText = bridge.accessor(XMLHttpRequest.getStatusText, null, .{});
|
||||
pub const readyState = bridge.accessor(XMLHttpRequest.getReadyState, null, .{});
|
||||
pub const response = bridge.accessor(XMLHttpRequest.getResponse, null, .{});
|
||||
pub const responseText = bridge.accessor(XMLHttpRequest.getResponseText, null, .{});
|
||||
pub const responseXML = bridge.accessor(XMLHttpRequest.getResponseXML, null, .{});
|
||||
pub const responseURL = bridge.accessor(XMLHttpRequest.getResponseURL, null, .{});
|
||||
pub const setRequestHeader = bridge.function(XMLHttpRequest.setRequestHeader, .{});
|
||||
pub const getResponseHeader = bridge.function(XMLHttpRequest.getResponseHeader, .{});
|
||||
pub const getAllResponseHeaders = bridge.function(XMLHttpRequest.getAllResponseHeaders, .{});
|
||||
pub const abort = bridge.function(XMLHttpRequest.abort, .{});
|
||||
};
|
||||
|
||||
const testing = @import("../../../testing.zig");
|
||||
|
||||
@@ -170,6 +170,22 @@ const TestHTTPServer = struct {
|
||||
fn handler(server: *TestHTTPServer, req: *std.http.Server.Request) !void {
|
||||
const path = req.head.target;
|
||||
|
||||
if (std.mem.eql(u8, path, "/xhr")) {
|
||||
return req.respond("1234567890" ** 10, .{
|
||||
.extra_headers = &.{
|
||||
.{ .name = "Content-Type", .value = "text/html; charset=utf-8" },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, path, "/xhr/json")) {
|
||||
return req.respond("{\"over\":\"9000!!!\"}", .{
|
||||
.extra_headers = &.{
|
||||
.{ .name = "Content-Type", .value = "application/json" },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// strip out leading '/' to make the path relative
|
||||
const file = try server.dir.openFile(path[1..], .{});
|
||||
defer file.close();
|
||||
|
||||
@@ -407,7 +407,6 @@ fn runWebApiTest(test_file: [:0]const u8) !void {
|
||||
test_session.fetchWait(2000);
|
||||
|
||||
page._session.browser.runMicrotasks();
|
||||
page._session.browser.runMessageLoop();
|
||||
|
||||
js_context.eval("testing.assertOk()", "testing.assertOk()") catch |err| {
|
||||
const msg = try_catch.err(arena_allocator) catch @errorName(err) orelse "unknown";
|
||||
@@ -508,12 +507,6 @@ fn serveCDP(wg: *std.Thread.WaitGroup) !void {
|
||||
fn testHTTPHandler(req: *std.http.Server.Request) !void {
|
||||
const path = req.head.target;
|
||||
|
||||
if (std.mem.eql(u8, path, "/loader")) {
|
||||
return req.respond("Hello!", .{
|
||||
.extra_headers = &.{.{ .name = "Connection", .value = "close" }},
|
||||
});
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, path, "/xhr")) {
|
||||
return req.respond("1234567890" ** 10, .{
|
||||
.extra_headers = &.{
|
||||
@@ -530,6 +523,33 @@ fn testHTTPHandler(req: *std.http.Server.Request) !void {
|
||||
});
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, path, "/xhr/redirect")) {
|
||||
return req.respond("", .{
|
||||
.status = .found,
|
||||
.extra_headers = &.{
|
||||
.{ .name = "Location", .value = "http://127.0.0.1:9582/xhr" },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, path, "/xhr/404")) {
|
||||
return req.respond("Not Found", .{
|
||||
.status = .not_found,
|
||||
.extra_headers = &.{
|
||||
.{ .name = "Content-Type", .value = "text/plain" },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, path, "/xhr/500")) {
|
||||
return req.respond("Internal Server Error", .{
|
||||
.status = .internal_server_error,
|
||||
.extra_headers = &.{
|
||||
.{ .name = "Content-Type", .value = "text/plain" },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (std.mem.startsWith(u8, path, "/src/browser/tests/")) {
|
||||
// strip off leading / so that it's relative to CWD
|
||||
return TestHTTPServer.sendFile(req, path[1..]);
|
||||
|
||||
Reference in New Issue
Block a user