Răsfoiți Sursa

Added partially working proxy browser

Toby Chui 3 ani în urmă
părinte
comite
b415d52ea3

+ 11 - 8
AGI Documentation.md

@@ -492,12 +492,12 @@ For filelib.readdir, it will return an array with the following object structure
 
 ```go
 type fileInfo struct {
-	Filename string
-	Filepath string
-	Ext      string
-	Filesize int64
-	Modtime  int64
-	IsDir    bool
+    Filename string
+    Filepath string
+    Ext      string
+    Filesize int64
+    Modtime  int64
+    IsDir    bool
 }
 ```
 
@@ -532,8 +532,6 @@ Example return value (in JSON object, not stringify JSON string)
 ]
 ```
 
-
-
 ### appdata
 
 An API for access files inside the web folder. This API only provide read only functions. Include the appdata lib as follows.
@@ -640,6 +638,11 @@ http.post("http://localhost:8080/system/file_system/listDir", JSON.stringify({
 }));    //Create a POST request with JSON payload
 http.head("http://localhost:8080/", "Content-Type"); //Get the header field "Content-Type" from the requested url, leave 2nd paramter empty to return the whole header in JSON string
 http.download("http://example.com/music.mp3", "user:/Desktop", "(Optional) My Music.mp3")
+
+
+//Since agi v2.0
+http.getb64("http://example.com/photo.png"); //Get target resources as base64 bytes, return null if error
+http.getCode("http://redirect.example.com"); //Get response code for the target endpoint,if the code is redirection related (e.g. 302), a new varaible "_location" will be created to store the redirection address in String.
 ```
 
 ### websocket

+ 1 - 1
mod/agi/agi.go

@@ -33,7 +33,7 @@ import (
 */
 
 var (
-	AgiVersion string = "1.7" //Defination of the agi runtime version. Update this when new function is added
+	AgiVersion string = "2.0" //Defination of the agi runtime version. Update this when new function is added
 
 	//AGI Internal Error Standard
 	exitcall  = errors.New("Exit")

+ 31 - 0
mod/agi/agi.http.go

@@ -132,6 +132,36 @@ func (g *Gateway) injectHTTPFunctions(vm *otto.Otto, u *user.User) {
 
 	})
 
+	//Get target status code for response
+	vm.Set("_http_code", func(call otto.FunctionCall) otto.Value {
+		//Get URL from function paramter
+		url, err := call.Argument(0).ToString()
+		if err != nil {
+			return otto.FalseValue()
+		}
+
+		req, err := http.NewRequest("GET", url, nil)
+		if err != nil {
+			g.raiseError(err)
+			return otto.FalseValue()
+		}
+
+		payload := ""
+		client := new(http.Client)
+		client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
+			//Redirection. Return the target location as well
+			dest, _ := req.Response.Location()
+			payload = dest.String()
+			return errors.New("Redirect")
+		}
+
+		response, _ := client.Do(req)
+		vm.Run(`var _location = "` + payload + `";`)
+		value, _ := otto.ToValue(response.StatusCode)
+		return value
+
+	})
+
 	vm.Set("_http_download", func(call otto.FunctionCall) otto.Value {
 		//Get URL from function paramter
 		downloadURL, err := call.Argument(0).ToString()
@@ -223,6 +253,7 @@ func (g *Gateway) injectHTTPFunctions(vm *otto.Otto, u *user.User) {
 		http.head = _http_head;
 		http.download = _http_download;
 		http.getb64 = _http_getb64;
+		http.getCode = _http_code;
 	`)
 
 }

+ 12 - 2
web/Browser/functions/getHeader.js

@@ -4,8 +4,18 @@
 */
 requirelib("http");
 if (url == "" || typeof(url) == "undefined"){
-    sendResp(JSON.stringify(""));
+    sendResp(JSON.stringify({}));
 }else{
     var header = http.head(url, "x-frame-options"); 
-    sendResp(header);
+    var code = http.getCode(url);
+    var redest = "";
+    if (typeof(_location) != "undefined"){
+        redest = _location;
+    }
+    var result = JSON.stringify({
+        "header": JSON.parse(header),
+        "code": code,
+        "location": redest,
+    })
+    sendResp(result);
 }

+ 43 - 2
web/Browser/functions/proxy.js

@@ -6,8 +6,49 @@
 //Get the target webpage body
 requirelib("http");
 var websiteContent = http.get(url);
+var rootURL = url.split("/");
+rootURL.pop();
+rootURL = rootURL.join("/");
+
 
 //replace the relative path files with absolutes
-websiteContent = websiteContent.split('src="/').join('src="' + url + '/');
-websiteContent = websiteContent.split('href="/').join('href="' + url + '/');
+websiteContent = websiteContent.split('src="/').join('src="' + rootURL + '/');
+websiteContent = websiteContent.split('href="/').join('href="' + rootURL + '/');
+
+//Replace href with redirection code
+var htmlSegmentChunks = websiteContent.split(" ");
+var chunksToBeReplaced = [];
+for (var i = 0; i < htmlSegmentChunks.length; i++){
+    var thisSegment = htmlSegmentChunks[i].trim();
+    if (thisSegment.substring(0, 5) == "href="){
+        //Process the segment and trim out only the href="xxx" part
+        var cutPosition = thisSegment.lastIndexOf('"');
+        thisSegment = thisSegment.substring(0, cutPosition + 1)
+        if (thisSegment.trim().length > 6){
+            chunksToBeReplaced.push(thisSegment);
+            //console.log("SEGMENT:", thisSegment, thisSegment.trim().length);
+        }
+    }
+}
+
+for (var k= 0; k < chunksToBeReplaced.length; k++){
+    var thisSegment = chunksToBeReplaced[k];
+    thisSegment = thisSegment.replace('href="', "parent.loadWebsite(\"")
+    thisSegment = thisSegment + ");"
+    thisSegment = thisSegment.split("\"").join("'");
+    thisSegment = "onclick=\"" + thisSegment + "\"";
+    
+
+    //Check if this is css / style files. If yes, bypass it
+    var expectedFileExtension = thisSegment.trim().substring(thisSegment.lastIndexOf("."), thisSegment.length -4);
+    if (expectedFileExtension == ".css" || expectedFileExtension == ".js" || thisSegment.indexOf(".css") >= 0){
+        continue;
+    }
+    //console.log("REPLACING", chunksToBeReplaced[k], thisSegment);
+    websiteContent = websiteContent.replace(chunksToBeReplaced[k], thisSegment);
+}
+
+
+
+//console.log(websiteContent);
 sendResp(websiteContent);

+ 15 - 7
web/Browser/index.html

@@ -219,20 +219,25 @@
 				
 
 				//Check if the website allow iframe
-				checkIfAllowIframing(targetURL, function(allowIframe){
+				checkIfAllowIframing(targetURL, function(allowIframe, redirectTarget){
 					if (allowIframe == null){
 						$("#xframe").attr("src", "notfound.html#" + targetURL);
 					}else{
 						if (allowIframe == true){
+							$("#xframe").removeAttr("srcdoc");
 							$("#xframe").attr("src", targetURL);
 						}else{
 							proxyWebContent(targetURL, function(content){
 								$("#xframe").attr("src", "");
-								$("#xframe").attr("srcdoc", content)
+								$("#xframe").attr("srcdoc", content);
 							
 							});
 							//alert("Target website do not allow embedding");
 						}
+
+						if (redirectTarget != undefined && redirectTarget != ""){
+							$("#urlText").val(redirectTarget);
+						}
 					}
 				
 				});
@@ -252,18 +257,21 @@
 				ao_module_agirun("Browser/functions/getHeader.js", {
 					url: url
 				}, function(data){
-					if (data == "null"){
+					let xFrameOptions = JSON.parse(data);
+					let header = xFrameOptions.header.toLowerCase().trim();
+					let location = xFrameOptions.location;
+					if (header == "null"){
 						//Site not exists
 						callback(null);
 					}
-					let xFrameOptions = JSON.parse(data).toLowerCase().trim();
 					
-					if (xFrameOptions == "sameorigin" || xFrameOptions == "deny"){
+					
+					if (xFrameOptions.header == "sameorigin" || xFrameOptions.header == "deny"){
 						//This webpage do not allow iframeing
-						callback(false);
+						callback(false, location);
 					}else{
 						//This webpage allow iframing. Show it
-						callback(true);
+						callback(true, location);
 					}
 				}, undefined, 5000)
 			}