/// <summary> /// Continues request with optional request overrides. To use this, request interception should be enabled with <see cref="Page.SetRequestInterceptionAsync(bool)"/>. Exception is immediately thrown if the request interception is not enabled. /// If the URL is set it won't perform a redirect. The request will be silently forwarded to the new url. For example, the address bar will show the original url. /// </summary> /// <param name="overrides">Optional request overwrites.</param> /// <returns>Task</returns> public async Task ContinueAsync(Payload overrides = null) { // Request interception is not supported for data: urls. if (Url.StartsWith("data:", StringComparison.InvariantCultureIgnoreCase)) { return; } if (!_allowInterception) { throw new PuppeteerException("Request Interception is not enabled!"); } if (_interceptionHandled) { throw new PuppeteerException("Request is already handled!"); } _interceptionHandled = true; try { var requestData = new FetchContinueRequestRequest { RequestId = InterceptionId }; if (overrides?.Url != null) { requestData.Url = overrides.Url; } if (overrides?.Method != null) { requestData.Method = overrides.Method.ToString(); } if (overrides?.PostData != null) { requestData.PostData = overrides.PostData; } if (overrides?.Headers?.Count > 0) { requestData.Headers = HeadersArray(overrides.Headers); } await _client.SendAsync("Fetch.continueRequest", requestData).ConfigureAwait(false); } catch (PuppeteerException ex) { // In certain cases, protocol will return error if the request was already canceled // or the page was closed. We should tolerate these errors _logger.LogError(ex.ToString()); } }
internal async Task InitializeAsync() { await _client.SendAsync("Network.enable").ConfigureAwait(false); if (_ignoreHTTPSErrors) { await _client.SendAsync("Security.setIgnoreCertificateErrors", new SecuritySetIgnoreCertificateErrorsRequest { Ignore = true }).ConfigureAwait(false); } }
/// <summary> /// Continues request with optional request overrides. To use this, request interception should be enabled with <see cref="Page.SetRequestInterceptionAsync(bool)"/>. Exception is immediately thrown if the request interception is not enabled. /// If the URL is set it won't perform a redirect. The request will be silently forwarded to the new url. For example, the address bar will show the original url. /// </summary> /// <param name="overrides">Optional request overwrites.</param> /// <returns>Task</returns> public async Task ContinueAsync(Payload overrides = null) { // Request interception is not supported for data: urls. if (Url.StartsWith("data:", StringComparison.InvariantCultureIgnoreCase)) { return; } if (!_allowInterception) { throw new PuppeteerException("Request Interception is not enabled!"); } if (_interceptionHandled) { throw new PuppeteerException("Request is already handled!"); } _interceptionHandled = true; try { var requestData = new FetchContinueRequestRequest { RequestId = InterceptionId }; if (overrides?.Url != null) { requestData.Url = overrides.Url; } if (overrides?.Method != null) { requestData.Method = overrides.Method.ToString(); } if (overrides?.PostData != null) { requestData.PostData = overrides.PostData; } if (overrides?.Headers?.Count > 0) { requestData.Headers = HeadersArray(overrides.Headers); } await _client.SendAsync("Fetch.continueRequest", requestData).ConfigureAwait(false); } catch (PuppeteerException) { } }
/// <summary> /// Continues request with optional request overrides. To use this, request interception should be enabled with <see cref="Page.SetRequestInterceptionAsync(bool)"/>. Exception is immediately thrown if the request interception is not enabled. /// </summary> /// <param name="overrides">Optional request overwrites.</param> /// <returns>Task</returns> public async Task ContinueAsync(Payload overrides = null) { if (!_allowInterception) { throw new PuppeteerException("Request Interception is not enabled!"); } if (_interceptionHandled) { throw new PuppeteerException("Request is already handled!"); } _interceptionHandled = true; try { var requestData = new NetworkContinueInterceptedRequestRequest { InterceptionId = InterceptionId }; if (overrides?.Url != null) { requestData.Url = overrides.Url; } if (overrides?.Method != null) { requestData.Method = overrides.Method.ToString(); } if (overrides?.PostData != null) { requestData.PostData = overrides.PostData; } if (overrides?.Headers?.Count > 0) { requestData.Headers = overrides.Headers; } await _client.SendAsync("Network.continueInterceptedRequest", requestData).ConfigureAwait(false); } catch (PuppeteerException ex) { // In certain cases, protocol will return error if the request was already canceled // or the page was closed. We should tolerate these errors _logger.LogError(ex.ToString()); } }
/// <summary> /// Returns a Task which resolves to a buffer with response body /// </summary> /// <returns>A Task which resolves to a buffer with response body</returns> public Task <string> BufferAsync() { if (ContentTaskWrapper == null) { ContentTaskWrapper = new TaskCompletionSource <string>(); Request.CompleteTask.ContinueWith(async(task) => { try { var response = await _client.SendAsync("Network.getResponseBody", new Dictionary <string, object> { { "requestId", Request.RequestId } }); ContentTaskWrapper.SetResult(response.body.ToString()); } catch (Exception ex) { ContentTaskWrapper.SetException(new BufferException("Unable to get response body", ex)); } }); } return(ContentTaskWrapper.Task); }
/// <summary> /// Accept the file chooser request with given paths. /// If some of the filePaths are relative paths, then they are resolved relative to the current working directory. /// </summary> /// <param name="filePaths">File paths to send to the file chooser</param> /// <returns>A task that resolves after the accept message is processed by the browser</returns> public Task AcceptAsync(params string[] filePaths) { if (_handled) { throw new PuppeteerException("Cannot accept FileChooser which is already handled!"); } _handled = true; var files = filePaths.Select(Path.GetFullPath); return(_client.SendAsync("Page.handleFileChooser", new PageHandleFileChooserRequest { Action = FileChooserAction.Accept, Files = files, })); }
/// <summary> /// Returns a Task which resolves to a buffer with response body /// </summary> /// <returns>A Task which resolves to a buffer with response body</returns> public async ValueTask <byte[]> BufferAsync() { if (_buffer == null) { var success = await BodyLoadedTaskWrapper.Task.ConfigureAwait(false); if (!success) { throw new PuppeteerException("Response body is unavailable for redirect responses"); } try { var response = await _client.SendAsync <NetworkGetResponseBodyResponse>("Network.getResponseBody", new NetworkGetResponseBodyRequest { RequestId = Request.RequestId }).ConfigureAwait(false); _buffer = response.Base64Encoded ? Convert.FromBase64String(response.Body) : Encoding.UTF8.GetBytes(response.Body); } catch (Exception ex) { throw new BufferException("Unable to get response body", ex); } } return(_buffer); }
/// <summary> /// Returns a Task which resolves to a buffer with response body /// </summary> /// <returns>A Task which resolves to a buffer with response body</returns> public async ValueTask <byte[]> BufferAsync() { if (_buffer == null) { await BodyLoadedTaskWrapper.Task.ConfigureAwait(false); try { var response = await _client.SendAsync <NetworkGetResponseBodyResponse>("Network.getResponseBody", new Dictionary <string, object> { { MessageKeys.RequestId, Request.RequestId } }).ConfigureAwait(false); _buffer = response.Base64Encoded ? Convert.FromBase64String(response.Body) : Encoding.UTF8.GetBytes(response.Body); } catch (Exception ex) { throw new BufferException("Unable to get response body", ex); } } return(_buffer); }
/// <summary> /// Continues request with optional request overrides. To use this, request interception should be enabled with <see cref="Page.SetRequestInterceptionAsync(bool)"/>. Exception is immediately thrown if the request interception is not enabled. /// </summary> /// <param name="overrides">Optional request overwrites.</param> /// <returns>Task</returns> public async Task ContinueAsync(Payload overrides = null) { if (!_allowInterception) { throw new PuppeteerException("Request Interception is not enabled!"); } if (_interceptionHandled) { throw new PuppeteerException("Request is already handled!"); } _interceptionHandled = true; try { var requestData = new Dictionary <string, object> { ["interceptionId"] = InterceptionId }; if (overrides?.Url != null) { requestData["url"] = overrides.Url; } if (overrides?.Method != null) { requestData["method"] = overrides.Method; } if (overrides?.PostData != null) { requestData["postData"] = overrides.PostData; } if (overrides?.Headers != null) { requestData["headers"] = overrides.Headers; } await _client.SendAsync("Network.continueInterceptedRequest", requestData); } catch (PuppeteerException ex) { // In certain cases, protocol will return error if the request was already canceled // or the page was closed. We should tolerate these errors _logger.LogError(ex.ToString()); } }
/// <summary> /// The method iterates JavaScript heap and finds all the objects with the given prototype. /// </summary> /// <returns>A task which resolves to a handle to an array of objects with this prototype.</returns> /// <param name="prototypeHandle">A handle to the object prototype.</param> public async Task <dynamic> QueryObjectsAsync(JSHandle prototypeHandle) { if (prototypeHandle.Disposed) { throw new PuppeteerException("Prototype JSHandle is disposed!"); } if (!((JObject)prototypeHandle.RemoteObject).TryGetValue("objectId", out var objectId)) { throw new PuppeteerException("Prototype JSHandle must not be referencing primitive value"); } dynamic response = await _client.SendAsync("Runtime.queryObjects", new Dictionary <string, object>() { { "prototypeObjectId", objectId.ToString() } }); return(ObjectHandleFactory(response.objects)); }
/// <summary> /// The method iterates JavaScript heap and finds all the objects with the given prototype. /// </summary> /// <returns>A task which resolves to a handle to an array of objects with this prototype.</returns> /// <param name="prototypeHandle">A handle to the object prototype.</param> public async Task <JSHandle> QueryObjectsAsync(JSHandle prototypeHandle) { if (prototypeHandle.Disposed) { throw new PuppeteerException("Prototype JSHandle is disposed!"); } if (prototypeHandle.RemoteObject.ObjectId == null) { throw new PuppeteerException("Prototype JSHandle must not be referencing primitive value"); } var response = await _client.SendAsync <RuntimeQueryObjectsResponse>("Runtime.queryObjects", new RuntimeQueryObjectsRequest { PrototypeObjectId = prototypeHandle.RemoteObject.ObjectId }).ConfigureAwait(false); return(CreateJSHandle(response.Objects)); }
internal Worker( CDPSession client, string url, Func <ConsoleType, JSHandle[], Task> consoleAPICalled, Action <EvaluateExceptionResponseDetails> exceptionThrown) { _client = client; Url = url; _exceptionThrown = exceptionThrown; _client.MessageReceived += OnMessageReceived; _executionContextCallback = new TaskCompletionSource <ExecutionContext>(TaskCreationOptions.RunContinuationsAsynchronously); _ = _client.SendAsync("Runtime.enable").ContinueWith(task => { }); _ = _client.SendAsync("Log.enable").ContinueWith(task => { }); }
internal async Task <bool> EmulateViewport(ViewPortOptions viewport) { var mobile = viewport.IsMobile; var width = viewport.Width; var height = viewport.Height; var deviceScaleFactor = viewport.DeviceScaleFactor; var screenOrientation = viewport.IsLandscape ? new ScreenOrientation { Angle = 90, Type = ScreenOrientationType.LandscapePrimary } : new ScreenOrientation { Angle = 0, Type = ScreenOrientationType.PortraitPrimary }; var hasTouch = viewport.HasTouch; await Task.WhenAll(new Task[] { _client.SendAsync("Emulation.setDeviceMetricsOverride", new EmulationSetDeviceMetricsOverrideRequest { Mobile = mobile, Width = width, Height = height, DeviceScaleFactor = deviceScaleFactor, ScreenOrientation = screenOrientation }), _client.SendAsync("Emulation.setTouchEmulationEnabled", new EmulationSetTouchEmulationEnabledRequest { Enabled = hasTouch, Configuration = viewport.IsMobile ? "mobile" : "desktop" }) }).ConfigureAwait(false); var reloadNeeded = _emulatingMobile != mobile || _hasTouch != hasTouch; _emulatingMobile = mobile; _hasTouch = hasTouch; return(reloadNeeded); }
/// <summary> /// Starts tracing. /// </summary> /// <returns>Start task</returns> /// <param name="options">Tracing options</param> public Task StartAsync(TracingOptions options) { if (_recording) { throw new InvalidOperationException("Cannot start recording trace while already recording trace."); } var categories = options.Categories ?? _defaultCategories; if (options.Screenshots) { categories.Add("disabled-by-default-devtools.screenshot"); } _path = options.Path; _recording = true; return(_client.SendAsync("Tracing.start", new TracingStartRequest { TransferMode = "ReturnAsStream", Categories = string.Join(", ", categories) })); }
internal Task SetExtraHTTPHeadersAsync(Dictionary <string, string> extraHTTPHeaders) { _extraHTTPHeaders = new Dictionary <string, string>(); foreach (var item in extraHTTPHeaders) { _extraHTTPHeaders[item.Key.ToLower()] = item.Value; } return(_client.SendAsync("Network.setExtraHTTPHeaders", new Dictionary <string, object> { { MessageKeys.Headers, _extraHTTPHeaders } })); }
internal async Task SetExtraHTTPHeadersAsync(Dictionary <string, string> extraHTTPHeaders) { _extraHTTPHeaders = new Dictionary <string, string>(); foreach (var item in extraHTTPHeaders) { _extraHTTPHeaders[item.Key.ToLower()] = item.Value; } await _client.SendAsync("Network.setExtraHTTPHeaders", new Dictionary <string, object> { { "headers", _extraHTTPHeaders } }); }
internal Task SetExtraHTTPHeadersAsync(Dictionary <string, string> extraHTTPHeaders) { _extraHTTPHeaders = new Dictionary <string, string>(); foreach (var item in extraHTTPHeaders) { _extraHTTPHeaders[item.Key.ToLower()] = item.Value; } return(_client.SendAsync("Network.setExtraHTTPHeaders", new NetworkSetExtraHTTPHeadersRequest { Headers = _extraHTTPHeaders })); }
private async Task NavigateAsync(CDPSession client, string url, string referrer, string frameId) { var response = await client.SendAsync <PageNavigateResponse>("Page.navigate", new { url, referrer = referrer ?? string.Empty, frameId }).ConfigureAwait(false); _ensureNewDocumentNavigation = !string.IsNullOrEmpty(response.LoaderId); if (!string.IsNullOrEmpty(response.ErrorText)) { throw new NavigationException(response.ErrorText, url); } }
/// <summary> /// The method iterates JavaScript heap and finds all the objects with the given prototype. /// </summary> /// <returns>A task which resolves to a handle to an array of objects with this prototype.</returns> /// <param name="prototypeHandle">A handle to the object prototype.</param> public async Task <JSHandle> QueryObjectsAsync(JSHandle prototypeHandle) { if (prototypeHandle.Disposed) { throw new PuppeteerException("Prototype JSHandle is disposed!"); } if (!((JObject)prototypeHandle.RemoteObject).TryGetValue(MessageKeys.ObjectId, out var objectId)) { throw new PuppeteerException("Prototype JSHandle must not be referencing primitive value"); } var response = await _client.SendAsync("Runtime.queryObjects", new Dictionary <string, object> { { "prototypeObjectId", objectId.ToString() } }).ConfigureAwait(false); return(CreateJSHandle(response[MessageKeys.Objects])); }
/// <summary> /// Returns a Task which resolves to a buffer with response body /// </summary> /// <returns>A Task which resolves to a buffer with response body</returns> public async ValueTask <string> BufferAsync() { if (_buffer == null) { await BodyLoadedTaskWrapper.Task.ConfigureAwait(false); try { var response = await _client.SendAsync("Network.getResponseBody", new Dictionary <string, object> { { "requestId", Request.RequestId } }).ConfigureAwait(false); _buffer = response.body.ToString(); } catch (Exception ex) { throw new BufferException("Unable to get response body", ex); } } return(_buffer); }
internal async Task <bool> EmulateViewport(ViewPortOptions viewport) { var mobile = viewport.IsMobile; var width = viewport.Width; var height = viewport.Height; var deviceScaleFactor = viewport.DeviceScaleFactor; ScreenOrientation screenOrientation = viewport.IsLandscape ? new ScreenOrientation { Angle = 90, Type = ScreenOrientationType.LandscapePrimary } : new ScreenOrientation { Angle = 0, Type = ScreenOrientationType.PortraitPrimary }; await Task.WhenAll(new Task[] { _client.SendAsync("Emulation.setDeviceMetricsOverride", new { mobile, width, height, deviceScaleFactor, screenOrientation }), _client.SendAsync("Emulation.setTouchEmulationEnabled", new { enabled = viewport.HasTouch, configuration = viewport.IsMobile ? "mobile" : "desktop" }) }); var reloadNeeded = false; if (viewport.HasTouch && string.IsNullOrEmpty(_injectedTouchScriptId)) { //TODO: It's not clear what to do here /* * var source = $"({ injectedTouchEventsFunction})()"; * this._injectedTouchScriptId = (await this._client.send('Page.addScriptToEvaluateOnNewDocument', { source })).identifier; * reloadNeeded = true; */ } else if (!viewport.HasTouch && !string.IsNullOrEmpty(_injectedTouchScriptId)) { await _client.SendAsync("Page.removeScriptToEvaluateOnNewDocument", new { identifier = _injectedTouchScriptId }); _injectedTouchScriptId = null; reloadNeeded = true; } if (_emulatingMobile != mobile) { reloadNeeded = true; } _emulatingMobile = mobile; return(reloadNeeded); }
/// <summary> /// Accept the Dialog. /// </summary> /// <returns>Task which resolves when the dialog has been accepted.</returns> /// <param name="promptText">A text to enter in prompt. Does not cause any effects if the dialog's type is not prompt.</param> public Task Accept(string promptText = "") => _client.SendAsync("Page.handleJavaScriptDialog", new PageHandleJavaScriptDialogRequest { Accept = true, PromptText = promptText });