Chromedp - how to get image file size and real dimensions - chromedp

I am trying to retrieve some information like page load time, first paint but also the images and scripts that are being loaded and their sizes.
I am able to detect everything that is being loaded in terms of images and scripts but when I look at the sizes, they do not match the size which I see in my (Firefox) inspector.
Can anyone please explain to me what I am doing wrong?
I would also like to get to know how long it took to load the specific file.
I came up with this code. This shows me the correct name and mimetype, but as said, the file size is not correct.
chromedp.ListenTarget(ctx, func(ev interface{}) {
switch ev := ev.(type) {
case *network.EventResponseReceived:
eventResponseReceived = append(eventResponseReceived, network.EventResponseReceived{
RequestID: ev.RequestID,
LoaderID: ev.LoaderID,
Timestamp: ev.Timestamp,
Type: ev.Type,
Response: ev.Response,
HasExtraInfo: ev.HasExtraInfo,
FrameID: ev.FrameID,
})
case *network.EventLoadingFinished:
eventLoadingFinished = append(eventLoadingFinished, network.EventLoadingFinished{
RequestID: ev.RequestID,
Timestamp: ev.Timestamp,
EncodedDataLength: ev.EncodedDataLength,
ShouldReportCorbBlocking: ev.ShouldReportCorbBlocking,
})
}
})
for i := range eventResponseReceived {
for i2 := range eventLoadingFinished {
if eventResponseReceived[i].RequestID == eventLoadingFinished[i2].RequestID {
fmt.Println(eventResponseReceived[i].Response.URL)
fmt.Println(eventResponseReceived[i].Response.ResponseTime.Time())
fmt.Println(eventResponseReceived[i2].Response.EncodedDataLength)
fmt.Println(eventResponseReceived[i].Response.MimeType)
}
}
}
I found out that I, in some cases, can get the content-length. But for a lot of files the content-length unfortunately is nil.
eventResponseReceived[i2].Response.Headers["content-length"]
So for the files where no content-length was given, I need a solution.

IIUC, you want to measure the response size and the load time. In this case, I think you should check both the Network.responseReceived event and the Network.loadingFinished event. (The corresponding events in chromedp are network.EventResponseReceived and network.EventLoadingFinished).
I have attached an example request to the end of this answer. I will try to answer the question based on this example request.
Size
It's correct to get the size from the Network.loadingFinished event. Please note that this is not the file size. It's the total number of bytes received for this request. And it could be 0 if the response is loaded from a cache. The following fields from the response field of the Network.responseReceived event would tell you why encodedDataLength is 0 (an example event has been attached, read it first):
fromDiskCache: specifies that the request was served from the disk cache.
fromServiceWorker: specifies that the request was served from the ServiceWorker.
fromPrefetchCache: specifies that the request was served from the prefetch cache.
Don't try to read encodedDataLength from the response field. Because it's just the total number of bytes received for this request so far. There could be more data to receive (reported by the Network.dataReceived events, see the screenshot).
And don't try to read the size from the Content-Length header. It's not always provided, and it's not correct to use it to measure network payload.
Time
I will try to list the metrics in the timing tab (see the screenshot) based on my try and test. If not specified, the data points are from the response.timing field of the Network.responseReceived event.
Stalled: dnsStart. It a connection is reused, it could be sendStart.
DNS Lookup: DnsEnd - DnsStart.
Initial connection: connectEnd - connectStart
SSL: sslEnd - sslStart
Request sent: sendEnd - sendStart
Waiting for server response: receiveHeadersEnd - sendEnd
Content Download: timestamp (from the Network.loadingFinished event) - requestTime - receiveHeadersEnd.
I think you want to check the Waiting for server response metric and the Content Download metric most of the time.
Recommentation
Protocol Monitor is a must-have tool if you want to work with Chrome DevTools Protocol.
Example Request
See the screenshot below:
Here is the Network.responseReceived event (some fields are removed):
{
"requestId": "580832.38",
"timestamp": 40037.455632,
"type": "Image",
"response": {
"url": "https://i.ytimg.com/vi/noIxfDrKx_Q/maxresdefault.jpg",
"status": 200,
"mimeType": "image/jpeg",
"connectionReused": false,
"fromDiskCache": false,
"fromServiceWorker": false,
"fromPrefetchCache": false,
"encodedDataLength": 55,
"timing": {
"requestTime": 40036.989753,
"proxyStart": -1,
"proxyEnd": -1,
"dnsStart": 0.662,
"dnsEnd": 81.792,
"connectStart": 81.792,
"connectEnd": 332.482,
"sslStart": 158.76,
"sslEnd": 332.473,
"workerStart": -1,
"workerReady": -1,
"workerFetchStart": -1,
"workerRespondWithSettled": -1,
"sendStart": 332.906,
"sendEnd": 333.142,
"pushStart": 0,
"pushEnd": 0,
"receiveHeadersEnd": 459.986
},
"responseTime": 1668830468734.381
},
"frameId": "83262FAD65C24B78F2B7E6F884B2B146"
}
And here is the Network.loadingFinished event:
{
"requestId": "580832.38",
"timestamp": 40037.577265,
"encodedDataLength": 50766,
"shouldReportCorbBlocking": false
}

Related

What does the BLE-status code "-402" mean?

I have a GarminIQ-project. Therefore I make a request. Since yesterday I get the error code -402.
According to https://developer.garmin.com/downloads/connect-iq/monkey-c/doc/Toybox/Communications/OAuthMessage.html#responseCode-instance_method negative values stand for BLE-responses, positive are the http-requestCode. Does anybody know what -402 stands for?
I am using the Connect IQ SDK 3.0.10.
I tried to find out, what the error code is meaning. But I haven't found a list with code "-402" or "402"
Down below are the two code snippets that are used for the request. The argument url is our api-url. This works fine in a browser.
//This function makes the request
function makeRequest(url) {
jsonFile = Communications.makeJsonRequest(url, {}, {}, method(:onReceive));
}
//This is the callback method that is called, when data have arrived
function onReceive(responseCode, data){
if (responseCode == 200) {
notify.invoke(1, data);
}else {
System.println(responseCode);
notify.invoke(0, "Failed to load\nError: "+responseCode.toString());
}
}
If you look at the API docs for the Communications module, you will see that -402 is the error code returned when the results sent back from your request were too large.
NETWORK_RESPONSE_TOO_LARGE = -402
Most devices have a very limited amount of memory and so you may need to run your request through some sort of proxy server to make the request and then trim down the results to only what you require back before sending the data to your device.

Python Request Session JIRA REST post http 405

Using python requests session I can connect to JIRA and retrieve issue information ...
session = requests.Session()
headers = {"Authorization": "Basic %s" % bas64_val}
session.post(jira_rest_url, headers=headers)
jira = session.get(jira_srch_issue_url + select_fields)
# select_fields = the fields I want from the issue
Now I'm trying to post a payload via the JIRA API, using a fixed issue url e.g. "https://my_jira_server.com:1234/rest/api/latest/issue/KEY-9876"
Which should be a case of the following, given: https://developer.atlassian.com/jiradev/jira-apis/about-the-jira-rest-apis/jira-rest-api-tutorials/jira-rest-api-example-edit-issues
payload = { "update": {
"fixVersions": [ {"set": "release-2.139.0"} ]
}}
posted = session.post(jira_task_url, data=payload)
# returns <Response [405]>
# jira_task_url = https://my_jira_server.com:1234/rest/api/latest/issue/KEY-9876
But this doesn't appear to work! Looking into the http 405 response, suggests that my payload is not properly formatted! Which notably, is the not easiest thing to diagnose.
What am I doing wrong here? Any help on this would be much appreciated.
Please note, I am not looking to use the python jira module, I am using requests.session to manage several sessions for different systems i.e. JIRA, TeamCity, etc..
Found the solution! I had two problems:
1) The actual syntax structure should have been:
fix_version = { "update": { "fixVersions": [ {"set" : [{ "name" : "release-2.139.0" }]}]
2) To ensure the payload is actually presented as JSON, use json.dumps() which takes an object and produces a string (see here) AND set 'content-type' to 'application/json':
payload = json.dumps(fix_version)
app_json = { 'content-type': 'application/json' }
session.put(https://.../rest/api/latest/issue/KEY-9876, headers=app_json, data=payload)
Rather than trying to define the JSON manually!

What am I doing wrong in this QBO v3 API (IPP) Attachments upload python request?

Intuit offers these instructions for uploading attachments (which become Attachable objects that can be associated with one or more transactions).
I believe I'm using python's requests module (via rauth's OAuth1Session module—see below for how I'm creating the session object) to generate these requests. Here's the code leading up to the request:
print request_type
print url
print headers
print request_body
r = session.request(request_type, url, header_auth,
self.company_id, headers = headers,
data = request_body, **req_kwargs)
result = r.json()
print json.dumps(result, indent=4)
and the output of these things:
POST
https://quickbooks.api.intuit.com/v3/company/0123456789/upload
{'Accept': 'application/json'}
Content-Disposition: form-data; name="Invoice 003"; filename="Invoice 003.pdf"
Content-Type: application/pdf
<#INCLUDE */MyDir/Invoice 003.pdf*#>
{
"Fault": {
"type": "SystemFault",
"Error": [
{
"Message": "An application error has occurred while processing your request",
"code": "10000",
"Detail": "System Failure Error: Cannot consume content type"
}
]
},
"time": "[timestamp]"
}
I have confirmed (by uploading an attachment through the QBO web UI and then querying the Attachable object through the API) that application/pdf is included in the list of acceptable file types.
At sigmavirus24's suggestion, I tried removing the Content-Type line from the headers, but I got the same result.
Here's how I'm creating the session object (which, again, is working fine for other QBO v3 API requests of every type you see in Intuit's API Explorer):
from rauth import OAuth1Session
def create_session(self):
if self.consumer_secret and self.consumer_key and self.access_token_secret and self.access_token:
session = OAuth1Session(self.consumer_key,
self.consumer_secret,
self.access_token,
self.access_token_secret,
)
self.session = session
else:
raise Exception("Need four creds for Quickbooks.create_session.")
return self.session
What might I be missing here?
EDIT: current area of exploration is here; I just formed the header you see (that has the "INCLUDE" string there) directly. Perhaps I should be using rauth to attach the file...
Without being able to see what code you're using with requests, I'm going to take a shot in the dark and tell you to remove setting your own Content-Type. You probably don't want that. It looks like you want multipart/form-data and requests will set that on its own if you stop fighting it.
It looks like you're missing the boundaries that QuickBooks is expecting (based on what you linked).
---------------------------acebdf13572468
Content-Disposition: form-data; name="file_content_01"; filename="IMG_0771.jpg"
Content-Type: image/jpeg
<#INCLUDE *Y:\Documents\IMG_0771.jpg*#>
---------------------------acebdf13572468--
The first and last line above seem to be what you're missing.

How do I inject new request header with json data in proxy request flow?

I am trying to inject a new request header in the proxy request flow using JS policy to be sent to the backend server. When I look at the debug trace, I see that the json data in the request header is distorted.
I am trying to inject some string like
{"scope":"","time_till":2264,"id_1":"hUXLXVqpA1J4vA9sayk2UttWNdM","custom_data":{"c_id":"test_data"}}
But when I look at the trace window I see this
{"scope":"","time_till":2264,id_1":"hUXLXVqpA1J4vA9sayk2UttWNdM,"custom_data":{"c_id":"test_data"}}
what am I doing wrong?
var obj = {"scope":"","time_till":2264,"id_1":"hUXLXVqpA1J4vA9sayk2UttWNdM","custom_data":{"c_id":"test_data"}};
var header_str = JSON.stringify(obj);
context.setVariable('json-header',header_str);
request.headers['x-json-hedar']= header_str;
I tested your code and it seems to work. Here's an example response where I set the header string as a response:
HTTP/1.1 200 OK
User-Agent: curl/7.30.0
Accept: */*
x-json-header: {"scope":"","time_till":2264,"id_1":"hUXLXVqpA1J4vA9sayk2UttWNdM","custom_data":{"c_id":"test_data"}}
Content-Length: 0
It appears this is only an issue with the Apigee debug session / trace tool as the header value was set correctly. Here was the JSON download of the debug session showing this header value:
{
"name": "x-json-header",
"value": "{\"scope\":\"\",\"time_till\":2264,id_1\":\"hUXLXVqpA1J4vA9sayk2UttWNdM,\"custom_data\":{\"c_id\":\"test_data\"}}"
}
You can see that the value passed to the UI for displaying the debug info has the malformed json:
id_1\":\"hUXLXVqpA1J4vA9sayk2UttWNdM,
This does not appear to be a problem with the Apigee debug/trace UI. I see the malformed JSON trickle down to my backend service.
Here is the header I'm trying to send -
{"timeStamp":"2349218349381274","latitude":"34.589","longitude":"-37.343","clientIp":"127.0.0.0","deviceId":"MOBILE_TEST_DEVICE_AGAIN","macAddress":"23:45:345:345","deviceType":"phone","deviceOS":"iOS","deviceModel":"iPhone 5S","connection":"5G","carrier":"Vodafone","refererURL":"http://www.google.com","xforwardedFor":"129.0.0.0","sessionId":"kfkls498327ksdjf","application":"mobile-app","appVersion":"7.6.5","serviceVersion":"1.0","userAgent":"Gecko"}
But Apigee reads the header as below. Note the missing start quotes from some fields.
{"timeStamp":"2349218349381274",latitude":"34.589,longitude":"-37.343,clientIp":"127.0.0.0,deviceId":"MOBILE_TEST_DEVICE_AGAIN,macAddress":"23:45:345:345,deviceType":"phone,deviceOS":"iOS,deviceModel":"iPhone 5S,connection":"5G,carrier":"Vodafone,refererURL":"http://www.google.com,xforwardedFor":"129.0.0.0,sessionId":"kfkls498327ksdjf,application":"mobile-app,appVersion":"7.6.5,serviceVersion":"1.0,"userAgent":"Gecko"}
The header is used in a service callout to a backend service which parses it. And rightly so, I get the below error -
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('l' (code 108)): was expecting double-quote to start field name
at [Source: java.io.StringReader#22549cdc; line: 1, column: 35]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1378)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:599)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:520)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleUnusualFieldName(ReaderBasedJsonParser.java:1275)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._parseFieldName(ReaderBasedJsonParser.java:1170)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:611)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:301)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2796)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1942)
I encounter strange behaviour when adding JSON to a context variable for example like the following:
var header_str = JSON.stringify(obj);
context.setVariable('json-header',header_str);
I appreciate this is an example so you may not have included the full extent of the problem but this normally works (now it is not added to a variable first):
request.headers['x-json-header'] = JSON.stringify(obj);
Code like this also works if you can send the request from JavaScript
var headers = {"Accept": "application/json", "Accept-Language": "en"};
var sessionRequest = new Request(url, 'POST', headers, body);
var exchange = httpClient.send(sessionRequest);
exchange.waitForComplete()
if (exchange.isSuccess()){
var responseObj = exchange.getResponse().content.asJSON;
if (responseObj.error){
request.content += JSON.stringify(responseObj);
}
}
Also, I have had success with using an AssignMessage policy to build a request, followed by a Callout policy to read the stored request and then make that request and store the result in a response object which can then be read by an Extract Variables policy.

Elixir: HTTPResponseStream to consume streaming API

I want to write a client which can consume streaming APIs. Essentially, have a getter that returns an HTTPResponseStream instead of HTTPResponse. I couldn't find one in HTTPotion, so I figured I'd give it a try instead. But I have no idea how to go about it, and would really appreciate some help!
You can do async requests with HTTPotion like so:
%HTTPotion.AsyncResponse{ id: id } = HTTPotion.get "http://example.com", [], [stream_to: self]
This will send messages of three different types to the current process (which is defined above via self):
# First, the response headers
%HTTPotion.AsyncHeaders{ id: ^id, status_code: 200, headers: _headers }
# Then, one or more chunks
%HTTPotion.AsyncChunk{ id: ^id, chunk: _chunk }
# And finally, an end message
%HTTPotion.AsyncEnd{ id: ^id }
The id can be used to handle the responses from multiple ongoing requests.

Resources