浏览代码

Added partially working proxy browser

Toby Chui 3 年之前
父节点
当前提交
b415d52ea3
共有 6 个文件被更改,包括 113 次插入20 次删除
  1. 11 8
      AGI Documentation.md
  2. 1 1
      mod/agi/agi.go
  3. 31 0
      mod/agi/agi.http.go
  4. 12 2
      web/Browser/functions/getHeader.js
  5. 43 2
      web/Browser/functions/proxy.js
  6. 15 7
      web/Browser/index.html

+ 11 - 8
AGI Documentation.md

@@ -492,12 +492,12 @@ For filelib.readdir, it will return an array with the following object structure
 
 
 ```go
 ```go
 type fileInfo struct {
 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
 ### appdata
 
 
 An API for access files inside the web folder. This API only provide read only functions. Include the appdata lib as follows.
 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
 }));    //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.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")
 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
 ### websocket

+ 1 - 1
mod/agi/agi.go

@@ -33,7 +33,7 @@ import (
 */
 */
 
 
 var (
 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
 	//AGI Internal Error Standard
 	exitcall  = errors.New("Exit")
 	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 {
 	vm.Set("_http_download", func(call otto.FunctionCall) otto.Value {
 		//Get URL from function paramter
 		//Get URL from function paramter
 		downloadURL, err := call.Argument(0).ToString()
 		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.head = _http_head;
 		http.download = _http_download;
 		http.download = _http_download;
 		http.getb64 = _http_getb64;
 		http.getb64 = _http_getb64;
+		http.getCode = _http_code;
 	`)
 	`)
 
 
 }
 }

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

@@ -4,8 +4,18 @@
 */
 */
 requirelib("http");
 requirelib("http");
 if (url == "" || typeof(url) == "undefined"){
 if (url == "" || typeof(url) == "undefined"){
-    sendResp(JSON.stringify(""));
+    sendResp(JSON.stringify({}));
 }else{
 }else{
     var header = http.head(url, "x-frame-options"); 
     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
 //Get the target webpage body
 requirelib("http");
 requirelib("http");
 var websiteContent = http.get(url);
 var websiteContent = http.get(url);
+var rootURL = url.split("/");
+rootURL.pop();
+rootURL = rootURL.join("/");
+
 
 
 //replace the relative path files with absolutes
 //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);
 sendResp(websiteContent);

+ 15 - 7
web/Browser/index.html

@@ -219,20 +219,25 @@
 				
 				
 
 
 				//Check if the website allow iframe
 				//Check if the website allow iframe
-				checkIfAllowIframing(targetURL, function(allowIframe){
+				checkIfAllowIframing(targetURL, function(allowIframe, redirectTarget){
 					if (allowIframe == null){
 					if (allowIframe == null){
 						$("#xframe").attr("src", "notfound.html#" + targetURL);
 						$("#xframe").attr("src", "notfound.html#" + targetURL);
 					}else{
 					}else{
 						if (allowIframe == true){
 						if (allowIframe == true){
+							$("#xframe").removeAttr("srcdoc");
 							$("#xframe").attr("src", targetURL);
 							$("#xframe").attr("src", targetURL);
 						}else{
 						}else{
 							proxyWebContent(targetURL, function(content){
 							proxyWebContent(targetURL, function(content){
 								$("#xframe").attr("src", "");
 								$("#xframe").attr("src", "");
-								$("#xframe").attr("srcdoc", content)
+								$("#xframe").attr("srcdoc", content);
 							
 							
 							});
 							});
 							//alert("Target website do not allow embedding");
 							//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", {
 				ao_module_agirun("Browser/functions/getHeader.js", {
 					url: url
 					url: url
 				}, function(data){
 				}, 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
 						//Site not exists
 						callback(null);
 						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
 						//This webpage do not allow iframeing
-						callback(false);
+						callback(false, location);
 					}else{
 					}else{
 						//This webpage allow iframing. Show it
 						//This webpage allow iframing. Show it
-						callback(true);
+						callback(true, location);
 					}
 					}
 				}, undefined, 5000)
 				}, undefined, 5000)
 			}
 			}