Render file to HTML with Firefox extension if Content-Type matches - browser-extension

I'm trying to define a new filetype for the web, which is rendered to HTML via a browser extension. What I would like to do is have the server return files in my filetype with the HTTP header "Content-Type: text/mytype". The extension will inspect the response headers, and if the content-type matches text/mytype, it will intercept the response body and replace it with the rendered HTML. This gives us a filetype that interacts nicely with the web if you have the plugin installed.
As a proof of concept, I created a plugin working which intercepts the headers and renders them into the response, but it only works if the content-type is text/html. If I change the response content type to text/mytype on the server, Firefox downloads the file, seemingly without running my extension code at all.
Is there a different event I should be listening to, in order to intercept/change headers before and run extension code instead of just downloading the file?
Here's my code:
manifest.json:
{
"description": "Altering HTTP responses",
"manifest_version": 2,
"name": "http-response-filter",
"version": "1.0",
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/http-response",
"icons": {
"48": "pen.svg"
},
"permissions": [
"webRequest", "webRequestBlocking", "<all_urls>"
],
"background": {
"scripts": ["background.js"]
},
"browser_specific_settings": {
"gecko": {
"strict_min_version": "57.0a1"
}
}
}
background.js:
var contentType;
function contentListener(details) {
//if(contentType === 'text/mytype') {
let filter = browser.webRequest.filterResponseData(details.requestId);
let decoder = new TextDecoder("utf-8");
let encoder = new TextEncoder();
filter.ondata = event => {
let str = decoder.decode(event.data, {stream: true});
// Later I want to replace this line with code that parses the
// document and renders it to HTML
str = str.replace(/Example/g, 'Content-Type: ' + contentType);
filter.write(encoder.encode(str));
filter.disconnect();
}
//}
return {};
}
browser.webRequest.onBeforeRequest.addListener(
contentListener,
{urls: ["<all_urls>"], types: ["main_frame"]},
["blocking"]
);
function headersListener(details) {
let headers = details.responseHeaders;
for(var i = 0; i < headers.length; i++) {
if(headers[i].name.toLowerCase() === 'content-type') {
contentType = headers[i].value;
// Try setting the content type to HTML to prevent downloading--
// doesn't work
headers[i].value = 'text/html; charset=utf-8';
}
}
browser.webRequest.onBeforeRequest.addListener(
contentListener,
{urls: ["<all_urls>"], types: ["main_frame"]},
["blocking"]
);
}
browser.webRequest.onHeadersReceived.addListener(
headersListener, {
urls: ["<all_urls>"],
types: ["main_frame"]
}, ["blocking", "responseHeaders"]
);

You may modify response headers only in onHeadersReceived handler.
If you can't execute onHeadersReceived for your file, then you can't change Content-Type header.
But anyway you could catch a url by content type with use documentUrl in onBeforeRequest handler, fetch data by url in background script and then open new window of your addon where you can render fetched content as you wish.
In this case page with content will have url like moz-extension://blah-blah-blah/pageRenderer.html#https://example.com/fileWithCustomType

Related

How to DRM Content in chromecast

we are trying to play drm MPD content from Chrome to Chromecast
Our receiver app code is as follow:
const context = cast.framework.CastReceiverContext.getInstance();
const playbackConfig = new cast.framework.PlaybackConfig();
playbackConfig.licenseUrl = 'http://widevine/yourLicenseServer';
playbackConfig.protectionSystem = cast.framework.ContentProtection.WIDEVINE;
playbackConfig.licenseRequestHandler = requestInfo => {
requestInfo.withCredentials = true;
};
context.start({playbackConfig: playbackConfig});
// Update playback config licenseUrl according to provided value in load request.
context.getPlayerManager().setMediaPlaybackInfoHandler((loadRequest, playbackConfig) => {
if (loadRequest.media.customData && loadRequest.media.customData.licenseUrl) {
playbackConfig.licenseUrl = loadRequest.media.customData.licenseUrl;
}
return playbackConfig;
});
I don't get a correct way to pass custom data for drm in the client application.
please help.
I think you are asking how you send the license URL from the sender client (the device 'casing') to the receiver (the device which will receive the request to cast and which actually get and plays the stream) in the custom data.
The custom data is a JSON object and you just need to put the license url into it.
There are two common ways of passing this custom data:
include it in the MediaInfo object using the MediaInfo.Builder.setCustomData method
include it the MediaLoadOptions data
As an example, looking at a MediaInfo example form the Google documents and adding in custom data:
List tracks = new ArrayList();
tracks.add(englishSubtitle);
tracks.add(frenchSubtitle);
tracks.add(frenchAudio);
MediaInfo mediaInfo = MediaInfo.Builder(url)
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setContentType(getContentType())
.setMetadata(getMetadata())
.setMediaTracks(tracks)
.setCustomData(yourCustomData) <--- This is the custom data
.build();
'yourCustomData' above is a JSON object which you create and add your data to, in your case your license server URL:
JSONObject yourCustomData = new JSONObject();
try {
yourCustomeData.put("licenseURL", "HTTPS://yourlicenseServerUrl.com");
} catch (JSONException e) {
// Add any error code you want here
e.printStackTrace();
}
please follow the code for js
new ChromecastJS().cast({
content: "xxxxxx",
contentType: "application/dash+xml",
poster: "xxxxxxx",
title: "xxxxx",
description: "xxxxx",
duration: "xxxx",
volume: 0.5,
muted: false,
paused: false,
time: "Xxxxx",
customData: {
drmHeaders: {
customdata: "xxxxxx",
},
drmLaUrl: "xxxx",
drmKsName: "com.widevine.alpha",
},
});

NativeScript Vue send request with form data (multipart/form-data)

I have a case in my application where I need to send data as form data to a server. The data includes a message and an optional list of files. The problem I'm facing is that when sending the request it's not being formed properly.
Request Payload
Expected (sample with the same request in the browser)
Actual (resulting request when running in NativeScript)
The actual result is that the payload is somehow being URL encoded.
Code example
sendData({ id, message, files }) {
const config = {
headers: {
'Content-Type': 'multipart/form-data'
}
};
const payload = new FormData();
payload.append('message', message);
if (files && files.length > 0) {
files.forEach((file) => {
payload.append(`files`, file, file.name);
});
}
return AXIOS_INSTANCE.post(
`/api/save/${id}`,
payload,
config
);
}
As you can see from the above, I'm using axios and also I'm trying to use FormData to format the data. From my research it seems that NativeScript used to not support binary data via XHR - however looking at this merge request on GitHub it looks like it's been fixed about a year ago.
So my suspicion is that I'm doing something wrong, maybe there's an alternative to using FormData, or else I shouldn't use axios for this particular request?
Version Numbers
nativescript 6.8.0
tns-android 6.5.3
tns-ios 6.5.3
Nativescript's background-http supports multipart form data.
See below for how its configured to do multipart upload
var bghttp = require("nativescript-background-http");
var session = bghttp.session("image-upload");
var request = {
url: url,
method: "POST",
headers: {
"Content-Type": "application/octet-stream"
},
description: "Uploading "
};
var params = [
{ name: "test", value: "value" },
{ name: "fileToUpload", filename: file, mimeType: "image/jpeg" }
];
var task = session.multipartUpload(params, request);

Displaying file in web page using AJAX and Spring Boot

I am building a REST API in Spring Boot for uploading and fetching file from the server, I want to upload various types of file that can either be text,image,audio,video,etc..
While uploading there is no problem, but when I want to display the file on my web page, on content is appearing, but I am getting the data from the server as a raw data.
I want to put that data into URL.createObjectURL() and then redirect to the URL which is generated.
There are some screenshots which I am uploading.
This is the data when I do console.log(response);
The code which I am using for AJAX
var form = new FormData();
form.append("qualifiedFilePath", "E://files/test.png");
var settings = {
"async": true,
"crossDomain": true,
"url": "http://localhost:8081/callTransaction/file",
"method": "POST",
"timeout": 0,
"processData": false,
"mimeType": "multipart/form-data",
"contentType": false,
"Accept": "image/png",
"data": form
};
$.ajax(settings).done(function(response) {
console.log(response);
const objectURL = URL.createObjectURL(new Blob([response], {
"type": "image/png"
}));
console.log(objectURL);
});
I get the URL:
blob:http://localhost:8080/81c9fbde-5e84-400e-8d92-5da6fc02c7ef
Output:
The Source Code in Spring Boot:
Controller:
#PostMapping(path="/file")
#CrossOrigin(origins = "http://localhost:8080")
public ResponseEntity<Resource> loadFile(#RequestPart("qualifiedFilePath") String qualifiedFilePath, HttpServletRequest request)
{
return ctbl.loadFile(qualifiedFilePath,request);
}
BusinessLogic:
public ResponseEntity<Resource> loadFile(String qualifiedFilePath, HttpServletRequest request)
{
Resource file=null;
if(qualifiedFilePath==null)
{
return new ResponseEntity<Resource>(file,HttpStatus.BAD_REQUEST);
}
try {
file=ctdi.loadFile(qualifiedFilePath);
} catch (MalformedURLException e) {
return new ResponseEntity<Resource>(file,HttpStatus.INTERNAL_SERVER_ERROR);
}
if(file==null)
{
return new ResponseEntity<Resource>(file,HttpStatus.NO_CONTENT);
}
String contentType = null;
try {
contentType = request.getServletContext().getMimeType(file.getFile().getAbsolutePath());
} catch (IOException ex) {
return new ResponseEntity<Resource>(file,HttpStatus.INTERNAL_SERVER_ERROR);
}
if(contentType == null) {
contentType = "application/octet-stream";
}
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"")
.body(file);
}
DAO:
#Override
public Resource loadFile(String qualifiedFilePath) throws MalformedURLException {
Path filePath = Paths.get(qualifiedFilePath);
Resource resource = new UrlResource(filePath.toUri());
return resource;
}
It has been a long time to answer since the question was posted, but the solution to it has been discovered.
It has a very simple solution.
I used the program logic from the CalliCoder webiste[the link is attached below], by using this I was able to store files, view files and download them too, they have given a very nice explanation of the program and how to do it.
By using this we can make a URL(endpoint) by which we can access the file we are approaching for, they too have given an example for accessing the file.
They have made a web-based front-end in which they are trying to upload files, but the module for displaying the file/downloading the file in front-end is missing.
Yes, We can just copy the URL(endpoint) in the browser and it starts displaying/playing the file.
If we want to use URL.createObjectURL() for making a temporary and local URL for the same source, then we can do like this:
URL.createObjectURL(await fetch("URL(endpoint)").then(r => r.blob()));
This example is taken from Stackoverflow[The link is attached bellow]
References:
CalliCoder
StackOverflow

react can't get restController response

I have tried to use restController generate file byte array but when i return it to react , react didn't get the byte array. front-end is using react , back-end is using spring restController and i use Http to communication both front and back. is it any wrong in my code? Thank you for your helping.
restController:
String fileName = DateUtility.dateToStr(new Date(), DateUtility.YYYYMMDD_HHMMSS) + " - "
+ reportNmaeByType.get(exportParam.getReportType()) + ".xls";
HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData("attachment", fileName);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<>(excelByte, HttpStatus.OK);
react:
createExcelFile(){
var params = {
reportResultList: this.state.reportResult,
reportType: getReportSelector().state.selectedReportType,
selectColumnMap: this.state.selectColumn,
selectCusColumnMap: this.state.selectCusColumn
}
fetch("http://localhost:8080/mark-web/file/createExcel", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params)
}).then(res => {
if (res.ok) {
console.log(res)
console.log(this)
console.log('create excel success!!')
} else {
console.log('create excel Fail!!')
}
})
}
response:
enter image description here
Update 2018/09/16:
I have added some code in react function and it finally could download excel file but the file is broken. i have checked the blob object in response. it shows blob is json object. is it because i didn't decode to the blob object?
React:
}).then(res => {
if(!res.ok){
console.log("Failed To Download File")
}else{
return res.blob()
}
}).then(blob => {
console.log(blob)
let url = URL.createObjectURL(blob)
console.log(url)
var downloadAnchorNode = document.createElement('a')
downloadAnchorNode.setAttribute("href", url)
downloadAnchorNode.setAttribute("download", "excel" + ".xls")
downloadAnchorNode.click()
downloadAnchorNode.remove()
})
response:
enter image description here
So, from your network graph, it looks like your request is completing as expected, but you are just unable to derive the ByteArray from the response.
With normal requests which return a JSON or XML for e.x. you can read them in one go, as they are part of the body. In your case however, your body contains a Stream. You will thus have to handle reading that stream on your own.
You can do that with response.blob() :
The blob() method reads the stream to completion and returns a Blob object. You can then use this blob object to embed an image or download the file. For all intent and purposes, I would recommend using this. Unless you are dealing with huge files (>500 MB), it should suffice your needs.
For example:
fetch("http://localhost:8080/mark-web/file/createExcel", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params)
}).then(res => {
if (!res.ok) {
throw new Error(res.statusText);
} else {
return res.blob()
}
}).then(blob => {// do your thing})
.catch(err => console.log(error))
Or
You can use the experimental ReadableStream interface for a more granular control over what you want to do with it.

Read SSL Certificates in a Firefox Extension

I am working on a Firefox extension that would display the SSL certificate information to the user. The actual information would be the same as the one built in to the browser, but I will be experimenting with layouts and other information for UX.
I've been working with Firefox extensions instead of add ons due to deprecation of add-ons in 2017, but this project will be finished before then.
I was trying the example found here, but the extension seems to stop on the require("chrome").
Next I tried writing simpler code to figure out how the example works, but this code doesn't have a channel attached to the request. My code, minus all sorts of printing statements, is below:
document.getElementById("click_button").addEventListener("click",
function(e) {
var url = "https://secure-website-example.google.com";
xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.addEventListener("error",
function(e) {
dumpSecurityInfo(xhr, -1);
}, false);
xhr.onload = function(e) {
dumpSecurityInfo(xhr);
};
xhr.send();
});
function dumpSecurityInfo(xhr, error) {
var channel = xhr.channel;
try {
console.log("Connection status:");
if (!error) { console.log("Succeeded"); }
else { console.log("Failed :("); }
var securityInfo = channel.securityInfo;
} catch(err) {
alert(err);
}
}
with a manifest like this:
"manifest_version": 2,
"name": "Certificate Browser",
"version": "1.0",
...
"permissions": [
"activeTab",
"webRequest",
"https://secure-website-example.google.com/*"
],
"browser_action": {
...
"default_popup": "popup/certificate_information.html"
}
Am I missing any permissions necessary to have access to the certificate? Is there a better way of grabbing certificate information?
The wiki page you linked to refers to APIs available in the addon sdk and bootstrapped extensions. The kind of manifest indicates you're writing a webextensions which are far more limited.

Resources