Chrome DevTools Approve Network Requests before executing - api

I'm looking for a way in Chrome DevTools (or any equivalent) to control the HTTP requests done by my web application:
I want to approve HTTP requests before executing, or let them fail in an unexpected way (give it status 500 or something).
USAGE EXAMPLE: Testing unexpected behavior
Does anyone know a way to achieve this.

I see 2 possible solutions to achieve this goal on the client side:
Use the Request-Blocking panel from the Drawer (Open Chrome DevTools -> Esc -> '...' -> Request blocking
This is completely out-of-the-box and works for most "offline-first" use cases.
Use a service worker. They are basically a way to proxy requests and respond individually (e.g. by responding with a 500-er). You might want to enable/disable such a debugging-feature by using Chrome Devtools Snippets (Open Chrome DevTools -> Sources -> Snippets) as you don't want your requests to fail all the time :)
First you need to register your serviceworker like this:
if('serviceWorker' in navigator) {
navigator.serviceWorker.register('/path-to-service-worker.js').then(function(registration) {
// registration successful
}).catch(function(err) {
// registration failed
});
}
Afterwards reload the browser (or install your service-worker in the DevTools -> Application -> Service Workers) so that your service-worker.js is active, may listen to the 'fetch' event and proxy the requests for this domain like this:
self.addEventListener('fetch', function(event) {
// this will set a breakpoint in chrome devtools, allowing you to manually edit the response
debugger;
// alternatively you could reponse with an error response like this:
event.respondWith(
new Response(null, {
status: 500
})
);
});
Sidenote: Due to security restrictions in the browser serviceworkers only work over https and on localhost.
Further information:
https://developer.mozilla.org/en-US/docs/Web/API/Response/Response
https://developers.google.com/web/fundamentals/primers/service-workers/

You can use Requestly Chrome extension to Redirect, Cancel, Block, Modify headers,... of the requests.
To approve requests before executing e.g. for AJAX requests create a redirect rule and point it to a static JSON file or another script.
To block a request use cancel request feature and set a custom pattern.

Related

Can Cypress intercept requests being made directly to a server?

I have been trying to intercept a server request using Cypress' intercept method.
I have noticed that Cypress can intercept requests made through the front-end/browser, however, the intercept method doesn't work if I make a request directly to the back-end server.
Let me clarify what I mean:
One thing is intercepting a request that the front-end/browser makes to the back-end server.
Another thing is intercepting a call that doesn't use the browser but calls directly the back-end endpoint.
For example:
I can create a user using the front-end interface
or I can create a user calling the back-end endpoint directly (directly calling the server).
Coming back to my question. Is there a way to intercept a call that was made directly to the back-end endpoint?
This is what I have tried so far:
I wrote a regex to intercept api/v0/customers
I then made a request to http://locahost:5440/api/v0/customers (which is the URL of the server)
Finally, I waited for the request to happen
Timeout request using Cypress intercept method
cy.intercept(/^\/api\/v0\/customers\/$/).as('createCustomer');
cy.request(createCustomer(customerData, headers));
cy.wait('#createCustomer').then(({ status, body }) => {
const customerId = body.customer_id;
console.log(body);
expect(status).equal(201);
});
Here's the problem: There was a timeout error.
As you can see in the image, I'm making a request to http://locahost:5440 which is the server URL. NOTE: I made sure the server was up and running.
The regex is also correct and it will match the endpoint http://locahost:5440/api/v0/customers
I suspect that intercept only works for requests being made through the browser. Is this assertion correct? I couldn't find this answer anywhere in the Cypress docs.
Is there a way for me to intercept a call being made directly to a server (not using the browser)?
You don't have to intercept the requests you explicitly make with cypress, just use .then to get the response, like this:
cy.request(createCustomer(customerData, headers)).then((response) => {
const customerId = response.body.customer_id;
console.log(response.body);
expect(response.status).equal(201);
});
Reference: https://docs.cypress.io/api/commands/request#Yields

How to use Chrome DevTools protocol in Selenium (using Python) for capturing HTTP requests and responses?

I know that Fetch Domain is used for this purpose but I do not know how exactly I can implement it. In Selenium python, I used the following code to enable issuing of requestPaused events.
driver.execute_cdp_cmd("Fetch.enable",{})
driver.get('https://www.example.com')
But I do not know how can I handle requestPaused event (I need to call one fulfillRequest or continueRequest/continueWithAuth). As a result, my program stops working.
I really appreciate it if anyone could provide me an example to help me understand how it works.
Yes, you saw it right.
As per the release notes of Selenium v4.0.0-alpha-3:
* Expose devtools APIs from chromium derived drivers.
* Expose presence of devtools support on a role-based interface
As per the release notes of Selenium v4.0.0.0-alpha-1:
* Basic support for CDP landed via the "DevTools" interface.
So chrome-devtools-protocol is all set to be available with selenium4 which will allow for tools to instrument, inspect, debug and profile Chromium, Chrome and other Blink-based browsers. In the discussion Controlling Chrome Devtools with Selenium Webdriver #AdiOhana mentions of the example usage of a few commands from the Profiler Domain as follows:
driver.getDevTools().createSession();
driver.getDevTools().send(new Command("Profiler.enable", ImmutableMap.of()));
driver.getDevTools().send(new Command("Profiler.start", ImmutableMap.of()));
//register to profiler events
driver.getDevTools().addListener(new Event("Profiler.consoleProfileStarted", ConsoleProfileStarted.class), new Consumer<Object>() {
#Override
public void accept(Object o) {
//do something
}
});
Note: Until the Profiler domain will added to Selenium java client, you will have to supply your Mapper.
Fetch Domain
Fetch Domain will enable clients substitute browser's network layer with client code.
The Fetch Domain methods are as follows:
Fetch.disable: Disables the fetch domain.
Fetch.enable: Enables issuing of requestPaused events. A request will be paused until client calls one of failRequest, fulfillRequest or continueRequest/continueWithAuth.
Fetch.failRequest: Causes the request to fail with specified reason.
Fetch.fulfillRequest: Provides response to the request.
Fetch.continueRequest: Continues the request, optionally modifying some of its parameters.
Fetch.continueWithAuth: Continues a request supplying authChallengeResponse following authRequired event.
Fetch.getResponseBody: Causes the body of the response to be received from the server and returned as a single string. May only be issued for a request that is paused in the Response stage and is mutually exclusive with takeResponseBodyForInterceptionAsStream. Calling other methods that affect the request or disabling fetch domain before body is received results in an undefined behavior.
Fetch.takeResponseBodyAsStream: Returns a handle to the stream representing the response body. The request must be paused in the HeadersReceived stage. Note that after this command the request can't be continued as is -- client either needs to cancel it or to provide the response body. The stream only supports sequential read, IO.read will fail if the position is specified. This method is mutually exclusive with getResponseBody. Calling other methods that affect the request or disabling fetch domain before body is received results in an undefined behavior.
The Fetch Domain events are as follows:
Fetch.requestPaused: Issued when the domain is enabled and the request URL matches the specified filter. The request is paused until the client responds with one of continueRequest, failRequest or fulfillRequest. The stage of the request can be determined by presence of responseErrorReason and responseStatusCode -- the request is at the response stage if either of these fields is present and in the request stage otherwise.
Fetch.authRequired: Issued when the domain is enabled with handleAuthRequests set to true. The request is paused until client responds with continueWithAuth.
References
You can find a couple of revelant discussions in:
Can Selenium WebDriver (java) interact with the Browser's inspect tool element selector?
What is the difference between WebDriver and DevTool protocol

Strategy for CORS - issue with IE10 : xhr status returns 0 for HTTP 401

I have the following setup on my server:
Apache HTTP Server is serving a BackboneJS frontend application
Apache Tomcat is serving a Java based backend (CORS enabled).
Everything is running on a single server that I have full control over.
I'm currently using com.thetransactioncompany.cors.CORSFilter in the Java based backend to enable CORS. Everything seens to be working fine.
My frontend has the following code to redirect the user to the login page in case an un-authenticated REST call occurred:
$.ajaxSetup({
statusCode: {
401: function(){
window.location.replace('/#login');
},
403: function() {
window.location.replace('/#denied');
}
},
cache: false
});
Everything works fine on all major browsers except for IE10.
In IE10, when the non-authenticated users calls the REST serverm the server returns an HTTP 401 (as it should). The XHR object I'm seeing in the IE debugger hoewever seems to have translated this into status = 0. (On chrome you can cleary see that it has status = 401.
This appears to be a bug in IE10 where IE10 is treating HTTP status 401 as a network error. The console shows:
SCRIPT7002: XMLHttpRequest: Network Error 0x80070005, Access is denied
Is there a way to workaround this ?
I can add handling for statusCode 0 in the ajaxSetup but that seems more of a hack.
Is there a way to disable CORS altogether through some kind of Apache / Tomcat configuration ?
Currently my apache configuration is setup using vhosts so that the following public URLs map their corresponding internal hostname / ports.
http://mywebapp.com -> http://myrealservername:8080/ -> /var/www/http
http://myrestapi.com -> http://myrealservername:8088/ -> /usr/local/tomcat/webapps/restapi
Would it be possible / advisable to have Apache
continue serving the static webapp from http://mywebapp.com/restapi
exposing the REST API on http://mywebapp.com/restapi (keeping it "inside" the webapp).
If such a setup were possible I wouldn't need CORS anymore ? It would keep things a lot simpler while increasing browser support ?

FB App Channel file. ChannelUrl not loading?

I have a Canvas app on Facebook that simply displays a page hosted on our external site. Working just fine.
What I have noticed in Firefox is there is a continuous loading and error being reported in Firebug:
GET http://0-68.channel.facebook.com/pull?channel=p_...1&partition=1&clientid=3744ab1f&cb=b3di&idle=287
200 Aborted
39.86s
This attempt to load always takes around 40s, and is retried instantly after failure. I have also tried loading the above URL by itself, but this just times out with a "Connection Reset" message.
Is this something to do with my channelUrl directive in the SDK setup? I have this setup as follows:
var channel_url = "http://mysite.com/facebook/channel/"; // Aside from the domain, this is the actual final url.
var app_id = "blahblahblah";
// Initialize the facebook object
FB.init({
appId: app_id, // From the globals set up at the top of this page
channelUrl : channel_url,
cookie: true,
xfbml: true,
oauth: true
});
The channel file only has this in it:
<script src="//connect.facebook.net/en_US/all.js"></script>
But I have also tried asynchronous loading the js too.
If I load http://mysite.com/facebook/channel/ in a browser, all is fine.
Any thoughts?
Facebook's JS SDK does long-polling for event updates. If no updates are available the connection will eventually time out, which you will see as Aborted in Firebug.
*copy and pasted from another location
These requests are the HTTP Long-Polling requests. I've only had the Facebook site open for a few minutes and I'm not really monitoring activity but it looks like:
Facebook are using HTTP Long-Polling where open connections are marked as 'pending'
HTTP Long-Poll requests stay open for 40 seconds and after that time if there is no activity that request closes and a new one opens.
If a response is sent (server to client) within the 40 seconds the connection closes (well, that's how HTTP Long-Polling works)

Log in to my web from a chrome extension

I've got a web where logged in users can fill out a form to send information. I wanted my users to do this from a chrome extension too. I managed to get the form to sen information working but I only want to be logged in users to be able to do that. It's like a twitter or Springpad extension when the user first opens up the extension, it would have to log in or register. I saw the following answer at stack overflow: Login to website with chrome extension and get data from it
I gave it a try and put this code in background.html:
function login() {
$.ajax({
url: "http://localhost/login", type: "GET", dataType: "html", success: function() {
$.ajax({
url: "http://localhost/login", type: "POST", data: {
"email": "me#alberto-elias.com",
"password": "mypassword",
},
dataType: "html",
success: function(data) {
//now you can parse your report screen
}
});
}
});
}
In my popup.html I put the following code:
var bkg = chrome.extension.getBackgroundPage()
$(document).ready(function() {
$('#pageGaffe').val(bkg.getBgText());
bkg.login();
});
And on my server, which is in node.js, I've got a console.log that shows user information when he logs in, so I saw that when I load my extension, it does log in. The problem is how can I get the user to log in by itself, instead of manually putting my details in the code, how to stay logged in in the extension and when submitting the form, sending the user's details to the web.
I hope I've managed to explain myself correctly.
Thanks.
Before answering this question I would like to bring to your notice that you can make cross origin xhr from your content scripts as of Chrome 13 if you have declared proper permissions. Here is the extract from the page
Version note: As of Chrome 13, content scripts can make cross-origin requests to the same servers as the rest of the extension. Before Chrome 13, a content script couldn't directly make requests; instead, it had to send a message to its parent extension asking the extension to make a cross-origin request.
Coming to the point. You simply have to make an XmlHttpRequest to your domain from your extension (content script or background page) and wait for the response.
At Server
Read the request and session cookie. If session is valid send proper response, else send an error code. 401 or anything else.
At client
If response is proper display it, else display a login link directing to login page of your website.
How it works:
It will work if cookies in user's browser is enabled. Whenever user logs in to your website your server sets a session cookie which resides in user's browser. Now with every request that the browser sends to your domain, this cookie is transmitted. This cookie will be transmitted even if the request is from a Google Chrome Extension.
Caveat
Make sure you display proper cues to user indicating that they are logged in to your application. Since your UI will be mostly inside the extension, it is possible that user might not be aware of their valid session with your website and they might leave an active session unattended which might be abused if user is accessing it from a public internet kiosk.
Reference
You can take a look at a similar implementation that I have done with my extension here.
So the user logs into your server and you know that. I am a bit confused if you then want the user to be able to browse your website with those credentials or a third party website with those credentials.
If it is your website then you should be able to set a cookie that indicates whether they are logged in. Then detect this server side when they navigate your site.
If it is a third party site then the best you can do is create a content script that either fills out the login form and autosubmits for them or analyze the login post data and send it along yourself, then force a refresh.